[solaredge] Fix code style warnings, fix NPE warnings, improve i18n (#14666)
* 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>
This commit is contained in:
@@ -100,5 +100,16 @@ public class SolarEdgeBindingConstants {
|
|||||||
public static final long WEB_REQUEST_INTERVAL = TimeUnit.SECONDS.toMillis(5);
|
public static final long WEB_REQUEST_INTERVAL = TimeUnit.SECONDS.toMillis(5);
|
||||||
public static final int WEB_REQUEST_QUEUE_MAX_SIZE = 20;
|
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);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_GENERIC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*
|
|||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
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.io.net.http.HttpClientFactory;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
@@ -62,7 +62,7 @@ public class SolarEdgeHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
if (thingTypeUID.equals(THING_TYPE_GENERIC)) {
|
if (thingTypeUID.equals(THING_TYPE_GENERIC)) {
|
||||||
return new GenericSolarEdgeHandler(thing, httpClient);
|
return new SolarEdgeGenericHandler(thing, httpClient);
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Unsupported Thing-Type: {}", thingTypeUID.getAsString());
|
logger.warn("Unsupported Thing-Type: {}", thingTypeUID.getAsString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.solaredge.internal.callback;
|
package org.openhab.binding.solaredge.internal.command;
|
||||||
|
|
||||||
import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
|
import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ import org.eclipse.jetty.client.api.Response;
|
|||||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.http.HttpStatus.Code;
|
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.config.SolarEdgeConfiguration;
|
||||||
import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
|
import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
|
||||||
import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
|
import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
|
||||||
@@ -47,12 +46,12 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
* @author Alexander Friese - initial contribution
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractCommandCallback extends BufferingResponseListener implements SolarEdgeCommand {
|
public abstract class AbstractCommand extends BufferingResponseListener implements SolarEdgeCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* logger
|
* logger
|
||||||
*/
|
*/
|
||||||
protected final Logger logger = LoggerFactory.getLogger(AbstractCommandCallback.class);
|
protected final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the configuration
|
* the configuration
|
||||||
@@ -72,27 +71,20 @@ public abstract class AbstractCommandCallback extends BufferingResponseListener
|
|||||||
/**
|
/**
|
||||||
* listener to provide updates to the WebInterface class
|
* listener to provide updates to the WebInterface class
|
||||||
*/
|
*/
|
||||||
private @Nullable StatusUpdateListener listener;
|
private final StatusUpdateListener listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the constructor
|
* the constructor
|
||||||
*
|
*
|
||||||
* @param config
|
* @param config
|
||||||
|
* @param listener
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public AbstractCommandCallback(SolarEdgeConfiguration config) {
|
public AbstractCommand(SolarEdgeConfiguration config, StatusUpdateListener listener) {
|
||||||
this.communicationStatus = new CommunicationStatus();
|
this.communicationStatus = new CommunicationStatus();
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.gson = new Gson();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the constructor
|
|
||||||
*
|
|
||||||
* @param config
|
|
||||||
*/
|
|
||||||
public AbstractCommandCallback(SolarEdgeConfiguration config, StatusUpdateListener listener) {
|
|
||||||
this(config);
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
this.gson = new Gson();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,7 +143,6 @@ public abstract class AbstractCommandCallback extends BufferingResponseListener
|
|||||||
} else {
|
} else {
|
||||||
// this is only relevant when using public API
|
// this is only relevant when using public API
|
||||||
request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
|
request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareRequest(request).send(this);
|
prepareRequest(request).send(this);
|
||||||
@@ -164,10 +155,15 @@ public abstract class AbstractCommandCallback extends BufferingResponseListener
|
|||||||
return communicationStatus;
|
return communicationStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void updateListenerStatus() {
|
* updates status of the registered listener.
|
||||||
if (listener != null) {
|
*/
|
||||||
|
protected final void updateListenerStatus() {
|
||||||
|
try {
|
||||||
listener.update(communicationStatus);
|
listener.update(communicationStatus);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// this should not happen
|
||||||
|
logger.warn("Exception caught: {}", ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,11 +182,6 @@ public abstract class AbstractCommandCallback extends BufferingResponseListener
|
|||||||
*/
|
*/
|
||||||
protected abstract String getURL();
|
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
|
* just a wrapper as fromJson could return null. This will avoid warnings as eclipse otherwise assumes unnecessary
|
||||||
* null checks which are not unnecessary
|
* null checks which are not unnecessary
|
||||||
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
|
|||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
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.handler.SolarEdgeHandler;
|
||||||
import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePrivateApi;
|
import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePrivateApi;
|
||||||
import org.openhab.binding.solaredge.internal.model.AggregateDataResponseTransformerPrivateApi;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class AggregateDataUpdatePrivateApi extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class AggregateDataUpdatePrivateApi extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the solaredge handler
|
* the solaredge handler
|
||||||
@@ -59,8 +59,9 @@ public class AggregateDataUpdatePrivateApi extends AbstractCommandCallback imple
|
|||||||
* @param handler
|
* @param handler
|
||||||
* @param period
|
* @param period
|
||||||
*/
|
*/
|
||||||
public AggregateDataUpdatePrivateApi(SolarEdgeHandler handler, AggregatePeriod period) {
|
public AggregateDataUpdatePrivateApi(SolarEdgeHandler handler, AggregatePeriod period,
|
||||||
super(handler.getConfiguration());
|
StatusUpdateListener listener) {
|
||||||
|
super(handler.getConfiguration(), listener);
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.transformer = new AggregateDataResponseTransformerPrivateApi(handler);
|
this.transformer = new AggregateDataResponseTransformerPrivateApi(handler);
|
||||||
this.period = period;
|
this.period = period;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.eclipse.jetty.client.api.Request;
|
|||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
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.handler.SolarEdgeHandler;
|
||||||
import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePublicApi;
|
import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePublicApi;
|
||||||
import org.openhab.binding.solaredge.internal.model.AggregateDataResponseTransformerPublicApi;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class AggregateDataUpdatePublicApi extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class AggregateDataUpdatePublicApi extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the solaredge handler
|
* the solaredge handler
|
||||||
@@ -61,8 +61,9 @@ public class AggregateDataUpdatePublicApi extends AbstractCommandCallback implem
|
|||||||
* @param handler
|
* @param handler
|
||||||
* @param period
|
* @param period
|
||||||
*/
|
*/
|
||||||
public AggregateDataUpdatePublicApi(SolarEdgeHandler handler, AggregatePeriod period) {
|
public AggregateDataUpdatePublicApi(SolarEdgeHandler handler, AggregatePeriod period,
|
||||||
super(handler.getConfiguration());
|
StatusUpdateListener listener) {
|
||||||
|
super(handler.getConfiguration(), listener);
|
||||||
this.dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
this.dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.transformer = new AggregateDataResponseTransformerPublicApi(handler);
|
this.transformer = new AggregateDataResponseTransformerPublicApi(handler);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
|
|||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
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.handler.SolarEdgeHandler;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponseMeterless;
|
import org.openhab.binding.solaredge.internal.model.LiveDataResponseMeterless;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LiveDataUpdateMeterless extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class LiveDataUpdateMeterless extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
private final SolarEdgeHandler handler;
|
private final SolarEdgeHandler handler;
|
||||||
private final LiveDataResponseTransformer transformer;
|
private final LiveDataResponseTransformer transformer;
|
||||||
private int retries = 0;
|
private int retries = 0;
|
||||||
|
|
||||||
public LiveDataUpdateMeterless(SolarEdgeHandler handler) {
|
public LiveDataUpdateMeterless(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
||||||
super(handler.getConfiguration());
|
super(handler.getConfiguration(), listener);
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.transformer = new LiveDataResponseTransformer(handler);
|
this.transformer = new LiveDataResponseTransformer(handler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
|
|||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
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.handler.SolarEdgeHandler;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
|
import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LiveDataUpdatePrivateApi extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class LiveDataUpdatePrivateApi extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
private final SolarEdgeHandler handler;
|
private final SolarEdgeHandler handler;
|
||||||
private final LiveDataResponseTransformer transformer;
|
private final LiveDataResponseTransformer transformer;
|
||||||
private int retries = 0;
|
private int retries = 0;
|
||||||
|
|
||||||
public LiveDataUpdatePrivateApi(SolarEdgeHandler handler) {
|
public LiveDataUpdatePrivateApi(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
||||||
super(handler.getConfiguration());
|
super(handler.getConfiguration(), listener);
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.transformer = new LiveDataResponseTransformer(handler);
|
this.transformer = new LiveDataResponseTransformer(handler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.eclipse.jetty.client.api.Request;
|
|||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
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.handler.SolarEdgeHandler;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
|
import org.openhab.binding.solaredge.internal.model.LiveDataResponse;
|
||||||
import org.openhab.binding.solaredge.internal.model.LiveDataResponseTransformer;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LiveDataUpdatePublicApi extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class LiveDataUpdatePublicApi extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
private final SolarEdgeHandler handler;
|
private final SolarEdgeHandler handler;
|
||||||
private final LiveDataResponseTransformer transformer;
|
private final LiveDataResponseTransformer transformer;
|
||||||
private int retries = 0;
|
private int retries = 0;
|
||||||
|
|
||||||
public LiveDataUpdatePublicApi(SolarEdgeHandler handler) {
|
public LiveDataUpdatePublicApi(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
||||||
super(handler.getConfiguration());
|
super(handler.getConfiguration(), listener);
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.transformer = new LiveDataResponseTransformer(handler);
|
this.transformer = new LiveDataResponseTransformer(handler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
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.connector.StatusUpdateListener;
|
||||||
import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class PrivateApiTokenCheck extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class PrivateApiTokenCheck extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
public PrivateApiTokenCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
public PrivateApiTokenCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
||||||
super(handler.getConfiguration(), listener);
|
super(handler.getConfiguration(), listener);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
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.connector.StatusUpdateListener;
|
||||||
import org.openhab.binding.solaredge.internal.handler.SolarEdgeHandler;
|
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
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class PublicApiKeyCheck extends AbstractCommandCallback implements SolarEdgeCommand {
|
public class PublicApiKeyCheck extends AbstractCommand implements SolarEdgeCommand {
|
||||||
|
|
||||||
public PublicApiKeyCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
public PublicApiKeyCheck(SolarEdgeHandler handler, StatusUpdateListener listener) {
|
||||||
super(handler.getConfiguration(), listener);
|
super(handler.getConfiguration(), listener);
|
||||||
|
|||||||
@@ -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.ContentListener;
|
||||||
import org.eclipse.jetty.client.api.Response.FailureListener;
|
import org.eclipse.jetty.client.api.Response.FailureListener;
|
||||||
import org.eclipse.jetty.client.api.Response.SuccessListener;
|
import org.eclipse.jetty.client.api.Response.SuccessListener;
|
||||||
import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* public interface for all commands
|
* public interface for all commands
|
||||||
@@ -36,17 +35,4 @@ public interface SolarEdgeCommand extends SuccessListener, FailureListener, Cont
|
|||||||
* @param asyncclient
|
* @param asyncclient
|
||||||
*/
|
*/
|
||||||
void performAction(HttpClient asyncclient);
|
void performAction(HttpClient asyncclient);
|
||||||
|
|
||||||
/**
|
|
||||||
* updates the listener's status
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void updateListenerStatus();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* register a listener
|
|
||||||
*
|
|
||||||
* @param listener
|
|
||||||
*/
|
|
||||||
void setListener(StatusUpdateListener listener);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
package org.openhab.binding.solaredge.internal.config;
|
package org.openhab.binding.solaredge.internal.config;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean holding configuration data according to bridge.xml
|
* Bean holding configuration data according to bridge.xml
|
||||||
@@ -23,8 +22,8 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class SolarEdgeConfiguration {
|
public class SolarEdgeConfiguration {
|
||||||
|
|
||||||
private @Nullable String tokenOrApiKey;
|
private String tokenOrApiKey = "";
|
||||||
private @Nullable String solarId;
|
private String solarId = "";
|
||||||
|
|
||||||
private boolean meterInstalled = false;
|
private boolean meterInstalled = false;
|
||||||
private boolean usePrivateApi = false;
|
private boolean usePrivateApi = false;
|
||||||
@@ -34,7 +33,7 @@ public class SolarEdgeConfiguration {
|
|||||||
private Integer liveDataPollingInterval = 10;
|
private Integer liveDataPollingInterval = 10;
|
||||||
private Integer aggregateDataPollingInterval = 60;
|
private Integer aggregateDataPollingInterval = 60;
|
||||||
|
|
||||||
public @Nullable String getTokenOrApiKey() {
|
public String getTokenOrApiKey() {
|
||||||
return tokenOrApiKey;
|
return tokenOrApiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ public class SolarEdgeConfiguration {
|
|||||||
this.tokenOrApiKey = tokenOrApiKey;
|
this.tokenOrApiKey = tokenOrApiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getSolarId() {
|
public String getSolarId() {
|
||||||
return solarId;
|
return solarId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,94 @@ public class WebInterface implements AtomicReferenceTrait {
|
|||||||
this.commandQueue = new BlockingArrayQueue<>(WEB_REQUEST_QUEUE_MAX_SIZE);
|
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
|
* puts a command into the queue
|
||||||
*
|
*
|
||||||
@@ -131,30 +219,23 @@ public class WebInterface implements AtomicReferenceTrait {
|
|||||||
authenticate();
|
authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isAuthenticated() && !commandQueue.isEmpty()) {
|
if (isAuthenticated() && !commandQueue.isEmpty()) {
|
||||||
StatusUpdateListener statusUpdater = new StatusUpdateListener() {
|
try {
|
||||||
@Override
|
executeCommand();
|
||||||
public void update(CommunicationStatus status) {
|
} catch (Exception ex) {
|
||||||
switch (status.getHttpCode()) {
|
logger.warn("command execution ended with exception:", ex);
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
}
|
* executes the next command in the queue. requires authenticated session.
|
||||||
};
|
*
|
||||||
|
* @throws ValidationException
|
||||||
SolarEdgeCommand command = commandQueue.poll();
|
*/
|
||||||
command.setListener(statusUpdater);
|
private void executeCommand() {
|
||||||
|
SolarEdgeCommand command = commandQueue.poll();
|
||||||
|
if (command != null) {
|
||||||
command.performAction(httpClient);
|
command.performAction(httpClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,107 +271,6 @@ public class WebInterface implements AtomicReferenceTrait {
|
|||||||
requestExecutor.enqueue(command);
|
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.
|
* will be called by the ThingHandler to abort periodic jobs.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ package org.openhab.binding.solaredge.internal.handler;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
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.config.SolarEdgeConfiguration;
|
||||||
import org.openhab.binding.solaredge.internal.connector.WebInterface;
|
import org.openhab.binding.solaredge.internal.connector.WebInterface;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
@@ -38,7 +39,7 @@ public interface SolarEdgeHandler extends ThingHandler, ChannelProvider {
|
|||||||
* @param statusDetail Bridge status detail
|
* @param statusDetail Bridge status detail
|
||||||
* @param description Bridge status description
|
* @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.
|
* Provides the web interface object.
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,7 +54,7 @@ abstract class AbstractDataResponseTransformer {
|
|||||||
/**
|
/**
|
||||||
* logger
|
* 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)
|
* 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) {
|
MeterTelemetry... values) {
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (MeterTelemetry value : values) {
|
for (MeterTelemetry value : values) {
|
||||||
if (value.value != null) {
|
Double innerValue = value.value;
|
||||||
sum += value.value;
|
if (innerValue != null) {
|
||||||
|
sum += innerValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
putEnergyType(targetMap, channel, sum, unit);
|
putEnergyType(targetMap, channel, sum, unit);
|
||||||
|
|||||||
@@ -56,8 +56,9 @@ public class AggregateDataResponseTransformerPublicApi extends AbstractDataRespo
|
|||||||
if (energyDetails != null) {
|
if (energyDetails != null) {
|
||||||
AggregatePeriod timeUnit = energyDetails.timeUnit;
|
AggregatePeriod timeUnit = energyDetails.timeUnit;
|
||||||
String unit = energyDetails.unit;
|
String unit = energyDetails.unit;
|
||||||
if (timeUnit != null && unit != null && energyDetails.meters != null) {
|
List<MeterTelemetries> meters = energyDetails.meters;
|
||||||
for (MeterTelemetries meter : energyDetails.meters) {
|
if (timeUnit != null && unit != null && meters != null) {
|
||||||
|
for (MeterTelemetries meter : meters) {
|
||||||
String type = meter.type;
|
String type = meter.type;
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
if (type.equals(METER_TYPE_PRODUCTION)) {
|
if (type.equals(METER_TYPE_PRODUCTION)) {
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.solaredge.internal.model;
|
package org.openhab.binding.solaredge.internal.model;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* defines the level of data aggregation
|
* defines the level of data aggregation
|
||||||
*
|
*
|
||||||
* @author Alexander Friese - initial contribution
|
* @author Alexander Friese - initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public enum AggregatePeriod {
|
public enum AggregatePeriod {
|
||||||
DAY,
|
DAY,
|
||||||
WEEK,
|
WEEK,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ package org.openhab.binding.solaredge.internal.model;
|
|||||||
import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
|
import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
@@ -142,28 +143,32 @@ public class LiveDataResponseTransformer extends AbstractDataResponseTransformer
|
|||||||
ZERO_POWER, siteCurrentPowerFlow.unit);
|
ZERO_POWER, siteCurrentPowerFlow.unit);
|
||||||
|
|
||||||
// determine power flow from connection list
|
// determine power flow from connection list
|
||||||
if (siteCurrentPowerFlow.connections != null) {
|
List<Connection> connections = siteCurrentPowerFlow.connections;
|
||||||
for (Connection con : siteCurrentPowerFlow.connections) {
|
if (connections != null) {
|
||||||
|
for (Connection con : connections) {
|
||||||
|
String conFrom = con.from;
|
||||||
|
String conTo = con.to;
|
||||||
if (grid != null) {
|
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),
|
putPowerType(result, channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_IMPORT),
|
||||||
grid.currentPower, siteCurrentPowerFlow.unit);
|
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),
|
putPowerType(result, channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_EXPORT),
|
||||||
grid.currentPower, siteCurrentPowerFlow.unit);
|
grid.currentPower, siteCurrentPowerFlow.unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage != null) {
|
if (storage != null) {
|
||||||
Double currentPower = storage.currentPower != null ? storage.currentPower : 0;
|
Double currentPower = storage.currentPower;
|
||||||
if (con.from != null && con.from.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
|
currentPower = currentPower != null ? currentPower : 0;
|
||||||
|
if (conFrom != null && conFrom.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
|
||||||
putPowerType(result,
|
putPowerType(result,
|
||||||
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_DISCHARGE),
|
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_DISCHARGE),
|
||||||
currentPower, siteCurrentPowerFlow.unit);
|
currentPower, siteCurrentPowerFlow.unit);
|
||||||
putPowerType(result,
|
putPowerType(result,
|
||||||
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE_DISCHARGE),
|
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE_DISCHARGE),
|
||||||
-1 * currentPower, siteCurrentPowerFlow.unit);
|
-1 * currentPower, siteCurrentPowerFlow.unit);
|
||||||
} else if (con.to != null && con.to.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
|
} else if (conTo != null && conTo.equalsIgnoreCase(LiveDataResponse.STORAGE)) {
|
||||||
putPowerType(result,
|
putPowerType(result,
|
||||||
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE),
|
channelProvider.getChannel(CHANNEL_GROUP_LIVE, CHANNEL_ID_BATTERY_CHARGE),
|
||||||
currentPower, siteCurrentPowerFlow.unit);
|
currentPower, siteCurrentPowerFlow.unit);
|
||||||
|
|||||||
@@ -129,3 +129,14 @@ channel-type.solaredge.type-energy.label = Energy
|
|||||||
channel-type.solaredge.type-percent.label = Percent
|
channel-type.solaredge.type-percent.label = Percent
|
||||||
channel-type.solaredge.type-power.label = Power
|
channel-type.solaredge.type-power.label = Power
|
||||||
channel-type.solaredge.type-status.label = Status Text
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user