[tesla] Introduce "allowWakeUpForCommands" option (#12184)

* Introduce "allowWakeUpForCommands" option

Signed-off-by: Kai Kreuzer <kai@openhab.org>
pull/12192/head
Kai Kreuzer 2022-02-02 20:28:48 +01:00 committed by GitHub
parent 624efab678
commit ca1e2b0e42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 92 additions and 30 deletions

View File

@ -109,6 +109,7 @@ public class TeslaBindingConstants {
// thing configurations
public static final String CONFIG_ALLOWWAKEUP = "allowWakeup";
public static final String CONFIG_ALLOWWAKEUPFORCOMMANDS = "allowWakeupForCommands";
public static final String CONFIG_ENABLEEVENTS = "enableEvents";
public static final String CONFIG_REFRESHTOKEN = "refreshToken";
public static final String CONFIG_USERNAME = "username";

View File

@ -71,7 +71,7 @@ import com.google.gson.JsonParser;
*/
public class TeslaAccountHandler extends BaseBridgeHandler {
public static final int API_MAXIMUM_ERRORS_IN_INTERVAL = 2;
public static final int API_MAXIMUM_ERRORS_IN_INTERVAL = 3;
public static final int API_ERROR_INTERVAL_SECONDS = 15;
private static final int CONNECT_RETRY_INTERVAL = 15000;
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
@ -219,7 +219,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
Vehicle[] vehicleArray = gson.fromJson(jsonObject.getAsJsonArray("response"), Vehicle[].class);
for (Vehicle vehicle : vehicleArray) {
String responseString = invokeAndParse(vehicle.id, VEHICLE_CONFIG, null, dataRequestTarget);
String responseString = invokeAndParse(vehicle.id, VEHICLE_CONFIG, null, dataRequestTarget, 0);
if (responseString == null || responseString.isBlank()) {
continue;
}
@ -308,7 +308,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) {
protected String invokeAndParse(String vehicleId, String command, String payLoad, WebTarget target,
int noOfretries) {
logger.debug("Invoking: {}", command);
if (vehicleId != null) {
@ -339,6 +340,16 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
logger.debug("An error occurred while communicating with the vehicle during request {}: {}: {}",
command, (response != null) ? response.getStatus() : "",
(response != null) ? response.getStatusInfo().getReasonPhrase() : "No Response");
if (response.getStatus() == 408 && noOfretries > 0) {
try {
// we give the vehicle a moment to wake up and try the request again
Thread.sleep(TimeUnit.SECONDS.toMillis(API_ERROR_INTERVAL_SECONDS));
logger.debug("Retrying to send the command {}.", command);
return invokeAndParse(vehicleId, command, payLoad, target, noOfretries - 1);
} catch (InterruptedException e) {
return null;
}
}
return null;
}
@ -445,16 +456,21 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
protected class Request implements Runnable {
private static final int NO_OF_RETRIES = 3;
private TeslaVehicleHandler handler;
private String request;
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, String payLoad, WebTarget target,
boolean allowWakeUpForCommands) {
this.handler = handler;
this.request = request;
this.payLoad = payLoad;
this.target = target;
this.allowWakeUpForCommands = allowWakeUpForCommands;
}
@Override
@ -463,7 +479,8 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
String result = "";
if (getThing().getStatus() == ThingStatus.ONLINE) {
result = invokeAndParse(handler.getVehicleId(), request, payLoad, target);
result = invokeAndParse(handler.getVehicleId(), request, payLoad, target,
allowWakeUpForCommands ? NO_OF_RETRIES : 0);
if (result != null && !"".equals(result)) {
handler.parseAndUpdate(request, payLoad, result);
}
@ -474,9 +491,9 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
}
}
public Request newRequest(TeslaVehicleHandler teslaVehicleHandler, String command, String payLoad,
WebTarget target) {
return new Request(teslaVehicleHandler, command, payLoad, target);
public Request newRequest(TeslaVehicleHandler teslaVehicleHandler, String command, String payLoad, WebTarget target,
boolean allowWakeUpForCommands) {
return new Request(teslaVehicleHandler, command, payLoad, target, allowWakeUpForCommands);
}
@Override

View File

@ -112,6 +112,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected ClimateState climateState;
protected boolean allowWakeUp;
protected boolean allowWakeUpForCommands;
protected boolean enableEvents = false;
protected long lastTimeStamp;
protected long apiIntervalTimestamp;
@ -151,6 +152,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
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);
// the streaming API seems to be broken - let's keep the code, if it comes back one day
// enableEvents = (boolean) getConfig().get(TeslaBindingConstants.CONFIG_ENABLEEVENTS);
@ -251,6 +253,11 @@ public class TeslaVehicleHandler extends BaseThingHandler {
requestAllData();
} else {
if (selector != null) {
if (!isAwake() && allowWakeUpForCommands) {
logger.debug("Waking vehicle to send command.");
wakeUp();
setActive();
}
try {
switch (selector) {
case CHARGE_LIMIT_SOC: {
@ -449,8 +456,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
}
public void sendCommand(String command, String payLoad, WebTarget target) {
if (command.equals(COMMAND_WAKE_UP) || isAwake()) {
Request request = account.newRequest(this, command, payLoad, target);
if (command.equals(COMMAND_WAKE_UP) || isAwake() || allowWakeUpForCommands) {
Request request = account.newRequest(this, command, payLoad, target, allowWakeUpForCommands);
if (stateThrottler != null) {
stateThrottler.submit(COMMAND_THROTTLE, request);
}
@ -462,8 +469,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
}
public void sendCommand(String command, String payLoad) {
if (command.equals(COMMAND_WAKE_UP) || isAwake()) {
Request request = account.newRequest(this, command, payLoad, account.commandTarget);
if (command.equals(COMMAND_WAKE_UP) || isAwake() || allowWakeUpForCommands) {
Request request = account.newRequest(this, command, payLoad, account.commandTarget, allowWakeUpForCommands);
if (stateThrottler != null) {
stateThrottler.submit(COMMAND_THROTTLE, request);
}
@ -471,8 +478,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
}
public void sendCommand(String command, WebTarget target) {
if (command.equals(COMMAND_WAKE_UP) || isAwake()) {
Request request = account.newRequest(this, command, "{}", target);
if (command.equals(COMMAND_WAKE_UP) || isAwake() || allowWakeUpForCommands) {
Request request = account.newRequest(this, command, "{}", target, allowWakeUpForCommands);
if (stateThrottler != null) {
stateThrottler.submit(COMMAND_THROTTLE, request);
}
@ -480,8 +487,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
}
public void requestData(String command, String payLoad) {
if (command.equals(COMMAND_WAKE_UP) || isAwake()) {
Request request = account.newRequest(this, command, payLoad, account.dataRequestTarget);
if (command.equals(COMMAND_WAKE_UP) || isAwake() || allowWakeUpForCommands) {
Request request = account.newRequest(this, command, payLoad, account.dataRequestTarget, false);
if (stateThrottler != null) {
stateThrottler.submit(DATA_THROTTLE, request);
}
@ -731,7 +738,8 @@ public class TeslaVehicleHandler extends BaseThingHandler {
Response response = account.vehiclesTarget.request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", authHeader).get();
logger.debug("Querying the vehicle : Response : {}:{}", response.getStatus(), response.getStatusInfo());
logger.debug("Querying the vehicle, response : {}, {}", response.getStatus(),
response.getStatusInfo().getReasonPhrase());
if (!checkResponse(response, true)) {
logger.error("An error occurred while querying the vehicle");
@ -965,23 +973,27 @@ public class TeslaVehicleHandler extends BaseThingHandler {
}
protected Runnable slowStateRunnable = () -> {
queryVehicleAndUpdate();
try {
queryVehicleAndUpdate();
boolean allowQuery = allowQuery();
boolean allowQuery = allowQuery();
if (allowQuery) {
requestData(CHARGE_STATE);
requestData(CLIMATE_STATE);
requestData(GUI_STATE);
queryVehicle(MOBILE_ENABLED_STATE);
} else {
if (allowWakeUp) {
wakeUp();
if (allowQuery) {
requestData(CHARGE_STATE);
requestData(CLIMATE_STATE);
requestData(GUI_STATE);
queryVehicle(MOBILE_ENABLED_STATE);
} else {
if (isAwake()) {
logger.debug("Vehicle is neither charging nor moving, skipping updates to allow it to sleep");
if (allowWakeUp) {
wakeUp();
} else {
if (isAwake()) {
logger.debug("Vehicle is neither charging nor moving, skipping updates to allow it to sleep");
}
}
}
} catch (Exception e) {
logger.warn("Exception occurred in slowStateRunnable", e);
}
};

View File

@ -21,7 +21,7 @@ import java.util.concurrent.TimeUnit;
/**
* The {@link ScheduledChannelThrottler} implements a throttler that maintains a
* single execution rates, and does not maintains order of calls (thus have to
* single execution rates, and does not maintain order of calls (thus has to
* start from back rather than try to insert things in middle)
*
* @author Karel Goderis - Initial contribution

View File

@ -26,24 +26,32 @@ thing-type.config.tesla.account.username.label = Username
thing-type.config.tesla.account.username.description = Username for the Tesla Remote Service, e.g email address.
thing-type.config.tesla.model3.allowWakeup.label = Allow Wake-Up
thing-type.config.tesla.model3.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain!
thing-type.config.tesla.model3.allowWakeupForCommands.label = Allow Wake-Up For Commands
thing-type.config.tesla.model3.allowWakeupForCommands.description = Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in this case and you could cause the vehicle to stay awake very long.
thing-type.config.tesla.model3.valetpin.label = Valet PIN
thing-type.config.tesla.model3.valetpin.description = PIN to use when enabling Valet Mode
thing-type.config.tesla.model3.vin.label = Vehicle Identification Number
thing-type.config.tesla.model3.vin.description = VIN of the vehicle
thing-type.config.tesla.models.allowWakeup.label = Allow Wake-Up
thing-type.config.tesla.models.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain!
thing-type.config.tesla.models.allowWakeupForCommands.label = Allow Wake-Up For Commands
thing-type.config.tesla.models.allowWakeupForCommands.description = Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in this case and you could cause the vehicle to stay awake very long.
thing-type.config.tesla.models.valetpin.label = Valet PIN
thing-type.config.tesla.models.valetpin.description = PIN to use when enabling Valet Mode
thing-type.config.tesla.models.vin.label = Vehicle Identification Number
thing-type.config.tesla.models.vin.description = VIN of the vehicle
thing-type.config.tesla.modelx.allowWakeup.label = Allow Wake-Up
thing-type.config.tesla.modelx.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain!
thing-type.config.tesla.modelx.allowWakeupForCommands.label = Allow Wake-Up For Commands
thing-type.config.tesla.modelx.allowWakeupForCommands.description = Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in this case and you could cause the vehicle to stay awake very long.
thing-type.config.tesla.modelx.valetpin.label = Valet PIN
thing-type.config.tesla.modelx.valetpin.description = PIN to use when enabling Valet Mode
thing-type.config.tesla.modelx.vin.label = Vehicle Identification Number
thing-type.config.tesla.modelx.vin.description = VIN of the vehicle
thing-type.config.tesla.modely.allowWakeup.label = Allow Wake-Up
thing-type.config.tesla.modely.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain!
thing-type.config.tesla.modely.allowWakeupForCommands.label = Allow Wake-Up For Commands
thing-type.config.tesla.modely.allowWakeupForCommands.description = Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in this case and you could cause the vehicle to stay awake very long.
thing-type.config.tesla.modely.valetpin.label = Valet PIN
thing-type.config.tesla.modely.valetpin.description = PIN to use when enabling Valet Mode
thing-type.config.tesla.modely.vin.label = Vehicle Identification Number

View File

@ -134,6 +134,12 @@
<label>Allow Wake-Up</label>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up For Commands</label>
<description>Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in
this case and you could cause the vehicle to stay awake very long.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -141,6 +141,12 @@
<label>Allow Wake-Up</label>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up For Commands</label>
<description>Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in
this case and you could cause the vehicle to stay awake very long.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -141,6 +141,12 @@
<label>Allow Wake-Up</label>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up For Commands</label>
<description>Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in
this case and you could cause the vehicle to stay awake very long.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -136,6 +136,12 @@
<label>Allow Wake-Up</label>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up For Commands</label>
<description>Allows waking up the vehicle, when commands are sent to it. Execution of commands will be delayed in
this case and you could cause the vehicle to stay awake very long.</description>
</parameter>
</config-description>
</thing-type>