mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[tesla] Add null annotations (#17582)
Signed-off-by: Leo Siepel <leosiepel@gmail.com>
This commit is contained in:
parent
931f39ff17
commit
f39415b631
@ -19,6 +19,8 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
@ -33,6 +35,7 @@ import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.Type;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* The {@link TeslaChannelSelectorProxy} class is a helper class to instantiate
|
||||
@ -40,6 +43,7 @@ import org.openhab.core.types.Type;
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TeslaChannelSelectorProxy {
|
||||
|
||||
public enum TeslaChannelSelector {
|
||||
@ -939,11 +943,11 @@ public class TeslaChannelSelectorProxy {
|
||||
@Override
|
||||
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
|
||||
State someState = super.getState(s);
|
||||
if (someState != null) {
|
||||
if (someState != UnDefType.UNDEF) {
|
||||
BigDecimal value = ((DecimalType) someState).toBigDecimal();
|
||||
return new QuantityType<>(value, ImperialUnits.MILES_PER_HOUR);
|
||||
} else {
|
||||
return null;
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1062,12 +1066,12 @@ public class TeslaChannelSelectorProxy {
|
||||
},
|
||||
WHEEL_TYPE("wheel_type", "wheeltype", StringType.class, true);
|
||||
|
||||
private final String restID;
|
||||
private final @Nullable String restID;
|
||||
private final String channelID;
|
||||
private Class<? extends Type> typeClass;
|
||||
private final boolean isProperty;
|
||||
|
||||
private TeslaChannelSelector(String restID, String channelID, Class<? extends Type> typeClass,
|
||||
private TeslaChannelSelector(@Nullable String restID, String channelID, Class<? extends Type> typeClass,
|
||||
boolean isProperty) {
|
||||
this.restID = restID;
|
||||
this.channelID = channelID;
|
||||
@ -1077,7 +1081,8 @@ public class TeslaChannelSelectorProxy {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return restID;
|
||||
String restID = this.restID;
|
||||
return restID != null ? restID : "null";
|
||||
}
|
||||
|
||||
public String getChannelID() {
|
||||
@ -1107,7 +1112,7 @@ public class TeslaChannelSelectorProxy {
|
||||
| InvocationTargetException e) {
|
||||
}
|
||||
|
||||
return null;
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
public static TeslaChannelSelector getValueSelectorFromChannelID(String valueSelectorText)
|
||||
@ -1124,7 +1129,8 @@ public class TeslaChannelSelectorProxy {
|
||||
public static TeslaChannelSelector getValueSelectorFromRESTID(String valueSelectorText)
|
||||
throws IllegalArgumentException {
|
||||
for (TeslaChannelSelector c : TeslaChannelSelector.values()) {
|
||||
if (c.restID != null && c.restID.equals(valueSelectorText)) {
|
||||
String restID = c.restID;
|
||||
if (restID != null && restID.equals(valueSelectorText)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.discovery;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants;
|
||||
import org.openhab.binding.tesla.internal.TeslaHandlerFactory;
|
||||
import org.openhab.binding.tesla.internal.handler.TeslaAccountHandler;
|
||||
import org.openhab.binding.tesla.internal.handler.VehicleListener;
|
||||
import org.openhab.binding.tesla.internal.protocol.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleConfig;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleConfig;
|
||||
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
@ -36,8 +37,9 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(scope = ServiceScope.PROTOTYPE, service = TeslaVehicleDiscoveryService.class)
|
||||
public class TeslaVehicleDiscoveryService extends AbstractThingHandlerDiscoveryService<@NonNull TeslaAccountHandler>
|
||||
public class TeslaVehicleDiscoveryService extends AbstractThingHandlerDiscoveryService<TeslaAccountHandler>
|
||||
implements VehicleListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(TeslaVehicleDiscoveryService.class);
|
||||
|
||||
@ -63,13 +65,13 @@ public class TeslaVehicleDiscoveryService extends AbstractThingHandlerDiscoveryS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void vehicleFound(Vehicle vehicle, VehicleConfig vehicleConfig) {
|
||||
public void vehicleFound(Vehicle vehicle, @Nullable VehicleConfig vehicleConfig) {
|
||||
ThingTypeUID type = vehicleConfig == null ? TeslaBindingConstants.THING_TYPE_VEHICLE
|
||||
: vehicleConfig.identifyModel();
|
||||
if (type != null) {
|
||||
logger.debug("Found a {} vehicle", type.getId());
|
||||
ThingUID thingUID = new ThingUID(type, thingHandler.getThing().getUID(), vehicle.vin);
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(vehicle.display_name)
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(vehicle.displayName)
|
||||
.withBridge(thingHandler.getThing().getUID()).withProperty(TeslaBindingConstants.VIN, vehicle.vin)
|
||||
.build();
|
||||
thingDiscovered(discoveryResult);
|
||||
|
@ -31,12 +31,14 @@ import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants;
|
||||
import org.openhab.binding.tesla.internal.discovery.TeslaVehicleDiscoveryService;
|
||||
import org.openhab.binding.tesla.internal.protocol.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleConfig;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleData;
|
||||
import org.openhab.binding.tesla.internal.protocol.sso.TokenResponse;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleConfig;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleData;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.sso.TokenResponse;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@ -63,6 +65,7 @@ import com.google.gson.JsonParser;
|
||||
* @author Nicolai Grødum - Adding token based auth
|
||||
* @author Kai Kreuzer - refactored to use separate vehicle handlers
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
|
||||
public static final int API_MAXIMUM_ERRORS_IN_INTERVAL = 3;
|
||||
@ -86,6 +89,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
private final ThingTypeMigrationService thingTypeMigrationService;
|
||||
|
||||
// Threading and Job related variables
|
||||
@Nullable
|
||||
protected ScheduledFuture<?> connectJob;
|
||||
|
||||
protected long lastTimeStamp;
|
||||
@ -93,10 +97,12 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
protected int apiIntervalErrors;
|
||||
protected long eventIntervalTimestamp;
|
||||
protected int eventIntervalErrors;
|
||||
protected ReentrantLock lock;
|
||||
|
||||
protected ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
@Nullable
|
||||
private TokenResponse logonToken;
|
||||
private final Set<VehicleListener> vehicleListeners = new HashSet<>();
|
||||
|
||||
@ -122,31 +128,17 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
lock = new ReentrantLock();
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
if (connectJob == null || connectJob.isCancelled()) {
|
||||
connectJob = scheduler.scheduleWithFixedDelay(connectRunnable, 0, CONNECT_RETRY_INTERVAL,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
connectJob = scheduler.scheduleWithFixedDelay(connectRunnable, 0, CONNECT_RETRY_INTERVAL,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing the Tesla account handler for {}", getThing().getUID());
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
if (connectJob != null && !connectJob.isCancelled()) {
|
||||
connectJob.cancel(true);
|
||||
connectJob = null;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
ScheduledFuture<?> connectJob = this.connectJob;
|
||||
if (connectJob != null && !connectJob.isCancelled()) {
|
||||
connectJob.cancel(true);
|
||||
this.connectJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,19 +159,25 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
// we do not have any channels -> nothing to do here
|
||||
}
|
||||
|
||||
public String getAuthHeader() {
|
||||
if (logonToken != null) {
|
||||
return "Bearer " + logonToken.access_token;
|
||||
public @Nullable String getAuthHeader() {
|
||||
String accessToken = getAccessToken();
|
||||
if (accessToken != null) {
|
||||
return "Bearer " + accessToken;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return logonToken.access_token;
|
||||
public @Nullable String getAccessToken() {
|
||||
TokenResponse logonToken = this.logonToken;
|
||||
if (logonToken != null) {
|
||||
return logonToken.accessToken;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkResponse(Response response, boolean immediatelyFail) {
|
||||
protected boolean checkResponse(@Nullable Response response, boolean immediatelyFail) {
|
||||
if (response != null && response.getStatus() == 200) {
|
||||
return true;
|
||||
} else if (response != null && response.getStatus() == 401) {
|
||||
@ -221,17 +219,23 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
|
||||
if (!checkResponse(response, true)) {
|
||||
logger.debug("An error occurred while querying the vehicle");
|
||||
return null;
|
||||
return new Vehicle[0];
|
||||
}
|
||||
|
||||
JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
|
||||
Vehicle[] vehicleArray = gson.fromJson(jsonObject.getAsJsonArray("response"), Vehicle[].class);
|
||||
|
||||
if (vehicleArray == null) {
|
||||
logger.debug("Response resulted in unexpected null array");
|
||||
return new Vehicle[0];
|
||||
}
|
||||
for (Vehicle vehicle : vehicleArray) {
|
||||
String responseString = invokeAndParse(vehicle.id, null, null, dataRequestTarget, 0);
|
||||
VehicleConfig vehicleConfig = null;
|
||||
if (responseString != null && !responseString.isBlank()) {
|
||||
vehicleConfig = gson.fromJson(responseString, VehicleData.class).vehicle_config;
|
||||
VehicleData vehicleData = gson.fromJson(responseString, VehicleData.class);
|
||||
if (vehicleData != null) {
|
||||
vehicleConfig = vehicleData.vehicleConfig;
|
||||
}
|
||||
}
|
||||
for (VehicleListener listener : vehicleListeners) {
|
||||
listener.vehicleFound(vehicle, vehicleConfig);
|
||||
@ -251,7 +255,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
logger.debug("Querying the vehicle: VIN {}", vehicle.vin);
|
||||
String vehicleJSON = gson.toJson(vehicle);
|
||||
vehicleHandler.parseAndUpdate("queryVehicle", null, vehicleJSON);
|
||||
logger.trace("Vehicle is id {}/vehicle_id {}/tokens {}", vehicle.id, vehicle.vehicle_id,
|
||||
logger.trace("Vehicle is id {}/vehicle_id {}/tokens {}", vehicle.id, vehicle.vehicleId,
|
||||
vehicle.tokens);
|
||||
}
|
||||
}
|
||||
@ -274,8 +278,8 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
logger.debug("Current authentication time {}", DATE_FORMATTER.format(Instant.now()));
|
||||
|
||||
if (token != null) {
|
||||
Instant tokenCreationInstant = Instant.ofEpochMilli(token.created_at * 1000);
|
||||
Instant tokenExpiresInstant = Instant.ofEpochMilli((token.created_at + token.expires_in) * 1000);
|
||||
Instant tokenCreationInstant = Instant.ofEpochMilli(token.createdAt * 1000);
|
||||
Instant tokenExpiresInstant = Instant.ofEpochMilli((token.createdAt + token.expiresIn) * 1000);
|
||||
logger.debug("Found a request token from {}", DATE_FORMATTER.format(tokenCreationInstant));
|
||||
logger.debug("Access token expiration time {}", DATE_FORMATTER.format(tokenExpiresInstant));
|
||||
|
||||
@ -306,8 +310,8 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
return new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
}
|
||||
|
||||
protected String invokeAndParse(String vehicleId, String command, String payLoad, WebTarget target,
|
||||
int noOfretries) {
|
||||
protected @Nullable String invokeAndParse(@Nullable String vehicleId, @Nullable String command,
|
||||
@Nullable String payLoad, WebTarget target, int noOfretries) {
|
||||
logger.debug("Invoking: {}", command);
|
||||
|
||||
if (vehicleId != null) {
|
||||
@ -316,26 +320,29 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
if (payLoad != null) {
|
||||
if (command != null) {
|
||||
response = target.resolveTemplate("cmd", command).resolveTemplate("vid", vehicleId).request()
|
||||
.header("Authorization", "Bearer " + logonToken.access_token)
|
||||
.header("Authorization", getAuthHeader())
|
||||
.post(Entity.entity(payLoad, MediaType.APPLICATION_JSON_TYPE));
|
||||
} else {
|
||||
response = target.resolveTemplate("vid", vehicleId).request()
|
||||
.header("Authorization", "Bearer " + logonToken.access_token)
|
||||
.header("Authorization", getAuthHeader())
|
||||
.post(Entity.entity(payLoad, MediaType.APPLICATION_JSON_TYPE));
|
||||
}
|
||||
} else if (command != null) {
|
||||
response = target.resolveTemplate("cmd", command).resolveTemplate("vid", vehicleId)
|
||||
.request(MediaType.APPLICATION_JSON_TYPE)
|
||||
.header("Authorization", "Bearer " + logonToken.access_token).get();
|
||||
.request(MediaType.APPLICATION_JSON_TYPE).header("Authorization", getAuthHeader()).get();
|
||||
} else {
|
||||
response = target.resolveTemplate("vid", vehicleId).request(MediaType.APPLICATION_JSON_TYPE)
|
||||
.header("Authorization", "Bearer " + logonToken.access_token).get();
|
||||
.header("Authorization", getAuthHeader()).get();
|
||||
}
|
||||
|
||||
if (!checkResponse(response, false)) {
|
||||
if (response == null) {
|
||||
logger.debug(
|
||||
"An error occurred while communicating with the vehicle during request, the response was null");
|
||||
return null;
|
||||
}
|
||||
logger.debug("An error occurred while communicating with the vehicle during request {}: {}: {}",
|
||||
command, (response != null) ? response.getStatus() : "",
|
||||
(response != null) ? response.getStatusInfo().getReasonPhrase() : "No Response");
|
||||
command, response.getStatus(), response.getStatusInfo().getReasonPhrase());
|
||||
if (response.getStatus() == 408 && noOfretries > 0) {
|
||||
try {
|
||||
// we give the vehicle a moment to wake up and try the request again
|
||||
@ -377,7 +384,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
if (authenticationResult.getStatus() == ThingStatus.ONLINE) {
|
||||
// get a list of vehicles
|
||||
Response response = productsTarget.request(MediaType.APPLICATION_JSON_TYPE)
|
||||
.header("Authorization", "Bearer " + logonToken.access_token).get();
|
||||
.header("Authorization", getAuthHeader()).get();
|
||||
|
||||
if (response != null && response.getStatus() == 200 && response.hasEntity()) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
@ -436,11 +443,12 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
|
||||
private TeslaVehicleHandler handler;
|
||||
private String request;
|
||||
@Nullable
|
||||
private String payLoad;
|
||||
private WebTarget target;
|
||||
private boolean allowWakeUpForCommands;
|
||||
|
||||
public Request(TeslaVehicleHandler handler, String request, String payLoad, WebTarget target,
|
||||
public Request(TeslaVehicleHandler handler, String request, @Nullable String payLoad, WebTarget target,
|
||||
boolean allowWakeUpForCommands) {
|
||||
this.handler = handler;
|
||||
this.request = request;
|
||||
@ -467,8 +475,8 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public Request newRequest(TeslaVehicleHandler teslaVehicleHandler, String command, String payLoad, WebTarget target,
|
||||
boolean allowWakeUpForCommands) {
|
||||
public Request newRequest(TeslaVehicleHandler teslaVehicleHandler, String command, @Nullable String payLoad,
|
||||
WebTarget target, boolean allowWakeUpForCommands) {
|
||||
return new Request(teslaVehicleHandler, command, payLoad, target, allowWakeUpForCommands);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPingPongListener;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.binding.tesla.internal.protocol.Event;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Event;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.util.ThingWebClientUtil;
|
||||
@ -54,25 +54,20 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
private final Logger logger = LoggerFactory.getLogger(TeslaEventEndpoint.class);
|
||||
|
||||
private String endpointId;
|
||||
protected WebSocketFactory webSocketFactory;
|
||||
|
||||
private WebSocketClient client;
|
||||
private ConnectionState connectionState = ConnectionState.CLOSED;
|
||||
private @Nullable Session session;
|
||||
private EventHandler eventHandler;
|
||||
private @Nullable EventHandler eventHandler;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public TeslaEventEndpoint(ThingUID uid, WebSocketFactory webSocketFactory) {
|
||||
try {
|
||||
this.endpointId = "TeslaEventEndpoint-" + uid.getAsString();
|
||||
this.endpointId = "TeslaEventEndpoint-" + uid.getAsString();
|
||||
|
||||
String name = ThingWebClientUtil.buildWebClientConsumerName(uid, null);
|
||||
client = webSocketFactory.createWebSocketClient(name);
|
||||
this.client.setConnectTimeout(TIMEOUT_MILLISECONDS);
|
||||
this.client.setMaxIdleTimeout(IDLE_TIMEOUT_MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String name = ThingWebClientUtil.buildWebClientConsumerName(uid, null);
|
||||
client = webSocketFactory.createWebSocketClient(name);
|
||||
this.client.setConnectTimeout(TIMEOUT_MILLISECONDS);
|
||||
this.client.setMaxIdleTimeout(IDLE_TIMEOUT_MILLISECONDS);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
@ -117,19 +112,22 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session) {
|
||||
logger.debug("{} : Connected to {} with hash {}", endpointId, session.getRemoteAddress().getAddress(),
|
||||
session.hashCode());
|
||||
public void onWebSocketConnect(@Nullable Session session) {
|
||||
logger.debug("{} : Connected to {} with hash {}", endpointId,
|
||||
(session != null) ? session.getRemoteAddress().getAddress() : "Unknown",
|
||||
(session != null) ? session.hashCode() : -1);
|
||||
connectionState = ConnectionState.CONNECTED;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void closeConnection() {
|
||||
Session session = this.session;
|
||||
try {
|
||||
connectionState = ConnectionState.CLOSING;
|
||||
if (session != null && session.isOpen()) {
|
||||
logger.debug("{} : Closing the session", endpointId);
|
||||
session.close(StatusCode.NORMAL, "bye");
|
||||
this.session = session;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("{} : An exception occurred while closing the session : {}", endpointId, e.getMessage());
|
||||
@ -138,14 +136,14 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason) {
|
||||
public void onWebSocketClose(int statusCode, @Nullable String reason) {
|
||||
logger.debug("{} : Closed the session with status {} for reason {}", endpointId, statusCode, reason);
|
||||
connectionState = ConnectionState.CLOSED;
|
||||
this.session = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message) {
|
||||
public void onWebSocketText(@Nullable String message) {
|
||||
// NoOp
|
||||
}
|
||||
|
||||
@ -158,10 +156,13 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
try {
|
||||
while ((str = in.readLine()) != null) {
|
||||
logger.trace("{} : Received raw data '{}'", endpointId, str);
|
||||
if (this.eventHandler != null) {
|
||||
EventHandler eventHandler = this.eventHandler;
|
||||
if (eventHandler != null) {
|
||||
try {
|
||||
Event event = gson.fromJson(str, Event.class);
|
||||
this.eventHandler.handleEvent(event);
|
||||
if (event != null) {
|
||||
eventHandler.handleEvent(event);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("{} : An exception occurred while processing raw data : {}", endpointId,
|
||||
e.getMessage());
|
||||
@ -176,12 +177,14 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause) {
|
||||
logger.error("{} : An error occurred in the session : {}", endpointId, cause.getMessage());
|
||||
Session session = this.session;
|
||||
if (session != null && session.isOpen()) {
|
||||
session.close(StatusCode.ABNORMAL, "Session Error");
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String message) throws IOException {
|
||||
Session session = this.session;
|
||||
try {
|
||||
if (session != null) {
|
||||
logger.debug("{} : Sending raw data '{}'", endpointId, message);
|
||||
@ -198,6 +201,7 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
}
|
||||
|
||||
public void ping() {
|
||||
Session session = this.session;
|
||||
try {
|
||||
if (session != null) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(8).putLong(System.nanoTime()).flip();
|
||||
@ -209,8 +213,9 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPing(ByteBuffer payload) {
|
||||
public void onWebSocketPing(@Nullable ByteBuffer payload) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(8).putLong(System.nanoTime()).flip();
|
||||
Session session = this.session;
|
||||
try {
|
||||
if (session != null) {
|
||||
session.getRemote().sendPing(buffer);
|
||||
@ -221,7 +226,10 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPong(ByteBuffer payload) {
|
||||
public void onWebSocketPong(@Nullable ByteBuffer payload) {
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
long start = payload.getLong();
|
||||
long roundTrip = System.nanoTime() - start;
|
||||
|
||||
|
@ -28,8 +28,8 @@ import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.tesla.internal.protocol.sso.RefreshTokenRequest;
|
||||
import org.openhab.binding.tesla.internal.protocol.sso.TokenResponse;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.sso.RefreshTokenRequest;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.sso.TokenResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -72,10 +72,10 @@ public class TeslaSSOHandler {
|
||||
String refreshTokenResponse = refreshResponse.getContentAsString();
|
||||
TokenResponse tokenResponse = gson.fromJson(refreshTokenResponse.trim(), TokenResponse.class);
|
||||
|
||||
if (tokenResponse != null && tokenResponse.access_token != null && !tokenResponse.access_token.isEmpty()) {
|
||||
tokenResponse.created_at = Instant.now().getEpochSecond();
|
||||
logger.debug("Access token expires in {} seconds at {}", tokenResponse.expires_in, DATE_FORMATTER
|
||||
.format(Instant.ofEpochMilli((tokenResponse.created_at + tokenResponse.expires_in) * 1000)));
|
||||
if (tokenResponse != null && tokenResponse.accessToken != null && !tokenResponse.accessToken.isEmpty()) {
|
||||
tokenResponse.createdAt = Instant.now().getEpochSecond();
|
||||
logger.debug("Access token expires in {} seconds at {}", tokenResponse.expiresIn, DATE_FORMATTER
|
||||
.format(Instant.ofEpochMilli((tokenResponse.createdAt + tokenResponse.expiresIn) * 1000)));
|
||||
return tokenResponse;
|
||||
} else {
|
||||
logger.debug("An error occurred while exchanging SSO auth token for API access token.");
|
||||
|
@ -25,6 +25,7 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -37,21 +38,22 @@ import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants;
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants.EventKeys;
|
||||
import org.openhab.binding.tesla.internal.TeslaChannelSelectorProxy;
|
||||
import org.openhab.binding.tesla.internal.TeslaChannelSelectorProxy.TeslaChannelSelector;
|
||||
import org.openhab.binding.tesla.internal.handler.TeslaAccountHandler.Request;
|
||||
import org.openhab.binding.tesla.internal.protocol.ChargeState;
|
||||
import org.openhab.binding.tesla.internal.protocol.ClimateState;
|
||||
import org.openhab.binding.tesla.internal.protocol.DriveState;
|
||||
import org.openhab.binding.tesla.internal.protocol.Event;
|
||||
import org.openhab.binding.tesla.internal.protocol.GUIState;
|
||||
import org.openhab.binding.tesla.internal.protocol.SoftwareUpdate;
|
||||
import org.openhab.binding.tesla.internal.protocol.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleData;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleState;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.ChargeState;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.ClimateState;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.DriveState;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Event;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.GUIState;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.SoftwareUpdate;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleData;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleState;
|
||||
import org.openhab.binding.tesla.internal.throttler.QueueChannelThrottler;
|
||||
import org.openhab.binding.tesla.internal.throttler.Rate;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
@ -64,6 +66,7 @@ import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
@ -88,9 +91,9 @@ import com.google.gson.JsonParser;
|
||||
* @author Karel Goderis - Initial contribution
|
||||
* @author Kai Kreuzer - Refactored to use separate account handler and improved configuration options
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
|
||||
private static final int FAST_STATUS_REFRESH_INTERVAL = 15000;
|
||||
private static final int SLOW_STATUS_REFRESH_INTERVAL = 60000;
|
||||
private static final int API_SLEEP_INTERVAL_MINUTES = 20;
|
||||
private static final int MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT = 5;
|
||||
@ -105,13 +108,21 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(TeslaVehicleHandler.class);
|
||||
|
||||
// Vehicle state variables
|
||||
@Nullable
|
||||
protected Vehicle vehicle;
|
||||
@Nullable
|
||||
protected String vehicleJSON;
|
||||
@Nullable
|
||||
protected DriveState driveState;
|
||||
@Nullable
|
||||
protected GUIState guiState;
|
||||
@Nullable
|
||||
protected VehicleState vehicleState;
|
||||
@Nullable
|
||||
protected ChargeState chargeState;
|
||||
@Nullable
|
||||
protected ClimateState climateState;
|
||||
@Nullable
|
||||
protected SoftwareUpdate softwareUpdate;
|
||||
|
||||
protected boolean allowWakeUp;
|
||||
@ -127,7 +138,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
protected long eventIntervalTimestamp;
|
||||
protected int eventIntervalErrors;
|
||||
protected int inactivity = MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT;
|
||||
protected ReentrantLock lock;
|
||||
protected ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected double lastLongitude;
|
||||
protected double lastLatitude;
|
||||
@ -140,13 +151,13 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
protected String lastState = "";
|
||||
protected boolean isInactive = false;
|
||||
|
||||
protected TeslaAccountHandler account;
|
||||
protected @NonNullByDefault({}) TeslaAccountHandler account;
|
||||
|
||||
protected QueueChannelThrottler stateThrottler;
|
||||
protected TeslaChannelSelectorProxy teslaChannelSelectorProxy = new TeslaChannelSelectorProxy();
|
||||
protected Thread eventThread;
|
||||
protected ScheduledFuture<?> stateJob;
|
||||
protected @Nullable QueueChannelThrottler stateThrottler;
|
||||
protected @Nullable Thread eventThread;
|
||||
protected @Nullable ScheduledFuture<?> stateJob;
|
||||
protected WebSocketFactory webSocketFactory;
|
||||
protected TeslaChannelSelectorProxy teslaChannelSelectorProxy = new TeslaChannelSelectorProxy();
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
@ -155,68 +166,62 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
this.webSocketFactory = webSocketFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.trace("Initializing the Tesla handler for {}", getThing().getUID());
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
allowWakeUp = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_ALLOWWAKEUP);
|
||||
allowWakeUpForCommands = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_ALLOWWAKEUPFORCOMMANDS);
|
||||
enableEvents = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_ENABLEEVENTS);
|
||||
Number inactivityParam = (Number) getConfig().get(TeslaBindingConstants.CONFIG_INACTIVITY);
|
||||
inactivity = inactivityParam == null ? MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT : inactivityParam.intValue();
|
||||
Boolean useDriveStateParam = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_USEDRIVESTATE);
|
||||
useDriveState = useDriveStateParam == null ? false : useDriveStateParam;
|
||||
Boolean useAdvancedStatesParam = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_USEDADVANCEDSTATES);
|
||||
useAdvancedStates = useAdvancedStatesParam == null ? false : useAdvancedStatesParam;
|
||||
|
||||
account = (TeslaAccountHandler) getBridge().getHandler();
|
||||
inactivity = Objects.requireNonNullElse((Number) getConfig().get(TeslaBindingConstants.CONFIG_INACTIVITY),
|
||||
MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT).intValue();
|
||||
useDriveState = Objects
|
||||
.requireNonNullElse((boolean) getConfig().get(TeslaBindingConstants.CONFIG_USEDRIVESTATE), false);
|
||||
useAdvancedStates = Objects
|
||||
.requireNonNullElse((boolean) getConfig().get(TeslaBindingConstants.CONFIG_USEDADVANCEDSTATES), false);
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null || !(bridge.getHandler() instanceof TeslaAccountHandler teslaAccountHandler)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
return;
|
||||
}
|
||||
account = teslaAccountHandler;
|
||||
lock = new ReentrantLock();
|
||||
scheduler.execute(this::queryVehicleAndUpdate);
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
Map<Object, Rate> channels = new HashMap<>();
|
||||
channels.put(DATA_THROTTLE, new Rate(1, 1, TimeUnit.SECONDS));
|
||||
channels.put(COMMAND_THROTTLE, new Rate(20, 1, TimeUnit.MINUTES));
|
||||
Map<Object, Rate> channels = new HashMap<>();
|
||||
channels.put(DATA_THROTTLE, new Rate(1, 1, TimeUnit.SECONDS));
|
||||
channels.put(COMMAND_THROTTLE, new Rate(20, 1, TimeUnit.MINUTES));
|
||||
|
||||
Rate firstRate = new Rate(20, 1, TimeUnit.MINUTES);
|
||||
Rate secondRate = new Rate(200, 10, TimeUnit.MINUTES);
|
||||
stateThrottler = new QueueChannelThrottler(firstRate, scheduler, channels);
|
||||
stateThrottler.addRate(secondRate);
|
||||
Rate firstRate = new Rate(20, 1, TimeUnit.MINUTES);
|
||||
Rate secondRate = new Rate(200, 10, TimeUnit.MINUTES);
|
||||
QueueChannelThrottler stateThrottler = new QueueChannelThrottler(firstRate, scheduler, channels);
|
||||
stateThrottler.addRate(secondRate);
|
||||
this.stateThrottler = stateThrottler;
|
||||
stateJob = scheduler.scheduleWithFixedDelay(stateRunnable, 0, SLOW_STATUS_REFRESH_INTERVAL,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
if (stateJob == null || stateJob.isCancelled()) {
|
||||
stateJob = scheduler.scheduleWithFixedDelay(stateRunnable, 0, SLOW_STATUS_REFRESH_INTERVAL,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (enableEvents) {
|
||||
if (eventThread == null) {
|
||||
eventThread = new Thread(eventRunnable, "OH-binding-" + getThing().getUID() + "-events");
|
||||
eventThread.start();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
if (enableEvents) {
|
||||
Thread eventThread = new Thread(eventRunnable, "OH-binding-" + getThing().getUID() + "-events");
|
||||
eventThread.start();
|
||||
this.eventThread = eventThread;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.trace("Disposing the Tesla handler for {}", getThing().getUID());
|
||||
lock.lock();
|
||||
try {
|
||||
if (stateJob != null && !stateJob.isCancelled()) {
|
||||
stateJob.cancel(true);
|
||||
stateJob = null;
|
||||
}
|
||||
|
||||
if (eventThread != null && !eventThread.isInterrupted()) {
|
||||
eventThread.interrupt();
|
||||
eventThread = null;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
ScheduledFuture<?> stateJob = this.stateJob;
|
||||
if (stateJob != null && !stateJob.isCancelled()) {
|
||||
stateJob.cancel(true);
|
||||
this.stateJob = null;
|
||||
}
|
||||
Thread eventThread = this.eventThread;
|
||||
if (eventThread != null && !eventThread.isInterrupted()) {
|
||||
eventThread.interrupt();
|
||||
this.eventThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +230,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
*
|
||||
* @return the vehicle id
|
||||
*/
|
||||
public String getVehicleId() {
|
||||
public @Nullable String getVehicleId() {
|
||||
Vehicle vehicle = this.vehicle;
|
||||
if (vehicle != null) {
|
||||
return vehicle.id;
|
||||
} else {
|
||||
@ -248,9 +254,9 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
setActive();
|
||||
|
||||
// Request the state of all known variables. This is sub-optimal, but the requests get scheduled and
|
||||
// throttled so we are safe not to break the Tesla SLA
|
||||
// throbridgettled so we are safe not to break the Tesla SLA
|
||||
requestAllData();
|
||||
} else if (selector != null) {
|
||||
} else {
|
||||
if (!isAwake() && allowWakeUpForCommands) {
|
||||
logger.debug("Waking vehicle to send command.");
|
||||
wakeUp();
|
||||
@ -267,10 +273,16 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
setChargeLimit(0);
|
||||
} else if (command instanceof IncreaseDecreaseType
|
||||
&& command == IncreaseDecreaseType.INCREASE) {
|
||||
setChargeLimit(Math.min(chargeState.charge_limit_soc + 1, 100));
|
||||
ChargeState chargeState = this.chargeState;
|
||||
if (chargeState != null) {
|
||||
setChargeLimit(Math.min(chargeState.chargeLimitSoc + 1, 100));
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType
|
||||
&& command == IncreaseDecreaseType.DECREASE) {
|
||||
setChargeLimit(Math.max(chargeState.charge_limit_soc - 1, 0));
|
||||
ChargeState chargeState = this.chargeState;
|
||||
if (chargeState != null) {
|
||||
setChargeLimit(Math.max(chargeState.chargeLimitSoc - 1, 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -298,23 +310,17 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
break;
|
||||
case COMBINED_TEMP: {
|
||||
QuantityType<Temperature> quantity = commandToQuantityType(command);
|
||||
if (quantity != null) {
|
||||
setCombinedTemperature(quanityToRoundedFloat(quantity));
|
||||
}
|
||||
setCombinedTemperature(quanityToRoundedFloat(quantity));
|
||||
break;
|
||||
}
|
||||
case DRIVER_TEMP: {
|
||||
QuantityType<Temperature> quantity = commandToQuantityType(command);
|
||||
if (quantity != null) {
|
||||
setDriverTemperature(quanityToRoundedFloat(quantity));
|
||||
}
|
||||
setDriverTemperature(quanityToRoundedFloat(quantity));
|
||||
break;
|
||||
}
|
||||
case PASSENGER_TEMP: {
|
||||
QuantityType<Temperature> quantity = commandToQuantityType(command);
|
||||
if (quantity != null) {
|
||||
setPassengerTemperature(quanityToRoundedFloat(quantity));
|
||||
}
|
||||
setPassengerTemperature(quanityToRoundedFloat(quantity));
|
||||
break;
|
||||
}
|
||||
case SENTRY_MODE: {
|
||||
@ -411,11 +417,12 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
case RT: {
|
||||
if (command instanceof OnOffType onOffCommand) {
|
||||
VehicleState vehicleState = this.vehicleState;
|
||||
if (onOffCommand == OnOffType.ON) {
|
||||
if (vehicleState.rt == 0) {
|
||||
if (vehicleState != null && vehicleState.rt == 0) {
|
||||
openTrunk();
|
||||
}
|
||||
} else if (vehicleState.rt == 1) {
|
||||
} else if (vehicleState != null && vehicleState.rt == 1) {
|
||||
closeTrunk();
|
||||
}
|
||||
}
|
||||
@ -459,9 +466,10 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendCommand(String command, String payLoad, WebTarget target) {
|
||||
public void sendCommand(String command, @Nullable String payLoad, WebTarget target) {
|
||||
if (COMMAND_WAKE_UP.equals(command) || isAwake() || allowWakeUpForCommands) {
|
||||
Request request = account.newRequest(this, command, payLoad, target, allowWakeUpForCommands);
|
||||
QueueChannelThrottler stateThrottler = this.stateThrottler;
|
||||
if (stateThrottler != null) {
|
||||
stateThrottler.submit(COMMAND_THROTTLE, request);
|
||||
}
|
||||
@ -475,6 +483,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
public void sendCommand(String command, String payLoad) {
|
||||
if (COMMAND_WAKE_UP.equals(command) || isAwake() || allowWakeUpForCommands) {
|
||||
Request request = account.newRequest(this, command, payLoad, account.commandTarget, allowWakeUpForCommands);
|
||||
QueueChannelThrottler stateThrottler = this.stateThrottler;
|
||||
if (stateThrottler != null) {
|
||||
stateThrottler.submit(COMMAND_THROTTLE, request);
|
||||
}
|
||||
@ -484,16 +493,18 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
public void sendCommand(String command, WebTarget target) {
|
||||
if (COMMAND_WAKE_UP.equals(command) || isAwake() || allowWakeUpForCommands) {
|
||||
Request request = account.newRequest(this, command, "{}", target, allowWakeUpForCommands);
|
||||
QueueChannelThrottler stateThrottler = this.stateThrottler;
|
||||
if (stateThrottler != null) {
|
||||
stateThrottler.submit(COMMAND_THROTTLE, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void requestData(String command, String payLoad) {
|
||||
public void requestData(String command, @Nullable String payLoad) {
|
||||
if (COMMAND_WAKE_UP.equals(command) || isAwake()
|
||||
|| (!"vehicleData".equals(command) && allowWakeUpForCommands)) {
|
||||
Request request = account.newRequest(this, command, payLoad, account.dataRequestTarget, false);
|
||||
QueueChannelThrottler stateThrottler = this.stateThrottler;
|
||||
if (stateThrottler != null) {
|
||||
stateThrottler.submit(DATA_THROTTLE, request);
|
||||
}
|
||||
@ -529,14 +540,16 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
protected boolean isAwake() {
|
||||
return vehicle != null && "online".equals(vehicle.state) && vehicle.vehicle_id != null;
|
||||
Vehicle vehicle = this.vehicle;
|
||||
return vehicle != null && "online".equals(vehicle.state) && vehicle.vehicleId != null;
|
||||
}
|
||||
|
||||
protected boolean isInMotion() {
|
||||
DriveState driveState = this.driveState;
|
||||
if (driveState != null) {
|
||||
if (driveState.speed != null && driveState.shift_state != null) {
|
||||
if (driveState.speed != null && driveState.shiftState != null) {
|
||||
return !"Undefined".equals(driveState.speed)
|
||||
&& (!"P".equals(driveState.shift_state) || !"Undefined".equals(driveState.shift_state));
|
||||
&& (!"P".equals(driveState.shiftState) || !"Undefined".equals(driveState.shiftState));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -551,15 +564,16 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
protected boolean isCharging() {
|
||||
return chargeState != null && "Charging".equals(chargeState.charging_state);
|
||||
ChargeState chargeState = this.chargeState;
|
||||
return chargeState != null && "Charging".equals(chargeState.chargingState);
|
||||
}
|
||||
|
||||
protected boolean notReadyForSleep() {
|
||||
boolean status;
|
||||
int computedInactivityPeriod = inactivity;
|
||||
|
||||
VehicleState vehicleState = this.vehicleState;
|
||||
if (useAdvancedStates) {
|
||||
if (vehicleState.is_user_present && !isInMotion()) {
|
||||
if (vehicleState != null && vehicleState.isUserPresent && !isInMotion()) {
|
||||
logger.debug("Car is occupied but stationary.");
|
||||
if (lastAdvModesTimestamp < (System.currentTimeMillis()
|
||||
- (THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES * 60 * 1000))) {
|
||||
@ -568,7 +582,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
return (backOffCounter++ % 6 == 0); // using 6 should make sure 1 out of 5 pollers get serviced,
|
||||
// about every min.
|
||||
}
|
||||
} else if (vehicleState.sentry_mode) {
|
||||
} else if (vehicleState != null && vehicleState.sentryMode) {
|
||||
logger.debug("Car is in sentry mode.");
|
||||
if (lastAdvModesTimestamp < (System.currentTimeMillis()
|
||||
- (THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES * 60 * 1000))) {
|
||||
@ -576,23 +590,23 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
} else {
|
||||
return (backOffCounter++ % 6 == 0);
|
||||
}
|
||||
} else if ((vehicleState.center_display_state != 0) && (!isInMotion())) {
|
||||
} else if (vehicleState != null && (vehicleState.centerDisplayState != 0) && (!isInMotion())) {
|
||||
logger.debug("Car is in camp, climate keep, dog, or other mode preventing sleep. Mode {}",
|
||||
vehicleState.center_display_state);
|
||||
vehicleState.centerDisplayState);
|
||||
return (backOffCounter++ % 6 == 0);
|
||||
} else {
|
||||
lastAdvModesTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
if (vehicleState != null && vehicleState.homelink_nearby) {
|
||||
if (vehicleState != null && vehicleState.homelinkNearby) {
|
||||
computedInactivityPeriod = MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT;
|
||||
logger.debug("Car is at home. Movement or drive state threshold is {} min.",
|
||||
MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT);
|
||||
}
|
||||
|
||||
DriveState driveState = this.driveState;
|
||||
if (useDriveState) {
|
||||
if (driveState.shift_state != null) {
|
||||
if (driveState != null && driveState.shiftState != null) {
|
||||
logger.debug("Car drive state not null and not ready to sleep.");
|
||||
return true;
|
||||
} else {
|
||||
@ -632,7 +646,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
lastLongitude = 0;
|
||||
}
|
||||
|
||||
protected boolean checkResponse(Response response, boolean immediatelyFail) {
|
||||
protected boolean checkResponse(@Nullable Response response, boolean immediatelyFail) {
|
||||
if (response != null && response.getStatus() == 200) {
|
||||
return true;
|
||||
} else if (response != null && response.getStatus() == 401) {
|
||||
@ -711,11 +725,13 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
public void setDriverTemperature(float temperature) {
|
||||
setTemperature(temperature, climateState != null ? climateState.passenger_temp_setting : temperature);
|
||||
ClimateState climateState = this.climateState;
|
||||
setTemperature(temperature, climateState != null ? climateState.passengerTempSetting : temperature);
|
||||
}
|
||||
|
||||
public void setPassengerTemperature(float temperature) {
|
||||
setTemperature(climateState != null ? climateState.driver_temp_setting : temperature, temperature);
|
||||
ClimateState climateState = this.climateState;
|
||||
setTemperature(climateState != null ? climateState.passengerTempSetting : temperature, temperature);
|
||||
}
|
||||
|
||||
public void openFrunk() {
|
||||
@ -734,7 +750,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
openTrunk();
|
||||
}
|
||||
|
||||
public void setValetMode(boolean b, Integer pin) {
|
||||
public void setValetMode(boolean b, @Nullable Integer pin) {
|
||||
JsonObject payloadObject = new JsonObject();
|
||||
payloadObject.addProperty("on", b);
|
||||
if (pin != null) {
|
||||
@ -785,7 +801,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
sendCommand(COMMAND_STEERING_WHEEL_HEATER, gson.toJson(payloadObject), account.commandTarget);
|
||||
}
|
||||
|
||||
protected Vehicle queryVehicle() {
|
||||
protected @Nullable Vehicle queryVehicle() {
|
||||
String authHeader = account.getAuthHeader();
|
||||
|
||||
if (authHeader != null) {
|
||||
@ -805,14 +821,17 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
|
||||
JsonObject jsonObject = JsonParser.parseString(response.readEntity(String.class)).getAsJsonObject();
|
||||
Vehicle[] vehicleArray = gson.fromJson(jsonObject.getAsJsonArray("response"), Vehicle[].class);
|
||||
|
||||
if (vehicleArray == null) {
|
||||
logger.debug("Response resulted in unexpected null array");
|
||||
return null;
|
||||
}
|
||||
for (Vehicle vehicle : vehicleArray) {
|
||||
logger.debug("Querying the vehicle: VIN {}", vehicle.vin);
|
||||
if (vehicle.vin.equals(getConfig().get(VIN))) {
|
||||
vehicleJSON = gson.toJson(vehicle);
|
||||
parseAndUpdate("queryVehicle", null, vehicleJSON);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Vehicle is id {}/vehicle_id {}/tokens {}", vehicle.id, vehicle.vehicle_id,
|
||||
logger.trace("Vehicle is id {}/vehicle_id {}/tokens {}", vehicle.id, vehicle.vehicleId,
|
||||
vehicle.tokens);
|
||||
}
|
||||
return vehicle;
|
||||
@ -831,9 +850,9 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
vehicle = queryVehicle();
|
||||
}
|
||||
|
||||
public void parseAndUpdate(String request, String payLoad, String result) {
|
||||
public void parseAndUpdate(@Nullable String request, @Nullable String payLoad, @Nullable String result) {
|
||||
final double locationThreshold = .0000001;
|
||||
|
||||
Vehicle vehicle = this.vehicle;
|
||||
try {
|
||||
if (request != null && result != null && !"null".equals(result)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
@ -848,12 +867,12 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vehicle != null && ("asleep".equals(vehicle.state) || "offline".equals(vehicle.state))) {
|
||||
if ("asleep".equals(vehicle.state) || "offline".equals(vehicle.state)) {
|
||||
logger.debug("Vehicle is {}", vehicle.state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vehicle != null && !lastState.equals(vehicle.state)) {
|
||||
if (!lastState.equals(vehicle.state)) {
|
||||
lastState = vehicle.state;
|
||||
|
||||
// in case vehicle changed to awake, refresh all data
|
||||
@ -888,43 +907,44 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
driveState = vehicleData.drive_state;
|
||||
if (Math.abs(lastLatitude - driveState.latitude) > locationThreshold
|
||||
|| Math.abs(lastLongitude - driveState.longitude) > locationThreshold) {
|
||||
DriveState driveState = this.driveState = vehicleData.driveState;
|
||||
|
||||
if (driveState != null && (Math.abs(lastLatitude - driveState.latitude) > locationThreshold
|
||||
|| Math.abs(lastLongitude - driveState.longitude) > locationThreshold)) {
|
||||
logger.debug("Vehicle moved, resetting last location timestamp");
|
||||
|
||||
lastLatitude = driveState.latitude;
|
||||
lastLongitude = driveState.longitude;
|
||||
lastLocationChangeTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
logger.trace("Drive state: {}", driveState.shift_state);
|
||||
logger.trace("Drive state: {}", driveState != null ? driveState.shiftState : "null");
|
||||
|
||||
if ((driveState.shift_state == null) && (lastValidDriveStateNotNull)) {
|
||||
if ((driveState != null && driveState.shiftState == null) && (lastValidDriveStateNotNull)) {
|
||||
logger.debug("Set NULL shiftstate time");
|
||||
lastValidDriveStateNotNull = false;
|
||||
lastDriveStateChangeToNullTimestamp = System.currentTimeMillis();
|
||||
} else if (driveState.shift_state != null) {
|
||||
} else if (driveState != null && driveState.shiftState != null) {
|
||||
logger.trace("Clear NULL shiftstate time");
|
||||
lastValidDriveStateNotNull = true;
|
||||
}
|
||||
|
||||
guiState = vehicleData.gui_settings;
|
||||
guiState = vehicleData.guiSettings;
|
||||
|
||||
vehicleState = vehicleData.vehicle_state;
|
||||
VehicleState vehicleState = this.vehicleState = vehicleData.vehicleState;
|
||||
|
||||
chargeState = vehicleData.charge_state;
|
||||
chargeState = vehicleData.chargeState;
|
||||
if (isCharging()) {
|
||||
updateState(CHANNEL_CHARGE, OnOffType.ON);
|
||||
} else {
|
||||
updateState(CHANNEL_CHARGE, OnOffType.OFF);
|
||||
}
|
||||
|
||||
climateState = vehicleData.climate_state;
|
||||
ClimateState climateState = this.climateState = vehicleData.climateState;
|
||||
BigDecimal avgtemp = roundBigDecimal(new BigDecimal(
|
||||
(climateState.driver_temp_setting + climateState.passenger_temp_setting) / 2.0f));
|
||||
(climateState.passengerTempSetting + climateState.passengerTempSetting) / 2.0f));
|
||||
updateState(CHANNEL_COMBINED_TEMP, new QuantityType<>(avgtemp, SIUnits.CELSIUS));
|
||||
|
||||
softwareUpdate = vehicleState.software_update;
|
||||
SoftwareUpdate softwareUpdate = this.softwareUpdate = vehicleState.softwareUpdate;
|
||||
|
||||
try {
|
||||
lock.lock();
|
||||
@ -990,8 +1010,13 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected QuantityType<Temperature> commandToQuantityType(Command command) {
|
||||
if (command instanceof QuantityType) {
|
||||
return ((QuantityType<Temperature>) command).toUnit(SIUnits.CELSIUS);
|
||||
if (command instanceof QuantityType quantityCommand) {
|
||||
QuantityType<Temperature> commandInCelsius = quantityCommand.toUnit(SIUnits.CELSIUS);
|
||||
if (commandInCelsius == null) {
|
||||
logger.warn("Unable to convert command {} to CELSIUS", command);
|
||||
} else {
|
||||
return commandInCelsius;
|
||||
}
|
||||
}
|
||||
return new QuantityType<>(new BigDecimal(command.toString()), SIUnits.CELSIUS);
|
||||
}
|
||||
@ -1024,18 +1049,19 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
};
|
||||
|
||||
protected Runnable eventRunnable = new Runnable() {
|
||||
@Nullable
|
||||
TeslaEventEndpoint eventEndpoint;
|
||||
boolean isAuthenticated = false;
|
||||
long lastPingTimestamp = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
eventEndpoint = new TeslaEventEndpoint(getThing().getUID(), webSocketFactory);
|
||||
TeslaEventEndpoint eventEndpoint = new TeslaEventEndpoint(getThing().getUID(), webSocketFactory);
|
||||
eventEndpoint.addEventHandler(new TeslaEventEndpoint.EventHandler() {
|
||||
@Override
|
||||
public void handleEvent(Event event) {
|
||||
public void handleEvent(@Nullable Event event) {
|
||||
if (event != null) {
|
||||
switch (event.msg_type) {
|
||||
switch (event.msgType) {
|
||||
case "control:hello":
|
||||
logger.debug("Event : Received hello");
|
||||
break;
|
||||
@ -1068,7 +1094,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
if (!selector.isProperty()) {
|
||||
State newState = teslaChannelSelectorProxy.getState(vals[i], selector,
|
||||
editProperties());
|
||||
if (newState != null && !"".equals(vals[i])) {
|
||||
if (!"".equals(vals[i])) {
|
||||
updateState(selector.getChannelID(), newState);
|
||||
} else {
|
||||
updateState(selector.getChannelID(), UnDefType.UNDEF);
|
||||
@ -1115,29 +1141,28 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
}
|
||||
break;
|
||||
case "data:error":
|
||||
logger.debug("Event : Received an error: '{}'/'{}'", event.value, event.error_type);
|
||||
logger.debug("Event : Received an error: '{}'/'{}'", event.value, event.errorType);
|
||||
eventEndpoint.closeConnection();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.eventEndpoint = eventEndpoint;
|
||||
while (true) {
|
||||
try {
|
||||
if (getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
if (isAwake()) {
|
||||
eventEndpoint.connect(new URI(URI_EVENT));
|
||||
|
||||
if (eventEndpoint.isConnected()) {
|
||||
if (!isAuthenticated) {
|
||||
logger.debug("Event : Authenticating vehicle {}", vehicle.vehicle_id);
|
||||
logger.debug("Event : Authenticating vehicle {}", vehicle.vehicleId);
|
||||
JsonObject payloadObject = new JsonObject();
|
||||
payloadObject.addProperty("msg_type", "data:subscribe_oauth");
|
||||
payloadObject.addProperty("token", account.getAccessToken());
|
||||
payloadObject.addProperty("value", Arrays.asList(EventKeys.values()).stream()
|
||||
.skip(1).map(Enum::toString).collect(Collectors.joining(",")));
|
||||
payloadObject.addProperty("tag", vehicle.vehicle_id);
|
||||
payloadObject.addProperty("tag", vehicle.vehicleId);
|
||||
|
||||
eventEndpoint.sendMessage(gson.toJson(payloadObject));
|
||||
isAuthenticated = true;
|
||||
@ -1200,6 +1225,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
|
||||
if (Thread.interrupted()) {
|
||||
logger.debug("Event : The event thread was interrupted");
|
||||
eventEndpoint.close();
|
||||
this.eventEndpoint = eventEndpoint;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ package org.openhab.binding.tesla.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tesla.internal.protocol.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.VehicleConfig;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.Vehicle;
|
||||
import org.openhab.binding.tesla.internal.protocol.dto.VehicleConfig;
|
||||
|
||||
/**
|
||||
* The {@link VehicleListener} interface can be implemented by classes that want to be informed about
|
||||
|
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link ChargeState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class ChargeState {
|
||||
public boolean battery_heater_on;
|
||||
public boolean charge_enable_request;
|
||||
public boolean charge_port_door_open;
|
||||
public boolean charge_to_max_range;
|
||||
public boolean eu_vehicle;
|
||||
public boolean fast_charger_present;
|
||||
public boolean managed_charging_active;
|
||||
public boolean managed_charging_user_canceled;
|
||||
public boolean motorized_charge_port;
|
||||
public boolean not_enough_power_to_heat;
|
||||
public boolean scheduled_charging_pending;
|
||||
public boolean trip_charging;
|
||||
public float battery_current;
|
||||
public float battery_range;
|
||||
public float charge_energy_added;
|
||||
public float charge_miles_added_ideal;
|
||||
public float charge_miles_added_rated;
|
||||
public float charge_rate;
|
||||
public float est_battery_range;
|
||||
public float ideal_battery_range;
|
||||
public float time_to_full_charge;
|
||||
public int battery_level;
|
||||
public int charge_amps;
|
||||
public int charge_current_request;
|
||||
public int charge_current_request_max;
|
||||
public int charge_limit_soc;
|
||||
public int charge_limit_soc_max;
|
||||
public int charge_limit_soc_min;
|
||||
public int charge_limit_soc_std;
|
||||
public int charger_actual_current;
|
||||
public int charger_phases;
|
||||
public int charger_pilot_current;
|
||||
public int charger_power;
|
||||
public int charger_voltage;
|
||||
public int max_range_charge_counter;
|
||||
public int usable_battery_level;
|
||||
public String charge_port_latch;
|
||||
public String charging_state;
|
||||
public String conn_charge_cable;
|
||||
public String fast_charger_brand;
|
||||
public String fast_charger_type;
|
||||
public String managed_charging_start_time;
|
||||
public String scheduled_charging_start_time;
|
||||
public String user_charge_enable_request;
|
||||
|
||||
ChargeState() {
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link ClimateState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class ClimateState {
|
||||
|
||||
public boolean battery_heater;
|
||||
public boolean battery_heater_no_power;
|
||||
public boolean is_auto_conditioning_on;
|
||||
public boolean is_climate_on;
|
||||
public boolean is_front_defroster_on;
|
||||
public boolean is_preconditioning;
|
||||
public boolean is_rear_defroster_on;
|
||||
public int seat_heater_left;
|
||||
public int seat_heater_rear_center;
|
||||
public int seat_heater_rear_left;
|
||||
public int seat_heater_rear_right;
|
||||
public int seat_heater_right;
|
||||
public boolean side_mirror_heaters;
|
||||
public boolean smart_preconditioning;
|
||||
public boolean steering_wheel_heater;
|
||||
public boolean wiper_blade_heater;
|
||||
public float driver_temp_setting;
|
||||
public float inside_temp;
|
||||
public float outside_temp;
|
||||
public float passenger_temp_setting;
|
||||
public int fan_status;
|
||||
public int left_temp_direction;
|
||||
public int max_avail_temp;
|
||||
public int min_avail_temp;
|
||||
public int right_temp_direction;
|
||||
public int seat_heater_rear_left_back;
|
||||
public int seat_heater_rear_right_back;
|
||||
|
||||
ClimateState() {
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link DriveState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class DriveState {
|
||||
|
||||
public String active_route_destination;
|
||||
public double active_route_latitude;
|
||||
public double active_route_longitude;
|
||||
public double active_route_miles_to_arrival;
|
||||
public double active_route_minutes_to_arrival;
|
||||
public double active_route_traffic_minutes_delay;
|
||||
public double latitude;
|
||||
public double longitude;
|
||||
public double native_latitude;
|
||||
public double native_longitude;
|
||||
public int gps_as_of;
|
||||
public int heading;
|
||||
public int native_location_supported;
|
||||
public String native_type;
|
||||
public String shift_state;
|
||||
public String speed;
|
||||
|
||||
DriveState() {
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link GUIState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class GUIState {
|
||||
|
||||
public String gui_distance_units;
|
||||
public String gui_temperature_units;
|
||||
public String gui_charge_rate_units;
|
||||
public String gui_24_hour_time;
|
||||
public String gui_range_display;
|
||||
|
||||
public GUIState() {
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link Vehicle} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class Vehicle {
|
||||
|
||||
public String color;
|
||||
public String display_name;
|
||||
public String id;
|
||||
public String option_codes;
|
||||
public String vehicle_id;
|
||||
public String vin;
|
||||
public String[] tokens;
|
||||
public String state;
|
||||
public boolean remote_start_enabled;
|
||||
public boolean calendar_enabled;
|
||||
public boolean notifications_enabled;
|
||||
public String backseat_token;
|
||||
public String backseat_token_updated_at;
|
||||
|
||||
Vehicle() {
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link VehicleConfig} is a data structure to capture
|
||||
* vehicle configuration variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class VehicleConfig {
|
||||
public boolean can_accept_navigation_requests;
|
||||
public boolean can_actuate_trunks;
|
||||
public boolean eu_vehicle;
|
||||
public boolean has_air_suspension;
|
||||
public boolean has_ludicrous_mode;
|
||||
public boolean motorized_charge_port;
|
||||
public boolean plg;
|
||||
public boolean rhd;
|
||||
public boolean use_range_badging;
|
||||
public int rear_seat_heaters;
|
||||
public int rear_seat_type;
|
||||
public int sun_roof_installed;
|
||||
public long timestamp;
|
||||
public String car_special_type;
|
||||
public String car_type;
|
||||
public String charge_port_type;
|
||||
public String exterior_color;
|
||||
public String roof_color;
|
||||
public String spoiler_type;
|
||||
public String third_row_seats;
|
||||
public String trim_badging;
|
||||
public String wheel_type;
|
||||
|
||||
public ThingTypeUID identifyModel() {
|
||||
switch (car_type) {
|
||||
case "models":
|
||||
case "models2":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELS;
|
||||
case "modelx":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELX;
|
||||
case "model3":
|
||||
return TeslaBindingConstants.THING_TYPE_MODEL3;
|
||||
case "modely":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELY;
|
||||
default:
|
||||
return TeslaBindingConstants.THING_TYPE_VEHICLE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link VehicleData} is a data structure to capture
|
||||
* variables sent by the Tesla API about a vehicle.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
public class VehicleData {
|
||||
|
||||
public String color;
|
||||
public String display_name;
|
||||
public String id;
|
||||
public String option_codes;
|
||||
public String vehicle_id;
|
||||
public String vin;
|
||||
public String[] tokens;
|
||||
public String state;
|
||||
public boolean remote_start_enabled;
|
||||
public boolean calendar_enabled;
|
||||
public boolean notifications_enabled;
|
||||
public String backseat_token;
|
||||
public String backseat_token_updated_at;
|
||||
|
||||
public ChargeState charge_state;
|
||||
public ClimateState climate_state;
|
||||
public DriveState drive_state;
|
||||
public GUIState gui_settings;
|
||||
public VehicleConfig vehicle_config;
|
||||
public VehicleState vehicle_state;
|
||||
|
||||
VehicleData() {
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol;
|
||||
|
||||
/**
|
||||
* The {@link VehicleState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class VehicleState {
|
||||
|
||||
public boolean dark_rims;
|
||||
public boolean has_spoiler;
|
||||
public boolean homelink_nearby;
|
||||
public boolean is_user_present;
|
||||
public boolean locked;
|
||||
public boolean notifications_supported;
|
||||
public boolean parsed_calendar_supported;
|
||||
public boolean remote_start;
|
||||
public boolean remote_start_supported;
|
||||
public boolean rhd;
|
||||
public boolean sentry_mode;
|
||||
public boolean valet_mode;
|
||||
public boolean valet_pin_needed;
|
||||
public float odometer;
|
||||
public int center_display_state;
|
||||
public int df;
|
||||
public int dr;
|
||||
public int ft;
|
||||
public int pf;
|
||||
public int pr;
|
||||
public int rear_seat_heaters;
|
||||
public int rt;
|
||||
public int seat_type;
|
||||
public int sun_roof_installed;
|
||||
public int sun_roof_percent_open;
|
||||
public String autopark_state;
|
||||
public String autopark_state_v2;
|
||||
public String autopark_style;
|
||||
public String car_version;
|
||||
public String exterior_color;
|
||||
public String last_autopark_error;
|
||||
public String perf_config;
|
||||
public String roof_color;
|
||||
public String sun_roof_state;
|
||||
public String vehicle_name;
|
||||
public String wheel_type;
|
||||
|
||||
public SoftwareUpdate software_update;
|
||||
|
||||
VehicleState() {
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link ChargeState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class ChargeState {
|
||||
@SerializedName("battery_heater_on")
|
||||
public boolean batteryHeaterOn;
|
||||
@SerializedName("charge_enable_request")
|
||||
public boolean chargeEnableRequest;
|
||||
@SerializedName("charge_port_door_open")
|
||||
public boolean chargePortDoorOpen;
|
||||
@SerializedName("charge_to_max_range")
|
||||
public boolean chargeToMaxRange;
|
||||
@SerializedName("eu_vehicle")
|
||||
public boolean euVehicle;
|
||||
@SerializedName("fast_charger_present")
|
||||
public boolean fastChargerPresent;
|
||||
@SerializedName("managed_charging_active")
|
||||
public boolean managedChargingActive;
|
||||
@SerializedName("managed_charging_user_canceled")
|
||||
public boolean managedChargingUserCanceled;
|
||||
@SerializedName("motorized_charge_port")
|
||||
public boolean motorizedChargePort;
|
||||
@SerializedName("not_enough_power_to_heat")
|
||||
public boolean notEnoughPowerToHeat;
|
||||
@SerializedName("scheduled_charging_pending")
|
||||
public boolean scheduledChargingPending;
|
||||
@SerializedName("trip_charging")
|
||||
public boolean tripCharging;
|
||||
@SerializedName("battery_current")
|
||||
public float batteryCurrent;
|
||||
@SerializedName("battery_range")
|
||||
public float batteryRange;
|
||||
@SerializedName("charge_energy_added")
|
||||
public float chargeEnergyAdded;
|
||||
@SerializedName("charge_miles_added_ideal")
|
||||
public float chargeMilesAddedIdeal;
|
||||
@SerializedName("charge_miles_added_rated")
|
||||
public float chargeMilesAddedRated;
|
||||
@SerializedName("aaacharge_rateaa")
|
||||
public float chargeRate;
|
||||
@SerializedName("est_battery_range")
|
||||
public float estBatteryRange;
|
||||
@SerializedName("ideal_battery_range")
|
||||
public float idealBatteryRange;
|
||||
@SerializedName("time_to_full_charge")
|
||||
public float timeToFullCharge;
|
||||
@SerializedName("battery_level")
|
||||
public int batteryLevel;
|
||||
@SerializedName("charge_amps")
|
||||
public int chargeAmps;
|
||||
@SerializedName("charge_current_request")
|
||||
public int chargeCurrentRequest;
|
||||
@SerializedName("charge_current_request_max")
|
||||
public int chargeCurrentRequestMax;
|
||||
@SerializedName("charge_limit_soc")
|
||||
public int chargeLimitSoc;
|
||||
@SerializedName("charge_limit_soc_max")
|
||||
public int chargeLimitSocMax;
|
||||
@SerializedName("charge_limit_soc_min")
|
||||
public int chargeLimitSocMin;
|
||||
@SerializedName("charge_limit_soc_std")
|
||||
public int chargeLimitSocStd;
|
||||
@SerializedName("charger_actual_current")
|
||||
public int chargerActualCurrent;
|
||||
@SerializedName("charger_phases")
|
||||
public int chargerPhases;
|
||||
@SerializedName("charger_pilot_current")
|
||||
public int chargerPilotCurrent;
|
||||
@SerializedName("charger_power")
|
||||
public int chargerPower;
|
||||
@SerializedName("charger_voltage")
|
||||
public int chargerVoltage;
|
||||
@SerializedName("max_range_charge_counter")
|
||||
public int maxRangeChargeCounter;
|
||||
@SerializedName("usable_battery_level")
|
||||
public int usableBatteryLevel;
|
||||
@SerializedName("charge_port_latch")
|
||||
public String chargePortLatch;
|
||||
@SerializedName("charging_state")
|
||||
public String chargingState;
|
||||
@SerializedName("conn_charge_cable")
|
||||
public String connChargeCable;
|
||||
@SerializedName("fast_charger_brand")
|
||||
public String fastChargerBrand;
|
||||
@SerializedName("fast_charger_type")
|
||||
public String fastChargerType;
|
||||
@SerializedName("managed_charging_start_time")
|
||||
public String managedChargingStartTime;
|
||||
@SerializedName("scheduled_charging_start_time")
|
||||
public String scheduledChargingStartTime;
|
||||
@SerializedName("user_charge_enable_request")
|
||||
public String userChargeEnableRequest;
|
||||
|
||||
ChargeState() {
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link ClimateState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class ClimateState {
|
||||
|
||||
@SerializedName("allow_cabin_overheat_protection")
|
||||
public boolean allowCabinOverheatProtection;
|
||||
@SerializedName("auto_seat_climate_left")
|
||||
public boolean autoSeatClimateLeft;
|
||||
@SerializedName("auto_seat_climate_right")
|
||||
public boolean autoSeatClimateRight;
|
||||
@SerializedName("battery_heater")
|
||||
public boolean batteryHeater;
|
||||
@SerializedName("battery_heater_no_power")
|
||||
public boolean batteryHeaterNoPower;
|
||||
@SerializedName("cabin_overheat_protection")
|
||||
public String cabinOverheatProtection;
|
||||
@SerializedName("cabin_overheat_protection_actively_cooling")
|
||||
public boolean cabinOverheatProtectionActivelyCooling;
|
||||
@SerializedName("climate_keeper_mode")
|
||||
public String climateKeeperMode;
|
||||
@SerializedName("cop_activation_temperature")
|
||||
public String copActivationTemperature;
|
||||
@SerializedName("defrost_mode")
|
||||
public int defrostMode;
|
||||
@SerializedName("driver_temp_setting")
|
||||
public float driverTempSetting;
|
||||
@SerializedName("fan_status")
|
||||
public int fanStatus;
|
||||
@SerializedName("hvac_auto_request")
|
||||
public String hvacAutoRequest;
|
||||
@SerializedName("inside_temp")
|
||||
public float insideTemp;
|
||||
@SerializedName("is_auto_conditioning_on")
|
||||
public boolean isAutoConditioningOn;
|
||||
@SerializedName("is_climate_on")
|
||||
public boolean isClimateOn;
|
||||
@SerializedName("is_front_defroster_on")
|
||||
public boolean isFrontDefrosterOn;
|
||||
@SerializedName("is_preconditioning")
|
||||
public boolean isPreconditioning;
|
||||
@SerializedName("is_rear_defroster_on")
|
||||
public boolean isRearDefrosterOn;
|
||||
@SerializedName("left_temp_direction")
|
||||
public int leftTempDirection;
|
||||
@SerializedName("max_avail_temp")
|
||||
public float maxAvailTemp;
|
||||
@SerializedName("min_avail_temp")
|
||||
public float minAvailTemp;
|
||||
@SerializedName("outside_temp")
|
||||
public float outsideTemp;
|
||||
@SerializedName("passenger_temp_setting")
|
||||
public float passengerTempSetting;
|
||||
@SerializedName("remote_heater_control_enabled")
|
||||
public boolean remoteHeaterControlEnabled;
|
||||
@SerializedName("right_temp_direction")
|
||||
public int rightTempDirection;
|
||||
@SerializedName("seat_heater_left")
|
||||
public int seatHeaterLeft;
|
||||
@SerializedName("seat_heater_right")
|
||||
public int seatHeaterRight;
|
||||
@SerializedName("side_mirror_heaters")
|
||||
public boolean sideMirrorHeaters;
|
||||
@SerializedName("supports_fan_only_cabin_overheat_protection")
|
||||
public boolean supportsFanOnlyCabinOverheatProtection;
|
||||
@SerializedName("timestamp")
|
||||
public long timestamp;
|
||||
@SerializedName("wiper_blade_heater")
|
||||
public boolean wiperBladeHeater;
|
||||
|
||||
ClimateState() {
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link DriveState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class DriveState {
|
||||
|
||||
@SerializedName("gps_as_of")
|
||||
public int gpsAsOf;
|
||||
@SerializedName("heading")
|
||||
public int heading;
|
||||
@SerializedName("latitude")
|
||||
public double latitude;
|
||||
@SerializedName("longitude")
|
||||
public double longitude;
|
||||
@SerializedName("native_latitude")
|
||||
public double nativeLatitude;
|
||||
@SerializedName("native_location_supported")
|
||||
public int nativeLocationSupported;
|
||||
@SerializedName("native_longitude")
|
||||
public double nativeLongitude;
|
||||
@SerializedName("native_type")
|
||||
public String nativeType;
|
||||
@SerializedName("power")
|
||||
public int power;
|
||||
@SerializedName("shift_state")
|
||||
public String shiftState;
|
||||
@SerializedName("speed")
|
||||
public String speed;
|
||||
@SerializedName("timestamp")
|
||||
public long timestamp;
|
||||
|
||||
DriveState() {
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link Event} is a datastructure to capture
|
||||
@ -19,9 +21,11 @@ package org.openhab.binding.tesla.internal.protocol;
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class Event {
|
||||
public String msg_type;
|
||||
@SerializedName("msg_type")
|
||||
public String msgType;
|
||||
public String value;
|
||||
public String tag;
|
||||
public String error_type;
|
||||
@SerializedName("error_type")
|
||||
public String errorType;
|
||||
public int connectionTimeout;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link GUIState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class GUIState {
|
||||
|
||||
@SerializedName("gui_24_hour_time")
|
||||
public boolean gui24HourTime;
|
||||
@SerializedName("gui_charge_rate_units")
|
||||
public String guiChargeRateUnits;
|
||||
@SerializedName("gui_distance_units")
|
||||
public String guiDistanceUnits;
|
||||
@SerializedName("gui_range_display")
|
||||
public String guiRangeDisplay;
|
||||
@SerializedName("gui_temperature_units")
|
||||
public String guiTemperatureUnits;
|
||||
@SerializedName("show_range_units")
|
||||
public boolean showRangeUnits;
|
||||
@SerializedName("timestamp")
|
||||
|
||||
public Long timestamp;
|
||||
|
||||
public GUIState() {
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SoftwareUpdate} is a datastructure to capture
|
||||
@ -20,9 +22,12 @@ package org.openhab.binding.tesla.internal.protocol;
|
||||
*/
|
||||
public class SoftwareUpdate {
|
||||
|
||||
public int download_perc;
|
||||
public int expected_duration_sec;
|
||||
public int install_perc;
|
||||
@SerializedName("download_perc")
|
||||
public int downloadPerc;
|
||||
@SerializedName("expected_duration_sec")
|
||||
public int expectedDurationSec;
|
||||
@SerializedName("install_perc")
|
||||
public int installPerc;
|
||||
public String status;
|
||||
public String version;
|
||||
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link Vehicle} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class Vehicle {
|
||||
|
||||
public String color;
|
||||
@SerializedName("display_name")
|
||||
public String displayName;
|
||||
public String id;
|
||||
@SerializedName("option_codes")
|
||||
public String optionCodes;
|
||||
@SerializedName("vehicle_id")
|
||||
public String vehicleId;
|
||||
public String vin;
|
||||
public String[] tokens;
|
||||
public String state;
|
||||
@SerializedName("remote_start_enabled")
|
||||
public boolean remoteStartEnabled;
|
||||
@SerializedName("calendar_enabled")
|
||||
public boolean calendarEnabled;
|
||||
@SerializedName("notifications_enabled")
|
||||
public boolean notificationsEnabled;
|
||||
@SerializedName("backseat_token")
|
||||
public String backseatToken;
|
||||
@SerializedName("backseat_token_updated_at")
|
||||
public String backseatTokenUpdatedAt;
|
||||
|
||||
Vehicle() {
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import org.openhab.binding.tesla.internal.TeslaBindingConstants;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link VehicleConfig} is a data structure to capture
|
||||
* vehicle configuration variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class VehicleConfig {
|
||||
|
||||
@SerializedName("can_accept_navigation_requests")
|
||||
public boolean canAcceptNavigationRequests;
|
||||
@SerializedName("can_actuate_trunks")
|
||||
public boolean canActuateTrunks;
|
||||
@SerializedName("car_special_type")
|
||||
public String carSpecialType;
|
||||
@SerializedName("car_type")
|
||||
public String carType;
|
||||
@SerializedName("charge_port_type")
|
||||
public String chargePortType;
|
||||
@SerializedName("ece_restrictions")
|
||||
public boolean eceRestrictions;
|
||||
@SerializedName("eu_vehicle")
|
||||
public boolean euVehicle;
|
||||
@SerializedName("exterior_color")
|
||||
public String exteriorColor;
|
||||
@SerializedName("has_air_suspension")
|
||||
public boolean hasAirSuspension;
|
||||
@SerializedName("has_ludicrous_mode")
|
||||
public boolean hasLudicrousMode;
|
||||
@SerializedName("motorized_charge_port")
|
||||
public boolean motorizedChargePort;
|
||||
@SerializedName("plg")
|
||||
public boolean plg;
|
||||
@SerializedName("rear_seat_heaters")
|
||||
public int rearSeatHeaters;
|
||||
@SerializedName("rear_seat_type")
|
||||
public int rearSeatType;
|
||||
@SerializedName("rhd")
|
||||
public boolean rhd;
|
||||
@SerializedName("roof_color")
|
||||
public String roofColor;
|
||||
@SerializedName("seat_type")
|
||||
public int seatType;
|
||||
@SerializedName("spoiler_type")
|
||||
public String spoilerType;
|
||||
@SerializedName("sun_roof_installed")
|
||||
public int sunRoofInstalled;
|
||||
@SerializedName("third_row_seats")
|
||||
public String thirdRowSeats;
|
||||
@SerializedName("timestamp")
|
||||
public Long timestamp;
|
||||
@SerializedName("trim_badging")
|
||||
public String trimBadging;
|
||||
@SerializedName("use_range_badging")
|
||||
public boolean useRangeBadging;
|
||||
@SerializedName("wheel_type")
|
||||
public String wheelType;
|
||||
|
||||
public ThingTypeUID identifyModel() {
|
||||
switch (carType) {
|
||||
case "models":
|
||||
case "models2":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELS;
|
||||
case "modelx":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELX;
|
||||
case "model3":
|
||||
return TeslaBindingConstants.THING_TYPE_MODEL3;
|
||||
case "modely":
|
||||
return TeslaBindingConstants.THING_TYPE_MODELY;
|
||||
default:
|
||||
return TeslaBindingConstants.THING_TYPE_VEHICLE;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link VehicleData} is a data structure to capture
|
||||
* variables sent by the Tesla API about a vehicle.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
public class VehicleData {
|
||||
|
||||
@SerializedName("id")
|
||||
public Long id;
|
||||
@SerializedName("user_id")
|
||||
public int userId;
|
||||
@SerializedName("vehicle_id")
|
||||
public String vehicleId;
|
||||
@SerializedName("vin")
|
||||
public String vin;
|
||||
@SerializedName("display_name")
|
||||
public String displayName;
|
||||
@SerializedName("color")
|
||||
public Object color;
|
||||
@SerializedName("access_type")
|
||||
public String accessType;
|
||||
@SerializedName("tokens")
|
||||
public List<String> tokens;
|
||||
@SerializedName("state")
|
||||
public String state;
|
||||
@SerializedName("in_service")
|
||||
public boolean inService;
|
||||
@SerializedName("id_s")
|
||||
public String idS;
|
||||
@SerializedName("calendar_enabled")
|
||||
public boolean calendarEnabled;
|
||||
@SerializedName("api_version")
|
||||
public int apiVersion;
|
||||
@SerializedName("backseat_token")
|
||||
public Object backseatToken;
|
||||
@SerializedName("backseat_token_updated_at")
|
||||
public Object backseatTokenUpdatedAt;
|
||||
@SerializedName("charge_state")
|
||||
public ChargeState chargeState;
|
||||
@SerializedName("climate_state")
|
||||
public ClimateState climateState;
|
||||
@SerializedName("drive_state")
|
||||
public DriveState driveState;
|
||||
@SerializedName("gui_settings")
|
||||
public GUIState guiSettings;
|
||||
@SerializedName("vehicle_config")
|
||||
public VehicleConfig vehicleConfig;
|
||||
@SerializedName("vehicle_state")
|
||||
public VehicleState vehicleState;
|
||||
|
||||
VehicleData() {
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.tesla.internal.protocol.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link VehicleState} is a datastructure to capture
|
||||
* variables sent by the Tesla Vehicle
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
public class VehicleState {
|
||||
|
||||
@SerializedName("dark_rims")
|
||||
public boolean darkRims;
|
||||
@SerializedName("has_spoiler")
|
||||
public boolean hasSpoiler;
|
||||
@SerializedName("homelink_nearby")
|
||||
public boolean homelinkNearby;
|
||||
@SerializedName("is_user_present")
|
||||
public boolean isUserPresent;
|
||||
public boolean locked;
|
||||
@SerializedName("notifications_supported")
|
||||
public boolean notificationsSupported;
|
||||
@SerializedName("parsed_calendar_supported")
|
||||
public boolean parsedCalendarSupported;
|
||||
@SerializedName("remote_start")
|
||||
public boolean remoteStart;
|
||||
@SerializedName("remote_start_supported")
|
||||
public boolean remoteStartSupported;
|
||||
public boolean rhd;
|
||||
@SerializedName("sentry_mode")
|
||||
public boolean sentryMode;
|
||||
@SerializedName("valet_mode")
|
||||
public boolean valetMode;
|
||||
@SerializedName("valet_pin_needed")
|
||||
public boolean valetPinNeeded;
|
||||
public float odometer;
|
||||
@SerializedName("center_display_state")
|
||||
public int centerDisplayState;
|
||||
public int df;
|
||||
public int dr;
|
||||
public int ft;
|
||||
public int pf;
|
||||
public int pr;
|
||||
@SerializedName("rear_seat_heaters")
|
||||
public int rearSeatHeaters;
|
||||
public int rt;
|
||||
@SerializedName("seat_type")
|
||||
public int seatType;
|
||||
@SerializedName("sun_roof_installed")
|
||||
public int sunRoofInstalled;
|
||||
@SerializedName("sun_roof_percent_open")
|
||||
public int sunRoofPercentOpen;
|
||||
@SerializedName("autopark_state")
|
||||
public String autoparkState;
|
||||
@SerializedName("autopark_state_v2")
|
||||
public String autoparkStateV2;
|
||||
@SerializedName("autopark_style")
|
||||
public String autoparkStyle;
|
||||
@SerializedName("car_version")
|
||||
public String carVersion;
|
||||
@SerializedName("exterior_color")
|
||||
public String exteriorColor;
|
||||
@SerializedName("last_autopark_error")
|
||||
public String lastAutoparkError;
|
||||
@SerializedName("perf_config")
|
||||
public String perfConfig;
|
||||
@SerializedName("roof_color")
|
||||
public String roofColor;
|
||||
@SerializedName("sun_roof_state")
|
||||
public String sunRoofState;
|
||||
@SerializedName("vehicle_name")
|
||||
public String vehicleName;
|
||||
@SerializedName("wheel_type")
|
||||
public String wheelType;
|
||||
|
||||
@SerializedName("software_update")
|
||||
public SoftwareUpdate softwareUpdate;
|
||||
|
||||
VehicleState() {
|
||||
}
|
||||
}
|
@ -10,10 +10,12 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto.sso;
|
||||
|
||||
import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link AuthorizationCodeExchangeRequest} is a datastructure to exchange
|
||||
* the authorization code for an access token on the SSO endpoint
|
||||
@ -22,14 +24,18 @@ import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
|
||||
*/
|
||||
@SuppressWarnings("unused") // Unused fields must not be removed since they are used for serialization to JSON
|
||||
public class AuthorizationCodeExchangeRequest {
|
||||
private String grant_type = "authorization_code";
|
||||
private String client_id = CLIENT_ID;
|
||||
@SerializedName("grant_type")
|
||||
private String grantType = "authorization_code";
|
||||
@SerializedName("client_id")
|
||||
private String clientId = CLIENT_ID;
|
||||
private String code;
|
||||
private String code_verifier;
|
||||
private String redirect_uri = URI_CALLBACK;
|
||||
@SerializedName("code_verifier")
|
||||
private String codeVerifier;
|
||||
@SerializedName("redirect_uri")
|
||||
private String redirectUri = URI_CALLBACK;
|
||||
|
||||
public AuthorizationCodeExchangeRequest(String code, String codeVerifier) {
|
||||
this.code = code;
|
||||
this.code_verifier = codeVerifier;
|
||||
this.codeVerifier = codeVerifier;
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto.sso;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link AuthorizationCodeExchangeResponse} is a datastructure to capture
|
||||
@ -19,9 +21,13 @@ package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
* @author Christian Güdel - Initial contribution
|
||||
*/
|
||||
public class AuthorizationCodeExchangeResponse {
|
||||
public String access_token;
|
||||
public String refresh_token;
|
||||
public String expires_in;
|
||||
@SerializedName("access_token")
|
||||
public String accessToken;
|
||||
@SerializedName("refresh_token")
|
||||
public String refreshToken;
|
||||
@SerializedName("expires_in")
|
||||
public String expiresIn;
|
||||
public String state;
|
||||
public String token_type;
|
||||
@SerializedName("token_type")
|
||||
public String tokenType;
|
||||
}
|
@ -10,10 +10,12 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto.sso;
|
||||
|
||||
import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link RefreshTokenRequest} is a datastructure to refresh
|
||||
* the access token for the SSO endpoint
|
||||
@ -21,12 +23,15 @@ import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
|
||||
* @author Christian Güdel - Initial contribution
|
||||
*/
|
||||
public class RefreshTokenRequest {
|
||||
public String grant_type = "refresh_token";
|
||||
public String client_id = CLIENT_ID;
|
||||
public String refresh_token;
|
||||
@SerializedName("grant_type")
|
||||
public String grantType = "refresh_token";
|
||||
@SerializedName("client_id")
|
||||
public String clientId = CLIENT_ID;
|
||||
@SerializedName("refresh_token")
|
||||
public String refreshToken;
|
||||
public String scope = SSO_SCOPES;
|
||||
|
||||
public RefreshTokenRequest(String refresh_token) {
|
||||
this.refresh_token = refresh_token;
|
||||
public RefreshTokenRequest(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto.sso;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link TokenExchangeRequest} is a datastructure to exchange
|
||||
@ -19,7 +21,10 @@ package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
* @author Christian Güdel - Initial contribution
|
||||
*/
|
||||
public class TokenExchangeRequest {
|
||||
public String grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
||||
public String client_id = "81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384";
|
||||
public String client_secret = "c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3";
|
||||
@SerializedName("grant_type")
|
||||
public String grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
||||
@SerializedName("client_id")
|
||||
public String clientId = "81527cff06843c8634fdc09e8ac0abefb46ac849f38fe1e431c2ef2106796384";
|
||||
@SerializedName("client_secret")
|
||||
public String clientSecret = "c7257eb71a564034f9419ee651c7d0e5f7aa6bfbd18bafb5c5c033b093bb2fa3";
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
package org.openhab.binding.tesla.internal.protocol.dto.sso;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link TokenResponse} is a datastructure to capture
|
||||
@ -19,12 +21,16 @@ package org.openhab.binding.tesla.internal.protocol.sso;
|
||||
* @author Nicolai Grødum - Initial contribution
|
||||
*/
|
||||
public class TokenResponse {
|
||||
|
||||
public String access_token;
|
||||
public String token_type;
|
||||
public Long expires_in;
|
||||
public Long created_at;
|
||||
public String refresh_token;
|
||||
@SerializedName("access_token")
|
||||
public String accessToken;
|
||||
@SerializedName("token_type")
|
||||
public String tokenType;
|
||||
@SerializedName("expires_in")
|
||||
public Long expiresIn;
|
||||
@SerializedName("created_at")
|
||||
public Long createdAt;
|
||||
@SerializedName("refresh_token")
|
||||
public String refreshToken;
|
||||
|
||||
public TokenResponse() {
|
||||
}
|
@ -16,12 +16,16 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link AbstractChannelThrottler} is abstract class implementing a
|
||||
* throttler with one global execution rate, or rate limiter
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class AbstractChannelThrottler implements ChannelThrottler {
|
||||
|
||||
protected final Rate totalRate;
|
||||
@ -37,7 +41,7 @@ abstract class AbstractChannelThrottler implements ChannelThrottler {
|
||||
this.timeProvider = timeProvider;
|
||||
}
|
||||
|
||||
protected synchronized long callTime(Rate channel) {
|
||||
protected synchronized long callTime(@Nullable Rate channel) {
|
||||
long now = timeProvider.getCurrentTimeInMillis();
|
||||
long callTime = totalRate.callTime(now);
|
||||
if (channel != null) {
|
||||
|
@ -18,12 +18,16 @@ import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link AbstractMultiRateChannelThrottler} is abstract class implementing
|
||||
* a throttler with multiple global execution rates, or rate limiters
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
abstract class AbstractMultiRateChannelThrottler implements ChannelThrottler {
|
||||
|
||||
protected final TimeProvider timeProvider;
|
||||
@ -43,7 +47,7 @@ abstract class AbstractMultiRateChannelThrottler implements ChannelThrottler {
|
||||
this.rates.add(rate);
|
||||
}
|
||||
|
||||
protected synchronized long callTime(Rate channel) {
|
||||
protected synchronized long callTime(@Nullable Rate channel) {
|
||||
long maxCallTime = 0;
|
||||
long finalCallTime = 0;
|
||||
long now = timeProvider.getCurrentTimeInMillis();
|
||||
|
@ -14,14 +14,20 @@ package org.openhab.binding.tesla.internal.throttler;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link ChannelThrottler} defines the interface for to submit tasks to a
|
||||
* throttler
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ChannelThrottler {
|
||||
@Nullable
|
||||
Future<?> submit(Runnable task);
|
||||
|
||||
@Nullable
|
||||
Future<?> submit(Object channelKey, Runnable task);
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -31,6 +33,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class QueueChannelThrottler extends AbstractMultiRateChannelThrottler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QueueChannelThrottler.class);
|
||||
@ -71,13 +74,13 @@ public final class QueueChannelThrottler extends AbstractMultiRateChannelThrottl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
public @Nullable Future<?> submit(Runnable task) {
|
||||
return submit(null, task);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Future<?> submit(Object channelKey, Runnable task) {
|
||||
public @Nullable Future<?> submit(@Nullable Object channelKey, Runnable task) {
|
||||
FutureTask runTask = new FutureTask(task, null);
|
||||
try {
|
||||
if (tasks.offer(runTask, overallRate.timeInMillis(), TimeUnit.MILLISECONDS)) {
|
||||
|
@ -17,6 +17,8 @@ import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Rate} defines a rate limiter that accepts a number of calls to be
|
||||
* executed in a given time length. If the quota of calls is used, then calls
|
||||
@ -24,6 +26,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class Rate {
|
||||
|
||||
private final int numberCalls;
|
||||
|
@ -19,6 +19,9 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link ScheduledChannelThrottler} implements a throttler that maintains a
|
||||
* single execution rates, and does not maintain order of calls (thus has to
|
||||
@ -26,6 +29,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class ScheduledChannelThrottler extends AbstractChannelThrottler {
|
||||
|
||||
public ScheduledChannelThrottler(Rate totalRate) {
|
||||
@ -53,13 +57,13 @@ public final class ScheduledChannelThrottler extends AbstractChannelThrottler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
public @Nullable Future<?> submit(Runnable task) {
|
||||
long delay = callTime(null) - timeProvider.getCurrentTimeInMillis();
|
||||
return scheduler.schedule(task, delay < 0 ? 0 : delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Object channelKey, Runnable task) {
|
||||
public @Nullable Future<?> submit(Object channelKey, Runnable task) {
|
||||
return scheduler.schedule(task, getThrottleDelay(channelKey), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.tesla.internal.throttler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link TimeProvider} provides time stamps
|
||||
*
|
||||
* @author Karel Goderis - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface TimeProvider {
|
||||
static final TimeProvider SYSTEM_PROVIDER = new TimeProvider() {
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user