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. * *

*/ 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