]> git.basschouten.com Git - openhab-addons.git/commitdiff
[solaredge] Fix code style warnings, fix NPE warnings, improve i18n (#14666)
authoralexf2015 <alexf2015@users.noreply.github.com>
Sun, 26 Mar 2023 11:42:00 +0000 (13:42 +0200)
committerGitHub <noreply@github.com>
Sun, 26 Mar 2023 11:42:00 +0000 (13:42 +0200)
* code style fixes
* fixed potential NPE
* fix warning
* simplified code
* refactoring, fixed some NPE warnings
* i18n
* refactoring

Signed-off-by: Alexander Friese <af944580@googlemail.com>
25 files changed:
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/SolarEdgeBindingConstants.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/SolarEdgeHandlerFactory.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/callback/AbstractCommandCallback.java [deleted file]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/AbstractCommand.java [new file with mode: 0644]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/AggregateDataUpdatePrivateApi.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/AggregateDataUpdatePublicApi.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/LiveDataUpdateMeterless.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/LiveDataUpdatePrivateApi.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/LiveDataUpdatePublicApi.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/PrivateApiTokenCheck.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/PublicApiKeyCheck.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/SolarEdgeCommand.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/config/SolarEdgeConfiguration.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/connector/WebInterface.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/GenericSolarEdgeHandler.java [deleted file]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeAggregateDataPolling.java [deleted file]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeBaseHandler.java [deleted file]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeGenericHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeHandler.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeLiveDataPolling.java [deleted file]
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/model/AbstractDataResponseTransformer.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/model/AggregateDataResponseTransformerPublicApi.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/model/AggregatePeriod.java
bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/model/LiveDataResponseTransformer.java
bundles/org.openhab.binding.solaredge/src/main/resources/OH-INF/i18n/solaredge.properties

index 7b5fa5a1e82c4c279c14a3aab0eb5a3c171b8e7d..dae67f3b5912ef84565701ab441b9643de4aa78f 100644 (file)
@@ -100,5 +100,16 @@ public class SolarEdgeBindingConstants {
     public static final long WEB_REQUEST_INTERVAL = TimeUnit.SECONDS.toMillis(5);
     public static final int WEB_REQUEST_QUEUE_MAX_SIZE = 20;
 
+    // Status Keys
+    public static final String STATUS_INVALID_SOLAR_ID = "@text/status.invalid.solarId";
+    public static final String STATUS_INVALID_TOKEN = "@text/status.invalid.token";
+    public static final String STATUS_UNKNOWN_ERROR = "@text/status.unknown.error";
+    public static final String STATUS_INVALID_TOKEN_LENGTH = "@text/status.invalid.token.length";
+    public static final String STATUS_INVALID_API_KEY_LENGTH = "@text/status.invalid.api.key.length";
+    public static final String STATUS_REQUEST_LIMIT_EXCEEDED = "@text/status.request.limit.exceeded [\""
+            + WEB_REQUEST_PUBLIC_API_DAY_LIMIT + "\"]";
+    public static final String STATUS_NO_METER_CONFIGURED = "@text/status.no.meter.configured";
+    public static final String STATUS_WAITING_FOR_LOGIN = "@text/status.waiting.for.login";
+
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_GENERIC);
 }
index 6c7f81b232f98a78e6cdd13f85b4a5a638b15f05..3301159c1f8bf65921b63c61002443797dff9a8f 100644 (file)
@@ -17,7 +17,7 @@ import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.HttpClient;
-import org.openhab.binding.solaredge.internal.handler.GenericSolarEdgeHandler;
+import org.openhab.binding.solaredge.internal.handler.SolarEdgeGenericHandler;
 import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingTypeUID;
@@ -62,7 +62,7 @@ public class SolarEdgeHandlerFactory extends BaseThingHandlerFactory {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (thingTypeUID.equals(THING_TYPE_GENERIC)) {
-            return new GenericSolarEdgeHandler(thing, httpClient);
+            return new SolarEdgeGenericHandler(thing, httpClient);
         } else {
             logger.warn("Unsupported Thing-Type: {}", thingTypeUID.getAsString());
         }
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/callback/AbstractCommandCallback.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/callback/AbstractCommandCallback.java
deleted file mode 100644 (file)
index 8f28187..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.solaredge.internal.callback;
-
-import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
-
-import java.net.CookieStore;
-import java.net.HttpCookie;
-import java.net.SocketTimeoutException;
-import java.net.URI;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.util.BufferingResponseListener;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpStatus.Code;
-import org.openhab.binding.solaredge.internal.command.SolarEdgeCommand;
-import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
-import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
-import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonSyntaxException;
-
-/**
- * base class for all commands. common logic should be implemented here
- *
- * @author Alexander Friese - initial contribution
- */
-@NonNullByDefault
-public abstract class AbstractCommandCallback extends BufferingResponseListener implements SolarEdgeCommand {
-
-    /**
-     * logger
-     */
-    protected final Logger logger = LoggerFactory.getLogger(AbstractCommandCallback.class);
-
-    /**
-     * the configuration
-     */
-    protected final SolarEdgeConfiguration config;
-
-    /**
-     * JSON deserializer
-     */
-    private final Gson gson;
-
-    /**
-     * status code of fulfilled request
-     */
-    private final CommunicationStatus communicationStatus;
-
-    /**
-     * listener to provide updates to the WebInterface class
-     */
-    private @Nullable StatusUpdateListener listener;
-
-    /**
-     * the constructor
-     *
-     * @param config
-     */
-    public AbstractCommandCallback(SolarEdgeConfiguration config) {
-        this.communicationStatus = new CommunicationStatus();
-        this.config = config;
-        this.gson = new Gson();
-    }
-
-    /**
-     * the constructor
-     *
-     * @param config
-     */
-    public AbstractCommandCallback(SolarEdgeConfiguration config, StatusUpdateListener listener) {
-        this(config);
-        this.listener = listener;
-    }
-
-    /**
-     * Log request success
-     */
-    @Override
-    public final void onSuccess(@Nullable Response response) {
-        super.onSuccess(response);
-        if (response != null) {
-            communicationStatus.setHttpCode(HttpStatus.getCode(response.getStatus()));
-            logger.debug("HTTP response {}", response.getStatus());
-        }
-    }
-
-    /**
-     * Log request failure
-     */
-    @Override
-    public final void onFailure(@Nullable Response response, @Nullable Throwable failure) {
-        super.onFailure(response, failure);
-        if (failure != null) {
-            logger.debug("Request failed: {}", failure.toString());
-            communicationStatus.setError((Exception) failure);
-
-            if (failure instanceof SocketTimeoutException || failure instanceof TimeoutException) {
-                communicationStatus.setHttpCode(Code.REQUEST_TIMEOUT);
-            } else if (failure instanceof UnknownHostException) {
-                communicationStatus.setHttpCode(Code.BAD_GATEWAY);
-            } else {
-                communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
-            }
-        } else {
-            logger.debug("Request failed");
-        }
-    }
-
-    @Override
-    public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
-        super.onContent(response, content);
-        logger.debug("received content, length: {}", getContentAsString().length());
-    }
-
-    @Override
-    public void performAction(HttpClient asyncclient) {
-        Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
-
-        // add authentication data for every request. Handling this here makes it obsolete to implement for each and
-        // every command
-        if (config.isUsePrivateApi()) {
-            // token cookie is only used by private API therefore this can be skipped when using public API
-            CookieStore cookieStore = asyncclient.getCookieStore();
-            HttpCookie c = new HttpCookie(PRIVATE_API_TOKEN_COOKIE_NAME, config.getTokenOrApiKey());
-            c.setDomain(PRIVATE_API_TOKEN_COOKIE_DOMAIN);
-            c.setPath(PRIVATE_API_TOKEN_COOKIE_PATH);
-            cookieStore.add(URI.create(getURL()), c);
-        } else {
-            // this is only relevant when using public API
-            request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
-
-        }
-
-        prepareRequest(request).send(this);
-    }
-
-    /**
-     * @return returns Http Status Code
-     */
-    public CommunicationStatus getCommunicationStatus() {
-        return communicationStatus;
-    }
-
-    @Override
-    public void updateListenerStatus() {
-        if (listener != null) {
-            listener.update(communicationStatus);
-        }
-    }
-
-    /**
-     * concrete implementation has to prepare the requests with additional parameters, etc
-     *
-     * @param requestToPrepare the request to prepare
-     * @return prepared Request object
-     */
-    protected abstract Request prepareRequest(Request requestToPrepare);
-
-    /**
-     * concrete implementation has to provide the URL
-     *
-     * @return Url
-     */
-    protected abstract String getURL();
-
-    @Override
-    public final void setListener(StatusUpdateListener listener) {
-        this.listener = listener;
-    }
-
-    /**
-     * just a wrapper as fromJson could return null. This will avoid warnings as eclipse otherwise assumes unnecessary
-     * null checks which are not unnecessary
-     *
-     * @param <T>
-     * @param json
-     * @param classOfT
-     * @return
-     * @throws JsonSyntaxException
-     */
-    protected <T> @Nullable T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
-        return gson.fromJson(json, classOfT);
-    }
-}
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/AbstractCommand.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/command/AbstractCommand.java
new file mode 100644 (file)
index 0000000..f5d1695
--- /dev/null
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.solaredge.internal.command;
+
+import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
+
+import java.net.CookieStore;
+import java.net.HttpCookie;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.util.BufferingResponseListener;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpStatus.Code;
+import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
+import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * base class for all commands. common logic should be implemented here
+ *
+ * @author Alexander Friese - initial contribution
+ */
+@NonNullByDefault
+public abstract class AbstractCommand extends BufferingResponseListener implements SolarEdgeCommand {
+
+    /**
+     * logger
+     */
+    protected final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);
+
+    /**
+     * the configuration
+     */
+    protected final SolarEdgeConfiguration config;
+
+    /**
+     * JSON deserializer
+     */
+    private final Gson gson;
+
+    /**
+     * status code of fulfilled request
+     */
+    private final CommunicationStatus communicationStatus;
+
+    /**
+     * listener to provide updates to the WebInterface class
+     */
+    private final StatusUpdateListener listener;
+
+    /**
+     * the constructor
+     *
+     * @param config
+     * @param listener
+     *
+     */
+    public AbstractCommand(SolarEdgeConfiguration config, StatusUpdateListener listener) {
+        this.communicationStatus = new CommunicationStatus();
+        this.config = config;
+        this.listener = listener;
+        this.gson = new Gson();
+    }
+
+    /**
+     * Log request success
+     */
+    @Override
+    public final void onSuccess(@Nullable Response response) {
+        super.onSuccess(response);
+        if (response != null) {
+            communicationStatus.setHttpCode(HttpStatus.getCode(response.getStatus()));
+            logger.debug("HTTP response {}", response.getStatus());
+        }
+    }
+
+    /**
+     * Log request failure
+     */
+    @Override
+    public final void onFailure(@Nullable Response response, @Nullable Throwable failure) {
+        super.onFailure(response, failure);
+        if (failure != null) {
+            logger.debug("Request failed: {}", failure.toString());
+            communicationStatus.setError((Exception) failure);
+
+            if (failure instanceof SocketTimeoutException || failure instanceof TimeoutException) {
+                communicationStatus.setHttpCode(Code.REQUEST_TIMEOUT);
+            } else if (failure instanceof UnknownHostException) {
+                communicationStatus.setHttpCode(Code.BAD_GATEWAY);
+            } else {
+                communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
+            }
+        } else {
+            logger.debug("Request failed");
+        }
+    }
+
+    @Override
+    public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
+        super.onContent(response, content);
+        logger.debug("received content, length: {}", getContentAsString().length());
+    }
+
+    @Override
+    public void performAction(HttpClient asyncclient) {
+        Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
+
+        // add authentication data for every request. Handling this here makes it obsolete to implement for each and
+        // every command
+        if (config.isUsePrivateApi()) {
+            // token cookie is only used by private API therefore this can be skipped when using public API
+            CookieStore cookieStore = asyncclient.getCookieStore();
+            HttpCookie c = new HttpCookie(PRIVATE_API_TOKEN_COOKIE_NAME, config.getTokenOrApiKey());
+            c.setDomain(PRIVATE_API_TOKEN_COOKIE_DOMAIN);
+            c.setPath(PRIVATE_API_TOKEN_COOKIE_PATH);
+            cookieStore.add(URI.create(getURL()), c);
+        } else {
+            // this is only relevant when using public API
+            request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
+        }
+
+        prepareRequest(request).send(this);
+    }
+
+    /**
+     * @return returns Http Status Code
+     */
+    public CommunicationStatus getCommunicationStatus() {
+        return communicationStatus;
+    }
+
+    /**
+     * updates status of the registered listener.
+     */
+    protected final void updateListenerStatus() {
+        try {
+            listener.update(communicationStatus);
+        } catch (Exception ex) {
+            // this should not happen
+            logger.warn("Exception caught: {}", ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * concrete implementation has to prepare the requests with additional parameters, etc
+     *
+     * @param requestToPrepare the request to prepare
+     * @return prepared Request object
+     */
+    protected abstract Request prepareRequest(Request requestToPrepare);
+
+    /**
+     * concrete implementation has to provide the URL
+     *
+     * @return Url
+     */
+    protected abstract String getURL();
+
+    /**
+     * just a wrapper as fromJson could return null. This will avoid warnings as eclipse otherwise assumes unnecessary
+     * null checks which are not unnecessary
+     *
+     * @param <T>
+     * @param json
+     * @param classOfT
+     * @return
+     * @throws JsonSyntaxException
+     */
+    protected <T> @Nullable T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
+        return gson.fromJson(json, classOfT);
+    }
+}
index 06606bdc8c11052a261c618442addbce67feef15..6d33505a1b71c33c6573e62c79599b2bb96c91f3 100644 (file)
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePrivateApi;
 import org.openhab.binding.solaredge.internal.model.AggregateDataResponseTransformerPrivateApi;
@@ -34,7 +34,7 @@ import org.openhab.binding.solaredge.internal.model.AggregatePeriod;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class AggregateDataUpdatePrivateApi extends AbstractCommandCallback implements SolarEdgeCommand {
+public class AggregateDataUpdatePrivateApi extends AbstractCommand implements SolarEdgeCommand {
 
     /**
      * the solaredge handler
@@ -59,8 +59,9 @@ public class AggregateDataUpdatePrivateApi extends AbstractCommandCallback imple
      * @param handler
      * @param period
      */
-    public AggregateDataUpdatePrivateApi(SolarEdgeHandler handler, AggregatePeriod period) {
-        super(handler.getConfiguration());
+    public AggregateDataUpdatePrivateApi(SolarEdgeHandler handler, AggregatePeriod period,
+            StatusUpdateListener listener) {
+        super(handler.getConfiguration(), listener);
         this.handler = handler;
         this.transformer = new AggregateDataResponseTransformerPrivateApi(handler);
         this.period = period;
index 28d3c0195cbac8e1f521a7a7cef9dfedff37aff6..4be0a17f2785345757f19000204d7a3dc8fc678d 100644 (file)
@@ -24,7 +24,7 @@ import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePublicApi;
 import org.openhab.binding.solaredge.internal.model.AggregateDataResponseTransformerPublicApi;
@@ -36,7 +36,7 @@ import org.openhab.binding.solaredge.internal.model.AggregatePeriod;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class AggregateDataUpdatePublicApi extends AbstractCommandCallback implements SolarEdgeCommand {
+public class AggregateDataUpdatePublicApi extends AbstractCommand implements SolarEdgeCommand {
 
     /**
      * the solaredge handler
@@ -61,8 +61,9 @@ public class AggregateDataUpdatePublicApi extends AbstractCommandCallback implem
      * @param handler
      * @param period
      */
-    public AggregateDataUpdatePublicApi(SolarEdgeHandler handler, AggregatePeriod period) {
-        super(handler.getConfiguration());
+    public AggregateDataUpdatePublicApi(SolarEdgeHandler handler, AggregatePeriod period,
+            StatusUpdateListener listener) {
+        super(handler.getConfiguration(), listener);
         this.dateFormat = new SimpleDateFormat("yyyy-MM-dd");
         this.handler = handler;
         this.transformer = new AggregateDataResponseTransformerPublicApi(handler);
index ca4f10bbe6a825a7e82b8038b06d9f8dd6918424..16dca88ac93086d6de4718832c6ab348fb36ab61 100644 (file)
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponseMeterless;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
@@ -33,14 +33,14 @@ import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class LiveDataUpdateMeterless extends AbstractCommandCallback implements SolarEdgeCommand {
+public class LiveDataUpdateMeterless extends AbstractCommand implements SolarEdgeCommand {
 
     private final SolarEdgeHandler handler;
     private final LiveDataResponseTransformer transformer;
     private int retries = 0;
 
-    public LiveDataUpdateMeterless(SolarEdgeHandler handler) {
-        super(handler.getConfiguration());
+    public LiveDataUpdateMeterless(SolarEdgeHandler handler, StatusUpdateListener listener) {
+        super(handler.getConfiguration(), listener);
         this.handler = handler;
         this.transformer = new LiveDataResponseTransformer(handler);
     }
index 58d00c94c8c1f7bcdee83cc111d447b2213eb27b..1806d5aebe5d752b6eddf36ec59aa4ca738a2f76 100644 (file)
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
@@ -33,14 +33,14 @@ import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class LiveDataUpdatePrivateApi extends AbstractCommandCallback implements SolarEdgeCommand {
+public class LiveDataUpdatePrivateApi extends AbstractCommand implements SolarEdgeCommand {
 
     private final SolarEdgeHandler handler;
     private final LiveDataResponseTransformer transformer;
     private int retries = 0;
 
-    public LiveDataUpdatePrivateApi(SolarEdgeHandler handler) {
-        super(handler.getConfiguration());
+    public LiveDataUpdatePrivateApi(SolarEdgeHandler handler, StatusUpdateListener listener) {
+        super(handler.getConfiguration(), listener);
         this.handler = handler;
         this.transformer = new LiveDataResponseTransformer(handler);
     }
index 016c668d1f9a62441fa88af87581dac9b91f260d..4000f704d4bf35e25080ae81aeaea9a3c4ec6f28 100644 (file)
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
+import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
 import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
@@ -33,14 +33,14 @@ import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class LiveDataUpdatePublicApi extends AbstractCommandCallback implements SolarEdgeCommand {
+public class LiveDataUpdatePublicApi extends AbstractCommand implements SolarEdgeCommand {
 
     private final SolarEdgeHandler handler;
     private final LiveDataResponseTransformer transformer;
     private int retries = 0;
 
-    public LiveDataUpdatePublicApi(SolarEdgeHandler handler) {
-        super(handler.getConfiguration());
+    public LiveDataUpdatePublicApi(SolarEdgeHandler handler, StatusUpdateListener listener) {
+        super(handler.getConfiguration(), listener);
         this.handler = handler;
         this.transformer = new LiveDataResponseTransformer(handler);
     }
index 4f9005e7fcdf78aac774cfecece50a3211f923e6..c2fe4deae2aebdb12cfb5431dd9b7308da26056c 100644 (file)
@@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
 import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 
@@ -29,7 +28,7 @@ import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class PrivateApiTokenCheck extends AbstractCommandCallback implements SolarEdgeCommand {
+public class PrivateApiTokenCheck extends AbstractCommand implements SolarEdgeCommand {
 
     public PrivateApiTokenCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
         super(handler.getConfiguration(), listener);
index ed956a60f491af4a1c48d9c3635b97d58321ea36..ee1de745902e0ac0e9aa6e04f42e299cd685c708 100644 (file)
@@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.http.HttpMethod;
-import org.openhab.binding.solaredge.internal.callback.AbstractCommandCallback;
 import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
 
@@ -29,7 +28,7 @@ import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
  * @author Alexander Friese - initial contribution
  */
 @NonNullByDefault
-public class PublicApiKeyCheck extends AbstractCommandCallback implements SolarEdgeCommand {
+public class PublicApiKeyCheck extends AbstractCommand implements SolarEdgeCommand {
 
     public PublicApiKeyCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
         super(handler.getConfiguration(), listener);
index cbd9879b02359bfd583fbe5c14cba9e91701390e..9d607f76186d17c3379dc78ec1f2bc5d995b55b6 100644 (file)
@@ -18,7 +18,6 @@ import org.eclipse.jetty.client.api.Response.CompleteListener;
 import org.eclipse.jetty.client.api.Response.ContentListener;
 import org.eclipse.jetty.client.api.Response.FailureListener;
 import org.eclipse.jetty.client.api.Response.SuccessListener;
-import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
 
 /**
  * public interface for all commands
@@ -36,17 +35,4 @@ public interface SolarEdgeCommand extends SuccessListener, FailureListener, Cont
      * @param asyncclient
      */
     void performAction(HttpClient asyncclient);
-
-    /**
-     * updates the listener's status
-     *
-     */
-    void updateListenerStatus();
-
-    /**
-     * register a listener
-     *
-     * @param listener
-     */
-    void setListener(StatusUpdateListener listener);
 }
index 9534cbbc51a3c6e7d4177e888397772805c68511..6fdb08b8be5c484fd8f75fa530044c96fac3786b 100644 (file)
@@ -13,7 +13,6 @@
 package org.openhab.binding.solaredge.internal.config;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
 
 /**
  * Bean holding configuration data according to bridge.xml
@@ -23,8 +22,8 @@ import org.eclipse.jdt.annotation.Nullable;
 @NonNullByDefault
 public class SolarEdgeConfiguration {
 
-    private @Nullable String tokenOrApiKey;
-    private @Nullable String solarId;
+    private String tokenOrApiKey = "";
+    private String solarId = "";
 
     private boolean meterInstalled = false;
     private boolean usePrivateApi = false;
@@ -34,7 +33,7 @@ public class SolarEdgeConfiguration {
     private Integer liveDataPollingInterval = 10;
     private Integer aggregateDataPollingInterval = 60;
 
-    public @Nullable String getTokenOrApiKey() {
+    public String getTokenOrApiKey() {
         return tokenOrApiKey;
     }
 
@@ -42,7 +41,7 @@ public class SolarEdgeConfiguration {
         this.tokenOrApiKey = tokenOrApiKey;
     }
 
-    public @Nullable String getSolarId() {
+    public String getSolarId() {
         return solarId;
     }
 
index fe3d2ffee210576057b51b74a60a2f59e31daeef..b9fff4b80bc3a4d9d47f27568559a232fe0499e9 100644 (file)
@@ -104,6 +104,94 @@ public class WebInterface implements AtomicReferenceTrait {
             this.commandQueue = new BlockingArrayQueue<>(WEB_REQUEST_QUEUE_MAX_SIZE);
         }
 
+        private void processAuthenticationResult(CommunicationStatus status) {
+            String errorMessageCodeFound;
+            String errorMessgaeCodeForbidden = STATUS_INVALID_SOLAR_ID;
+            if (config.isUsePrivateApi()) {
+                errorMessageCodeFound = STATUS_INVALID_TOKEN;
+            } else {
+                errorMessageCodeFound = STATUS_UNKNOWN_ERROR;
+            }
+
+            switch (status.getHttpCode()) {
+                case OK:
+                    handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
+                    setAuthenticated(true);
+                    break;
+                case FOUND:
+                    handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                            errorMessageCodeFound);
+                    setAuthenticated(false);
+                    break;
+                case FORBIDDEN:
+                    handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                            errorMessgaeCodeForbidden);
+                    setAuthenticated(false);
+                    break;
+                case SERVICE_UNAVAILABLE:
+                    handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, status.getMessage());
+                    setAuthenticated(false);
+                    break;
+                default:
+                    handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                            status.getMessage());
+                    setAuthenticated(false);
+            }
+        }
+
+        /**
+         * authenticates with the Solaredge WEB interface
+         */
+        private synchronized void authenticate() {
+            setAuthenticated(false);
+
+            if (preCheck()) {
+                SolarEdgeCommand tokenCheckCommand;
+
+                if (config.isUsePrivateApi()) {
+                    tokenCheckCommand = new PrivateApiTokenCheck(handler, this::processAuthenticationResult);
+                } else {
+                    tokenCheckCommand = new PublicApiKeyCheck(handler, this::processAuthenticationResult);
+                }
+                tokenCheckCommand.performAction(httpClient);
+            }
+        }
+
+        /**
+         * performs some pre cheks on configuration before attempting to login
+         *
+         * @return true on success, false otherwise
+         */
+        private boolean preCheck() {
+            String preCheckStatusMessage = "";
+            String localTokenOrApiKey = config.getTokenOrApiKey();
+
+            if (config.isUsePrivateApi() && localTokenOrApiKey.length() < TOKEN_THRESHOLD) {
+                preCheckStatusMessage = STATUS_INVALID_TOKEN_LENGTH;
+            } else if (!config.isUsePrivateApi() && localTokenOrApiKey.length() > API_KEY_THRESHOLD) {
+                preCheckStatusMessage = STATUS_INVALID_API_KEY_LENGTH;
+            } else if (!config.isUsePrivateApi() && calcRequestsPerDay() > WEB_REQUEST_PUBLIC_API_DAY_LIMIT) {
+                preCheckStatusMessage = STATUS_REQUEST_LIMIT_EXCEEDED;
+            } else if (config.isUsePrivateApi() && !config.isMeterInstalled()) {
+                preCheckStatusMessage = STATUS_NO_METER_CONFIGURED;
+            } else {
+                return true;
+            }
+
+            handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, preCheckStatusMessage);
+            return false;
+        }
+
+        /**
+         * calculates requests per day. just an internal helper
+         *
+         * @return
+         */
+        private long calcRequestsPerDay() {
+            return MINUTES_PER_DAY / config.getLiveDataPollingInterval()
+                    + 4 * MINUTES_PER_DAY / config.getAggregateDataPollingInterval();
+        }
+
         /**
          * puts a command into the queue
          *
@@ -131,30 +219,23 @@ public class WebInterface implements AtomicReferenceTrait {
                 authenticate();
             }
 
-            else if (isAuthenticated() && !commandQueue.isEmpty()) {
-                StatusUpdateListener statusUpdater = new StatusUpdateListener() {
-                    @Override
-                    public void update(CommunicationStatus status) {
-                        switch (status.getHttpCode()) {
-                            case SERVICE_UNAVAILABLE:
-                                handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
-                                        status.getMessage());
-                                setAuthenticated(false);
-                                break;
-                            case OK:
-                                // no action needed as the thing is already online.
-                                break;
-                            default:
-                                handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                                        status.getMessage());
-                                setAuthenticated(false);
-
-                        }
-                    }
-                };
-
-                SolarEdgeCommand command = commandQueue.poll();
-                command.setListener(statusUpdater);
+            if (isAuthenticated() && !commandQueue.isEmpty()) {
+                try {
+                    executeCommand();
+                } catch (Exception ex) {
+                    logger.warn("command execution ended with exception:", ex);
+                }
+            }
+        }
+
+        /**
+         * executes the next command in the queue. requires authenticated session.
+         *
+         * @throws ValidationException
+         */
+        private void executeCommand() {
+            SolarEdgeCommand command = commandQueue.poll();
+            if (command != null) {
                 command.performAction(httpClient);
             }
         }
@@ -190,107 +271,6 @@ public class WebInterface implements AtomicReferenceTrait {
         requestExecutor.enqueue(command);
     }
 
-    /**
-     * authenticates with the Solaredge WEB interface
-     */
-    private synchronized void authenticate() {
-        setAuthenticated(false);
-
-        if (preCheck()) {
-            SolarEdgeCommand tokenCheckCommand;
-
-            StatusUpdateListener tokenCheckListener = new StatusUpdateListener() {
-
-                @Override
-                public void update(CommunicationStatus status) {
-                    String errorMessageCodeFound;
-                    String errorMessgaeCodeForbidden;
-                    if (config.isUsePrivateApi()) {
-                        errorMessageCodeFound = "login error with private API: invalid token";
-                        errorMessgaeCodeForbidden = "login error with private API: invalid solarId";
-                    } else {
-                        errorMessageCodeFound = "login error with public API: unknown error";
-                        errorMessgaeCodeForbidden = "login error with public API: invalid api key or solarId is not valid for this api key";
-                    }
-
-                    switch (status.getHttpCode()) {
-                        case OK:
-                            handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, "logged in");
-                            setAuthenticated(true);
-                            break;
-                        case FOUND:
-                            handler.setStatusInfo(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_ERROR,
-                                    errorMessageCodeFound);
-                            setAuthenticated(false);
-                            break;
-                        case FORBIDDEN:
-                            handler.setStatusInfo(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_ERROR,
-                                    errorMessgaeCodeForbidden);
-                            setAuthenticated(false);
-                            break;
-                        case SERVICE_UNAVAILABLE:
-                            handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
-                                    status.getMessage());
-                            setAuthenticated(false);
-                            break;
-                        default:
-                            handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                                    status.getMessage());
-                            setAuthenticated(false);
-                    }
-                }
-            };
-
-            if (config.isUsePrivateApi()) {
-                tokenCheckCommand = new PrivateApiTokenCheck(handler, tokenCheckListener);
-            } else {
-                tokenCheckCommand = new PublicApiKeyCheck(handler, tokenCheckListener);
-            }
-            tokenCheckCommand.performAction(httpClient);
-        }
-    }
-
-    /**
-     * performs some pre cheks on configuration before attempting to login
-     *
-     * @return true on success, false otherwise
-     */
-    private boolean preCheck() {
-        String preCheckStatusMessage = "";
-        String localTokenOrApiKey = config.getTokenOrApiKey();
-        String localSolarId = config.getSolarId();
-
-        if (localTokenOrApiKey == null || localTokenOrApiKey.isEmpty()) {
-            preCheckStatusMessage = "please configure token/api_key first";
-        } else if (localSolarId == null || localSolarId.isEmpty()) {
-            preCheckStatusMessage = "please configure solarId first";
-        } else if (config.isUsePrivateApi() && localTokenOrApiKey.length() < TOKEN_THRESHOLD) {
-            preCheckStatusMessage = "you will have to use a 'token' and not an 'api key' when using private API";
-        } else if (!config.isUsePrivateApi() && localTokenOrApiKey.length() > API_KEY_THRESHOLD) {
-            preCheckStatusMessage = "you will have to use an 'api key' and not a 'token' when using public API";
-        } else if (!config.isUsePrivateApi() && calcRequestsPerDay() > WEB_REQUEST_PUBLIC_API_DAY_LIMIT) {
-            preCheckStatusMessage = "daily request limit (" + WEB_REQUEST_PUBLIC_API_DAY_LIMIT + ") exceeded: "
-                    + calcRequestsPerDay();
-        } else if (config.isUsePrivateApi() && !config.isMeterInstalled()) {
-            preCheckStatusMessage = "a meter must be present in order to use the private API";
-        } else {
-            return true;
-        }
-
-        this.handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, preCheckStatusMessage);
-        return false;
-    }
-
-    /**
-     * calculates requests per day. just an internal helper
-     *
-     * @return
-     */
-    private long calcRequestsPerDay() {
-        return MINUTES_PER_DAY / this.config.getLiveDataPollingInterval()
-                + 4 * MINUTES_PER_DAY / this.config.getAggregateDataPollingInterval();
-    }
-
     /**
      * will be called by the ThingHandler to abort periodic jobs.
      */
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/GenericSolarEdgeHandler.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/GenericSolarEdgeHandler.java
deleted file mode 100644 (file)
index 4b93b0b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.solaredge.internal.handler;
-
-import java.util.List;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelGroupUID;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingUID;
-
-/**
- * generic thing handler for solaredge
- *
- * @author Alexander Friese - initial contribution
- */
-@NonNullByDefault
-public class GenericSolarEdgeHandler extends SolarEdgeBaseHandler {
-
-    public GenericSolarEdgeHandler(Thing thing, HttpClient httpClient) {
-        super(thing, httpClient);
-    }
-
-    @Override
-    public List<Channel> getChannels() {
-        return getThing().getChannels();
-    }
-
-    @Override
-    public @Nullable Channel getChannel(String groupId, String channelId) {
-        ThingUID thingUID = this.getThing().getUID();
-        ChannelGroupUID channelGroupUID = new ChannelGroupUID(thingUID, groupId);
-        Channel channel = getThing().getChannel(new ChannelUID(channelGroupUID, channelId));
-        return channel;
-    }
-}
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeAggregateDataPolling.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeAggregateDataPolling.java
deleted file mode 100644 (file)
index 601c481..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.solaredge.internal.handler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.solaredge.internal.command.AggregateDataUpdatePrivateApi;
-import org.openhab.binding.solaredge.internal.command.AggregateDataUpdatePublicApi;
-import org.openhab.binding.solaredge.internal.command.SolarEdgeCommand;
-import org.openhab.binding.solaredge.internal.model.AggregatePeriod;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Polling worker class. This is responsible for periodic polling of sensor data.
- *
- * @author Alexander Friese - initial contribution
- */
-@NonNullByDefault
-public class SolarEdgeAggregateDataPolling implements Runnable {
-    /**
-     * Logger
-     */
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
-    /**
-     * Handler for delegation to callbacks.
-     */
-    private final SolarEdgeHandler handler;
-
-    /**
-     * Constructor.
-     *
-     * @param handler handler which handles results of polling
-     */
-    public SolarEdgeAggregateDataPolling(SolarEdgeHandler handler) {
-        this.handler = handler;
-    }
-
-    /**
-     * Poll the SolarEdge Webservice one time per call.
-     */
-    @Override
-    public void run() {
-        // if no meter is present all data will be fetched by the 'LiveDataUpdateMeterless'
-        if (handler.getConfiguration().isMeterInstalled()) {
-            logger.debug("polling SolarEdge aggregate data {}", handler.getConfiguration());
-
-            List<SolarEdgeCommand> commands = new ArrayList<>();
-
-            if (handler.getConfiguration().isUsePrivateApi()) {
-                commands.add(new AggregateDataUpdatePrivateApi(handler, AggregatePeriod.DAY));
-                commands.add(new AggregateDataUpdatePrivateApi(handler, AggregatePeriod.WEEK));
-                commands.add(new AggregateDataUpdatePrivateApi(handler, AggregatePeriod.MONTH));
-                commands.add(new AggregateDataUpdatePrivateApi(handler, AggregatePeriod.YEAR));
-            } else {
-                commands.add(new AggregateDataUpdatePublicApi(handler, AggregatePeriod.DAY));
-                commands.add(new AggregateDataUpdatePublicApi(handler, AggregatePeriod.WEEK));
-                commands.add(new AggregateDataUpdatePublicApi(handler, AggregatePeriod.MONTH));
-                commands.add(new AggregateDataUpdatePublicApi(handler, AggregatePeriod.YEAR));
-            }
-
-            for (SolarEdgeCommand command : commands) {
-                handler.getWebInterface().enqueueCommand(command);
-            }
-        }
-    }
-}
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeBaseHandler.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeBaseHandler.java
deleted file mode 100644 (file)
index 681fcea..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.solaredge.internal.handler;
-
-import java.util.Map;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
-import org.openhab.binding.solaredge.internal.AtomicReferenceTrait;
-import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
-import org.openhab.binding.solaredge.internal.connector.WebInterface;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
-import org.openhab.core.thing.binding.BaseThingHandler;
-import org.openhab.core.types.Command;
-import org.openhab.core.types.State;
-import org.openhab.core.types.UnDefType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The {@link SolarEdgeBaseHandler} is responsible for handling commands, which are
- * sent to one of the channels.
- *
- * @author Alexander Friese - initial contribution
- */
-@NonNullByDefault
-public abstract class SolarEdgeBaseHandler extends BaseThingHandler implements SolarEdgeHandler, AtomicReferenceTrait {
-    private final Logger logger = LoggerFactory.getLogger(SolarEdgeBaseHandler.class);
-
-    private final long LIVE_POLLING_INITIAL_DELAY = 1;
-    private final long AGGREGATE_POLLING_INITIAL_DELAY = 2;
-
-    /**
-     * Interface object for querying the Solaredge web interface
-     */
-    private WebInterface webInterface;
-
-    /**
-     * Schedule for polling live data
-     */
-    private final AtomicReference<@Nullable Future<?>> liveDataPollingJobReference;
-
-    /**
-     * Schedule for polling aggregate data
-     */
-    private final AtomicReference<@Nullable Future<?>> aggregateDataPollingJobReference;
-
-    public SolarEdgeBaseHandler(Thing thing, HttpClient httpClient) {
-        super(thing);
-        this.webInterface = new WebInterface(scheduler, this, httpClient);
-        this.liveDataPollingJobReference = new AtomicReference<>(null);
-        this.aggregateDataPollingJobReference = new AtomicReference<>(null);
-    }
-
-    @Override
-    public void handleCommand(ChannelUID channelUID, Command command) {
-        logger.debug("command for {}: {}", channelUID, command);
-        // write access is not supported.
-    }
-
-    @Override
-    public void initialize() {
-        logger.debug("About to initialize SolarEdge");
-        SolarEdgeConfiguration config = getConfiguration();
-        logger.debug("Solaredge initialized with configuration: {}", config);
-
-        startPolling();
-        webInterface.start();
-        updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting for web api login");
-    }
-
-    /**
-     * Start the polling.
-     */
-    private void startPolling() {
-        updateJobReference(liveDataPollingJobReference,
-                scheduler.scheduleWithFixedDelay(new SolarEdgeLiveDataPolling(this), LIVE_POLLING_INITIAL_DELAY,
-                        getConfiguration().getLiveDataPollingInterval(), TimeUnit.MINUTES));
-
-        updateJobReference(aggregateDataPollingJobReference,
-                scheduler.scheduleWithFixedDelay(new SolarEdgeAggregateDataPolling(this),
-                        AGGREGATE_POLLING_INITIAL_DELAY, getConfiguration().getAggregateDataPollingInterval(),
-                        TimeUnit.MINUTES));
-    }
-
-    /**
-     * Disposes the bridge.
-     */
-    @Override
-    public void dispose() {
-        logger.debug("Handler disposed.");
-
-        cancelJobReference(liveDataPollingJobReference);
-        cancelJobReference(aggregateDataPollingJobReference);
-
-        webInterface.dispose();
-    }
-
-    @Override
-    public WebInterface getWebInterface() {
-        return webInterface;
-    }
-
-    /**
-     * will update all channels provided in the map
-     */
-    @Override
-    public void updateChannelStatus(Map<Channel, State> values) {
-        logger.debug("Handling channel update.");
-
-        for (Channel channel : values.keySet()) {
-            if (getChannels().contains(channel)) {
-                State value = values.get(channel);
-                if (value != null) {
-                    logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
-                    updateState(channel.getUID(), value);
-                } else {
-                    logger.debug("Value is null or not provided by solaredge (channel: {})",
-                            channel.getUID().getAsString());
-                    updateState(channel.getUID(), UnDefType.UNDEF);
-                }
-            } else {
-                logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
-                        getThing().getThingTypeUID().getAsString());
-            }
-        }
-    }
-
-    @Override
-    public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, String description) {
-        super.updateStatus(status, statusDetail, description);
-    }
-
-    @Override
-    public SolarEdgeConfiguration getConfiguration() {
-        return this.getConfigAs(SolarEdgeConfiguration.class);
-    }
-}
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeGenericHandler.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeGenericHandler.java
new file mode 100644 (file)
index 0000000..0af1180
--- /dev/null
@@ -0,0 +1,240 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.solaredge.internal.handler;
+
+import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.STATUS_WAITING_FOR_LOGIN;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.solaredge.internal.AtomicReferenceTrait;
+import org.openhab.binding.solaredge.internal.command.AggregateDataUpdatePrivateApi;
+import org.openhab.binding.solaredge.internal.command.AggregateDataUpdatePublicApi;
+import org.openhab.binding.solaredge.internal.command.LiveDataUpdateMeterless;
+import org.openhab.binding.solaredge.internal.command.LiveDataUpdatePrivateApi;
+import org.openhab.binding.solaredge.internal.command.LiveDataUpdatePublicApi;
+import org.openhab.binding.solaredge.internal.command.SolarEdgeCommand;
+import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
+import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
+import org.openhab.binding.solaredge.internal.connector.WebInterface;
+import org.openhab.binding.solaredge.internal.model.AggregatePeriod;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelGroupUID;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link SolarEdgeGenericHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Alexander Friese - initial contribution
+ */
+@NonNullByDefault
+public class SolarEdgeGenericHandler extends BaseThingHandler implements SolarEdgeHandler, AtomicReferenceTrait {
+    private final Logger logger = LoggerFactory.getLogger(SolarEdgeGenericHandler.class);
+
+    private static final long LIVE_POLLING_INITIAL_DELAY = 1;
+    private static final long AGGREGATE_POLLING_INITIAL_DELAY = 2;
+
+    /**
+     * Interface object for querying the Solaredge web interface
+     */
+    private WebInterface webInterface;
+
+    /**
+     * Schedule for polling live data
+     */
+    private final AtomicReference<@Nullable Future<?>> liveDataPollingJobReference;
+
+    /**
+     * Schedule for polling aggregate data
+     */
+    private final AtomicReference<@Nullable Future<?>> aggregateDataPollingJobReference;
+
+    public SolarEdgeGenericHandler(Thing thing, HttpClient httpClient) {
+        super(thing);
+        this.webInterface = new WebInterface(scheduler, this, httpClient);
+        this.liveDataPollingJobReference = new AtomicReference<>(null);
+        this.aggregateDataPollingJobReference = new AtomicReference<>(null);
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        logger.debug("command for {}: {}", channelUID, command);
+        // write access is not supported.
+    }
+
+    @Override
+    public void initialize() {
+        logger.debug("About to initialize SolarEdge");
+        SolarEdgeConfiguration config = getConfiguration();
+        logger.debug("SolarEdge initialized with configuration: {}", config);
+
+        updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, STATUS_WAITING_FOR_LOGIN);
+        webInterface.start();
+        startPolling();
+    }
+
+    /**
+     * Start the polling.
+     */
+    private void startPolling() {
+        updateJobReference(liveDataPollingJobReference, scheduler.scheduleWithFixedDelay(this::liveDataPollingRun,
+                LIVE_POLLING_INITIAL_DELAY, getConfiguration().getLiveDataPollingInterval(), TimeUnit.MINUTES));
+
+        updateJobReference(aggregateDataPollingJobReference,
+                scheduler.scheduleWithFixedDelay(this::aggregateDataPollingRun, AGGREGATE_POLLING_INITIAL_DELAY,
+                        getConfiguration().getAggregateDataPollingInterval(), TimeUnit.MINUTES));
+    }
+
+    /**
+     * Poll the SolarEdge Webservice one time per call to retrieve live data.
+     */
+    void liveDataPollingRun() {
+        logger.debug("polling SolarEdge live data {}", getConfiguration());
+        SolarEdgeCommand ldu;
+
+        if (getConfiguration().isUsePrivateApi()) {
+            ldu = new LiveDataUpdatePrivateApi(this, this::updateOnlineStatus);
+        } else {
+            if (getConfiguration().isMeterInstalled()) {
+                ldu = new LiveDataUpdatePublicApi(this, this::updateOnlineStatus);
+            } else {
+                ldu = new LiveDataUpdateMeterless(this, this::updateOnlineStatus);
+            }
+        }
+        getWebInterface().enqueueCommand(ldu);
+    }
+
+    /**
+     * Poll the SolarEdge Webservice one time per call to retrieve aggregate data.
+     */
+    void aggregateDataPollingRun() {
+        // if no meter is present all data will be fetched by the 'LiveDataUpdateMeterless'
+        if (getConfiguration().isMeterInstalled()) {
+            logger.debug("polling SolarEdge aggregate data {}", getConfiguration());
+            List<SolarEdgeCommand> commands = new ArrayList<>();
+
+            if (getConfiguration().isUsePrivateApi()) {
+                commands.add(new AggregateDataUpdatePrivateApi(this, AggregatePeriod.DAY, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePrivateApi(this, AggregatePeriod.WEEK, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePrivateApi(this, AggregatePeriod.MONTH, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePrivateApi(this, AggregatePeriod.YEAR, this::updateOnlineStatus));
+            } else {
+                commands.add(new AggregateDataUpdatePublicApi(this, AggregatePeriod.DAY, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePublicApi(this, AggregatePeriod.WEEK, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePublicApi(this, AggregatePeriod.MONTH, this::updateOnlineStatus));
+                commands.add(new AggregateDataUpdatePublicApi(this, AggregatePeriod.YEAR, this::updateOnlineStatus));
+            }
+
+            for (SolarEdgeCommand command : commands) {
+                getWebInterface().enqueueCommand(command);
+            }
+        }
+    }
+
+    private void updateOnlineStatus(CommunicationStatus status) {
+        switch (status.getHttpCode()) {
+            case SERVICE_UNAVAILABLE:
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, status.getMessage());
+                break;
+            case OK:
+                updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+                break;
+            default:
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, status.getMessage());
+        }
+    }
+
+    /**
+     * Disposes the bridge.
+     */
+    @Override
+    public void dispose() {
+        logger.debug("Handler disposed.");
+
+        cancelJobReference(liveDataPollingJobReference);
+        cancelJobReference(aggregateDataPollingJobReference);
+
+        webInterface.dispose();
+    }
+
+    @Override
+    public WebInterface getWebInterface() {
+        return webInterface;
+    }
+
+    /**
+     * will update all channels provided in the map
+     */
+    @Override
+    public void updateChannelStatus(Map<Channel, State> values) {
+        logger.debug("Handling channel update.");
+
+        for (Channel channel : values.keySet()) {
+            if (getChannels().contains(channel)) {
+                State value = values.get(channel);
+                if (value != null) {
+                    logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
+                    updateState(channel.getUID(), value);
+                } else {
+                    logger.debug("Value is null or not provided by solaredge (channel: {})",
+                            channel.getUID().getAsString());
+                    updateState(channel.getUID(), UnDefType.UNDEF);
+                }
+            } else {
+                logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
+                        getThing().getThingTypeUID().getAsString());
+            }
+        }
+    }
+
+    @Override
+    public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
+        super.updateStatus(status, statusDetail, description);
+    }
+
+    @Override
+    public SolarEdgeConfiguration getConfiguration() {
+        return this.getConfigAs(SolarEdgeConfiguration.class);
+    }
+
+    @Override
+    public List<Channel> getChannels() {
+        return getThing().getChannels();
+    }
+
+    @Override
+    public @Nullable Channel getChannel(String groupId, String channelId) {
+        ThingUID thingUID = this.getThing().getUID();
+        ChannelGroupUID channelGroupUID = new ChannelGroupUID(thingUID, groupId);
+        Channel channel = getThing().getChannel(new ChannelUID(channelGroupUID, channelId));
+        return channel;
+    }
+}
index bdd44133a0d84ff55ee6ed416ea096bda9f9b413..0834b72467ec7a19012425e5c515e0e3079a6960 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.solaredge.internal.handler;
 import java.util.Map;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
 import org.openhab.binding.solaredge.internal.connector.WebInterface;
 import org.openhab.core.thing.Channel;
@@ -38,7 +39,7 @@ public interface SolarEdgeHandler extends ThingHandler, ChannelProvider {
      * @param statusDetail Bridge status detail
      * @param description Bridge status description
      */
-    void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, String description);
+    void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description);
 
     /**
      * Provides the web interface object.
diff --git a/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeLiveDataPolling.java b/bundles/org.openhab.binding.solaredge/src/main/java/org/openhab/binding/solaredge/internal/handler/SolarEdgeLiveDataPolling.java
deleted file mode 100644 (file)
index f4d5180..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.solaredge.internal.handler;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.solaredge.internal.command.LiveDataUpdateMeterless;
-import org.openhab.binding.solaredge.internal.command.LiveDataUpdatePrivateApi;
-import org.openhab.binding.solaredge.internal.command.LiveDataUpdatePublicApi;
-import org.openhab.binding.solaredge.internal.command.SolarEdgeCommand;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Polling worker class. This is responsible for periodic polling of sensor data.
- *
- * @author Alexander Friese - initial contribution
- */
-@NonNullByDefault
-public class SolarEdgeLiveDataPolling implements Runnable {
-    /**
-     * Logger
-     */
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
-    /**
-     * Handler for delegation to callbacks.
-     */
-    private final SolarEdgeHandler handler;
-
-    /**
-     * Constructor.
-     *
-     * @param handler handler which handles results of polling
-     */
-    public SolarEdgeLiveDataPolling(SolarEdgeHandler handler) {
-        this.handler = handler;
-    }
-
-    /**
-     * Poll the SolarEdge Webservice one time per call.
-     */
-    @Override
-    public void run() {
-        logger.debug("polling SolarEdge live data {}", handler.getConfiguration());
-
-        SolarEdgeCommand ldu;
-
-        if (handler.getConfiguration().isUsePrivateApi()) {
-            ldu = new LiveDataUpdatePrivateApi(handler);
-        } else {
-            if (handler.getConfiguration().isMeterInstalled()) {
-                ldu = new LiveDataUpdatePublicApi(handler);
-            } else {
-                ldu = new LiveDataUpdateMeterless(handler);
-            }
-        }
-
-        handler.getWebInterface().enqueueCommand(ldu);
-    }
-}
index 4931c13772828b5be1a19518a1ad7ff3116fd825..2763357ecefe4dc0dfac461af36193c997c2a1bb 100644 (file)
@@ -54,7 +54,7 @@ abstract class AbstractDataResponseTransformer {
     /**
      * logger
      */
-    private static final Logger logger = LoggerFactory.getLogger(AbstractDataResponseTransformer.class);
+    private final Logger logger = LoggerFactory.getLogger(AbstractDataResponseTransformer.class);
 
     /**
      * determines the unit, also handles wrong spelling of kWh (which is spelled with capital K by API)
@@ -178,8 +178,9 @@ abstract class AbstractDataResponseTransformer {
             MeterTelemetry... values) {
         double sum = 0.0;
         for (MeterTelemetry value : values) {
-            if (value.value != null) {
-                sum += value.value;
+            Double innerValue = value.value;
+            if (innerValue != null) {
+                sum += innerValue;
             }
         }
         putEnergyType(targetMap, channel, sum, unit);
index 3a2d4fe4979528f5e9000b9da86e634eaf92e946..a9533ad9ece57de0da998a5a55ca74405d7af022 100644 (file)
@@ -56,8 +56,9 @@ public class AggregateDataResponseTransformerPublicApi extends AbstractDataRespo
         if (energyDetails != null) {
             AggregatePeriod timeUnit = energyDetails.timeUnit;
             String unit = energyDetails.unit;
-            if (timeUnit != null && unit != null && energyDetails.meters != null) {
-                for (MeterTelemetries meter : energyDetails.meters) {
+            List<MeterTelemetries> meters = energyDetails.meters;
+            if (timeUnit != null && unit != null && meters != null) {
+                for (MeterTelemetries meter : meters) {
                     String type = meter.type;
                     if (type != null) {
                         if (type.equals(METER_TYPE_PRODUCTION)) {
index 120c325420da690dab132207e7fe660011f3af00..2767e3cfd70139dc176524925de584ffe664f8a8 100644 (file)
  */
 package org.openhab.binding.solaredge.internal.model;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * defines the level of data aggregation
  *
  * @author Alexander Friese - initial contribution
  */
+@NonNullByDefault
 public enum AggregatePeriod {
     DAY,
     WEEK,
index f66f9050c62f1a113637d74a876583635c7b887d..3e3ef5c2ee7da177e7d6e659daaf6ed58d515af8 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.solaredge.internal.model;
 import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -142,28 +143,32 @@ public class LiveDataResponseTransformer extends AbstractDataResponseTransformer
                     ZERO_POWER, siteCurrentPowerFlow.unit);
 
             // determine power flow from connection list
-            if (siteCurrentPowerFlow.connections != null) {
-                for (Connection con : siteCurrentPowerFlow.connections) {
+            List<Connection> connections = siteCurrentPowerFlow.connections;
+            if (connections != null) {
+                for (Connection con : connections) {
+                    String conFrom = con.from;
+                    String conTo = con.to;
                     if (grid != null) {
-                        if (con.from != null && con.from.equalsIgnoreCase(LiveDataResponse.GRID)) {
+                        if (conFrom != null && conFrom.equalsIgnoreCase(LiveDataResponse.GRID)) {
                             putPowerType(result, channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_IMPORT),
                                     grid.currentPower, siteCurrentPowerFlow.unit);
-                        } else if (con.to != null && con.to.equalsIgnoreCase(LiveDataResponse.GRID)) {
+                        } else if (conTo != null && conTo.equalsIgnoreCase(LiveDataResponse.GRID)) {
                             putPowerType(result, channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_EXPORT),
                                     grid.currentPower, siteCurrentPowerFlow.unit);
                         }
                     }
 
                     if (storage != null) {
-                        Double currentPower = storage.currentPower != null ? storage.currentPower : 0;
-                        if (con.from != null && con.from.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
+                        Double currentPower = storage.currentPower;
+                        currentPower = currentPower != null ? currentPower : 0;
+                        if (conFrom != null && conFrom.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
                             putPowerType(result,
                                     channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_DISCHARGE),
                                     currentPower, siteCurrentPowerFlow.unit);
                             putPowerType(result,
                                     channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE_DISCHARGE),
                                     -1 * currentPower, siteCurrentPowerFlow.unit);
-                        } else if (con.to != null && con.to.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
+                        } else if (conTo != null && conTo.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
                             putPowerType(result,
                                     channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE),
                                     currentPower, siteCurrentPowerFlow.unit);
index 3f4598dd1ff1689d992f59c0a201c6c5e3b8a751..d553da644fa14377d3e628b838fa8aa19ff8b4a1 100644 (file)
@@ -129,3 +129,14 @@ channel-type.solaredge.type-energy.label = Energy
 channel-type.solaredge.type-percent.label = Percent
 channel-type.solaredge.type-power.label = Power
 channel-type.solaredge.type-status.label = Status Text
+
+# status translations
+
+status.invalid.solarId = solarId is either invalid or belongs to another account.
+status.invalid.token = The token seems to be invalid.
+status.unknown.error = Unknown error
+status.invalid.token.length = You will have to use a 'token' and not an 'api key' when using private API.
+status.invalid.api.key.length = You will have to use an 'api key' and not a 'token' when using public API.
+status.request.limit.exceeded = Daily request limit exceeded: {0}.
+status.no.meter.configured = A meter must be present in order to use the private API.
+status.waiting.for.login = Waiting for web api login.