From 94856fa85ebd7d08d6019b20ae63cd6fe04ec4b4 Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Mon, 11 Mar 2024 16:06:16 +0100 Subject: [PATCH 1/6] Refactored to use HttpBridge --- .../edge/io/shelly/shelly25/IoShelly25.java | 203 ++++++++++++++++++ .../io/shelly/shelly25/IoShelly25Impl.java | 142 +++++++----- .../shelly/shelly25/IoShelly25ImplTest.java | 4 +- 3 files changed, 294 insertions(+), 55 deletions(-) diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java index b276675dc5e..8ef4d094474 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java @@ -41,6 +41,29 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .accessMode(AccessMode.READ_WRITE) // .persistencePriority(PersistencePriority.HIGH) // .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_1)), + + /** + * Indicates whether the associated meter is functioning properly. + * + * + */ + RELAY_1_OVERTEMP(Doc.of(Level.WARNING) // + .text("Relay 1 has been switched off due to Overtemperature.")), + /** + * Indicates whether the associated Relay is in Overpower-State. + * + * + */ + RELAY_1_OVERPOWER(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overpower.")), /** * Holds writes to Relay Output 2 for debugging. * @@ -64,6 +87,28 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .accessMode(AccessMode.READ_WRITE) // .persistencePriority(PersistencePriority.HIGH) // .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_2)), + /** + * Indicates whether the associated Relay is in Overtemp-State. + * + * + */ + RELAY_2_OVERTEMP(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overtemperature.")), + /** + * Indicates whether the associated Relay is in Overpower-State. + * + * + */ + RELAY_2_OVERPOWER(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overpower.")), /** * Slave Communication Failed Fault. * @@ -123,6 +168,164 @@ public default void setRelay1(boolean value) throws OpenemsNamedException { this.getRelay1Channel().setNextWriteValue(value); } + /** + * Gets the Channel for {@link ChannelId#RELAY_1_OVERTEMP}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay1OvertempChannel() { + return this.channel(ChannelId.RELAY_1_OVERTEMP); + } + + /** + * Gets the Overtemperature State for Relay 1. See + * {@link ChannelId#RELAY_1_OVERTEMP}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay1Overtemp() { + return this.getRelay1OvertempChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. + * + * @param value the next value + */ + public default void _setRelay1Overtemp(Boolean value) { + this.getRelay1OvertempChannel().setNextValue(value); + } + + /** + * Sets the Overtemperature State for Relay 1. See + * {@link ChannelId#RELAY_1_OVERTEMP}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay1Overtemp(boolean value) throws OpenemsNamedException { + this.getRelay1OvertempChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_2_OVERTEMP}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay2OvertempChannel() { + return this.channel(ChannelId.RELAY_2_OVERTEMP); + } + + /** + * Gets the Overtemperature State for Relay 2. See + * {@link ChannelId#RELAY_2_OVERTEMP}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay2Overtemp() { + return this.getRelay2OvertempChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. + * + * @param value the next value + */ + public default void _setRelay2Overtemp(Boolean value) { + this.getRelay2OvertempChannel().setNextValue(value); + } + + /** + * Sets the Overtemperature State for Relay 2. See + * {@link ChannelId#RELAY_2_OVERTEMP}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay2Overtemp(boolean value) throws OpenemsNamedException { + this.getRelay2OvertempChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_1_OVERPOWER}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay1OverpowerChannel() { + return this.channel(ChannelId.RELAY_1_OVERPOWER); + } + + /** + * Gets the Overpower State for Relay 1. See + * {@link ChannelId#RELAY_1_OVERPOWER}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay1Overpower() { + return this.getRelay1OverpowerChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. + * + * @param value the next value + */ + public default void _setRelay1Overpower(Boolean value) { + this.getRelay1OverpowerChannel().setNextValue(value); + } + + /** + * Sets the Overpower State for Relay 1. See + * {@link ChannelId#RELAY_1_OVERPOWER}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay1Overpower(boolean value) throws OpenemsNamedException { + this.getRelay1OverpowerChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_2_OVERPOWER}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay2OverpowerChannel() { + return this.channel(ChannelId.RELAY_2_OVERPOWER); + } + + /** + * Gets the Overpower State for Relay 2. See + * {@link ChannelId#RELAY_2_OVERPOWER}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay2Overpower() { + return this.getRelay2OverpowerChannel().value(); + } + + /** + * Sets the Overpower State for Relay 2. See + * {@link ChannelId#RELAY_2_OVERPOWER}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void _setRelay2Overpower(boolean value) { + this.getRelay2OverpowerChannel().setNextValue(value); + } + + /** + * Sets the Overpower State for Relay 2. See + * {@link ChannelId#RELAY_2_OVERPOWER}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay2Overpower(boolean value) throws OpenemsNamedException { + this.getRelay2OverpowerChannel().setNextWriteValue(value); + } + /** * Gets the Channel for {@link ChannelId#RELAY_2}. * diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index d802358f7db..914cd6d0e0d 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -7,6 +7,7 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.event.propertytypes.EventTopics; @@ -14,33 +15,38 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.JsonElement; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.utils.JsonUtils; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; import io.openems.edge.common.channel.BooleanWriteChannel; -import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.io.api.DigitalOutput; -import io.openems.edge.io.shelly.common.ShellyApi; @Designate(ocd = Config.class, factory = true) @Component(// name = "IO.Shelly.25", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE// + configurationPolicy = ConfigurationPolicy.REQUIRE // ) @EventTopics({ // - EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) + public class IoShelly25Impl extends AbstractOpenemsComponent implements IoShelly25, DigitalOutput, OpenemsComponent, EventHandler { private final Logger log = LoggerFactory.getLogger(IoShelly25Impl.class); private final BooleanWriteChannel[] digitalOutputChannels; + private String baseUrl; - private ShellyApi shellyApi = null; + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; public IoShelly25Impl() { super(// @@ -55,14 +61,25 @@ public IoShelly25Impl() { } @Activate - private void activate(ComponentContext context, Config config) { + protected void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); - this.shellyApi = new ShellyApi(config.ip()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (this.isEnabled()) { + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/status", (t, u) -> { + + this.processHttpResult(t, u); + + }); + } + } - @Override @Deactivate protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; super.deactivate(); } @@ -75,20 +92,19 @@ public BooleanWriteChannel[] digitalOutputChannels() { public String debugLog() { var b = new StringBuilder(); var i = 1; - for (WriteChannel channel : this.digitalOutputChannels) { + for (BooleanWriteChannel channel : this.digitalOutputChannels) { String valueText; var valueOpt = channel.value().asOptional(); if (valueOpt.isPresent()) { - valueText = valueOpt.get() ? "x" : "-"; + valueText = valueOpt.get() ? "ON" : "OFF"; } else { - valueText = "?"; + valueText = "Unknown"; } - b.append(i + valueText); - - // add space for all but the last - if (++i <= this.digitalOutputChannels.length) { - b.append(" "); + b.append(valueText); + if (i < this.digitalOutputChannels.length) { + b.append("|"); } + i++; } return b.toString(); } @@ -100,68 +116,86 @@ public void handleEvent(Event event) { } switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - this.eventBeforeProcessImage(); - break; - - case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE: - this.eventExecuteWrite(); - break; + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.eventExecuteWrite(); } } /** * Execute on Cycle Event "Before Process Image". + * + * @param result The JSON element containing the result of the HTTP request. + * @param error The throwable error, if any occurred during the HTTP request. + * @throws OpenemsNamedException if the processing of the HTTP result fails or + * communication with the slave device is + * unsuccessful. */ - private void eventBeforeProcessImage() { - Boolean relay1IsOn; - Boolean relay2IsOn; - try { - var json = this.shellyApi.getStatus(); - var relays = JsonUtils.getAsJsonArray(json, "relays"); - var relay1 = JsonUtils.getAsJsonObject(relays.get(0)); - relay1IsOn = JsonUtils.getAsBoolean(relay1, "ison"); - var relay2 = JsonUtils.getAsJsonObject(relays.get(1)); - relay2IsOn = JsonUtils.getAsBoolean(relay2, "ison"); + private void processHttpResult(JsonElement result, Throwable error) { + this._setSlaveCommunicationFailed(result == null); + Boolean relay1 = null; + Boolean overtemp1 = null; + Boolean overpower1 = null; + Boolean relay2 = null; + Boolean overtemp2 = null; + Boolean overpower2 = null; + try { + JsonElement jsonElement = JsonUtils.getAsJsonElement(result); + final var relays = JsonUtils.getAsJsonArray(jsonElement, "relays"); + for (int i = 0; i < relays.size(); i++) { + final var relay = JsonUtils.getAsJsonObject(relays.get(i)); + final var relayIson = JsonUtils.getAsBoolean(relay, "ison"); + final var relayOverpower = JsonUtils.getAsBoolean(relay, "overpower"); + final var relayOvertemp = JsonUtils.getAsBoolean(relay, "overtemperature"); + + if (i == 0) { + relay1 = relayIson; + overtemp1 = relayOvertemp; + overpower1 = relayOverpower; + } else if (i == 1) { + relay2 = relayIson; + overtemp2 = relayOvertemp; + overpower2 = relayOverpower; + } + } this._setSlaveCommunicationFailed(false); - - } catch (OpenemsNamedException | IndexOutOfBoundsException e) { - relay1IsOn = null; - relay2IsOn = null; - this.logError(this.log, "Unable to read from Shelly API: " + e.getMessage()); - this._setSlaveCommunicationFailed(true); + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); } - this._setRelay1(relay1IsOn); - this._setRelay2(relay2IsOn); + // Sets the Fault Channels accordingly + this._setRelay1Overpower(overpower1); + this._setRelay2Overpower(overpower2); + this._setRelay1Overtemp(overtemp1); + this._setRelay2Overtemp(overtemp2); + + this._setRelay1(relay1); + this._setRelay2(relay2); + } /** * Execute on Cycle Event "Execute Write". */ private void eventExecuteWrite() { - try { - this.executeWrite(this.getRelay1Channel(), 0); - this.executeWrite(this.getRelay2Channel(), 1); - - this._setSlaveCommunicationFailed(false); - } catch (OpenemsNamedException e) { - this._setSlaveCommunicationFailed(true); + for (int i = 0; i < this.digitalOutputChannels.length; i++) { + this.executeWrite(this.digitalOutputChannels[i], i); } } - private void executeWrite(BooleanWriteChannel channel, int index) throws OpenemsNamedException { + private void executeWrite(BooleanWriteChannel channel, int index) { var readValue = channel.value().get(); var writeValue = channel.getNextWriteValueAndReset(); - if (!writeValue.isPresent()) { - // no write value + if (writeValue.isEmpty()) { return; } if (Objects.equals(readValue, writeValue.get())) { - // read value = write value return; } - this.shellyApi.setRelayTurn(index, writeValue.get()); + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((t, e) -> { + if (e != null) { + this.logError(this.log, "HTTP request failed: " + e.getMessage()); + } + }); } - } \ No newline at end of file diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java index 6e778d2393c..2e6e2a98902 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; public class IoShelly25ImplTest { @@ -11,6 +12,7 @@ public class IoShelly25ImplTest { @Test public void test() throws Exception { new ComponentTest(new IoShelly25Impl()) // + .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setIp("127.0.0.1") // @@ -18,4 +20,4 @@ public void test() throws Exception { ; } -} +} \ No newline at end of file From f235d617eac4b9c5a1378c963073aa401c82c1f2 Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Mon, 1 Apr 2024 16:09:50 +0200 Subject: [PATCH 2/6] Refactoring --- .../edge/io/shelly/shelly25/IoShelly25.java | 2 +- .../io/shelly/shelly25/IoShelly25Impl.java | 58 +++++++++---------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java index 8ef4d094474..30df2101ab1 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java @@ -43,7 +43,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_1)), /** - * Indicates whether the associated meter is functioning properly. + * Indicates whether the associated Relay is in Overtemp-State. * *
    *
  • Interface: Shelly25 diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index 914cd6d0e0d..2e97fe74ea9 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -61,19 +61,14 @@ public IoShelly25Impl() { } @Activate - protected void activate(ComponentContext context, Config config) { + private void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); this.baseUrl = "http://" + config.ip(); this.httpBridge = this.httpBridgeFactory.get(); if (this.isEnabled()) { - this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/status", (t, u) -> { - - this.processHttpResult(t, u); - - }); + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/status", this::processHttpResult); } - } @Deactivate @@ -121,6 +116,16 @@ public void handleEvent(Event event) { } } + record RelayState(Boolean relayIsOn, Boolean overtemp, Boolean overpower) { + } + + private static RelayState parseRelay(JsonElement relay) throws OpenemsNamedException { + Boolean relayIsOn = JsonUtils.getAsBoolean(relay, "ison"); + Boolean overtemp = JsonUtils.getAsBoolean(relay, "overtemperature"); + Boolean overpower = JsonUtils.getAsBoolean(relay, "overpower"); + return new RelayState(relayIsOn, overtemp, overpower); + } + /** * Execute on Cycle Event "Before Process Image". * @@ -132,44 +137,33 @@ public void handleEvent(Event event) { */ private void processHttpResult(JsonElement result, Throwable error) { this._setSlaveCommunicationFailed(result == null); - Boolean relay1 = null; - Boolean overtemp1 = null; - Boolean overpower1 = null; - Boolean relay2 = null; - Boolean overtemp2 = null; - Boolean overpower2 = null; + RelayState relay1State = null; + RelayState relay2State = null; try { JsonElement jsonElement = JsonUtils.getAsJsonElement(result); final var relays = JsonUtils.getAsJsonArray(jsonElement, "relays"); - for (int i = 0; i < relays.size(); i++) { - final var relay = JsonUtils.getAsJsonObject(relays.get(i)); - final var relayIson = JsonUtils.getAsBoolean(relay, "ison"); - final var relayOverpower = JsonUtils.getAsBoolean(relay, "overpower"); - final var relayOvertemp = JsonUtils.getAsBoolean(relay, "overtemperature"); + for (int i = 0; i < 2; i++) { if (i == 0) { - relay1 = relayIson; - overtemp1 = relayOvertemp; - overpower1 = relayOverpower; + relay1State = parseRelay(JsonUtils.getAsJsonObject(relays.get(0))); } else if (i == 1) { - relay2 = relayIson; - overtemp2 = relayOvertemp; - overpower2 = relayOverpower; + relay2State = parseRelay(JsonUtils.getAsJsonObject(relays.get(1))); } } this._setSlaveCommunicationFailed(false); } catch (OpenemsNamedException e) { this.logDebug(this.log, e.getMessage()); } - // Sets the Fault Channels accordingly - this._setRelay1Overpower(overpower1); - this._setRelay2Overpower(overpower2); - this._setRelay1Overtemp(overtemp1); - this._setRelay2Overtemp(overtemp2); - - this._setRelay1(relay1); - this._setRelay2(relay2); + + this._setRelay1(relay1State.relayIsOn()); + this._setRelay2(relay2State.relayIsOn()); + + this._setRelay1Overtemp(relay1State.overtemp()); + this._setRelay2Overtemp(relay2State.overtemp()); + + this._setRelay1Overpower(relay1State.overpower()); + this._setRelay2Overpower(relay2State.overpower()); } From a8e0df1dd9953e15579a4a90333215f1722f99ac Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Mon, 1 Apr 2024 16:12:27 +0200 Subject: [PATCH 3/6] Refactoring --- .../io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index 2e97fe74ea9..5c1afc48eba 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -187,8 +187,11 @@ private void executeWrite(BooleanWriteChannel channel, int index) { } final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); this.httpBridge.get(url).whenComplete((t, e) -> { - if (e != null) { - this.logError(this.log, "HTTP request failed: " + e.getMessage()); + this._setSlaveCommunicationFailed(e != null); + if (e == null) { + this.logInfo(this.log, "Executed write successfully for URL: " + url); + } else { + this.logError(this.log, "Failed to execute write for URL: " + url + "; Error: " + e.getMessage()); } }); } From 5e4a28765d452aa52ce979c36bd61568d572de45 Mon Sep 17 00:00:00 2001 From: Hannes Date: Tue, 16 Apr 2024 22:15:59 +0200 Subject: [PATCH 4/6] Update IoShelly25Impl.java --- .../io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index 5c1afc48eba..e5ebd427d3f 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -91,7 +91,7 @@ public String debugLog() { String valueText; var valueOpt = channel.value().asOptional(); if (valueOpt.isPresent()) { - valueText = valueOpt.get() ? "ON" : "OFF"; + valueText = valueOpt.get() ? "x" : "-"; } else { valueText = "Unknown"; } @@ -195,4 +195,4 @@ private void executeWrite(BooleanWriteChannel channel, int index) { } }); } -} \ No newline at end of file +} From f6a74a8bc5b02034b8deca7f9d24310fc5ef0c62 Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Tue, 16 Apr 2024 22:23:15 +0200 Subject: [PATCH 5/6] use "var" instead of "BooleanWriteChannel" --- .../src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index e5ebd427d3f..2bd5efa1b0c 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -87,7 +87,7 @@ public BooleanWriteChannel[] digitalOutputChannels() { public String debugLog() { var b = new StringBuilder(); var i = 1; - for (BooleanWriteChannel channel : this.digitalOutputChannels) { + for (var channel : this.digitalOutputChannels) { String valueText; var valueOpt = channel.value().asOptional(); if (valueOpt.isPresent()) { From 148bda0d8222cd64e551e6d32ab9d2ab4527901a Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 1 Jun 2024 16:56:11 +0200 Subject: [PATCH 6/6] Fix errors; improve code quality --- .../edge/io/shelly/shelly25/IoShelly25.java | 234 ------------------ .../io/shelly/shelly25/IoShelly25Impl.java | 65 ++--- .../edge/io/shelly/shelly25/ShellyApi.java | 107 -------- 3 files changed, 33 insertions(+), 373 deletions(-) delete mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java index 30df2101ab1..01149dde732 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java @@ -5,10 +5,8 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.BooleanDoc; -import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; @@ -131,238 +129,6 @@ public Doc doc() { } } - /** - * Gets the Channel for {@link ChannelId#RELAY_1}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay1Channel() { - return this.channel(ChannelId.RELAY_1); - } - - /** - * Gets the Relay Output 1. See {@link ChannelId#RELAY_1}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay1() { - return this.getRelay1Channel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. - * - * @param value the next value - */ - public default void _setRelay1(Boolean value) { - this.getRelay1Channel().setNextValue(value); - } - - /** - * Sets the Relay Output 1. See {@link ChannelId#RELAY_1}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay1(boolean value) throws OpenemsNamedException { - this.getRelay1Channel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_1_OVERTEMP}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay1OvertempChannel() { - return this.channel(ChannelId.RELAY_1_OVERTEMP); - } - - /** - * Gets the Overtemperature State for Relay 1. See - * {@link ChannelId#RELAY_1_OVERTEMP}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay1Overtemp() { - return this.getRelay1OvertempChannel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. - * - * @param value the next value - */ - public default void _setRelay1Overtemp(Boolean value) { - this.getRelay1OvertempChannel().setNextValue(value); - } - - /** - * Sets the Overtemperature State for Relay 1. See - * {@link ChannelId#RELAY_1_OVERTEMP}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay1Overtemp(boolean value) throws OpenemsNamedException { - this.getRelay1OvertempChannel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_2_OVERTEMP}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay2OvertempChannel() { - return this.channel(ChannelId.RELAY_2_OVERTEMP); - } - - /** - * Gets the Overtemperature State for Relay 2. See - * {@link ChannelId#RELAY_2_OVERTEMP}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay2Overtemp() { - return this.getRelay2OvertempChannel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. - * - * @param value the next value - */ - public default void _setRelay2Overtemp(Boolean value) { - this.getRelay2OvertempChannel().setNextValue(value); - } - - /** - * Sets the Overtemperature State for Relay 2. See - * {@link ChannelId#RELAY_2_OVERTEMP}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay2Overtemp(boolean value) throws OpenemsNamedException { - this.getRelay2OvertempChannel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_1_OVERPOWER}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay1OverpowerChannel() { - return this.channel(ChannelId.RELAY_1_OVERPOWER); - } - - /** - * Gets the Overpower State for Relay 1. See - * {@link ChannelId#RELAY_1_OVERPOWER}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay1Overpower() { - return this.getRelay1OverpowerChannel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. - * - * @param value the next value - */ - public default void _setRelay1Overpower(Boolean value) { - this.getRelay1OverpowerChannel().setNextValue(value); - } - - /** - * Sets the Overpower State for Relay 1. See - * {@link ChannelId#RELAY_1_OVERPOWER}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay1Overpower(boolean value) throws OpenemsNamedException { - this.getRelay1OverpowerChannel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_2_OVERPOWER}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay2OverpowerChannel() { - return this.channel(ChannelId.RELAY_2_OVERPOWER); - } - - /** - * Gets the Overpower State for Relay 2. See - * {@link ChannelId#RELAY_2_OVERPOWER}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay2Overpower() { - return this.getRelay2OverpowerChannel().value(); - } - - /** - * Sets the Overpower State for Relay 2. See - * {@link ChannelId#RELAY_2_OVERPOWER}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void _setRelay2Overpower(boolean value) { - this.getRelay2OverpowerChannel().setNextValue(value); - } - - /** - * Sets the Overpower State for Relay 2. See - * {@link ChannelId#RELAY_2_OVERPOWER}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay2Overpower(boolean value) throws OpenemsNamedException { - this.getRelay2OverpowerChannel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_2}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay2Channel() { - return this.channel(ChannelId.RELAY_2); - } - - /** - * Gets the Relay Output 2. See {@link ChannelId#RELAY_2}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay2() { - return this.getRelay2Channel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_2} Channel. - * - * @param value the next value - */ - public default void _setRelay2(Boolean value) { - this.getRelay2Channel().setNextValue(value); - } - - /** - * Sets the Relay Output 2. See {@link ChannelId#RELAY_2}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay2(boolean value) throws OpenemsNamedException { - this.getRelay2Channel().setNextWriteValue(value); - } - /** * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. * diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index 2bd5efa1b0c..d69c0cd2ffd 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -1,5 +1,9 @@ package io.openems.edge.io.shelly.shelly25; +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; + import java.util.Objects; import org.osgi.service.component.ComponentContext; @@ -18,7 +22,6 @@ import com.google.gson.JsonElement; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.utils.JsonUtils; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpFactory; import io.openems.edge.common.channel.BooleanWriteChannel; @@ -42,6 +45,7 @@ public class IoShelly25Impl extends AbstractOpenemsComponent private final Logger log = LoggerFactory.getLogger(IoShelly25Impl.class); private final BooleanWriteChannel[] digitalOutputChannels; + private String baseUrl; @Reference @@ -85,6 +89,7 @@ public BooleanWriteChannel[] digitalOutputChannels() { @Override public String debugLog() { + // TODO share code with AbstractKmtronicRelay.debugLog() var b = new StringBuilder(); var i = 1; for (var channel : this.digitalOutputChannels) { @@ -116,14 +121,20 @@ public void handleEvent(Event event) { } } - record RelayState(Boolean relayIsOn, Boolean overtemp, Boolean overpower) { - } + private record RelayState(Boolean relayIsOn, Boolean overtemp, Boolean overpower) { + private static RelayState from(JsonElement relay) throws OpenemsNamedException { + var relayIsOn = getAsBoolean(relay, "ison"); + var overtemp = getAsBoolean(relay, "overtemperature"); + var overpower = getAsBoolean(relay, "overpower"); + return new RelayState(relayIsOn, overtemp, overpower); + } - private static RelayState parseRelay(JsonElement relay) throws OpenemsNamedException { - Boolean relayIsOn = JsonUtils.getAsBoolean(relay, "ison"); - Boolean overtemp = JsonUtils.getAsBoolean(relay, "overtemperature"); - Boolean overpower = JsonUtils.getAsBoolean(relay, "overpower"); - return new RelayState(relayIsOn, overtemp, overpower); + private void applyChannels(IoShelly25 component, IoShelly25.ChannelId relayChannel, + IoShelly25.ChannelId overtempChannel, IoShelly25.ChannelId overpowerChannel) { + component.channel(relayChannel).setNextValue(this.relayIsOn); + component.channel(overtempChannel).setNextValue(this.overtemp); + component.channel(overpowerChannel).setNextValue(this.overpower); + } } /** @@ -136,35 +147,25 @@ private static RelayState parseRelay(JsonElement relay) throws OpenemsNamedExcep * unsuccessful. */ private void processHttpResult(JsonElement result, Throwable error) { - this._setSlaveCommunicationFailed(result == null); - RelayState relay1State = null; - RelayState relay2State = null; + var slaveCommunicationFailed = result == null; + var relay1State = new RelayState(null, null, null); + var relay2State = new RelayState(null, null, null); try { - JsonElement jsonElement = JsonUtils.getAsJsonElement(result); - final var relays = JsonUtils.getAsJsonArray(jsonElement, "relays"); - - for (int i = 0; i < 2; i++) { - if (i == 0) { - relay1State = parseRelay(JsonUtils.getAsJsonObject(relays.get(0))); - } else if (i == 1) { - relay2State = parseRelay(JsonUtils.getAsJsonObject(relays.get(1))); - } - } - this._setSlaveCommunicationFailed(false); - } catch (OpenemsNamedException e) { + final var relays = getAsJsonArray(result, "relays"); + relay1State = RelayState.from(getAsJsonObject(relays.get(0))); + relay2State = RelayState.from(getAsJsonObject(relays.get(1))); + + } catch (OpenemsNamedException | IndexOutOfBoundsException e) { this.logDebug(this.log, e.getMessage()); + slaveCommunicationFailed = true; } - this._setRelay1(relay1State.relayIsOn()); - this._setRelay2(relay2State.relayIsOn()); - - this._setRelay1Overtemp(relay1State.overtemp()); - this._setRelay2Overtemp(relay2State.overtemp()); - - this._setRelay1Overpower(relay1State.overpower()); - this._setRelay2Overpower(relay2State.overpower()); - + this._setSlaveCommunicationFailed(slaveCommunicationFailed); + relay1State.applyChannels(this, IoShelly25.ChannelId.RELAY_1, // + IoShelly25.ChannelId.RELAY_1_OVERTEMP, IoShelly25.ChannelId.RELAY_1_OVERPOWER); + relay2State.applyChannels(this, IoShelly25.ChannelId.RELAY_2, // + IoShelly25.ChannelId.RELAY_2_OVERTEMP, IoShelly25.ChannelId.RELAY_2_OVERPOWER); } /** diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java deleted file mode 100644 index 6b3b8a3db6f..00000000000 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java +++ /dev/null @@ -1,107 +0,0 @@ -package io.openems.edge.io.shelly.shelly25; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; - -// TODO replace with HttpBridge -/** - * Implements the local Shelly REST Api. - * - *

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

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

    - * See https://shelly-api-docs.shelly.cloud/#shelly2-5-relay-index - * - * @param index the index of the relay - * @return the boolean value - * @throws OpenemsNamedException on error - */ - public boolean getRelayIson(int index) throws OpenemsNamedException { - var json = this.sendGetRequest("/relay/" + index); - return JsonUtils.getAsBoolean(json, "ison"); - } - - /** - * Turns the relay with the given index on or off. - * - * @param index the index of the relay - * @param value true to turn on; false to turn off - * @throws OpenemsNamedException on error - */ - public void setRelayTurn(int index, boolean value) throws OpenemsNamedException { - this.sendGetRequest("/relay/" + index + "?turn=" + (value ? "on" : "off")); - } - - /** - * Sends a get request to the Shelly API. - * - * @param endpoint the REST Api endpoint - * @return a JsonObject or JsonArray - * @throws OpenemsNamedException on error - */ - private JsonElement sendGetRequest(String endpoint) throws OpenemsNamedException { - try { - var url = new URL(this.baseUrl + endpoint); - var con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - con.setConnectTimeout(5000); - con.setReadTimeout(5000); - var status = con.getResponseCode(); - String body; - try (var in = new BufferedReader(new InputStreamReader(con.getInputStream()))) { - // Read HTTP response - var content = new StringBuilder(); - String line; - while ((line = in.readLine()) != null) { - content.append(line); - content.append(System.lineSeparator()); - } - body = content.toString(); - } - if (status < 300) { - // Parse response to JSON - return JsonUtils.parseToJsonObject(body); - } - throw new OpenemsException("Error while reading from Shelly API. Response code: " + status + ". " + body); - } catch (OpenemsNamedException | IOException e) { - throw new OpenemsException( - "Unable to read from Shelly API. " + e.getClass().getSimpleName() + ": " + e.getMessage()); - } - } - -}