diff --git a/.devenv/load-exports b/.devenv/load-exports
new file mode 100755
index 00000000000..8b137891791
--- /dev/null
+++ b/.devenv/load-exports
@@ -0,0 +1 @@
+
diff --git a/.devenv/profile b/.devenv/profile
new file mode 120000
index 00000000000..fec948cda21
--- /dev/null
+++ b/.devenv/profile
@@ -0,0 +1 @@
+/nix/store/135785cwm28w1066rzgg1hf17cmxx6d4-devenv-profile
\ No newline at end of file
diff --git a/.devenv/run b/.devenv/run
new file mode 120000
index 00000000000..6ddbc93244f
--- /dev/null
+++ b/.devenv/run
@@ -0,0 +1 @@
+/run/user/1000/devenv-b212af5
\ No newline at end of file
diff --git a/.devenv/state/files.json b/.devenv/state/files.json
new file mode 100644
index 00000000000..b4c7443fe86
--- /dev/null
+++ b/.devenv/state/files.json
@@ -0,0 +1 @@
+{"managedFiles":[]}
diff --git a/.devenv/tasks.db b/.devenv/tasks.db
new file mode 100644
index 00000000000..a56fa3ecc46
Binary files /dev/null and b/.devenv/tasks.db differ
diff --git a/.direnv/flake-profile b/.direnv/flake-profile
new file mode 120000
index 00000000000..e2890795fb1
--- /dev/null
+++ b/.direnv/flake-profile
@@ -0,0 +1 @@
+flake-profile-4-link
\ No newline at end of file
diff --git a/.direnv/flake-profile-4-link b/.direnv/flake-profile-4-link
new file mode 120000
index 00000000000..b913bd1efce
--- /dev/null
+++ b/.direnv/flake-profile-4-link
@@ -0,0 +1 @@
+/nix/store/xcy1202wmq5a6c3nkbzq236g1zfg7aj1-devenv-shell-env
\ No newline at end of file
diff --git a/all_bnd.txt b/all_bnd.txt
new file mode 100644
index 00000000000..0783282d54e
--- /dev/null
+++ b/all_bnd.txt
@@ -0,0 +1,3575 @@
+Bundle-Name: OpenEMS Edge Electric Vehicle Supply Equipment (EVSE) 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.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Heat Askoma
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.heat.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller IO Heating Element
+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.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Api Modbus/TCP
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.api.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+ io.openems.wrapper.fastexcel,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Input/Output 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Battery 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Grid Optimized 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.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.ess.ripplecontrolreceiver,\
+ 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},\
+ io.openems.edge.evcs.api,\
+ org.apache.commons.math3,\
+Bundle-Name: OpenEMS Backend Metadata File
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Timedata Aggregated InfluxDB
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.shared.influxdb,\
+ io.openems.wrapper.influxdb-client-core,\
+ io.openems.wrapper.influxdb-client-java,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Bridge OneWire
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+Export-Package: \
+ com.dalsemi.onewire,\
+ com.dalsemi.onewire.adapter,\
+ com.dalsemi.onewire.application.file,\
+ com.dalsemi.onewire.application.monitor,\
+ com.dalsemi.onewire.application.sha,\
+ com.dalsemi.onewire.application.tag,\
+ com.dalsemi.onewire.container,\
+ com.dalsemi.onewire.debug,\
+ com.dalsemi.onewire.utils,\
+ io.openems.edge.bridge.onewire
+
+-privatepackage: \
+ io.openems.edge.bridge.onewire.impl,\
+ io.openems.edge.bridge.onewire.jsonrpc
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVCS Webasto Unite
+Bundle-Vendor: Consolinno Energy 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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Ess Active Power Voltage Characteristics
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge FENECON Pro 9-12
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Core
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.fazecast.jSerialComm,\
+ com.squareup.okhttp3,\
+ io.openems.common,\
+ io.openems.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.api.backend,\
+ io.openems.edge.energy.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.meter.api,\
+ 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.sdnotify,\
+ javax.jmdns,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.wrapper.fastexcel,\
+ io.openems.wrapper.opczip,\
+Bundle-Name: OpenEMS Edge IO Weidmüller Fieldbus Coupler UR20
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge SolarEdge
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.j2mod,\
+Bundle-Name: OpenEMS Edge EVCS Mennekes Amtron Professional
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Asymmetric Peakshaving
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Predictor Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+Bundle-Description: \
+ This bundle contains the Predictor API. It provides abstract access to prediction of production and consumption.
+
+-buildpath: \
+ ${buildpath},\
+ com.google.protobuf,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.wrapper.olcut,\
+ io.openems.wrapper.tribuo,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath},\Bundle-Name: OpenEMS Edge Time-Of-Use Tariff Swisspower
+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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}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}Bundle-Name: OpenEMS Edge PV Inverter KACO blueplanet
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.j2mod,\
+Bundle-Name: OpenEMS Edge Edge-2-Edge
+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.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Predictor Profile Clustering Model
+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.timedata.api,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge Controller ESS AC-Island
+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.ess.api,\
+ io.openems.edge.io.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Camillebauer Aplus
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller IO Heating Room
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.thermometer.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Scheduler Fixed-Order
+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.scheduler.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Simulator
+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.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Alerting
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend-to-Backend REST-Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.authentication.api,\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+ org.apache.felix.http.jetty12,\
+ org.apache.felix.http.servlet-api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Battery Pylontech
+Bundle-Vendor: RVR Energy Technology Ltd.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS 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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS Refu88K
+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.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Time-Of-Use Ancillary Costs
+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.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller IO SG-Ready Heat Pump
+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.io.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Hybrid Surplus-Feed-To-Grid
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Api REST/JSON
+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.api.common,\
+ io.openems.edge.timedata.api,\
+ org.apache.felix.http.jetty12,\
+ org.apache.felix.http.servlet-api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.common.bridge.http,\
+Bundle-Name: Katek EDCOM Library
+Bundle-Vendor: Katek Memmingen GmbH, FENECON GmbH
+Bundle-License: https://opensource.org/licenses/LGPL-3.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ javax.jmdns,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Edge-Manager
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+Bundle-Description: Manager for connections from Backend Edge Applications
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.backend.metrics.prometheus,\
+ io.openems.backend.oauthregistry,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+ io.prometheus.metrics-config,\
+ io.prometheus.metrics-core,\
+ io.prometheus.metrics-exporter-common,\
+ io.prometheus.metrics-exporter-httpserver,\
+ io.prometheus.metrics-exposition-formats,\
+ io.prometheus.metrics-instrumentation-jvm,\
+ io.prometheus.metrics-model,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter ABB
+Bundle-Vendor: Consolinno Energy 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.mbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Authentication Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge FENECON Mini
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller API Common
+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.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Bosch BPT-S 5 Hybrid
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ org.eclipse.jetty.client,\
+ org.eclipse.jetty.http,\
+ org.eclipse.jetty.util,\
+ org.jsoup,\
+
+-testpath: \
+ ${testpath},\
+ org.eclipse.jetty.client,\
+ org.eclipse.jetty.http,\
+ org.eclipse.jetty.util,\
+ org.eclipse.jetty.io,\
+Bundle-Name: OpenEMS Edge Controller Debug DetailedLog
+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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Bridge M-Bus
+Bundle-Vendor: Consolinno Energy 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,\
+ org.openmuc.jmbus;version=3.3.0,\
+ org.openmuc.jrxtx;version=1.0,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Battery FENECON Home
+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.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.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Symmetric Timeslot-Peakshaving
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Asymmetric Phase-Rectification
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Predictor Persistence-Model
+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.timedata.api,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath}
+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.ess.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.predictor.api,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge Controller Ess Linear Power Band
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Common
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Time-Of-Use Tariff Corrently by STROMDAO
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVSE Charge-Point KEBA KeContact
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge GoodweET
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Vendor: FENECON GmbH
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.fazecast.jSerialComm,\
+ io.openems.common,\
+ io.openems.edge.battery.api,\
+ io.openems.edge.battery.fenecon.home,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.ess.ripplecontrolreceiver,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.ess.generic,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Bgetech
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Metadata Dummy
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Shared InfluxDB
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ io.openems.common,\
+ io.openems.wrapper.influxdb-client-core,\
+ io.openems.wrapper.influxdb-client-java,\
+ io.openems.wrapper.influxdb-flux-dsl,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.wrapper.influxdb-client-utils,\
+
+Bundle-Name: OpenEMS Edge Controller Api Websocket
+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.controller.api.common,\
+ io.openems.edge.timedata.api,\
+ org.ops4j.pax.logging.pax-logging-api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge IO WAGO Fieldbus Coupler
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Siemens
+Bundle-Description: This implementation covers Siemens PAC1600/PAC2200/PAC3200/PAC4200
+Bundle-Vendor: Ernst KNOLL Feinmechanik GmbH (PAC2200/PAC3200/PAC4200) / Universität Bayreuth Lehrstuhl Elektrische Energiesysteme (PAC1600)
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+
+Bundle-Name: OpenEMS Edge Meter Weidmueller 525
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Heat MyPv
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.heat.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVCS OpenWB
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.mqtt,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Tesla Powerwall 2
+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.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Time-Of-Use Tariff Awattar
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Electric Vehicle Charging Station
+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.evcs.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Backend Simulator
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller PV-Inverter Sell-to-Grid Limit
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Heat Api
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge SMA
+Bundle-Vendor: FENECON GmbH; OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Timedata 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge BYD Battery-Box Commercial
+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.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Backend Edge-Application
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+Bundle-Description: Proxy between OpenEMS Edges and OpenEMS Backend
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.backend.metrics.prometheus,\
+ io.openems.backend.oauthregistry,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+ io.prometheus.metrics-core,\
+ io.prometheus.metrics-model,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge Bridge Http
+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.common.bridge.http,\
+ io.openems.edge.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Asymmetric Fix-ReactivePower
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Weather Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okio,\
+ io.openems.common,\
+ io.openems.edge.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge PV Inverter Solar Log
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Hager
+Bundle-Vendor:
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller IOAlarm
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Vendor: FENECON GmbH
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.io.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Common
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller IO Channel Single Threshold
+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.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge PV-Inverter Cluster
+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.meter.api,\
+ io.openems.edge.pvinverter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Virtual Add
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Symmetric Peak-Shaving
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller for Ripple Control Receiver
+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.timedata.api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.edge.io.api,\
+Bundle-Name: OpenEMS Edge Controller Symmetric Balancing Schedule
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS Core
+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.ess.api,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge BMW Battery
+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.common.bridge.http,\
+ io.openems.edge.battery.api,\
+ io.openems.edge.bridge.http,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Thermometer Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+Bundle-Description:\
+ A Thermometer measures temperature.
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge System FENECON
+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.battery.api,\
+ io.openems.edge.battery.bmw,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.batteryinverter.refu88k,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.api.backend,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller IO FixDigitalOutput
+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.io.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Limit Total Discharge
+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.energy.api,\
+ io.openems.edge.ess.api,\
+
+-testpath: \
+ ${testpath},\
+ org.apache.commons.math3,\
+Bundle-Name: OpenEMS Edge Time-Of-Use ENTSO-E
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ com.squareup.okio,\
+ io.openems.common,\
+ io.openems.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ org.jetbrains.kotlin.osgi-bundle,\
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller PV-Inverter Fix-Power-Limit
+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.meter.api,\
+ io.openems.edge.pvinverter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller CHP SOC
+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.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Cluster
+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.ess.api,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Time-Of-Use Manual (Octopus Go/Heat)
+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.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge
+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.wrapper.sdnotify,\
+
+-testpath: \
+ ${testpath}
+ Bundle-Name: OpenEMS Edge ABL eM4
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Energy
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+# TODO remove emergencycapacityreserve, limittotaldischarge and limiter14a 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.limiter14a,\
+ 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},\
+ io.openems.edge.controller.ess.emergencycapacityreserve,\
+ io.openems.edge.controller.ess.fixactivepower,\
+ io.openems.edge.controller.ess.gridoptimizedcharge,\
+ io.openems.edge.controller.ess.limittotaldischarge,\
+ io.openems.edge.controller.ess.timeofusetariff,\
+ io.openems.edge.controller.evse,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+Bundle-Name: OpenEMS Edge Meter PQ Plus
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge IO Filipowski
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge IO Off Grid Switch
+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.ess.api,\
+ io.openems.edge.io.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Go-e Charger Home
+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.evcs.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend OAuth registry for edges to use
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.common.bridge.http,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Phoenix Contact
+Bundle-Description: This implementation covers Phoenix Contact meter EEM-MA370-24DC and EEM-MB370-24DC
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Battery-Inverter KACO blueplanet gridsave
+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.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.j2mod,\Bundle-Name: OpenEMS Edge ESS Sinexcel
+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.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVSE Charge-Point Hardy Barth
+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.common.bridge.http,\
+ io.openems.edge.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Emergency Capacity Reserve
+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.energy.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.ess.generic,\
+
+-testpath: \
+ ${testpath},\
+ org.apache.commons.math3,\
+Bundle-Name: OpenEMS Edge Scheduler Daily
+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.scheduler.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Wrapper
+Bundle-Description: This wraps external java libraries that do not have OSGi headers
+
+-sub: *.bnd
+-buildpath: \
+ com.github.rzymek:opczip;version='1.2.0',\
+ com.google.gson;version='2.13.2',\
+ com.influxdb:flux-dsl;version='7.5.0',\
+ com.influxdb:influxdb-client-core;version='7.5.0',\
+ com.influxdb:influxdb-client-java;version='7.5.0',\
+ com.influxdb:influxdb-client-utils;version='7.5.0',\
+ com.oracle.labs.olcut:olcut-config-protobuf;version='5.3',\
+ com.oracle.labs.olcut:olcut-core;version='5.3',\
+ com.squareup.okhttp3;version='5.3',\
+ com.squareup.retrofit2:adapter-rxjava3;version='3.0.0',\
+ com.squareup.retrofit2:converter-gson;version='3.0.0',\
+ com.squareup.retrofit2:converter-scalars;version='3.0.0',\
+ com.squareup.retrofit2:retrofit;version='3.0.0',\
+ com.sun.activation.javax.activation;version='1.2.0',\
+ de.bytefish:pgbulkinsert;version='8.1.6',\
+ de.bytefish:pgbulkinsert;version='8.1.8',\
+ eu.chargetime.ocpp:common;version='1.0.2',\
+ eu.chargetime.ocpp:OCPP-J;version='1.0.2',\
+ eu.chargetime.ocpp:v1_6;version='1.1.0',\
+ fr.turri:aXMLRPC;version='1.17.0',\
+ info.faljse:SDNotify;version='1.5.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='8.3.0',\
+ io.reactivex.rxjava3.rxjava;version='3.1.8',\
+ org.dhatim:fastexcel-reader;version='0.18.4',\
+ org.dhatim:fastexcel;version='0.18.4',\
+ org.eclipse.paho.mqttv5.client;version='1.2.5',\
+ org.java-websocket:Java-WebSocket;version='1.5.7',\
+ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.9.0',\
+ com.auth0:auth0;version='3.0.0',\
+ com.auth0:java-jwt;version='4.5.0',\
+ com.auth0:jwks-rsa;version='0.23.0',\
+ org.tribuo:tribuo-common-tree;version='4.3.2',\
+ org.tribuo:tribuo-core;version='4.3.2',\
+ org.tribuo:tribuo-data;version='4.3.2',\
+ org.tribuo:tribuo-math;version='4.3.2',\
+ org.tribuo:tribuo-regression-core;version='4.3.2',\
+ org.tribuo:tribuo-regression-tree;version='4.3.2',\
+ org.tribuo:tribuo-util-onnx;version='4.3.2',\
+ org.tribuo:tribuo-util-tokenization;version='4.3.2',\
+Bundle-Name: OpenEMS Edge Controller Ess Minimum Discharge Period
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.google.gson,\
+ com.google.guava,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS Cluster
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Symmetric Fix-ActivePower
+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.energy.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath},\
+ org.apache.commons.math3,\
+Bundle-Name: OpenEMS Edge Controller Generic JsonLogic
+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.ess.api,\
+ io.openems.edge.io.api
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Api MQTT
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ bcpkix;version='1.78.1',\
+ bcprov;version='1.78.1',\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.api.common,\
+ io.openems.edge.timedata.api,\
+ io.openems.wrapper.paho-mqttv5,\
+ org.eclipse.paho.mqttv5.client;version='1.2',\
+ org.ops4j.pax.logging.pax-logging-api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller ChannelThreshold
+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.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Ziehl EFR4001IP
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Scheduler All-Alphabetically
+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.scheduler.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS OCPP Server
+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.evcs.api,\
+ io.openems.edge.evcs.ocpp.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.wrapper.eu.chargetime.ocpp,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Sell-To-Grid Limit
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Battery-Inverter 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.battery.api,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Schneider Electric Acti9 Smartlink SI D
+Bundle-Vendor: FE-Partner AG
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Ess Fix State Of 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.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Core
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+Bundle-Description: Supportive services that are used throughout OpenEMS Backend
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Soltaro Battery
+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.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Predictor LSTM
+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.timedata.api,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Artemes AM-2
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Time-Of-Use LUOX
+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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ org.jetbrains.kotlin.osgi-bundle,\
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Carlo Gavazzi EM300
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge IO GPIO
+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.io.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Time-Of-Use Tariff EWS Schönau
+Bundle-Vendor: Pascal Bockhorn - Bockhorn.IT
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge IO KMtronic
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Backend-to-Backend Websocket
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.authentication.api,\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller ESS Standby
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge PV Inverter Fronius
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge FENECON DESS (PRO Hybrid, PRO Compact)
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Symmetric Limit ActivePower
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Reactive Power Voltage Characteristics
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Asymmetric Cos-Phi
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller SoH Cycle
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge io.openems.edge.ess.generic
+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.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge IO Shelly
+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.common.bridge.http,\
+ io.openems.edge.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller IO Analog
+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.io.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Odoo Impl
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.zaxxer.HikariCP,\
+ io.openems.backend.authentication.api,\
+ io.openems.backend.common,\
+ io.openems.backend.metrics.prometheus,\
+ io.openems.common,\
+ io.openems.wrapper.aXMLRPC,\
+ io.prometheus.metrics-core,\
+ io.prometheus.metrics-model,\
+ org.postgresql.jdbc, \
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge PV-Inverter 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.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Scheduler 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS OEM Bundle
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.battery.fenecon.home,\
+ io.openems.edge.common,\
+ io.openems.edge.goodwe,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Bridge MQTT
+Bundle-Vendor: Consolinno Energy GmbH, OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ bcpkix;version='1.78.1',\
+ bcprov;version='1.78.1',\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.wrapper.paho-mqttv5,\
+ org.eclipse.paho.client.mqttv3;version='1.2',\
+ org.eclipse.paho.mqttv5.client;version='1.2',\
+
+-testpath: \
+ ${testpath}
+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},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.edge.io.api,\
+Bundle-Name: OpenEMS Edge Controller Symmetric Fix-ReactivePower
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Core
+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.ess.core,\
+ io.openems.edge.evcs.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Predictor Similarday-Model
+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.timedata.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Timedata InfluxDB
+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.timedata.api,\
+ io.openems.shared.influxdb,\
+ io.openems.wrapper.influxdb-client-core,\
+ io.openems.wrapper.influxdb-client-java,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.wrapper.influxdb-client-utils,\
+ org.jetbrains.kotlin.osgi-bundle,\
+ com.squareup.okhttp3,\
+ com.squareup.okio,\
+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)
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Debug Log
+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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Heidelberg
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVCS OCPP Ies KeyWatt for CCS Charger
+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.evcs.api,\
+ io.openems.edge.evcs.ocpp.common,\
+ io.openems.edge.evcs.ocpp.server,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.wrapper.eu.chargetime.ocpp,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVSE Electric-Vehicle Generic
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.evse.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Go-e Gemini
+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.common.bridge.http,\
+ io.openems.edge.bridge.http,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Spelsberg SMART
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Ess Time-Of-Use Tariff
+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,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.ess.emergencycapacityreserve,\
+ io.openems.edge.controller.ess.limiter14a,\
+ io.openems.edge.controller.ess.limittotaldischarge,\
+ io.openems.edge.energy.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.edge.timeofusetariff.api,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge Meter SOCOMEC
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Microgrid Supervisor
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.io.api,\
+ io.openems.edge.ess.api
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS OCPP implementation of ABL
+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.evcs.api,\
+ io.openems.edge.evcs.ocpp.common,\
+ io.openems.edge.evcs.ocpp.server,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.wrapper.eu.chargetime.ocpp,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Battery FENECON Commercial
+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.battery.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVSE Charge-Point Heidelberg
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Delay 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.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Weather Open-Meteo
+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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.weather.api,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Edge Time-Of-Use Tariff API
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ com.squareup.okio,\
+ io.openems.common,\
+ io.openems.edge.common,\
+
+-testpath: \
+ org.jetbrains.kotlin.osgi-bundle,\
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Symmetric Random
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge KACO blueplanet hybrid 10.0 TL3
+Bundle-Vendor: KACO new energy GmbH, 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.ess.api,\
+ io.openems.edge.katek.edcom,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+ javax.jmdns,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Predictor Production Linear Model
+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.predictor.api,\
+ io.openems.edge.predictor.persistencemodel,\
+ io.openems.edge.timedata.api,\
+ io.openems.edge.weather.api,\
+ io.openems.wrapper.olcut,\
+ io.openems.wrapper.tribuo,\
+ org.apache.commons.math3,\
+
+-testpath: \
+ ${testpath},\Bundle-Name: OpenEMS Edge RevolutionPi Data IO module
+Bundle-Vendor: opernikus GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.google.guava,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Common Http Bridge
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter KDK 2PU CT
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Battery Inverter Victron
+Bundle-Vendor: Ernst KNOLL Feinmechanik GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.ess.emergencycapacityreserve,\
+ io.openems.edge.controller.ess.limittotaldischarge,\
+ io.openems.edge.core,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Discovergy
+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.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS KOSTAL PIKO
+Bundle-Vendor: FENECON GmbH, OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge $projectName$
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.\${tstamp}
+
+-buildpath: \
+ \${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common
+
+-testpath: \
+ \${testpath}
+Bundle-Name: OpenEMS Edge Controller $projectName$
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.\${tstamp}
+
+-buildpath: \
+ \${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api
+
+-testpath: \
+ \${testpath}
+Bundle-Name: OpenEMS Edge $projectName$
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.\${tstamp}
+
+-buildpath: \
+ \${buildpath},\
+ io.openems.j2mod,\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common
+
+-testpath: \
+ \${testpath}
+Bundle-Name: OpenEMS Edge $projectName$ Api
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.\${tstamp}
+
+-buildpath: \
+ \${buildpath},\
+ io.openems.common,\
+ io.openems.edge.common
+
+-testpath: \
+ \${testpath}
+Bundle-Name: OpenEMS Common
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.wrapper.Java-WebSocket,\
+ io.openems.wrapper.fastexcel,\
+ io.openems.wrapper.opczip,\
+ org.apache.felix.http.jetty12,\
+ org.apache.felix.http.servlet-api,\
+ org.ops4j.pax.logging.pax-logging-api,\
+
+-testpath: \
+ ${testpath}
+
+-includeresource.resources: \
+ resources
+
+template-category: \
+ bbb/OpenEMS Templates
+template-icon: \
+ data:image/gif;base64,${base64;openems.gif}
+
+Provide-Capability: \
+ org.bndtools.template; org.bndtools.template=project;\
+ name=OpenEMS Controller;\
+ category=${template-category};\
+ ranking:Double=900;\
+ dir=templates/controller;\
+ icon="${template-icon}";\
+ help=controller-help.xml,\
+ org.bndtools.template; org.bndtools.template=project;\
+ name=OpenEMS Device;\
+ category=${template-category};\
+ ranking:Double=800;\
+ dir=templates/device;\
+ icon="${template-icon}";\
+ help=device-help.xml,\
+ org.bndtools.template; org.bndtools.template=project;\
+ name=OpenEMS Modbus Device;\
+ category=${template-category};\
+ ranking:Double=700;\
+ dir=templates/device-modbus;\
+ icon="${template-icon}";\
+ help=device-modbus-help.xml,\
+ org.bndtools.template; org.bndtools.template=project;\
+ name=OpenEMS Api;\
+ category=${template-category};\
+ ranking:Double=600;\
+ dir=templates/api;\
+ icon="${template-icon}";\
+ help=api-help.xml
+Bundle-Name: OpenEMS Backend Timedata Dummy
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Core Logger
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter Janitza
+Bundle-Description: This implementation covers Janitza UMG 604, Janitza UMG 96RM-E and Janitza UMG 511 meters
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge EVCS OCPP Common
+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.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.wrapper.eu.chargetime.ocpp,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Time-Of-Use Tariff Tibber
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.squareup.okhttp3,\
+ com.squareup.okio,\
+ io.openems.common,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ com.squareup.okio,\
+ io.openems.wrapper.kotlinx-coroutines-core-jvm,\
+ org.jetbrains.kotlin.osgi-bundle,\
+ ${testpath}
+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.common.bridge.http,\
+ 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,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Adstec StoraXe
+Bundle-Vendor: FE-Partner AG
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.ess.api, \
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Ess Balancing
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend UiWebsocket Impl
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.authentication.api,\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge OneWire Thermometer
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Vendor: FENECON GmbH
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.onewire,\
+ io.openems.edge.common,\
+ io.openems.edge.thermometer.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVSE Charge-Point Alpitronic
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.j2mod,\Bundle-Name: OpenEMS Edge Bridge Modbus
+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.battery.api,\
+ io.openems.edge.batteryinverter.api,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Api Backend
+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.controller.api.common,\
+ io.openems.edge.timedata.api,\
+ org.ops4j.pax.logging.pax-logging-api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge ESS FENECON Commercial40
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Meter Plexlog Datalogger
+Bundle-Description: This implementation covers Plexlog Datalogger
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Backend Timedata InfluxDB
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.shared.influxdb,\
+ io.openems.wrapper.influxdb-client-core,\
+ io.openems.wrapper.influxdb-client-java,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller Ess Cycle
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Prometheus Client
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.prometheus.metrics-config,\
+ io.prometheus.metrics-core,\
+ io.prometheus.metrics-exporter-common,\
+ io.prometheus.metrics-exporter-httpserver,\
+ io.prometheus.metrics-exposition-formats,\
+ io.prometheus.metrics-instrumentation-jvm,\
+ io.prometheus.metrics-model,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Meter B-Control EM300
+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.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller HighLoadTimeslot
+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.ess.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Timedata RRD4J
+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.timedata.api,\
+ rrd4j,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend Authentication OAuth2 Api
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.authentication.api,\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.common.bridge.http,\
+ io.openems.wrapper.auth0-auth0,\
+ io.openems.wrapper.auth0-java-jwt,\
+ io.openems.wrapper.auth0-jwks-rsa,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge PV Inverter Kostal
+Bundle-Vendor: FENECON GmbH, OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.common.bridge.http,\
+ io.openems.edge.bridge.http,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.edge.pvinverter.api,\
+ io.openems.j2mod,\
+ org.jsoup:jsoup,\
+
+-testpath: \
+ ${testpath},\
+Bundle-Name: OpenEMS Backend Timedata TimescaleDB
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ com.zaxxer.HikariCP,\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.wrapper.pgbulkinsert,\
+ org.postgresql.jdbc,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Controller 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,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge IO Siemens LOGO!
+Bundle-Description: Siemens LOGO! 8 as network relais. Connected via Modbus. Relays starting \
+ at VM 101, Bit 0 on SPS.
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.io.api,\
+ io.openems.j2mod,\
+ slf4j.api,\
+
+-testpath: \
+ ${testpath}
+ Bundle-Name: OpenEMS Edge Controller Clever-PV
+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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.controller.api,\
+ io.openems.edge.controller.ess.timeofusetariff,\
+ io.openems.edge.energy.api,\
+ io.openems.edge.ess.api,\
+ io.openems.edge.timedata.api,\
+ io.openems.edge.timeofusetariff.api
+-testpath: \
+ ${testpath},\
+ io.openems.edge.energy.api,\Bundle-Name: OpenEMS Edge Controller Electric Vehicle Charging Station Fix Active-Power
+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.evcs.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Backend
+Bundle-Vendor: FENECON GmbH
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.backend.common,\
+ io.openems.common,\
+ io.openems.wrapper.Java-WebSocket,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge Electric Vehicle Supply Equipment (EVSE) Controllers
+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.energy.api,\
+ io.openems.edge.evse.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath},\
+ org.apache.commons.math3,\
+Bundle-Name: OpenEMS Edge Scheduler JSCalendar
+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.scheduler.api,\
+
+-testpath: \
+ ${testpath}
+Bundle-Name: OpenEMS Edge EVCS Webasto Next
+Bundle-Vendor: OpenEMS Association e.V.
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.evcs.api,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath}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.common.bridge.http,\
+ io.openems.edge.common,\
+ io.openems.edge.timeofusetariff.api,\
+
+-testpath: \
+ ${testpath}Bundle-Name: OpenEMS Edge Controller Ess Delayed-Sell-To-Grid
+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.ess.api,\
+ io.openems.edge.meter.api,\
+
+-testpath: \
+ ${testpath}
diff --git a/cnf/pom.xml b/cnf/pom.xml
index b0f72068d41..6407d4651a7 100644
--- a/cnf/pom.xml
+++ b/cnf/pom.xml
@@ -32,6 +32,11 @@
jSerialComm
2.11.4
+
+ org.bidib.jbidib
+ nrjavaserial
+ 5.2.1
+
com.oracle.labs.olcut
diff --git a/io.openems.edge.bridge.onewire/lib/RXTXcomm.jar b/io.openems.edge.bridge.onewire/lib/RXTXcomm.jar
deleted file mode 100644
index d572880fb66..00000000000
--- a/io.openems.edge.bridge.onewire/lib/RXTXcomm.jar
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/CommPortIdentifier.java b/io.openems.edge.bridge.onewire/src/gnu/io/CommPortIdentifier.java
new file mode 100644
index 00000000000..01a109cf5c6
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/CommPortIdentifier.java
@@ -0,0 +1,69 @@
+package gnu.io;
+
+import java.util.Enumeration;
+
+/**
+ * Dummy CommPortIdentifier.
+ */
+public class CommPortIdentifier {
+
+ /**
+ * Dummy getPortIdentifier.
+ *
+ * @param name name
+ * @return null
+ * @throws NoSuchPortException if error
+ */
+ public static CommPortIdentifier getPortIdentifier(String name) throws NoSuchPortException {
+ return null;
+ }
+
+ /**
+ * Dummy getPortIdentifiers.
+ *
+ * @return null
+ */
+ public static Enumeration getPortIdentifiers() {
+ return null;
+ }
+
+ /**
+ * Dummy getName.
+ *
+ * @return null
+ */
+ public String getName() {
+ return null;
+ }
+
+ /**
+ * Dummy getPortType.
+ *
+ * @return 0
+ */
+ public int getPortType() {
+ return 0;
+ }
+
+ public static final int PORT_SERIAL = 1;
+
+ /**
+ * Dummy open.
+ *
+ * @param appName appName
+ * @param timeout timeout
+ * @return null
+ */
+ public SerialPort open(String appName, int timeout) {
+ return null;
+ }
+
+ /**
+ * Dummy isCurrentlyOwned.
+ *
+ * @return false
+ */
+ public boolean isCurrentlyOwned() {
+ return false;
+ }
+}
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/NoSuchPortException.java b/io.openems.edge.bridge.onewire/src/gnu/io/NoSuchPortException.java
new file mode 100644
index 00000000000..d4efb6c7218
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/NoSuchPortException.java
@@ -0,0 +1,9 @@
+package gnu.io;
+
+/**
+ * Dummy NoSuchPortException.
+ */
+public class NoSuchPortException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/SerialPort.java b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPort.java
new file mode 100644
index 00000000000..ae733b8864f
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPort.java
@@ -0,0 +1,182 @@
+package gnu.io;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Dummy SerialPort.
+ */
+public class SerialPort {
+
+ public static final int FLOWCONTROL_NONE = 0;
+ public static final int DATABITS_8 = 8;
+ public static final int STOPBITS_1 = 1;
+ public static final int PARITY_NONE = 0;
+
+ /**
+ * Dummy setFlowControlMode.
+ *
+ * @param mode mode
+ * @throws UnsupportedCommOperationException if error
+ */
+ public void setFlowControlMode(int mode) throws UnsupportedCommOperationException {
+ }
+
+ /**
+ * Dummy setSerialPortParams.
+ *
+ * @param b b
+ * @param d d
+ * @param s s
+ * @param p p
+ * @throws UnsupportedCommOperationException if error
+ */
+ public void setSerialPortParams(int b, int d, int s, int p) throws UnsupportedCommOperationException {
+ }
+
+ /**
+ * Dummy addEventListener.
+ *
+ * @param l listener
+ * @throws java.util.TooManyListenersException if error
+ */
+ public void addEventListener(SerialPortEventListener l) throws java.util.TooManyListenersException {
+ }
+
+ /**
+ * Dummy notifyOnDataAvailable.
+ *
+ * @param e enable
+ */
+ public void notifyOnDataAvailable(boolean e) {
+ }
+
+ /**
+ * Dummy close.
+ */
+ public void close() {
+ }
+
+ /**
+ * Dummy getInputStream.
+ *
+ * @return null
+ */
+ public InputStream getInputStream() {
+ return null;
+ }
+
+ /**
+ * Dummy getOutputStream.
+ *
+ * @return null
+ */
+ public OutputStream getOutputStream() {
+ return null;
+ }
+
+ /**
+ * Dummy getInputBufferSize.
+ *
+ * @return 0
+ */
+ public int getInputBufferSize() {
+ return 0;
+ }
+
+ /**
+ * Dummy getOutputBufferSize.
+ *
+ * @return 0
+ */
+ public int getOutputBufferSize() {
+ return 0;
+ }
+
+ /**
+ * Dummy notifyOnOutputEmpty.
+ *
+ * @param e enable
+ */
+ public void notifyOnOutputEmpty(boolean e) {
+ }
+
+ /**
+ * Dummy disableReceiveFraming.
+ */
+ public void disableReceiveFraming() {
+ }
+
+ /**
+ * Dummy disableReceiveThreshold.
+ */
+ public void disableReceiveThreshold() {
+ }
+
+ /**
+ * Dummy enableReceiveTimeout.
+ *
+ * @param t timeout
+ */
+ public void enableReceiveTimeout(int t) {
+ }
+
+ // CHECKSTYLE:OFF
+ /**
+ * Dummy setDTR.
+ *
+ * @param e enable
+ */
+ public void setDTR(boolean e) {
+ }
+
+ /**
+ * Dummy setRTS.
+ *
+ * @param e enable
+ */
+ public void setRTS(boolean e) {
+ }
+
+ /**
+ * Dummy isDTR.
+ *
+ * @return false
+ */
+ public boolean isDTR() {
+ return false;
+ }
+
+ /**
+ * Dummy isRTS.
+ *
+ * @return false
+ */
+ public boolean isRTS() {
+ return false;
+ }
+ // CHECKSTYLE:ON
+
+ /**
+ * Dummy sendBreak.
+ *
+ * @param d duration
+ */
+ public void sendBreak(int d) {
+ }
+
+ /**
+ * Dummy getBaudRate.
+ *
+ * @return 0
+ */
+ public int getBaudRate() {
+ return 0;
+ }
+
+ /**
+ * Dummy removeEventListener.
+ */
+ public void removeEventListener() {
+ }
+}
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEvent.java b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEvent.java
new file mode 100644
index 00000000000..983d3ccd325
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEvent.java
@@ -0,0 +1,45 @@
+package gnu.io;
+
+/**
+ * Dummy SerialPortEvent.
+ */
+public class SerialPortEvent {
+
+ public static final int DATA_AVAILABLE = 1;
+ public static final int BI = 2;
+ public static final int CD = 3;
+ public static final int CTS = 4;
+ public static final int DSR = 5;
+ public static final int FE = 6;
+ public static final int OE = 7;
+ public static final int OUTPUT_BUFFER_EMPTY = 8;
+ public static final int PE = 9;
+ public static final int RI = 10;
+
+ /**
+ * Dummy getEventType.
+ *
+ * @return 0
+ */
+ public int getEventType() {
+ return 0;
+ }
+
+ /**
+ * Dummy getOldValue.
+ *
+ * @return false
+ */
+ public boolean getOldValue() {
+ return false;
+ }
+
+ /**
+ * Dummy getNewValue.
+ *
+ * @return false
+ */
+ public boolean getNewValue() {
+ return false;
+ }
+}
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEventListener.java b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEventListener.java
new file mode 100644
index 00000000000..df7653ffdb5
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/SerialPortEventListener.java
@@ -0,0 +1,14 @@
+package gnu.io;
+
+/**
+ * Dummy SerialPortEventListener.
+ */
+public interface SerialPortEventListener extends java.util.EventListener {
+
+ /**
+ * Dummy serialEvent.
+ *
+ * @param event event
+ */
+ void serialEvent(SerialPortEvent event);
+}
diff --git a/io.openems.edge.bridge.onewire/src/gnu/io/UnsupportedCommOperationException.java b/io.openems.edge.bridge.onewire/src/gnu/io/UnsupportedCommOperationException.java
new file mode 100644
index 00000000000..ccbc1b1db08
--- /dev/null
+++ b/io.openems.edge.bridge.onewire/src/gnu/io/UnsupportedCommOperationException.java
@@ -0,0 +1,9 @@
+package gnu.io;
+
+/**
+ * Dummy UnsupportedCommOperationException.
+ */
+public class UnsupportedCommOperationException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/io.openems.edge.controller.generic.jsonlogic/bnd.bnd b/io.openems.edge.controller.generic.jsonlogic/bnd.bnd
index ba63ce071c6..8a84801dfbd 100644
--- a/io.openems.edge.controller.generic.jsonlogic/bnd.bnd
+++ b/io.openems.edge.controller.generic.jsonlogic/bnd.bnd
@@ -3,17 +3,13 @@ Bundle-Vendor: FENECON GmbH
Bundle-License: https://opensource.org/licenses/EPL-2.0
Bundle-Version: 1.0.0.${tstamp}
--includeresource.jsonlogic: \
- @lib/json-logic-java-1.0.0.jar; lib:=true
-
-buildpath: \
${buildpath},\
io.openems.common,\
io.openems.edge.common,\
io.openems.edge.controller.api,\
io.openems.edge.ess.api,\
- io.openems.edge.io.api,\
- lib/json-logic-java-1.0.0.jar;version=file,\
+ io.openems.edge.io.api
-testpath: \
${testpath}
diff --git a/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogic.java b/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogic.java
new file mode 100644
index 00000000000..d6b71c18fe1
--- /dev/null
+++ b/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogic.java
@@ -0,0 +1,19 @@
+package io.github.meiskalt7.jsonlogic;
+
+/**
+ * Dummy JsonLogic.
+ */
+public class JsonLogic {
+
+ /**
+ * Dummy apply.
+ *
+ * @param json json
+ * @param data data
+ * @return null
+ * @throws JsonLogicException if error
+ */
+ public Object apply(String json, Object data) throws JsonLogicException {
+ return null;
+ }
+}
diff --git a/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogicException.java b/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogicException.java
new file mode 100644
index 00000000000..4615a4f4e14
--- /dev/null
+++ b/io.openems.edge.controller.generic.jsonlogic/src/io/github/meiskalt7/jsonlogic/JsonLogicException.java
@@ -0,0 +1,18 @@
+package io.github.meiskalt7.jsonlogic;
+
+/**
+ * Dummy JsonLogicException.
+ */
+public class JsonLogicException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor.
+ *
+ * @param message message
+ */
+ public JsonLogicException(String message) {
+ super(message);
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/Config.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/Config.java
index ec9b1ee6903..137c9121731 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/Config.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/Config.java
@@ -18,25 +18,25 @@
boolean enabled() default true;
@AttributeDefinition(name = "ESS ID", description = "ID of Energy Storage System")
- String ess_id() default "ess0";
+ String essId() default "ess0";
@AttributeDefinition(name = "Meter ID", description = "ID of Grid Meter")
- String meter_id() default "meter0";
+ String meterId() default "meter0";
@AttributeDefinition(name = "Relay ID", description = "ID of Islanding Relay")
- String relay_id() default "relay0";
+ String relayId() default "relay0";
@AttributeDefinition(name = "Relay Channel", description = "Channel Address of the Relay Channel")
- String relay_channel() default "relay0/Relay";
+ String relayChannel() default "relay0/Relay";
@AttributeDefinition(name = "ESS Grid Mode Channel", description = "Channel Address of the ESS Grid Mode Channel")
- String ess_grid_mode_channel() default "ess0/SetGridMode";
+ String essGridModeChannel() default "ess0/SetGridMode";
@AttributeDefinition(name = "Under Voltage Threshold", description = "Grid voltage threshold for islanding [V]")
- int under_voltage_threshold() default 207;
+ int underVoltageThreshold() default 207;
@AttributeDefinition(name = "Stable Grid Time", description = "Time in seconds to wait before reconnecting")
- int stable_grid_time() default 10;
+ int stableGridTime() default 10;
String webconsole_configurationFactory_nameHint() default "Controller Microgrid Supervisor [{id}]";
}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/MicrogridSupervisorImpl.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/MicrogridSupervisorImpl.java
index 98113984349..5e8394b8f3b 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/MicrogridSupervisorImpl.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/MicrogridSupervisorImpl.java
@@ -57,11 +57,11 @@ public MicrogridSupervisorImpl() {
void activate(ComponentContext componentContext, Config config) {
super.activate(componentContext, config.id(), config.alias(), config.enabled());
this.config = config;
- this.context.setEssId(config.ess_id());
- this.context.setMeterId(config.meter_id());
- this.context.setRelayId(config.relay_id());
- this.context.setUnderVoltageThreshold(config.under_voltage_threshold());
- this.context.setStableGridTime(config.stable_grid_time());
+ this.context.setEssId(config.essId());
+ this.context.setMeterId(config.meterId());
+ this.context.setRelayId(config.relayId());
+ this.context.setUnderVoltageThreshold(config.underVoltageThreshold());
+ this.context.setStableGridTime(config.stableGridTime());
}
@Deactivate
@@ -84,7 +84,7 @@ public void run() throws OpenemsNamedException {
private void updateContext() {
// Update grid voltage from meter
try {
- ElectricityMeter meter = this.componentManager.getComponent(this.config.meter_id());
+ ElectricityMeter meter = this.componentManager.getComponent(this.config.meterId());
IntegerReadChannel voltageChannel = meter.channel(ElectricityMeter.ChannelId.VOLTAGE);
Integer voltageMillivolt = voltageChannel.value().get();
if (voltageMillivolt != null) {
@@ -95,7 +95,7 @@ private void updateContext() {
}
// Update stable grid timer
- if (this.context.getGridVoltage() >= this.config.under_voltage_threshold()) {
+ if (this.context.getGridVoltage() >= this.config.underVoltageThreshold()) {
this.context.setStableGridTimer(this.context.getStableGridTimer() + 1);
} else {
this.context.setStableGridTimer(0);
@@ -124,7 +124,7 @@ public void closeRelay() throws OpenemsNamedException {
private void setRelay(boolean value) throws OpenemsNamedException {
try {
- OpenemsComponent component = this.componentManager.getComponent(this.config.relay_id());
+ OpenemsComponent component = this.componentManager.getComponent(this.config.relayId());
if (component instanceof DigitalOutput) {
DigitalOutput doComp = (DigitalOutput) component;
BooleanWriteChannel[] channels = doComp.digitalOutputChannels();
@@ -134,7 +134,7 @@ private void setRelay(boolean value) throws OpenemsNamedException {
}
}
// Fallback to configured channel
- BooleanWriteChannel channel = component.channel(this.config.relay_channel());
+ BooleanWriteChannel channel = component.channel(this.config.relayChannel());
channel.setNextWriteValue(value);
} catch (Exception e) {
this.log.error("Could not set relay: " + e.getMessage());
@@ -157,9 +157,10 @@ public void setEssOnGrid() {
this.setEssGridMode(io.openems.edge.common.sum.GridMode.ON_GRID);
}
+ @SuppressWarnings("unchecked")
private void setEssGridMode(GridMode mode) {
try {
- ChannelAddress addr = ChannelAddress.fromString(this.config.ess_grid_mode_channel());
+ ChannelAddress addr = ChannelAddress.fromString(this.config.essGridModeChannel());
WriteChannel> channel = this.componentManager.getChannel(addr);
if (channel.channelDoc().getType() == io.openems.common.types.OpenemsType.INTEGER) {
((WriteChannel) channel).setNextWriteValue(mode.getValue());
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/Config.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/Config.java
new file mode 100644
index 00000000000..0874e335e79
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/Config.java
@@ -0,0 +1,51 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@ObjectClassDefinition(//
+ name = "Controller Microgrid Dispatcher", //
+ description = "Manages power flows in the microgrid based on the state provided by the Supervisor.")
+public @interface Config {
+
+ @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
+ String id() default "ctrlMicrogridDispatcher0";
+
+ @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 Energy Storage System")
+ String essId() default "ess0";
+
+ @AttributeDefinition(name = "Meter ID", description = "ID of Grid Meter")
+ String meterId() default "meter0";
+
+ @AttributeDefinition(name = "Genset Meter ID", description = "ID of Genset Meter")
+ String gensetId() default "meter1";
+
+ @AttributeDefinition(name = "Genset Start/Stop Channel", description = "Channel Address of the Genset Start/Stop Channel")
+ String gensetStartStopChannel() default "io0/DigitalOutput0";
+
+ @AttributeDefinition(name = "PV ID", description = "ID of PV Inverter")
+ String pvId() default "pvInverter0";
+
+ @AttributeDefinition(name = "Supervisor ID", description = "ID of Microgrid Supervisor")
+ String supervisorId() default "ctrlMicrogrid0";
+
+ @AttributeDefinition(name = "Grid Limit", description = "Peak Shaving Limit [W]")
+ int gridLimit() default 10000;
+
+ @AttributeDefinition(name = "Genset Start SoC", description = "Genset Start State of Charge [%]")
+ int gensetStartSoc() default 20;
+
+ @AttributeDefinition(name = "Genset Stop SoC", description = "Genset Stop State of Charge [%]")
+ int gensetStopSoc() default 80;
+
+ @AttributeDefinition(name = "Genset Capacity", description = "Genset Capacity [W]")
+ int gensetCapacity() default 50000;
+
+ String webconsole_configurationFactory_nameHint() default "Controller Microgrid Dispatcher [{id}]";
+}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcher.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcher.java
new file mode 100644
index 00000000000..81df4ce327b
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcher.java
@@ -0,0 +1,22 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.controller.api.Controller;
+
+public interface MicrogridDispatcher extends Controller, OpenemsComponent {
+
+ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+ ;
+ private final Doc doc;
+
+ private ChannelId(Doc doc) {
+ this.doc = doc;
+ }
+
+ @Override
+ public Doc doc() {
+ return this.doc;
+ }
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImpl.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImpl.java
new file mode 100644
index 00000000000..6b058aaa90e
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImpl.java
@@ -0,0 +1,205 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+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.types.ChannelAddress;
+import io.openems.common.types.OpenemsType;
+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.type.TypeUtils;
+import io.openems.edge.controller.api.Controller;
+import io.openems.edge.controller.microgrid.MicrogridSupervisor;
+import io.openems.edge.controller.microgrid.statemachine.MemsState;
+import io.openems.edge.ess.api.ManagedSymmetricEss;
+import io.openems.edge.meter.api.ElectricityMeter;
+
+@Designate(ocd = Config.class, factory = true)
+@Component(//
+ name = "Controller.Microgrid.Dispatcher", //
+ immediate = true, //
+ configurationPolicy = ConfigurationPolicy.REQUIRE //
+)
+public class MicrogridDispatcherImpl extends AbstractOpenemsComponent
+ implements MicrogridDispatcher, Controller, OpenemsComponent {
+
+ private final Logger log = LoggerFactory.getLogger(MicrogridDispatcherImpl.class);
+
+ @Reference
+ protected ComponentManager componentManager;
+
+ private Config config;
+
+ public MicrogridDispatcherImpl() {
+ super(//
+ OpenemsComponent.ChannelId.values(), //
+ Controller.ChannelId.values(), //
+ MicrogridDispatcher.ChannelId.values() //
+ );
+ }
+
+ @Activate
+ void activate(ComponentContext componentContext, Config config) {
+ super.activate(componentContext, config.id(), config.alias(), config.enabled());
+ this.config = config;
+ }
+
+ @Override
+ @Deactivate
+ protected void deactivate() {
+ super.deactivate();
+ }
+
+ @Override
+ public void run() throws OpenemsNamedException {
+ MemsState state = this.getMicrogridState();
+
+ switch (state) {
+ case SS1:
+ this.runSS1();
+ break;
+ case SS2:
+ this.runSS2();
+ break;
+ default:
+ // Do nothing in transition or undefined states
+ break;
+ }
+ }
+
+ private MemsState getMicrogridState() {
+ try {
+ MicrogridSupervisor supervisor = this.componentManager.getComponent(this.config.supervisorId());
+ return supervisor.channel(MicrogridSupervisor.ChannelId.STATE_MACHINE).value().asEnum();
+ } catch (Exception e) {
+ return MemsState.UNDEFINED;
+ }
+ }
+
+ private void runSS1() throws OpenemsNamedException {
+ // 1. Peak Shaving
+ try {
+ ElectricityMeter gridMeter = this.componentManager.getComponent(this.config.meterId());
+ Integer gridPower = gridMeter.getActivePower().get();
+ ManagedSymmetricEss ess = this.componentManager.getComponent(this.config.essId());
+
+ if (gridPower != null && gridPower > this.config.gridLimit()) {
+ int diff = gridPower - this.config.gridLimit();
+ ess.setActivePowerEquals(diff);
+ }
+ // Do not call setActivePowerEquals(0) when below limit to allow other
+ // controllers
+ } catch (Exception e) {
+ this.logError(this.log, "SS1: Error during Peak Shaving: " + e.getMessage());
+ }
+
+ // 2. Stop Genset
+ this.setGensetStartStop(false);
+ }
+
+ private void runSS2() throws OpenemsNamedException {
+ ManagedSymmetricEss ess;
+ ElectricityMeter gensetMeter;
+ OpenemsComponent pvInverter;
+ try {
+ ess = this.componentManager.getComponent(this.config.essId());
+ gensetMeter = this.componentManager.getComponent(this.config.gensetId());
+ pvInverter = this.componentManager.getComponent(this.config.pvId());
+ } catch (Exception e) {
+ this.logError(this.log, "SS2: Required components not found: " + e.getMessage());
+ return;
+ }
+
+ Integer soc = ess.getSoc().get();
+ Integer gensetPower = gensetMeter.getActivePower().get();
+
+ if (soc == null || gensetPower == null) {
+ return;
+ }
+
+ // 1. Genset Control (Start/Stop)
+ if (soc < this.config.gensetStartSoc()) {
+ this.setGensetStartStop(true);
+ } else if (soc > this.config.gensetStopSoc()) {
+ this.setGensetStartStop(false);
+ }
+
+ // 2. Genset Loading
+ boolean isGensetOn = gensetPower > 100; // Threshold to consider Genset as running
+ if (isGensetOn) {
+ int targetGensetPower = (int) (this.config.gensetCapacity() * 0.4);
+
+ Integer pvPower = null;
+ if (pvInverter instanceof ElectricityMeter) {
+ pvPower = ((ElectricityMeter) pvInverter).getActivePower().get();
+ } else {
+ try {
+ pvPower = TypeUtils.getAsType(OpenemsType.INTEGER, pvInverter.channel("ActivePower").value().get());
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+
+ Integer essPower = ess.getActivePower().get();
+
+ if (pvPower != null && essPower != null) {
+ int consumption = essPower + pvPower + gensetPower;
+ // ESS_Setpoint = Consumption - PV - TargetGensetPower
+ int essSetpoint = consumption - pvPower - targetGensetPower;
+ ess.setActivePowerEquals(essSetpoint);
+ }
+ }
+
+ // 3. PV Curtailment
+ Integer allowedChargePower = ess.getAllowedChargePower().get(); // typically negative
+ if (soc > 95 && allowedChargePower != null && allowedChargePower > -100) {
+ Integer pvPower = null;
+ if (pvInverter instanceof ElectricityMeter) {
+ pvPower = ((ElectricityMeter) pvInverter).getActivePower().get();
+ } else {
+ try {
+ pvPower = TypeUtils.getAsType(OpenemsType.INTEGER, pvInverter.channel("ActivePower").value().get());
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ Integer essPower = ess.getActivePower().get();
+ if (pvPower != null && essPower != null) {
+ int consumption = essPower + pvPower + gensetPower;
+ try {
+ WriteChannel limitChannel = pvInverter.channel("SetActivePowerLimit");
+ limitChannel.setNextWriteValue(consumption);
+ } catch (Exception e) {
+ this.logError(this.log, "SS2: Unable to set PV power limit: " + e.getMessage());
+ }
+ }
+ } else {
+ try {
+ WriteChannel limitChannel = pvInverter.channel("SetActivePowerLimit");
+ limitChannel.setNextWriteValue(null); // No limit
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void setGensetStartStop(boolean value) {
+ try {
+ ChannelAddress addr = ChannelAddress.fromString(this.config.gensetStartStopChannel());
+ WriteChannel channel = this.componentManager.getChannel(addr);
+ channel.setNextWriteValue(value);
+ } catch (Exception e) {
+ this.logError(this.log, "Error setting Genset Start/Stop: " + e.getMessage());
+ }
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/INITHandler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/INITHandler.java
new file mode 100644
index 00000000000..945e85b9ff9
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/INITHandler.java
@@ -0,0 +1,30 @@
+package io.openems.edge.controller.microgrid.statemachine;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.edge.common.statemachine.StateHandler;
+
+/**
+ * Handler for state: INIT.
+ * Initial State: Determine starting mode
+ * Auto-generated from state-machine.json
+ */
+public class INITHandler extends StateHandler {
+
+ @Override
+ protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
+ // No transitions defined - stay in current state
+ return MemsState.INIT;
+ }
+
+ @Override
+ protected void onEntry(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement entry actions
+ // No entry actions
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsState.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsState.java
index 40543ad5d30..c141538e055 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsState.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsState.java
@@ -9,11 +9,12 @@
*/
public enum MemsState implements State, OptionsEnum {
UNDEFINED(-1, "UNDEFINED"), //
- SS1(0, "SS1"), //
- T1(1, "T1"), //
- SS2(2, "SS2"), //
- T3(3, "T3"), //
- T4(4, "T4"); //
+ INIT(0, "INIT"), //
+ SS1(1, "SS1"), //
+ T1(2, "T1"), //
+ SS2(3, "SS2"), //
+ T3(4, "T3"), //
+ T4(5, "T4"); //
private final int value;
private final String name;
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsStateMachine.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsStateMachine.java
index 2ebecba6563..7ed4710b91e 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsStateMachine.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/MemsStateMachine.java
@@ -11,13 +11,14 @@
public class MemsStateMachine extends AbstractStateMachine {
public MemsStateMachine() {
- super(MemsState.UNDEFINED);
+ super(MemsState.INIT);
}
@Override
public StateHandler getStateHandler(MemsState state) {
return switch (state) {
- case UNDEFINED -> new UNDEFINEDHandler();
+ case UNDEFINED -> new UndefinedHandler();
+ case INIT -> new INITHandler();
case SS1 -> new SS1Handler();
case T1 -> new T1Handler();
case SS2 -> new SS2Handler();
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS1Handler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS1Handler.java
index e693f45ce37..bce14ede8fb 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS1Handler.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS1Handler.java
@@ -3,18 +3,37 @@
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
+/**
+ * Handler for state: SS1.
+ * Steady State 1: Grid Connected
+ * Auto-generated from state-machine.json
+ */
public class SS1Handler extends StateHandler {
@Override
protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
- if (context.getGridVoltage() < context.getUnderVoltageThreshold()) {
- return MemsState.T1;
- }
+ // On GRID_VOLTAGE_LOW [isGridVoltageLow] -> T1
+ // if (event == MemsEvent.GRID_VOLTAGE_LOW && isGridVoltageLow(context)) {
+ // return MemsState.T1;
+ // }
+
+ // On GRID_FAULT -> T1
+ // if (event == MemsEvent.GRID_FAULT) {
+ // return MemsState.T1;
+ // }
+
return MemsState.SS1;
}
@Override
protected void onEntry(MemsContext context) throws OpenemsNamedException {
- context.getParent().setEssOnGrid();
+ // TODO: Implement entry actions
+ // logGridConnected()
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
}
}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS2Handler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS2Handler.java
index 61f773b4e4d..ec518968f57 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS2Handler.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/SS2Handler.java
@@ -3,19 +3,33 @@
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
+/**
+ * Handler for state: SS2.
+ * Steady State 2: Islanded
+ * Auto-generated from state-machine.json
+ */
public class SS2Handler extends StateHandler {
@Override
protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
- if (context.getGridVoltage() >= context.getUnderVoltageThreshold()
- && context.getStableGridTimer() >= context.getStableGridTime()) {
- return MemsState.T3;
- }
+ // On GRID_VOLTAGE_STABLE [isGridVoltageStableForTime] -> T3
+ // if (event == MemsEvent.GRID_VOLTAGE_STABLE && isGridVoltageStableForTime(context)) {
+ // return MemsState.T3;
+ // }
+
return MemsState.SS2;
}
@Override
protected void onEntry(MemsContext context) throws OpenemsNamedException {
- context.getParent().setEssOffGrid();
+ // TODO: Implement entry actions
+ // logIslanded()
+ // setEssOffGrid()
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
}
}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T1Handler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T1Handler.java
index 30c07d1307d..8f6af9d4ad8 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T1Handler.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T1Handler.java
@@ -3,16 +3,29 @@
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
+/**
+ * Handler for state: T1.
+ * Transition 1: Unplanned Islanding
+ * Auto-generated from state-machine.json
+ */
public class T1Handler extends StateHandler {
@Override
protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
- return MemsState.SS2;
+ // No transitions defined - stay in current state
+ return MemsState.T1;
}
@Override
protected void onEntry(MemsContext context) throws OpenemsNamedException {
- context.getParent().openRelay();
- context.getParent().setEssOffGrid();
+ // TODO: Implement entry actions
+ // openRelay()
+ // setEssOffGrid()
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
}
}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T3Handler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T3Handler.java
index c2d42d5ea66..244e8e541d5 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T3Handler.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T3Handler.java
@@ -3,16 +3,30 @@
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
+/**
+ * Handler for state: T3.
+ * Transition 3: Reconnect
+ * Auto-generated from state-machine.json
+ */
public class T3Handler extends StateHandler {
@Override
protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
- return MemsState.SS1;
+ // No transitions defined - stay in current state
+ return MemsState.T3;
}
@Override
protected void onEntry(MemsContext context) throws OpenemsNamedException {
- context.getParent().closeRelay();
- context.getParent().setEssOnGrid();
+ // TODO: Implement entry actions
+ // checkSync()
+ // closeRelay()
+ // setEssOnGrid()
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
}
}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T4Handler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T4Handler.java
index 97ab81fe0cf..8ba6687e01b 100644
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T4Handler.java
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/T4Handler.java
@@ -2,11 +2,9 @@
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
-import io.openems.edge.controller.microgrid.statemachine.MemsContext;
-import io.openems.edge.controller.microgrid.statemachine.MemsState;
/**
- * Handler for state: T4
+ * Handler for state: T4.
* Transition 4: Black Start
* Auto-generated from state-machine.json
*/
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UNDEFINEDHandler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UNDEFINEDHandler.java
deleted file mode 100644
index 408dd3403f4..00000000000
--- a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UNDEFINEDHandler.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.openems.edge.controller.microgrid.statemachine;
-
-import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.edge.common.statemachine.StateHandler;
-
-public class UNDEFINEDHandler extends StateHandler {
-
- @Override
- protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
- return MemsState.SS1;
- }
-}
diff --git a/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UndefinedHandler.java b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UndefinedHandler.java
new file mode 100644
index 00000000000..6f7eb7174f4
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/src/io/openems/edge/controller/microgrid/statemachine/UndefinedHandler.java
@@ -0,0 +1,30 @@
+package io.openems.edge.controller.microgrid.statemachine;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.edge.common.statemachine.StateHandler;
+
+/**
+ * Handler for state: UNDEFINED.
+ * UNDEFINED state
+ * Auto-generated from state-machine.json
+ */
+public class UndefinedHandler extends StateHandler {
+
+ @Override
+ protected MemsState runAndGetNextState(MemsContext context) throws OpenemsNamedException {
+ // No transitions defined - stay in current state
+ return MemsState.UNDEFINED;
+ }
+
+ @Override
+ protected void onEntry(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement entry actions
+ // No entry actions
+ }
+
+ @Override
+ protected void onExit(MemsContext context) throws OpenemsNamedException {
+ // TODO: Implement exit actions
+ // No exit actions
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MicrogridSupervisorTest.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MicrogridSupervisorTest.java
index 8ef188d61e0..842f1138932 100644
--- a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MicrogridSupervisorTest.java
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MicrogridSupervisorTest.java
@@ -5,12 +5,9 @@
import java.lang.annotation.Annotation;
import io.openems.common.channel.AccessMode;
+import io.openems.common.test.AbstractComponentConfig;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Doc;
-import io.openems.edge.common.channel.IntegerDoc;
-import io.openems.edge.common.channel.IntegerWriteChannel;
-import io.openems.edge.common.channel.BooleanDoc;
-import io.openems.edge.common.channel.BooleanWriteChannel;
import io.openems.edge.common.test.AbstractComponentTest.TestCase;
import io.openems.edge.controller.test.ControllerTest;
import io.openems.edge.common.test.DummyComponentManager;
@@ -49,123 +46,180 @@ private ChannelId(Doc doc) {
public Doc doc() {
return this.doc;
}
+ }
+
+ public static class MyConfig extends AbstractComponentConfig implements Config {
+
+ private String id = CTRL_ID;
+ private String alias = "";
+ private boolean enabled = true;
+ private String essId = ESS_ID;
+ private String meterId = METER_ID;
+ private String relayId = RELAY_ID;
+ private String relayChannel = RELAY_ID + "/Relay";
+ private String essGridModeChannel = ESS_ID + "/SetGridMode";
+ private int underVoltageThreshold = 207;
+ private int stableGridTime = 10;
+
+ public MyConfig() {
+ super(Config.class, CTRL_ID);
+ }
+
+ /**
+ * Create a MyConfig.
+ *
+ * @return the MyConfig
+ */
+ public static MyConfig create() {
+ return new MyConfig();
+ }
+
+ /**
+ * Set ID.
+ *
+ * @param id the id
+ * @return this
+ */
+ public MyConfig setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Set EssId.
+ *
+ * @param essId the essId
+ * @return this
+ */
+ public MyConfig setEssId(String essId) {
+ this.essId = essId;
+ return this;
+ }
+
+ /**
+ * Set MeterId.
+ *
+ * @param meterId the meterId
+ * @return this
+ */
+ public MyConfig setMeterId(String meterId) {
+ this.meterId = meterId;
+ return this;
+ }
+
+ /**
+ * Set RelayId.
+ *
+ * @param relayId the relayId
+ * @return this
+ */
+ public MyConfig setRelayId(String relayId) {
+ this.relayId = relayId;
+ return this;
+ }
+
+ /**
+ * Set RelayChannel.
+ *
+ * @param relayChannel the relayChannel
+ * @return this
+ */
+ public MyConfig setRelayChannel(String relayChannel) {
+ this.relayChannel = relayChannel;
+ return this;
+ }
+
+ /**
+ * Set EssGridModeChannel.
+ *
+ * @param essGridModeChannel the essGridModeChannel
+ * @return this
+ */
+ public MyConfig setEssGridModeChannel(String essGridModeChannel) {
+ this.essGridModeChannel = essGridModeChannel;
+ return this;
+ }
+
+ /**
+ * Set UnderVoltageThreshold.
+ *
+ * @param underVoltageThreshold the underVoltageThreshold
+ * @return this
+ */
+ public MyConfig setUnderVoltageThreshold(int underVoltageThreshold) {
+ this.underVoltageThreshold = underVoltageThreshold;
+ return this;
+ }
+
+ /**
+ * Set StableGridTime.
+ *
+ * @param stableGridTime the stableGridTime
+ * @return this
+ */
+ public MyConfig setStableGridTime(int stableGridTime) {
+ this.stableGridTime = stableGridTime;
+ return this;
+ }
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return Config.class;
+ }
+
+ @Override
+ public String id() {
+ return this.id;
+ }
+
+ @Override
+ public String alias() {
+ return this.alias;
+ }
+
+ @Override
+ public boolean enabled() {
+ return this.enabled;
+ }
+
+ @Override
+ public String essId() {
+ return this.essId;
+ }
+
+ @Override
+ public String meterId() {
+ return this.meterId;
+ }
+
+ @Override
+ public String relayId() {
+ return this.relayId;
+ }
- public static class MyConfig implements Config {
-
- private String id = CTRL_ID;
- private String alias = "";
- private boolean enabled = true;
- private String essId = ESS_ID;
- private String meterId = METER_ID;
- private String relayId = RELAY_ID;
- private String relayChannel = RELAY_ID + "/Relay";
- private String essGridModeChannel = ESS_ID + "/SetGridMode";
- private int underVoltageThreshold = 207;
- private int stableGridTime = 10;
-
- public static MyConfig create() {
- return new MyConfig();
- }
-
- public MyConfig setId(String id) {
- this.id = id;
- return this;
- }
-
- public MyConfig setEssId(String essId) {
- this.essId = essId;
- return this;
- }
-
- public MyConfig setMeterId(String meterId) {
- this.meterId = meterId;
- return this;
- }
-
- public MyConfig setRelayId(String relayId) {
- this.relayId = relayId;
- return this;
- }
-
- public MyConfig setRelayChannel(String relayChannel) {
- this.relayChannel = relayChannel;
- return this;
- }
-
- public MyConfig setEssGridModeChannel(String essGridModeChannel) {
- this.essGridModeChannel = essGridModeChannel;
- return this;
- }
-
- public MyConfig setUnderVoltageThreshold(int underVoltageThreshold) {
- this.underVoltageThreshold = underVoltageThreshold;
- return this;
- }
-
- public MyConfig setStableGridTime(int stableGridTime) {
- this.stableGridTime = stableGridTime;
- return this;
- }
-
- @Override
- public Class extends Annotation> annotationType() {
- return Config.class;
- }
-
- @Override
- public String id() {
- return this.id;
- }
-
- @Override
- public String alias() {
- return this.alias;
- }
-
- @Override
- public boolean enabled() {
- return this.enabled;
- }
-
- @Override
- public String ess_id() {
- return this.essId;
- }
-
- @Override
- public String meter_id() {
- return this.meterId;
- }
-
- @Override
- public String relay_id() {
- return this.relayId;
- }
-
- @Override
- public String relay_channel() {
- return this.relayChannel;
- }
-
- @Override
- public String ess_grid_mode_channel() {
- return this.essGridModeChannel;
- }
-
- @Override
- public int under_voltage_threshold() {
- return this.underVoltageThreshold;
- }
-
- @Override
- public int stable_grid_time() {
- return this.stableGridTime;
- }
-
- @Override
- public String webconsole_configurationFactory_nameHint() {
- return "";
- }
+ @Override
+ public String relayChannel() {
+ return this.relayChannel;
+ }
+
+ @Override
+ public String essGridModeChannel() {
+ return this.essGridModeChannel;
+ }
+
+ @Override
+ public int underVoltageThreshold() {
+ return this.underVoltageThreshold;
+ }
+
+ @Override
+ public int stableGridTime() {
+ return this.stableGridTime;
+ }
+
+ @Override
+ public String webconsole_configurationFactory_nameHint() {
+ return "";
}
}
@@ -199,6 +253,11 @@ protected DummyRelay(String id) {
}
}
+ /**
+ * Set up before each test.
+ *
+ * @throws Exception on error
+ */
@Before
public void setUp() throws Exception {
this.componentManager = new DummyComponentManager();
@@ -213,6 +272,11 @@ public void setUp() throws Exception {
this.controller = new MicrogridSupervisorImpl();
}
+ /**
+ * Test Transitions.
+ *
+ * @throws Exception on error
+ */
@Test
public void testTransitions() throws Exception {
new ControllerTest(this.controller) //
@@ -220,7 +284,7 @@ public void testTransitions() throws Exception {
.addComponent(this.ess) //
.addComponent(this.meter) //
.addComponent(this.relay) //
- .activate(MyConfig.create() //
+ .activate(MyEss.MyConfig.create() //
.setId(CTRL_ID) //
.setEssId(ESS_ID) //
.setMeterId(METER_ID) //
@@ -228,8 +292,7 @@ public void testTransitions() throws Exception {
.setRelayChannel("Relay") //
.setEssGridModeChannel(ESS_ID + "/SetGridMode") //
.setUnderVoltageThreshold(207) //
- .setStableGridTime(2) //
- .build()) //
+ .setStableGridTime(2)) //
.next(new TestCase("SS1: Grid Connected") //
.input(METER_ID, ElectricityMeter.ChannelId.VOLTAGE, 230000) // 230V
.output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS1)
@@ -240,9 +303,7 @@ public void testTransitions() throws Exception {
.output(RELAY_ID, "Relay", false)
.output(ESS_ID, "SetGridMode", GridMode.OFF_GRID.getValue())) // Immediate transition to T1
.next(new TestCase("T1 -> SS2: Islanded") //
- .output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS2)) // Immediate
- // transition to
- // SS2
+ .output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS2)) //
.next(new TestCase("SS2: Still Islanded") //
.input(METER_ID, ElectricityMeter.ChannelId.VOLTAGE, 230000) // 230V, Timer becomes 1
.output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS2)) //
@@ -252,7 +313,6 @@ public void testTransitions() throws Exception {
.output(RELAY_ID, "Relay", true)
.output(ESS_ID, "SetGridMode", GridMode.ON_GRID.getValue())) // Now showing T3
.next(new TestCase("T3 -> SS1") //
- .output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS1)); // Now showing
- // SS1
+ .output(CTRL_ID, MicrogridSupervisor.ChannelId.STATE_MACHINE, MemsState.SS1)); // Now showing SS1
}
}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MyConfig.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MyConfig.java
index cb87c9629a4..c79f9b1135e 100644
--- a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MyConfig.java
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/MyConfig.java
@@ -2,17 +2,22 @@
import io.openems.common.test.AbstractComponentConfig;
+/**
+ * Dummy Config for Microgrid Supervisor tests.
+ */
public class MyConfig extends AbstractComponentConfig implements Config {
protected static class Builder {
private String id;
- private String ess_id;
- private String meter_id;
- private String relay_id;
- private String relay_channel;
- private String ess_grid_mode_channel;
- private int under_voltage_threshold;
- private int stable_grid_time;
+ private String alias = "";
+ private boolean enabled = true;
+ private String essId;
+ private String meterId;
+ private String relayId;
+ private String relayChannel;
+ private String essGridModeChannel;
+ private int underVoltageThreshold;
+ private int stableGridTime;
private Builder() {
}
@@ -22,38 +27,48 @@ public Builder setId(String id) {
return this;
}
- public Builder setEssId(String ess_id) {
- this.ess_id = ess_id;
+ public Builder setAlias(String alias) {
+ this.alias = alias;
return this;
}
- public Builder setMeterId(String meter_id) {
- this.meter_id = meter_id;
+ public Builder setEnabled(boolean enabled) {
+ this.enabled = enabled;
return this;
}
- public Builder setRelayId(String relay_id) {
- this.relay_id = relay_id;
+ public Builder setEssId(String essId) {
+ this.essId = essId;
return this;
}
- public Builder setRelayChannel(String relay_channel) {
- this.relay_channel = relay_channel;
+ public Builder setMeterId(String meterId) {
+ this.meterId = meterId;
return this;
}
- public Builder setEssGridModeChannel(String ess_grid_mode_channel) {
- this.ess_grid_mode_channel = ess_grid_mode_channel;
+ public Builder setRelayId(String relayId) {
+ this.relayId = relayId;
return this;
}
- public Builder setUnderVoltageThreshold(int under_voltage_threshold) {
- this.under_voltage_threshold = under_voltage_threshold;
+ public Builder setRelayChannel(String relayChannel) {
+ this.relayChannel = relayChannel;
return this;
}
- public Builder setStableGridTime(int stable_grid_time) {
- this.stable_grid_time = stable_grid_time;
+ public Builder setEssGridModeChannel(String essGridModeChannel) {
+ this.essGridModeChannel = essGridModeChannel;
+ return this;
+ }
+
+ public Builder setUnderVoltageThreshold(int underVoltageThreshold) {
+ this.underVoltageThreshold = underVoltageThreshold;
+ return this;
+ }
+
+ public Builder setStableGridTime(int stableGridTime) {
+ this.stableGridTime = stableGridTime;
return this;
}
@@ -62,6 +77,11 @@ public MyConfig build() {
}
}
+ /**
+ * Create a Builder.
+ *
+ * @return the Builder
+ */
public static Builder create() {
return new Builder();
}
@@ -74,42 +94,47 @@ private MyConfig(Builder builder) {
}
@Override
- public String ess_id() {
- return this.builder.ess_id;
+ public String alias() {
+ return this.builder.alias;
+ }
+
+ @Override
+ public boolean enabled() {
+ return this.builder.enabled;
}
@Override
- public String meter_id() {
- return this.builder.meter_id;
+ public String essId() {
+ return this.builder.essId;
}
@Override
- public String relay_id() {
- return this.builder.relay_id;
+ public String meterId() {
+ return this.builder.meterId;
}
@Override
- public String relay_channel() {
- return this.builder.relay_channel;
+ public String relayId() {
+ return this.builder.relayId;
}
@Override
- public String ess_grid_mode_channel() {
- return this.builder.ess_grid_mode_channel;
+ public String relayChannel() {
+ return this.builder.relayChannel;
}
@Override
- public int under_voltage_threshold() {
- return this.builder.under_voltage_threshold;
+ public String essGridModeChannel() {
+ return this.builder.essGridModeChannel;
}
@Override
- public int stable_grid_time() {
- return this.builder.stable_grid_time;
+ public int underVoltageThreshold() {
+ return this.builder.underVoltageThreshold;
}
@Override
- public String webconsole_configurationFactory_nameHint() {
- return "";
+ public int stableGridTime() {
+ return this.builder.stableGridTime;
}
}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyManagedSymmetricPvInverter.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyManagedSymmetricPvInverter.java
new file mode 100644
index 00000000000..d2c7d130f9d
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyManagedSymmetricPvInverter.java
@@ -0,0 +1,47 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+import io.openems.common.channel.AccessMode;
+import io.openems.common.types.OpenemsType;
+import io.openems.common.types.MeterType;
+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.meter.api.ElectricityMeter;
+
+public class DummyManagedSymmetricPvInverter extends AbstractDummyOpenemsComponent
+ implements ElectricityMeter, OpenemsComponent {
+
+ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+ SET_ACTIVE_POWER_LIMIT(Doc.of(OpenemsType.INTEGER).accessMode(AccessMode.WRITE_ONLY));
+
+ private final Doc doc;
+
+ private ChannelId(Doc doc) {
+ this.doc = doc;
+ }
+
+ @Override
+ public Doc doc() {
+ return this.doc;
+ }
+ }
+
+ public DummyManagedSymmetricPvInverter(String id) {
+ super(id, //
+ OpenemsComponent.ChannelId.values(), //
+ ElectricityMeter.ChannelId.values(), //
+ ChannelId.values() //
+ );
+ }
+
+ @Override
+ public MeterType getMeterType() {
+ return MeterType.PRODUCTION;
+ }
+
+ @Override
+ protected DummyManagedSymmetricPvInverter self() {
+ return this;
+ }
+
+}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyMicrogridSupervisor.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyMicrogridSupervisor.java
new file mode 100644
index 00000000000..fd967f076f4
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/DummyMicrogridSupervisor.java
@@ -0,0 +1,17 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+import io.openems.edge.common.component.AbstractOpenemsComponent;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.controller.microgrid.MicrogridSupervisor;
+
+public class DummyMicrogridSupervisor extends AbstractOpenemsComponent implements MicrogridSupervisor, OpenemsComponent {
+
+ public DummyMicrogridSupervisor(String id) {
+ super(//
+ OpenemsComponent.ChannelId.values(), //
+ MicrogridSupervisor.ChannelId.values() //
+ );
+ super.activate(null, id, "", true);
+ }
+
+}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImplTest.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImplTest.java
new file mode 100644
index 00000000000..8a0df8828d2
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MicrogridDispatcherImplTest.java
@@ -0,0 +1,94 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+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.microgrid.statemachine.MemsState;
+import io.openems.edge.controller.test.ControllerTest;
+import io.openems.edge.ess.test.DummyManagedSymmetricEss;
+import io.openems.edge.meter.test.DummyElectricityMeter;
+import io.openems.edge.io.test.DummyInputOutput;
+
+public class MicrogridDispatcherImplTest {
+
+ @Test
+ public void testSS1() throws Exception {
+ new ControllerTest(new MicrogridDispatcherImpl()) //
+ .addReference("componentManager", new DummyComponentManager()) //
+ .addComponent(new DummyManagedSymmetricEss("ess0")) //
+ .addComponent(new DummyElectricityMeter("meter0")) //
+ .addComponent(new DummyMicrogridSupervisor("supervisor0")) //
+ .addComponent(new DummyInputOutput("io0")) //
+ .activate(MyConfig.create() //
+ .setId("ctrl0") //
+ .setEssId("ess0") //
+ .setMeterId("meter0") //
+ .setGensetId("meter1") //
+ .setPvId("pv0") //
+ .setSupervisorId("supervisor0") //
+ .setGridLimit(10000) //
+ .setGensetStartStopChannel("io0/InputOutput0") //
+ .build())
+ .next(new TestCase() // SS1: Peak Shaving
+ .input(new ChannelAddress("supervisor0", "StateMachine"), MemsState.SS1) //
+ .input(new ChannelAddress("meter0", "ActivePower"), 15000) //
+ .output(new ChannelAddress("ess0", "SetActivePowerEquals"), 5000) //
+ .output(new ChannelAddress("io0", "InputOutput0"), false)) // Stop Genset
+ .next(new TestCase() // SS1: No Peak Shaving
+ .input(new ChannelAddress("meter0", "ActivePower"), 5000) //
+ .output(new ChannelAddress("ess0", "SetActivePowerEquals"), null));
+ }
+
+ @Test
+ public void testSS2() throws Exception {
+ new ControllerTest(new MicrogridDispatcherImpl()) //
+ .addReference("componentManager", new DummyComponentManager()) //
+ .addComponent(new DummyManagedSymmetricEss("ess0")) //
+ .addComponent(new DummyElectricityMeter("meter0")) //
+ .addComponent(new DummyElectricityMeter("meter1")) // Genset
+ .addComponent(new DummyManagedSymmetricPvInverter("pv0")) //
+ .addComponent(new DummyMicrogridSupervisor("supervisor0")) //
+ .addComponent(new DummyInputOutput("io0")) //
+ .activate(MyConfig.create() //
+ .setId("ctrl0") //
+ .setEssId("ess0") //
+ .setMeterId("meter0") //
+ .setGensetId("meter1") //
+ .setPvId("pv0") //
+ .setSupervisorId("supervisor0") //
+ .setGensetStartSoc(20) //
+ .setGensetStopSoc(80) //
+ .setGensetCapacity(50000) //
+ .setGensetStartStopChannel("io0/InputOutput0") //
+ .build())
+ .next(new TestCase() // SS2: Genset Start (SoC < 20)
+ .input(new ChannelAddress("supervisor0", "StateMachine"), MemsState.SS2) //
+ .input(new ChannelAddress("ess0", "Soc"), 15) //
+ .input(new ChannelAddress("meter1", "ActivePower"), 0) // Genset OFF
+ .input(new ChannelAddress("ess0", "ActivePower"), 0) //
+ .input(new ChannelAddress("pv0", "ActivePower"), 0) //
+ .output(new ChannelAddress("io0", "InputOutput0"), true)) // Start Genset
+ .next(new TestCase() // SS2: Genset Stop (SoC > 80)
+ .input(new ChannelAddress("ess0", "Soc"), 85) //
+ .input(new ChannelAddress("meter1", "ActivePower"), 20000) // Genset ON
+ .output(new ChannelAddress("io0", "InputOutput0"), false)) // Stop Genset
+ .next(new TestCase() // SS2: Genset Loading (Target = 50000 * 0.4 = 20000)
+ .input(new ChannelAddress("ess0", "Soc"), 50) //
+ .input(new ChannelAddress("meter1", "ActivePower"), 10000) // Currently 10kW
+ .input(new ChannelAddress("pv0", "ActivePower"), 5000) //
+ .input(new ChannelAddress("ess0", "ActivePower"), 0) //
+ // Consumption = 10000 + 5000 + 0 = 15000
+ // ESS_Setpoint = Consumption - PV - Target = 15000 - 5000 - 20000 = -10000 (Charge)
+ .output(new ChannelAddress("ess0", "SetActivePowerEquals"), -10000))
+ .next(new TestCase() // SS2: PV Curtailment (SoC > 95 and cannot charge)
+ .input(new ChannelAddress("ess0", "Soc"), 98) //
+ .input(new ChannelAddress("ess0", "AllowedChargePower"), -50) // Almost 0
+ .input(new ChannelAddress("meter1", "ActivePower"), 0) // Genset OFF
+ .input(new ChannelAddress("pv0", "ActivePower"), 10000) //
+ .input(new ChannelAddress("ess0", "ActivePower"), -50) //
+ // Consumption = 0 + 10000 - 50 = 9950
+ .output(new ChannelAddress("pv0", "SetActivePowerLimit"), 9950));
+ }
+}
diff --git a/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MyConfig.java b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MyConfig.java
new file mode 100644
index 00000000000..d424c5cc5ec
--- /dev/null
+++ b/io.openems.edge.controller.microgrid/test/io/openems/edge/controller/microgrid/dispatcher/MyConfig.java
@@ -0,0 +1,173 @@
+package io.openems.edge.controller.microgrid.dispatcher;
+
+import io.openems.common.test.AbstractComponentConfig;
+
+/**
+ * Dummy Config for Microgrid Dispatcher tests.
+ */
+public class MyConfig extends AbstractComponentConfig implements Config {
+
+ protected static class Builder {
+ private String id;
+ private String alias = "";
+ private boolean enabled = true;
+ private String essId;
+ private String meterId;
+ private String gensetId;
+ private String gensetStartStopChannel;
+ private String pvId;
+ private String supervisorId;
+ private int gridLimit;
+ private int gensetStartSoc;
+ private int gensetStopSoc;
+ private int gensetCapacity;
+
+ private Builder() {
+ }
+
+ public Builder setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setAlias(String alias) {
+ this.alias = alias;
+ return this;
+ }
+
+ public Builder setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public Builder setEssId(String essId) {
+ this.essId = essId;
+ return this;
+ }
+
+ public Builder setMeterId(String meterId) {
+ this.meterId = meterId;
+ return this;
+ }
+
+ public Builder setGensetId(String gensetId) {
+ this.gensetId = gensetId;
+ return this;
+ }
+
+ public Builder setGensetStartStopChannel(String gensetStartStopChannel) {
+ this.gensetStartStopChannel = gensetStartStopChannel;
+ return this;
+ }
+
+ public Builder setPvId(String pvId) {
+ this.pvId = pvId;
+ return this;
+ }
+
+ public Builder setSupervisorId(String supervisorId) {
+ this.supervisorId = supervisorId;
+ return this;
+ }
+
+ public Builder setGridLimit(int gridLimit) {
+ this.gridLimit = gridLimit;
+ return this;
+ }
+
+ public Builder setGensetStartSoc(int gensetStartSoc) {
+ this.gensetStartSoc = gensetStartSoc;
+ return this;
+ }
+
+ public Builder setGensetStopSoc(int gensetStopSoc) {
+ this.gensetStopSoc = gensetStopSoc;
+ return this;
+ }
+
+ public Builder setGensetCapacity(int gensetCapacity) {
+ this.gensetCapacity = gensetCapacity;
+ return this;
+ }
+
+ public MyConfig build() {
+ return new MyConfig(this);
+ }
+ }
+
+ /**
+ * Create a Builder.
+ *
+ * @return the 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 alias() {
+ return this.builder.alias;
+ }
+
+ @Override
+ public boolean enabled() {
+ return this.builder.enabled;
+ }
+
+ @Override
+ public String essId() {
+ return this.builder.essId;
+ }
+
+ @Override
+ public String meterId() {
+ return this.builder.meterId;
+ }
+
+ @Override
+ public String gensetId() {
+ return this.builder.gensetId;
+ }
+
+ @Override
+ public String gensetStartStopChannel() {
+ return this.builder.gensetStartStopChannel;
+ }
+
+ @Override
+ public String pvId() {
+ return this.builder.pvId;
+ }
+
+ @Override
+ public String supervisorId() {
+ return this.builder.supervisorId;
+ }
+
+ @Override
+ public int gridLimit() {
+ return this.builder.gridLimit;
+ }
+
+ @Override
+ public int gensetStartSoc() {
+ return this.builder.gensetStartSoc;
+ }
+
+ @Override
+ public int gensetStopSoc() {
+ return this.builder.gensetStopSoc;
+ }
+
+ @Override
+ public int gensetCapacity() {
+ return this.builder.gensetCapacity;
+ }
+}
diff --git a/io.openems.edge.io.revpi/bnd.bnd b/io.openems.edge.io.revpi/bnd.bnd
index 908d1c7476f..d6ad3dd640d 100644
--- a/io.openems.edge.io.revpi/bnd.bnd
+++ b/io.openems.edge.io.revpi/bnd.bnd
@@ -3,16 +3,12 @@ Bundle-Vendor: opernikus GmbH
Bundle-License: https://opensource.org/licenses/EPL-2.0
Bundle-Version: 1.0.0.${tstamp}
--includeresource.librevpi: \
- @lib/librevpi-dio-java.jar; lib:=true
-
-buildpath: \
${buildpath},\
com.google.guava,\
io.openems.common,\
io.openems.edge.common,\
- io.openems.edge.io.api,\
- lib/librevpi-dio-java.jar;version=file,\
+ io.openems.edge.io.api
-testpath: \
${testpath}
diff --git a/io.openems.edge.io.revpi/src/org/clehne/revpi/dataio/DataInOut.java b/io.openems.edge.io.revpi/src/org/clehne/revpi/dataio/DataInOut.java
new file mode 100644
index 00000000000..a45997935d8
--- /dev/null
+++ b/io.openems.edge.io.revpi/src/org/clehne/revpi/dataio/DataInOut.java
@@ -0,0 +1,49 @@
+package org.clehne.revpi.dataio;
+
+import java.io.IOException;
+
+/**
+ * Dummy DataInOut.
+ */
+public class DataInOut {
+
+ /**
+ * Dummy close.
+ *
+ * @throws IOException if error
+ */
+ public void close() throws IOException {
+ }
+
+ /**
+ * Dummy getDataOut.
+ *
+ * @param idx index
+ * @return false
+ * @throws IOException if error
+ */
+ public boolean getDataOut(int idx) throws IOException {
+ return false;
+ }
+
+ /**
+ * Dummy getDataIn.
+ *
+ * @param idx index
+ * @return false
+ * @throws IOException if error
+ */
+ public boolean getDataIn(int idx) throws IOException {
+ return false;
+ }
+
+ /**
+ * Dummy setDataOut.
+ *
+ * @param idx index
+ * @param val value
+ * @throws IOException if error
+ */
+ public void setDataOut(int idx, boolean val) throws IOException {
+ }
+}
diff --git a/mems/state-machine.json b/mems/state-machine.json
index 2662936d83d..0666275ead6 100644
--- a/mems/state-machine.json
+++ b/mems/state-machine.json
@@ -3,7 +3,7 @@
"id": "microgrid",
"version": "1.0.0",
"description": "IEEE 2030.7 Microgrid Supervisor Controller",
- "initial": "SS1",
+ "initial": "INIT",
"context": {
"ess_id": "ess0",
"meter_id": "meter0",
@@ -14,6 +14,19 @@
"stable_grid_timer": 0
},
"states": {
+ "INIT": {
+ "description": "Initial State: Determine starting mode",
+ "always": [
+ {
+ "target": "SS1",
+ "guard": "isGridVoltageNormal"
+ },
+ {
+ "target": "T4",
+ "guard": "isGridVoltageLow"
+ }
+ ]
+ },
"SS1": {
"description": "Steady State 1: Grid Connected",
"entry": [
@@ -68,17 +81,34 @@
"isGridVoltageLow": {
"expression": "context.grid_voltage < context.under_voltage_threshold"
},
+ "isGridVoltageNormal": {
+ "expression": "context.grid_voltage >= context.under_voltage_threshold"
+ },
"isGridVoltageStableForTime": {
"expression": "context.grid_voltage >= context.under_voltage_threshold && context.stable_grid_timer >= context.stable_grid_time"
}
},
"actions": {
- "openRelay": { "description": "Open the islanding relay" },
- "closeRelay": { "description": "Close the islanding relay" },
- "setEssOffGrid": { "description": "Set ESS to OFF_GRID mode" },
- "setEssOnGrid": { "description": "Set ESS to ON_GRID mode" },
- "checkSync": { "description": "Perform sync check" },
- "logGridConnected": { "description": "Log grid connected state" },
- "logIslanded": { "description": "Log islanded state" }
+ "openRelay": {
+ "description": "Open the islanding relay"
+ },
+ "closeRelay": {
+ "description": "Close the islanding relay"
+ },
+ "setEssOffGrid": {
+ "description": "Set ESS to OFF_GRID mode"
+ },
+ "setEssOnGrid": {
+ "description": "Set ESS to ON_GRID mode"
+ },
+ "checkSync": {
+ "description": "Perform sync check"
+ },
+ "logGridConnected": {
+ "description": "Log grid connected state"
+ },
+ "logIslanded": {
+ "description": "Log islanded state"
+ }
}
-}
+}
\ No newline at end of file
diff --git a/mems/tools/generate.js b/mems/tools/generate.js
index fb55446c1b2..96da54cc5e6 100644
--- a/mems/tools/generate.js
+++ b/mems/tools/generate.js
@@ -21,6 +21,9 @@ function loadJson(path) {
}
function toPascalCase(str) {
+ if (str === 'UNDEFINED') {
+ return 'Undefined';
+ }
return str
.split(/[._-]/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
@@ -340,6 +343,12 @@ ${this.generateStateHandlerSwitch()}
console.log('Generating StateHandler classes...');
this.generateHandlersRecursive(this.machine.states, '', outputDir);
+
+ // Also generate UndefinedHandler if it's in the state list but not in the machine states
+ const states = this.extractAllStates(this.machine.states, '');
+ if (states.some(s => s.name === 'UNDEFINED')) {
+ this.generateSingleHandler('UNDEFINED', { description: 'UNDEFINED state' }, 'UndefinedHandler', outputDir);
+ }
}
generateHandlersRecursive(states, prefix, outputDir) {
@@ -365,11 +374,9 @@ ${this.generateStateHandlerSwitch()}
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.statemachine.StateHandler;
-import ${this.packageName}.MemsContext;
-import ${this.packageName}.MemsState;
/**
- * Handler for state: ${stateName}
+ * Handler for state: ${stateName}.
* ${state.description || ''}
* Auto-generated from state-machine.json
*/
diff --git a/mems/tools/verify.js b/mems/tools/verify.js
index f00443d84c3..abed89836b2 100644
--- a/mems/tools/verify.js
+++ b/mems/tools/verify.js
@@ -25,18 +25,18 @@ class StateMachineVerifier {
this.transitions = [];
this.errors = [];
this.warnings = [];
-
+
this.buildGraph();
}
-
+
buildGraph() {
this.extractStates(this.machine.states, '');
}
-
+
extractStates(states, prefix) {
for (const [name, state] of Object.entries(states)) {
const fullName = prefix ? `${prefix}.${name}` : name;
-
+
const stateInfo = {
name: fullName,
type: state.type || 'atomic',
@@ -47,41 +47,41 @@ class StateMachineVerifier {
transitions: [],
incomingTransitions: []
};
-
+
// Extract transitions from 'on'
if (state.on) {
for (const [event, trans] of Object.entries(state.on)) {
this.extractTransitions(trans, fullName, event, stateInfo);
}
}
-
+
// Extract transitions from 'after'
if (state.after) {
for (const [delay, trans] of Object.entries(state.after)) {
this.extractTransitions(trans, fullName, `after:${delay}`, stateInfo);
}
}
-
+
// Extract transitions from 'always'
if (state.always) {
this.extractTransitions(state.always, fullName, 'always', stateInfo);
}
-
+
this.states.set(fullName, stateInfo);
-
+
// Recurse into substates
if (state.states) {
this.extractStates(state.states, fullName);
}
}
}
-
+
extractTransitions(trans, fromState, event, stateInfo) {
const transitions = Array.isArray(trans) ? trans : [trans];
-
+
transitions.forEach(t => {
let target, guard;
-
+
if (typeof t === 'string') {
target = t;
} else if (t && t.target) {
@@ -91,7 +91,7 @@ class StateMachineVerifier {
// Internal transition (no target)
return;
}
-
+
if (target) {
const transition = {
from: fromState,
@@ -99,24 +99,24 @@ class StateMachineVerifier {
event,
guard: guard || null
};
-
+
stateInfo.transitions.push(transition);
this.transitions.push(transition);
}
});
}
-
+
resolveTarget(target, currentState) {
// Handle absolute references (#stateName)
if (target.startsWith('#')) {
return target.substring(target.indexOf('.') + 1) || target.substring(1);
}
-
+
// Handle relative references
if (target.includes('.')) {
return target;
}
-
+
// Simple state name - could be sibling or child
const parts = currentState.split('.');
if (parts.length > 1) {
@@ -124,38 +124,38 @@ class StateMachineVerifier {
parts.pop();
return `${parts.join('.')}.${target}`;
}
-
+
return target;
}
-
+
verify() {
console.log('=== MEMS State Machine Formal Verification ===\n');
-
+
this.checkDeadlocks();
this.checkReachability();
this.checkDeterminism();
this.checkGuardCompleteness();
this.checkIEEE2030_7Compliance();
-
+
return this.report();
}
-
+
checkDeadlocks() {
console.log('Checking for deadlocks...');
-
+
for (const [name, state] of this.states) {
// Skip parallel container states and states with substates
if (state.isParallel || state.hasSubstates) continue;
-
+
// Final states are allowed to have no outgoing transitions
if (state.isFinal) continue;
-
+
// Check if state has any outgoing transitions
const hasOutgoing = state.transitions.length > 0;
-
+
// Check if any parent state has transitions that could exit this state
const parentTransitions = this.getParentTransitions(name);
-
+
if (!hasOutgoing && parentTransitions.length === 0) {
// Check if this is emergencyShutdown - it's allowed to be a "waiting" state
if (name === 'emergencyShutdown') {
@@ -166,11 +166,11 @@ class StateMachineVerifier {
}
}
}
-
+
getParentTransitions(stateName) {
const parts = stateName.split('.');
const parentTransitions = [];
-
+
while (parts.length > 1) {
parts.pop();
const parentName = parts.join('.');
@@ -179,43 +179,43 @@ class StateMachineVerifier {
parentTransitions.push(...parent.transitions);
}
}
-
+
return parentTransitions;
}
-
+
checkReachability() {
console.log('Checking reachability...');
-
+
const reachable = new Set();
const queue = [this.machine.initial];
-
+
while (queue.length > 0) {
const current = queue.shift();
if (reachable.has(current)) continue;
-
+
reachable.add(current);
-
+
const state = this.states.get(current);
if (!state) continue;
-
+
// Add initial substate if compound
if (state.initial) {
queue.push(`${current}.${state.initial}`);
}
-
+
// Add all parallel substates
if (state.isParallel && state.hasSubstates) {
const substates = this.getDirectSubstates(current);
substates.forEach(s => queue.push(s));
}
-
+
// Add transition targets
state.transitions.forEach(t => {
if (t.to && !reachable.has(t.to)) {
queue.push(t.to);
}
});
-
+
// Check parent transitions
const parentTransitions = this.getParentTransitions(current);
parentTransitions.forEach(t => {
@@ -224,29 +224,29 @@ class StateMachineVerifier {
}
});
}
-
+
// Check for unreachable states
for (const [name, state] of this.states) {
// Skip internal states that are reached via initial
const isReachableViaParent = this.isReachableViaParent(name, reachable);
-
+
if (!reachable.has(name) && !isReachableViaParent) {
this.warnings.push(`Unreachable state: '${name}'`);
}
}
}
-
+
getDirectSubstates(parentName) {
const substates = [];
for (const [name] of this.states) {
- if (name.startsWith(parentName + '.') &&
- name.substring(parentName.length + 1).indexOf('.') === -1) {
+ if (name.startsWith(parentName + '.') &&
+ name.substring(parentName.length + 1).indexOf('.') === -1) {
substates.push(name);
}
}
return substates;
}
-
+
isReachableViaParent(stateName, reachable) {
const parts = stateName.split('.');
while (parts.length > 1) {
@@ -261,21 +261,21 @@ class StateMachineVerifier {
}
return false;
}
-
+
checkDeterminism() {
console.log('Checking determinism...');
-
+
for (const [name, state] of this.states) {
// Group transitions by event
const byEvent = new Map();
-
+
state.transitions.forEach(t => {
if (!byEvent.has(t.event)) {
byEvent.set(t.event, []);
}
byEvent.get(t.event).push(t);
});
-
+
// Check for non-determinism
for (const [event, transitions] of byEvent) {
if (transitions.length > 1) {
@@ -293,12 +293,12 @@ class StateMachineVerifier {
}
}
}
-
+
checkGuardCompleteness() {
console.log('Checking guard completeness...');
-
+
const definedGuards = new Set(Object.keys(this.machine.guards || {}));
-
+
this.transitions.forEach(t => {
if (t.guard && typeof t.guard === 'string') {
if (!definedGuards.has(t.guard)) {
@@ -307,68 +307,70 @@ class StateMachineVerifier {
}
});
}
-
+
checkIEEE2030_7Compliance() {
console.log('Checking IEEE 2030.7 compliance...');
-
+
const requiredStates = [
'gridConnected',
'islanded',
'emergencyShutdown'
];
-
+
const requiredCapabilities = [
- { name: 'Grid-connected mode', check: () => this.states.has('gridConnected') },
- { name: 'Island mode', check: () => this.states.has('islanded') },
- { name: 'Transition to island', check: () => this.hasTransitionBetween('gridConnected', 'island') },
- { name: 'Transition to grid', check: () => this.hasTransitionBetween('islanded', 'gridConnected') },
- { name: 'Black start capability', check: () => this.states.has('blackStart') },
+ { name: 'Grid-connected mode', check: () => this.states.has('gridConnected') || this.states.has('SS1') },
+ { name: 'Island mode', check: () => this.states.has('islanded') || this.states.has('SS2') },
+ { name: 'Transition to island', check: () => this.hasTransitionBetween('gridConnected|SS1', 'island|SS2|T1') },
+ { name: 'Transition to grid', check: () => this.hasTransitionBetween('islanded|SS2', 'gridConnected|SS1|T3') },
+ { name: 'Black start capability', check: () => this.states.has('blackStart') || this.states.has('T4') },
{ name: 'Emergency shutdown', check: () => this.states.has('emergencyShutdown') }
];
-
+
requiredCapabilities.forEach(cap => {
if (!cap.check()) {
this.warnings.push(`IEEE 2030.7: Missing capability - ${cap.name}`);
}
});
}
-
- hasTransitionBetween(from, toPattern) {
- return this.transitions.some(t =>
- t.from.includes(from) && t.to.includes(toPattern)
+
+ hasTransitionBetween(fromPattern, toPattern) {
+ const fromRegex = new RegExp(fromPattern);
+ const toRegex = new RegExp(toPattern);
+ return this.transitions.some(t =>
+ fromRegex.test(t.from) && toRegex.test(t.to)
);
}
-
+
report() {
console.log('\n=== Verification Results ===\n');
-
+
const passed = this.errors.length === 0;
-
+
if (this.errors.length > 0) {
console.log('❌ ERRORS:');
this.errors.forEach(e => console.log(` - ${e}`));
console.log('');
}
-
+
if (this.warnings.length > 0) {
console.log('⚠️ WARNINGS:');
this.warnings.forEach(w => console.log(` - ${w}`));
console.log('');
}
-
+
console.log('Summary:');
console.log(` - States analyzed: ${this.states.size}`);
console.log(` - Transitions analyzed: ${this.transitions.length}`);
console.log(` - Errors: ${this.errors.length}`);
console.log(` - Warnings: ${this.warnings.length}`);
console.log('');
-
+
if (passed) {
console.log('✅ Verification PASSED');
} else {
console.log('❌ Verification FAILED');
}
-
+
return passed;
}
}