diff --git a/io.openems.edge.evcs.openwb/bnd.bnd b/io.openems.edge.evcs.openwb/bnd.bnd
index 47f2ec83951..befbfb48ef6 100644
--- a/io.openems.edge.evcs.openwb/bnd.bnd
+++ b/io.openems.edge.evcs.openwb/bnd.bnd
@@ -6,6 +6,8 @@ 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.evcs.api,\
io.openems.edge.meter.api,\
diff --git a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/Config.java b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/Config.java
index 72fe74b7f99..e09ab853dc8 100644
--- a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/Config.java
+++ b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/Config.java
@@ -3,6 +3,8 @@
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import io.openems.edge.meter.api.PhaseRotation;
+
@ObjectClassDefinition(//
name = "EVCS OpenWB", //
description = "Implements the evcs component for OpenWB Series2 with internal chargepoints via HTTP API")
@@ -26,6 +28,9 @@
@AttributeDefinition(name = "Chargepoint", description = "Number of the internal chargepoint")
ChargePoint chargePoint() default ChargePoint.CP0;
+ @AttributeDefinition(name = "Phase rotation", description = "The way in which the phases are physically rotated.")
+ PhaseRotation phaseRotation() default PhaseRotation.L1_L2_L3;
+
String webconsole_configurationFactory_nameHint() default "EVCS OpenWB [{id}]";
}
\ No newline at end of file
diff --git a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWb.java b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWb.java
index 0dc09df9159..ecf0c7e4417 100644
--- a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWb.java
+++ b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWb.java
@@ -12,16 +12,16 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Slave Communication Failed Fault.
*
*
- * Indicates a failure in communication with a slave device, which might affect
- * system operations.
+ * Indicates a failure in communication with the OpenWB charger, which might
+ * affect system operations.
*
*
- * - Interface: ShellyPlug
+ *
- Interface: EvcsOpenWb
*
- Type: State
*
*/
SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)//
- .text("Communication with slave device failed."));
+ .text("Communication with OpenWB charger failed."));
private final Doc doc;
@@ -34,4 +34,14 @@ public Doc doc() {
return this.doc;
}
}
+
+ /**
+ * Internal method to set the 'nextValue' on
+ * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel.
+ *
+ * @param value the next value
+ */
+ public default void _setSlaveCommunicationFailed(boolean value) {
+ this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED).setNextValue(value);
+ }
}
diff --git a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWbImpl.java b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWbImpl.java
index c0029dff614..c1693320a7b 100644
--- a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWbImpl.java
+++ b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/EvcsOpenWbImpl.java
@@ -1,6 +1,10 @@
package io.openems.edge.evcs.openwb;
-import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE;
+import static io.openems.common.utils.JsonUtils.getAsBoolean;
+import static io.openems.common.utils.JsonUtils.getAsFloat;
+import static io.openems.common.utils.JsonUtils.getAsInt;
+import static io.openems.common.utils.JsonUtils.getAsJsonArray;
+import static io.openems.common.utils.JsonUtils.parseToJsonObject;
import static org.osgi.service.component.annotations.ConfigurationPolicy.REQUIRE;
import static org.osgi.service.component.annotations.ReferenceCardinality.OPTIONAL;
import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC;
@@ -8,54 +12,72 @@
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-import org.osgi.service.event.propertytypes.EventTopics;
import org.osgi.service.metatype.annotations.Designate;
+import io.openems.common.bridge.http.api.BridgeHttp;
+import io.openems.common.bridge.http.api.BridgeHttpFactory;
import io.openems.common.channel.AccessMode;
-import io.openems.common.exceptions.InvalidValueException;
import io.openems.common.exceptions.OpenemsException;
import io.openems.common.types.MeterType;
import io.openems.common.utils.InetAddressUtils;
+import io.openems.edge.bridge.http.cycle.HttpBridgeCycleService;
+import io.openems.edge.bridge.http.cycle.HttpBridgeCycleServiceDefinition;
import io.openems.edge.common.component.AbstractOpenemsComponent;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.modbusslave.ModbusSlave;
import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable;
import io.openems.edge.common.modbusslave.ModbusSlaveTable;
+import io.openems.edge.evcs.api.ChargingType;
import io.openems.edge.evcs.api.Evcs;
+import io.openems.edge.evcs.api.Status;
import io.openems.edge.meter.api.ElectricityMeter;
import io.openems.edge.meter.api.PhaseRotation;
import io.openems.edge.timedata.api.Timedata;
import io.openems.edge.timedata.api.TimedataProvider;
-import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower;
@Designate(ocd = Config.class, factory = true)
@Component(//
name = "Evcs.OpenWB", //
immediate = true, //
configurationPolicy = REQUIRE)
-@EventTopics({ //
- TOPIC_CYCLE_AFTER_PROCESS_IMAGE, //
-})
public class EvcsOpenWbImpl extends AbstractOpenemsComponent
- implements EvcsOpenWb, ElectricityMeter, OpenemsComponent, Evcs, TimedataProvider, EventHandler, ModbusSlave {
+ implements EvcsOpenWb, ElectricityMeter, OpenemsComponent, Evcs, TimedataProvider, ModbusSlave {
- private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this,
- ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY);
- private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this,
- ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY);
+ private static final String URL_GET_POWER = "power";
+ private static final String URL_GET_POWERS = "powers";
+ private static final String URL_GET_VOLTAGES = "voltages";
+ private static final String URL_GET_CURRENTS = "currents";
+ private static final String URL_GET_CHARGE_STATE = "charge_state";
+ private static final String URL_GET_PLUG_STATE = "plug_state";
+ private static final String URL_IMPORTED = "imported";
@Reference(policy = DYNAMIC, policyOption = GREEDY, cardinality = OPTIONAL)
private volatile Timedata timedata;
- private ReadWorker worker = null;
+ @Reference
+ private BridgeHttpFactory httpBridgeFactory;
+ @Reference
+ private HttpBridgeCycleServiceDefinition httpBridgeCycleServiceDefinition;
+
+ private BridgeHttp httpBridge;
+ private HttpBridgeCycleService cycleService;
+
+ private Config config;
+ private String baseUrl;
+ private Integer energyStartSession = null;
public EvcsOpenWbImpl() {
super(//
@@ -72,58 +94,293 @@ public EvcsOpenWbImpl() {
@Activate
protected void activate(ComponentContext context, Config config)
- throws InvalidValueException, KeyManagementException, NoSuchAlgorithmException, OpenemsException {
+ throws KeyManagementException, NoSuchAlgorithmException, OpenemsException {
super.activate(context, config.id(), config.alias(), config.enabled());
+ this.config = config;
+
+ var ip = InetAddressUtils.parseOrError(config.ip());
+ this.baseUrl = "https://" + ip.getHostAddress() + ":" + config.port() + "/v1?topic=openWB/internal_chargepoint/"
+ + config.chargePoint().value + "/get/";
+
+ this._setStatus(Status.NOT_READY_FOR_CHARGING);
+ this._setChargingType(ChargingType.AC);
- this.worker = new ReadWorker(this, InetAddressUtils.parseOrError(config.ip()), config.port(),
- config.chargePoint());
- this.worker.activate(config.id());
+ this.setupSslTrustAll();
+
+ this.httpBridge = this.httpBridgeFactory.get();
+ this.cycleService = this.httpBridge.createService(this.httpBridgeCycleServiceDefinition);
+
+ this.subscribeToEndpoints();
}
- @Deactivate
- protected void deactivate() {
- if (this.worker != null) {
- this.worker.deactivate();
+ /**
+ * Disables SSL certificate checking for HTTPS connections. OpenWB Series 2 uses
+ * self-signed certificates.
+ */
+ private void setupSslTrustAll() throws NoSuchAlgorithmException, KeyManagementException {
+ var sslContext = SSLContext.getInstance("TLSv1.2");
+ TrustManager[] trustManager = { new X509TrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certificate, String str) {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certificate, String str) {
+ }
+ } };
+ sslContext.init(null, trustManager, new SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+ }
+
+ /**
+ * Subscribes to all OpenWB API endpoints.
+ */
+ private void subscribeToEndpoints() {
+ // Voltages
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_VOLTAGES, //
+ response -> this.handleVoltagesResponse(response.data()), //
+ error -> this.handleError());
+
+ // Powers
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_POWERS, //
+ response -> this.handlePowersResponse(response.data()), //
+ error -> this.handleError());
+
+ // Total Power
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_POWER, //
+ response -> this.handlePowerResponse(response.data()), //
+ error -> this.handleError());
+
+ // Currents
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_CURRENTS, //
+ response -> this.handleCurrentsResponse(response.data()), //
+ error -> this.handleError());
+
+ // Imported (Energy)
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_IMPORTED, //
+ response -> this.handleImportedResponse(response.data()), //
+ error -> this.handleError());
+
+ // Plug State
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_PLUG_STATE, //
+ response -> this.handlePlugStateResponse(response.data()), //
+ error -> this.handleError());
+
+ // Charge State
+ this.cycleService.subscribeEveryCycle(//
+ this.baseUrl + URL_GET_CHARGE_STATE, //
+ response -> this.handleChargeStateResponse(response.data()), //
+ error -> this.handleError());
+ }
+
+ private void handleVoltagesResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ var voltages = getAsJsonArray(json, "message");
+ this._setVoltageL1(getAsInt(voltages.get(0)) * 1000);
+ this._setVoltageL2(getAsInt(voltages.get(1)) * 1000);
+ this._setVoltageL3(getAsInt(voltages.get(2)) * 1000);
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this.resetVoltages();
+ this._setSlaveCommunicationFailed(true);
}
- super.deactivate();
}
- @Override
- public String debugLog() {
- return "L:" + this.getActivePower().asString();
+ private void handlePowersResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ var powers = getAsJsonArray(json, "message");
+ this._setActivePowerL1(getAsInt(powers.get(0)));
+ this._setActivePowerL2(getAsInt(powers.get(1)));
+ this._setActivePowerL3(getAsInt(powers.get(2)));
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this.resetPowers();
+ this._setSlaveCommunicationFailed(true);
+ }
}
- @Override
- public void handleEvent(Event event) {
- if (!this.isEnabled() || this.worker == null) {
- return;
+ private void handlePowerResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ this._setActivePower(Math.round(getAsFloat(json, "message")));
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this._setActivePower(null);
+ this._setSlaveCommunicationFailed(true);
+ }
+ }
+
+ private void handleCurrentsResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ var currents = getAsJsonArray(json, "message");
+ this._setCurrentL1(getAsInt(currents.get(0)) * 1000);
+ this._setCurrentL2(getAsInt(currents.get(1)) * 1000);
+ this._setCurrentL3(getAsInt(currents.get(2)) * 1000);
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this.resetCurrents();
+ this._setSlaveCommunicationFailed(true);
+ }
+ }
+
+ private void handleImportedResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ var energyTotal = Math.round(getAsFloat(json, "message"));
+
+ // Set energy channels directly from OpenWB readings
+ // EVCS only consumes energy, so production is always 0
+ this._setActiveProductionEnergy(0L);
+ this._setActiveConsumptionEnergy(energyTotal);
+
+ // Calculate session energy
+ if (this.energyStartSession != null) {
+ var energySession = (int) Math.max(0, energyTotal - this.energyStartSession);
+ this._setEnergySession(energySession);
+ }
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this._setActiveProductionEnergy(null);
+ this._setActiveConsumptionEnergy(null);
+ this._setEnergySession(null);
+ this._setSlaveCommunicationFailed(true);
}
+ }
+
+ // Keep track of plug/charge states to determine status
+ private Boolean lastPlugState = null;
+ private Boolean lastChargeState = null;
- switch (event.getTopic()) {
- case TOPIC_CYCLE_AFTER_PROCESS_IMAGE: //
- this.worker.triggerNextRun();
- this.calculateEnergy();
+ private void handlePlugStateResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ this.lastPlugState = getAsBoolean(json, "message");
+ this.updateStatus();
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this.lastPlugState = null;
+ this._setStatus(null);
+ this._setSlaveCommunicationFailed(true);
+ }
+ }
- break;
+ private void handleChargeStateResponse(String data) {
+ try {
+ var json = parseToJsonObject(data);
+ this.lastChargeState = getAsBoolean(json, "message");
+ this.updateStatus();
+ this._setSlaveCommunicationFailed(false);
+ } catch (Exception e) {
+ this.lastChargeState = null;
+ this._setStatus(null);
+ this._setSlaveCommunicationFailed(true);
}
}
/**
- * Calculate the Energy values from ActivePower.
+ * Updates the EVCS status based on plug and charge states.
*/
- private void calculateEnergy() {
- // Calculate Energy
- final var activePower = this.getActivePower().get();
- if (activePower == null) {
- this.calculateProductionEnergy.update(null);
- this.calculateConsumptionEnergy.update(null);
- } else if (activePower >= 0) {
- this.calculateProductionEnergy.update(activePower);
- this.calculateConsumptionEnergy.update(0);
+ private void updateStatus() {
+ if (this.lastPlugState == null || this.lastChargeState == null) {
+ return;
+ }
+
+ Status previousStatus = this.getStatus();
+ Status newStatus;
+
+ if (this.lastChargeState) {
+ newStatus = Status.CHARGING;
+ if (previousStatus == Status.NOT_READY_FOR_CHARGING) {
+ // Session starts when plugged in and charging
+ this.startNewSession();
+ }
+ } else if (this.lastPlugState) {
+ newStatus = Status.READY_FOR_CHARGING;
+ if (previousStatus == Status.NOT_READY_FOR_CHARGING) {
+ // Session starts when plugged in
+ this.startNewSession();
+ }
} else {
- this.calculateProductionEnergy.update(0);
- this.calculateConsumptionEnergy.update(-activePower);
+ newStatus = Status.NOT_READY_FOR_CHARGING;
}
+
+ this._setStatus(newStatus);
+ }
+
+ /**
+ * Starts a new charging session by recording the current energy total.
+ */
+ private void startNewSession() {
+ // Get current energy total from the imported response
+ // This will be set when the next imported response comes in
+ try {
+ var response = this.httpBridge.get(this.baseUrl + URL_IMPORTED).get();
+ var json = parseToJsonObject(response.data());
+ this.energyStartSession = Math.round(getAsFloat(json, "message"));
+ } catch (Exception e) {
+ // Will be set on next cycle
+ }
+ }
+
+ private void handleError() {
+ this._setSlaveCommunicationFailed(true);
+ this.resetAllChannels();
+ }
+
+ private void resetVoltages() {
+ this._setVoltageL1(null);
+ this._setVoltageL2(null);
+ this._setVoltageL3(null);
+ }
+
+ private void resetPowers() {
+ this._setActivePowerL1(null);
+ this._setActivePowerL2(null);
+ this._setActivePowerL3(null);
+ }
+
+ private void resetCurrents() {
+ this._setCurrentL1(null);
+ this._setCurrentL2(null);
+ this._setCurrentL3(null);
+ }
+
+ private void resetAllChannels() {
+ this.resetVoltages();
+ this.resetPowers();
+ this.resetCurrents();
+ this._setActivePower(null);
+ this._setActiveProductionEnergy(null);
+ this._setActiveConsumptionEnergy(null);
+ this._setStatus(null);
+ this._setEnergySession(null);
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ this.httpBridgeFactory.unget(this.httpBridge);
+ this.httpBridge = null;
+ super.deactivate();
+ }
+
+ @Override
+ public String debugLog() {
+ return "L:" + this.getActivePower().asString();
}
@Override
@@ -147,6 +404,6 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
@Override
public PhaseRotation getPhaseRotation() {
- return PhaseRotation.L1_L2_L3;
+ return this.config.phaseRotation();
}
}
diff --git a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/ReadWorker.java b/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/ReadWorker.java
deleted file mode 100644
index 2cf5865f5f9..00000000000
--- a/io.openems.edge.evcs.openwb/src/io/openems/edge/evcs/openwb/ReadWorker.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package io.openems.edge.evcs.openwb;
-
-import static io.openems.edge.common.channel.ChannelUtils.setValue;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.Inet4Address;
-import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
-import java.util.stream.Collectors;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import com.google.gson.JsonObject;
-
-import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.exceptions.OpenemsException;
-import io.openems.common.utils.JsonUtils;
-import io.openems.common.worker.AbstractCycleWorker;
-import io.openems.edge.evcs.api.ChargingType;
-import io.openems.edge.evcs.api.Status;
-
-public class ReadWorker extends AbstractCycleWorker {
-
- private static final String URL_GET_POWER = "power";
- private static final String URL_GET_POWERS = "powers";
- private static final String URL_GET_VOLTAGES = "voltages";
- private static final String URL_GET_CURRENTS = "currents";
- private static final String URL_GET_CHARGE_STATE = "charge_state";
- private static final String URL_GET_PLUG_STATE = "plug_state";
- private static final String URL_IMPORTED = "imported";
-
- private final EvcsOpenWbImpl parent;
- private final String baseUrl;
-
- private Integer energyStartSession = null;
-
- protected ReadWorker(EvcsOpenWbImpl parent, Inet4Address ip, int port, ChargePoint chargePoint)
- throws NoSuchAlgorithmException, KeyManagementException {
- this.parent = parent;
-
- this.baseUrl = "https://" + ip.getHostAddress() + ":" + port + "/v1?topic=openWB/internal_chargepoint/"
- + chargePoint.value + "/get/";
- this.energyStartSession = null;
-
- parent._setStatus(Status.NOT_READY_FOR_CHARGING);
-
- /*
- * Disable SSL certificate checking
- */
- var context = SSLContext.getInstance("TLSv1.2");
- TrustManager[] trustManager = { new X509TrustManager() {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] certificate, String str) {
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] certificate, String str) {
- }
- } };
- context.init(null, trustManager, new SecureRandom());
- HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
- }
-
- @Override
- protected void forever() {
- final var openWb = this.parent;
-
- Integer activePower = null;
- Integer activePowerL1 = null;
- Integer activePowerL2 = null;
- Integer activePowerL3 = null;
- Integer voltageL1 = null;
- Integer voltageL2 = null;
- Integer voltageL3 = null;
- Integer currentL1 = null;
- Integer currentL2 = null;
- Integer currentL3 = null;
- Integer energyTotal = null;
- Integer energySession = null;
- Status status = null;
-
- var communicationError = false;
-
- try {
- /**
- * ElectricityMeter channels.
- */
- var voltageResponse = this.getResponse(URL_GET_VOLTAGES);
- var voltages = JsonUtils.getAsJsonArray(voltageResponse, "message");
- voltageL1 = JsonUtils.getAsInt(voltages.get(0)) * 1000;
- voltageL2 = JsonUtils.getAsInt(voltages.get(1)) * 1000;
- voltageL3 = JsonUtils.getAsInt(voltages.get(2)) * 1000;
-
- var powerResponse = this.getResponse(URL_GET_POWERS);
- var powers = JsonUtils.getAsJsonArray(powerResponse, "message");
- activePowerL1 = JsonUtils.getAsInt(powers.get(0));
- activePowerL2 = JsonUtils.getAsInt(powers.get(1));
- activePowerL3 = JsonUtils.getAsInt(powers.get(2));
- activePower = Math.round(JsonUtils.getAsFloat(this.getResponse(URL_GET_POWER), "message"));
-
- var currentResponse = this.getResponse(URL_GET_CURRENTS);
- var currents = JsonUtils.getAsJsonArray(currentResponse, "message");
- currentL1 = JsonUtils.getAsInt(currents.get(0)) * 1000;
- currentL2 = JsonUtils.getAsInt(currents.get(1)) * 1000;
- currentL3 = JsonUtils.getAsInt(currents.get(2)) * 1000;
-
- /**
- * EVCS channels.
- */
- openWb._setChargingType(ChargingType.AC);
-
- /*
- * Read total energy from the box and calculate session energy
- */
- energyTotal = Math.round(JsonUtils.getAsFloat(this.getResponse(URL_IMPORTED), "message"));
- if (this.energyStartSession != null) {
- energySession = (int) Math.max(0, energyTotal - this.energyStartSession);
- }
-
- /*
- * There are only two boolean state values plug state (unplugged and plugged)
- * and charge state (charging and not charging)
- */
- var plugState = JsonUtils.getAsBoolean(this.getResponse(URL_GET_PLUG_STATE), "message");
- var chargeState = JsonUtils.getAsBoolean(this.getResponse(URL_GET_CHARGE_STATE), "message");
-
- if (chargeState) {
- status = Status.CHARGING;
-
- if (openWb.getStatus() == Status.NOT_READY_FOR_CHARGING) { // Session starts if plugged in
- this.energyStartSession = energyTotal;
- }
-
- } else if (plugState) {
- status = Status.READY_FOR_CHARGING;
-
- if (openWb.getStatus() == Status.NOT_READY_FOR_CHARGING) { // Session starts if plugged in
- this.energyStartSession = energyTotal;
- }
-
- } else {
- status = Status.NOT_READY_FOR_CHARGING;
- }
-
- } catch (OpenemsNamedException e) {
- communicationError = true;
- }
-
- openWb._setVoltageL1(voltageL1);
- openWb._setVoltageL2(voltageL2);
- openWb._setVoltageL3(voltageL3);
-
- openWb._setActivePower(activePower);
- openWb._setActivePowerL1(activePowerL1);
- openWb._setActivePowerL2(activePowerL2);
- openWb._setActivePowerL3(activePowerL3);
-
- openWb._setCurrentL1(currentL1);
- openWb._setCurrentL2(currentL2);
- openWb._setCurrentL3(currentL3);
-
- openWb._setStatus(status);
-
- openWb._setEnergySession(energySession);
-
- setValue(openWb, EvcsOpenWb.ChannelId.SLAVE_COMMUNICATION_FAILED, communicationError);
- }
-
- /**
- * Gets the JSON response of a HTTPS GET Request.
- *
- * @param path the api path
- * @return the JsonObject
- * @throws OpenemsNamedException on error
- */
- private JsonObject getResponse(String path) throws OpenemsNamedException {
- try {
- var url = URI.create(this.baseUrl + path).toURL();
- var connection = (HttpsURLConnection) url.openConnection();
- connection.setHostnameVerifier((hostname, session) -> true);
- try (var reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
- var content = reader.lines().collect(Collectors.joining());
- return JsonUtils.parseToJsonObject(content);
- }
- } catch (IOException e) {
- throw new OpenemsException(e.getClass().getSimpleName() + ": " + e.getMessage());
- }
- }
-}
diff --git a/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/EvcsOpenWbImplTest.java b/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/EvcsOpenWbImplTest.java
index e55669c48e8..6ccc0ecb2f9 100644
--- a/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/EvcsOpenWbImplTest.java
+++ b/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/EvcsOpenWbImplTest.java
@@ -1,7 +1,12 @@
package io.openems.edge.evcs.openwb;
+import static io.openems.common.bridge.http.dummy.DummyBridgeHttpFactory.ofBridgeImpl;
+
import org.junit.Test;
+import io.openems.common.bridge.http.dummy.DummyBridgeHttpFactory;
+import io.openems.edge.bridge.http.cycle.HttpBridgeCycleServiceDefinition;
+import io.openems.edge.bridge.http.cycle.dummy.DummyCycleSubscriber;
import io.openems.edge.common.test.AbstractComponentTest.TestCase;
import io.openems.edge.common.test.ComponentTest;
@@ -10,10 +15,15 @@ public class EvcsOpenWbImplTest {
@Test
public void test() throws Exception {
new ComponentTest(new EvcsOpenWbImpl()) //
+ .addReference("httpBridgeFactory",
+ ofBridgeImpl(DummyBridgeHttpFactory::dummyEndpointFetcher,
+ DummyBridgeHttpFactory::dummyBridgeHttpExecutor)) //
+ .addReference("httpBridgeCycleServiceDefinition",
+ new HttpBridgeCycleServiceDefinition(new DummyCycleSubscriber()))
.activate(MyConfig.create() //
.setId("evcs0") //
.setIp("127.0.0.1") //
- .setPort(443) //
+ .setPort(8443) //
.build()) //
.next(new TestCase()) //
.deactivate();
diff --git a/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/MyConfig.java b/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/MyConfig.java
index 937655c69e8..9b543ec6a90 100644
--- a/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/MyConfig.java
+++ b/io.openems.edge.evcs.openwb/test/io/openems/edge/evcs/openwb/MyConfig.java
@@ -1,6 +1,7 @@
package io.openems.edge.evcs.openwb;
import io.openems.common.test.AbstractComponentConfig;
+import io.openems.edge.meter.api.PhaseRotation;
@SuppressWarnings("all")
public class MyConfig extends AbstractComponentConfig implements Config {
@@ -9,6 +10,8 @@ protected static class Builder {
private String id;
private String ip;
private int port;
+ private ChargePoint chargePoint = ChargePoint.CP0;
+ private PhaseRotation phaseRotation = PhaseRotation.L1_L2_L3;
private Builder() {
}
@@ -28,6 +31,16 @@ public Builder setPort(int port) {
return this;
}
+ public Builder setChargePoint(ChargePoint chargePoint) {
+ this.chargePoint = chargePoint;
+ return this;
+ }
+
+ public Builder setPhaseRotation(PhaseRotation phaseRotation) {
+ this.phaseRotation = phaseRotation;
+ return this;
+ }
+
public MyConfig build() {
return new MyConfig(this);
}
@@ -61,6 +74,11 @@ public int port() {
@Override
public ChargePoint chargePoint() {
- return ChargePoint.CP0;
+ return this.builder.chargePoint;
+ }
+
+ @Override
+ public PhaseRotation phaseRotation() {
+ return this.builder.phaseRotation;
}
}
\ No newline at end of file