[tesla] Options to control polling frequency and sleep (#13337)

* Options to control polling frequency and sleep mode
* Update documentation
* Fix request token expiration calculation and additional logging for tokens

Signed-off-by: Bill Forsyth <git@billforsyth.net>
This commit is contained in:
billfor 2022-10-15 08:25:29 -04:00 committed by GitHub
parent 45bf7aeeda
commit 39e2a29bcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 415 additions and 73 deletions

View File

@ -41,16 +41,35 @@ Please note that we in general consider it dangerous to enter your credentials i
When using one of such apps, simply copy and paste the received refresh token into the account configuration.
## Thing Configuration
## Thing Configuration Parameters
The vehicle Thing requires the vehicle's VIN as a configuration parameter `vin`.
Additionally, the optional boolean parameter `allowWakeup` can be set.
This determines whether openHAB is allowed to wake up the vehicle in order to retrieve data from it.
Additionally, the follow optional parameters may be defined.
| Parameter Name | Label | Default Value | Description |
|------------------------|----------------------------|---------------|------------------------------------------------------------------------------|
| valetpin | Valet PIN | false | PIN to use when enabling Valet Mode |
| allowWakeupForCommands | Allow Wake-Up For Commands | false | Wake up the vehicle to send commands. May cause vehicle to stay awake |
For further flexibility and experimentation, the following advanced parameters may also be set.
| Parameter Name | Label | Default Value | Description |
|-----------------------------|------------------------------------------------|---------------|----------------------------------------------------------------------------------------------------|
| allowWakeup | Allow Wake-Up | false | Allows waking up the vehicle to retrieve data. See caution below |
| enableEvents | Enable Events | false | Enable the event stream for the vehicle. See note below |
| inactivity | Inactivity Interval | 5 | The inactivity period in minutes after which the binding stops for 20 minutes to let the car sleep |
| useDriveState | Use Drive State for Inactivity | false | Use the drive state instead of location to determine vehicle inactivity |
| useAdvancedStatesForPolling | Use Console Modes and Occupancy for Inactivity | false | Use these states to help continue the fast polling of the API |
`allowWakeup` should be used with caution as this determines whether openHAB is allowed to wake up the vehicle in order to retrieve data from it.
This setting is not recommended as it will result in a significant vampire drain (i.e. energy consumption although the vehicle is parking).
In addition, the optional boolean parameter `enableEvents` can be set.
By doing so, events streamed by the Tesla back-end system will be captured and processed, providing near real-time updates of some key variables generated by the vehicle.
`enableEvents` captures and processes data in near real-time for key variables by enabling events streamed by the Tesla back-end system.
`inactivity` setting is ignored and will always be five minutes if homelink is available (car is at home)
## Channels
@ -191,60 +210,186 @@ Bridge tesla:account:myaccount "My Tesla Account" [ refreshToken="xxxx" ] {
demo.items:
```
Switch TeslaCharge {channel="tesla:model3:myaccount:mycar:charge"}
Location TeslaLocation {channel="tesla:model3:myaccount:mycar:location"}
Dimmer TeslaChargeLimit {channel="tesla:model3:myaccount:mycar:chargelimit"}
String TeslaChargeRate {channel="tesla:model3:myaccount:mycar:chargerate"}
String TeslaChargingState {channel="tesla:model3:myaccount:mycar:chargingstate"}
Number TeslaTimeToFullCharge {channel="tesla:model3:myaccount:mycar:timetofullcharge"}
Number TeslaChargerPower {channel="tesla:model3:myaccount:mycar:chargerpower"}
DateTime TeslaScheduledChargingStart {channel="tesla:model3:myaccount:mycar:scheduledchargingstart"}
Dimmer TeslaSoC {channel="tesla:model3:myaccount:mycar:soc"}
Number:Speed TeslaSpeed {channel="tesla:model3:myaccount:mycar:speed"}
String TeslaState {channel="tesla:model3:myaccount:mycar:state"}
Number TeslaPower {channel="tesla:model3:myaccount:mycar:power"}
Number:Temperature TeslaInsideTemperature {channel="tesla:model3:myaccount:mycar:insidetemp"}
Number:Temperature TeslaOutsideTemperature {channel="tesla:model3:myaccount:mycar:outsidetemp"}
Switch TeslaAutoconditioning {channel="tesla:model3:myaccount:mycar:autoconditioning"}
Number:Temperature TeslaTemperature {channel="tesla:model3:myaccount:mycar:temperature"}
String TeslaShiftState {channel="tesla:model3:myaccount:mycar:shiftstate"}
Number TeslaBatteryCurrent {channel="tesla:model3:myaccount:mycar:batterycurrent"}
Number TeslaBatteryLevel {channel="tesla:model3:myaccount:mycar:batterylevel"}
DateTime TeslaEventstamp {channel="tesla:model3:myaccount:mycar:eventstamp"}
Number:Length TeslaOdometer {channel="tesla:model3:myaccount:mycar:odometer"}
Number TeslaHeading {channel="tesla:model3:myaccount:mycar:heading"}
DateTime TeslaGPSStamp {channel="tesla:model3:myaccount:mycar:gpstimestamp"}
DateTime TeslaEventstamp {channel="model3:myaccount:mycar:eventstamp"}
String TeslaState {channel="model3:myaccount:mycar:state"}
Number TeslaSpeed {channel="model3:myaccount:mycar:speed"}
String TeslaShiftState {channel="model3:myaccount:mycar:shiftstate"}
Number TeslaOdometer {channel="model3:myaccount:mycar:odometer"}
Number TeslaRange {channel="model3:myaccount:mycar:range"}
Number TeslaBatteryLevel {channel="model3:myaccount:mycar:batterylevel"}
Number TeslaPower {channel="model3:myaccount:mycar:power"}
Number TeslaBatteryCurrent {channel="model3:myaccount:mycar:batterycurrent"}
Number TeslaBatteryRange {channel="model3:myaccount:mycar:batteryrange"}
Number TeslaEstBatteryRange {channel="model3:myaccount:mycar:estimatedbatteryrange"}
Number TeslaIdealBatteryRange {channel="model3:myaccount:mycar:idealbatteryrange"}
Number TeslaUsableBatteryLevel {channel="model3:myaccount:mycar:usablebatterylevel"}
Switch TeslaPreconditioning {channel="model3:myaccount:mycar:preconditioning"}
Switch TeslaCharge {channel="model3:myaccount:mycar:charge"}
Switch TeslaChargeToMax {channel="model3:myaccount:mycar:chargetomax"}
Dimmer TeslaChargeLimit {channel="model3:myaccount:mycar:chargelimit"}
Number TeslaChargeRate {channel="model3:myaccount:mycar:chargerate"}
String TeslaChargingState {channel="model3:myaccount:mycar:chargingstate"}
Number TeslaChargerPower {channel="model3:myaccount:mycar:chargerpower"}
Number TeslaTimeToFullCharge {channel="model3:myaccount:mycar:timetofullcharge"}
Number TeslaMaxCharges {channel="model3:myaccount:mycar:maxcharges"}
Number TeslaChargerVoltage {channel="model3:myaccount:mycar:chargervoltage"}
Number TeslaChargerPower {channel="model3:myaccount:mycar:chargerpower"}
Number TeslaChargerCurrent {channel="model3:myaccount:mycar:chargercurrent"}
DateTime TeslaScheduledChargingStart {channel="model3:myaccount:mycar:scheduledchargingstart"}
Dimmer TeslaSoC {channel="model3:myaccount:mycar:soc"}
Switch TeslaDoorLock {channel="model3:myaccount:mycar:doorlock"}
Switch TeslaHorn {channel="model3:myaccount:mycar:honkhorn"}
Switch TeslaStart {channel="model3:myaccount:mycar:remotestart"}
Switch TeslaSentry {channel="model3:myaccount:mycar:sentrymode"}
Switch TeslaLights {channel="model3:myaccount:mycar:flashlights"}
Switch TeslaValet {channel="model3:myaccount:mycar:valetmode"}
Switch TeslaWakeup {channel="model3:myaccount:mycar:wakeup"}
Switch TeslaBatteryHeater {channel="model3:myaccount:mycar:batteryheater"}
Switch TeslaFrontDefrost {channel="model3:myaccount:mycar:frontdefroster"}
Switch TeslaRearDefrost {channel="model3:myaccount:mycar:reardefroster"}
Switch TeslaLeftSeatHeater {channel="model3:myaccount:mycar:leftseatheater"}
Switch TeslaRightSeatHeater {channel="model3:myaccount:mycar:rightseatheater"}
Switch TeslaHomelink {channel="model3:myaccount:mycar:homelink"}
Location TeslaLocation {channel="model3:myaccount:mycar:location"}
Number TeslaHeading {channel="model3:myaccount:mycar:heading"}
DateTime TeslaLocationTime {channel="model3:myaccount:mycar:gpstimestamp"}
Switch TeslaAutoconditioning {channel="model3:myaccount:mycar:autoconditioning"}
Number:Temperature TeslaTemperature {channel="model3:myaccount:mycar:temperature"}
Number:Temperature TeslaTemperatureCombined {channel="model3:myaccount:mycar:combinedtemp"}
Number:Temperature TeslaInsideTemperature {channel="model3:myaccount:mycar:insidetemp"}
Number:Temperature TeslaOutsideTemperature {channel="model3:myaccount:mycar:outsidetemp"}
```
demo.sitemap:
```
sitemap demo label="Main Menu"
sitemap main label="Main"
{
Text label="Car" {
Text label="Drive" {
Text item=TeslaEventstamp label="Last Event Timestamp [%1$td.%1$tm.%1$tY %1$tT]"
Text item=TeslaState label="State [%s]"
Text item=TeslaSpeed label="Speed [%.1f]"
Text item=TeslaShiftState label="Shift State [%s]"
Text item=TeslaOdometer label="Odometer [%.1f km]"
}
Text label="Climate" {
Switch item=TeslaAutoconditioning label="Auto Conditioning" mappings=[ON=ON, OFF=OFF ]
Setpoint item=TeslaTemperature step=0.5 minValue=18 maxValue=34 label="Auto Conditioning Temperature [%.1f °C]" icon="temperature"
Text item=TeslaInsideTemperature label="Inside Temperature [%.1f]"
}
Text label="Power" {
Text item=TeslaBatteryCurrent label="Current [%.1f]"
}
Text item=TeslaSoC {
Switch item=TeslaCharge label="Charge" mappings=[ON=ON, OFF=OFF ]
Slider item=TeslaChargeLimit label="Charge Limit [%.1f]"
Text item=TeslaChargingState label="Charging State [%s]"
Text item=TeslaChargeRate label="Charge Rate [%s]"
Text item=TeslaScheduledChargingStart label="Charging Start [%1$td.%1$tm.%1$tY %1$tT]"
Text item=TeslaTimeToFullCharge label="Time To Full Charge [%.1f hours]"
}
}
Text item=TeslaUsableBatteryLevel label="Car" icon="tesla" valuecolor=[<=20="red",>60="green"]
{
Frame
{
Text item=TeslaEventstamp icon="time"
Text item=TeslaState label="State [%s]" icon=""
Text item=TeslaHomelink label="Homelink Available[%s]" icon=""
Text item=TeslaDistance
Text item=TeslaSpeed label="Speed [%.1f]"
Text item=TeslaShiftState label="Shift State [%s]" icon=""
Text item=nTeslaShiftState
Text item=TeslaOdometer label="Odometer [%.1f miles]"
Text item=TeslaRange
}
Frame
{
Switch item=TeslaAutoconditioning label="Enable Heat or AC"
Setpoint item=TeslaTemperature step=0.5 minValue=65 maxValue=78 label="Auto Conditioning Temperature [%.1f °F]"
Text item=TeslaInsideTemperature label="Inside Temperature [%.1f °F]" valuecolor=[<=32="blue",>95="red"]
Text item=TeslaOutsideTemperature label="Outside Temperature [%.1f °F]" valuecolor=[<=32="blue",>95="red"]
}
Frame
{
Text item=TeslaBatteryLevel
Text item=TeslaUsableBatteryLevel
Text item=TeslaPower
Text item=TeslaBatteryCurrent label="Current [%.1f]"
Text item=TeslaBatteryRange label="Battery Range [%.1f miles]"
Text item=TeslaEstBatteryRange label="Battery Est Range [%.1f miles]"
Text item=TeslaIdealBatteryRange label="Battery Ideal Range [%.1f miles]"
}
Frame
{
Switch item=TeslaCharge label="Charge"
Slider item=TeslaChargeLimit label="Charge Limit [%.1f]"
Text item=TeslaChargingState label="Charging State [%s]" icon=""
Text item=TeslaTimeToFullCharge label="Time To Full Charge [%.1f hours]"
Text item=TeslaPreconditioning label="Preconditioning [%s]" icon=""
Text item=TeslaChargeRate label="Charge Rate [%d miles/hr]"
Text item=TeslaScheduledChargingStart icon="time"
Text item=TeslaChargerVoltage label="Charge Voltage [%.1f V]"
Text item=TeslaChargerPower label="Charge Power [%.1f kW]"
Text item=TeslaChargerCurrent label="Charge Current [%.1f A]"
Text item=TeslaChargeToMax label="Charge To Max [%s]" icon=""
Text item=TeslaMaxCharges label="Consec Max Charge[%d]"
}
Frame
{
Switch item=TeslaWakeup label="Wakeup the Car"
}
Frame
{
Switch item=TeslaDoorLock label="Doorlock"
Switch item=TeslaHorn label="Horn"
Switch item=TeslaLights label="Lights"
Switch item=TeslaStart label="Remote Start"
Switch item=TeslaValet label="Valet Mode"
Switch item=TeslaSentry label="Sentry Mode"
Switch item=TeslaBatteryHeater label="Battery Heater"
Switch item=TeslaFrontDefrost label="Defrost Front"
Switch item=TeslaRearDefrost label="Defrost Rear"
Switch item=TeslaLeftSeatHeater label="Seat Heat Left"
Switch item=TeslaRightSeatHeater label="Seat Heat Right"
}
Frame
{
Switch label="State" item=nTeslaState_chart icon=line mappings=[0="Hide", 1="Hour", 2="Day", 3="Week", 4="Month"]
Chart item=nTeslaState period=h refresh=30000 visibility=[nTeslaState_chart==1]
Chart item=nTeslaState period=D refresh=30000 visibility=[nTeslaState_chart==2]
Chart item=nTeslaState period=W refresh=30000 visibility=[nTeslaState_chart==3]
Chart item=nTeslaState period=M refresh=30000 visibility=[nTeslaState_chart==4]
}
Frame
{
Switch label="Battery" item=TeslaBatteryLevel_chart icon=line mappings=[0="Hide", 1="Hour", 2="Day", 3="Week", 4="Month"]
Chart item=TeslaUsableBatteryLevel period=h refresh=30000 visibility=[TeslaBatteryLevel_chart==1]
Chart item=TeslaUsableBatteryLevel period=D refresh=30000 visibility=[TeslaBatteryLevel_chart==2]
Chart item=TeslaUsableBatteryLevel period=W refresh=30000 visibility=[TeslaBatteryLevel_chart==3]
Chart item=TeslaUsableBatteryLevel period=M refresh=30000 visibility=[TeslaBatteryLevel_chart==4]
}
Frame
{
Mapview item=TeslaLocation height=10 icon=location
}
}
}
```
demo.rule (for graphing online status in sitemap above)
```
rule "Tesla State Changed"
when
Item TeslaState changed
then
if (previousState == NULL) return;
switch (TeslaState.state) {
case "online" : {
nTeslaState.postUpdate(1)
}
case "asleep" : {
nTeslaState.postUpdate(0)
}
case "offline" : {
nTeslaState.postUpdate(-0.5)
}
case "waking" : {
nTeslaState.postUpdate(0.5)
}
case "unknown" : {
nTeslaState.postUpdate(-1)
}
}
end
```

View File

@ -112,4 +112,7 @@ public class TeslaBindingConstants {
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_INACTIVITY = "inactivity";
public static final String CONFIG_USEDRIVESTATE = "useDriveState";
public static final String CONFIG_USEDADVANCEDSTATES = "useAdvancedStatesForPolling";
}

View File

@ -110,7 +110,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
@Override
public void initialize() {
logger.trace("Initializing the Tesla account handler for {}", this.getStorageKey());
logger.debug("Initializing the Tesla account handler for {}", this.getStorageKey());
updateStatus(ThingStatus.UNKNOWN);
@ -129,7 +129,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
@Override
public void dispose() {
logger.trace("Disposing the Tesla account handler for {}", getThing().getUID());
logger.debug("Disposing the Tesla account handler for {}", getThing().getUID());
lock.lock();
try {
@ -256,16 +256,19 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
TokenResponse token = logonToken;
boolean hasExpired = true;
logger.debug("Current authentication time {}", dateFormatter.format(Instant.now()));
if (token != null) {
Instant tokenCreationInstant = Instant.ofEpochMilli(token.created_at * 1000);
logger.debug("Found a request token created at {}", dateFormatter.format(tokenCreationInstant));
Instant tokenExpiresInstant = Instant.ofEpochMilli(token.created_at * 1000 + 60 * token.expires_in);
Instant tokenExpiresInstant = Instant.ofEpochMilli((token.created_at + token.expires_in) * 1000);
logger.debug("Found a request token from {}", dateFormatter.format(tokenCreationInstant));
logger.debug("Access token expiration time {}", dateFormatter.format(tokenExpiresInstant));
if (tokenExpiresInstant.isBefore(Instant.now())) {
logger.debug("The token has expired at {}", dateFormatter.format(tokenExpiresInstant));
logger.debug("The access token has expired");
hasExpired = true;
} else {
logger.debug("The access token has not expired yet");
hasExpired = false;
}
}

View File

@ -15,6 +15,8 @@ package org.openhab.binding.tesla.internal.handler;
import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -44,6 +46,8 @@ public class TeslaSSOHandler {
private final HttpClient httpClient;
private final Gson gson = new Gson();
private final Logger logger = LoggerFactory.getLogger(TeslaSSOHandler.class);
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
public TeslaSSOHandler(HttpClient httpClient) {
this.httpClient = httpClient;
@ -70,6 +74,8 @@ public class TeslaSSOHandler {
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, dateFormatter
.format(Instant.ofEpochMilli((tokenResponse.created_at + tokenResponse.expires_in) * 1000)));
return tokenResponse;
} else {
logger.debug("An error occurred while exchanging SSO auth token for API access token.");

View File

@ -89,7 +89,8 @@ 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 = 5;
private static final int MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT = 5;
private static final int THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES = 60;
private static final int EVENT_MAXIMUM_ERRORS_IN_INTERVAL = 10;
private static final int EVENT_ERROR_INTERVAL_SECONDS = 15;
private static final int EVENT_STREAM_PAUSE = 3000;
@ -111,18 +112,26 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected boolean allowWakeUp;
protected boolean allowWakeUpForCommands;
protected boolean enableEvents = false;
protected boolean useDriveState = false;
protected boolean useAdvancedStates = false;
protected boolean lastValidDriveStateNotNull = true;
protected long lastTimeStamp;
protected long apiIntervalTimestamp;
protected int apiIntervalErrors;
protected long eventIntervalTimestamp;
protected int eventIntervalErrors;
protected int inactivity = MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT;
protected ReentrantLock lock;
protected double lastLongitude;
protected double lastLatitude;
protected long lastLocationChangeTimestamp;
protected long lastDriveStateChangeToNullTimestamp;
protected long lastAdvModesTimestamp = System.currentTimeMillis();
protected long lastStateTimestamp = System.currentTimeMillis();
protected int backOffCounter = 0;
protected String lastState = "";
protected boolean isInactive = false;
@ -150,6 +159,12 @@ public class TeslaVehicleHandler extends BaseThingHandler {
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();
lock = new ReentrantLock();
@ -535,17 +550,79 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected boolean isInactive() {
// vehicle is inactive in case
// - it does not charge
// - it has not moved in the observation period
return isInactive && !isCharging() && !hasMovedInSleepInterval();
// - it has not moved or optionally stopped reporting drive state, in the observation period
// - it is not in dog, camp, keep, sentry or any other mode that keeps it online
return isInactive && !isCharging() && !notReadyForSleep();
}
protected boolean isCharging() {
return chargeState != null && "Charging".equals(chargeState.charging_state);
}
protected boolean hasMovedInSleepInterval() {
return lastLocationChangeTimestamp > (System.currentTimeMillis()
- (MOVE_THRESHOLD_INTERVAL_MINUTES * 60 * 1000));
protected boolean notReadyForSleep() {
boolean status;
int computedInactivityPeriod = inactivity;
if (useAdvancedStates) {
if (vehicleState.is_user_present && !isInMotion()) {
logger.debug("Car is occupied but stationary.");
if (lastAdvModesTimestamp < (System.currentTimeMillis()
- (THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES * 60 * 1000))) {
logger.debug("Ignoring after {} minutes.", THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES);
} else {
return (backOffCounter++ % 6 == 0); // using 6 should make sure 1 out of 5 pollers get serviced,
// about every min.
}
} else if (vehicleState.sentry_mode) {
logger.debug("Car is in sentry mode.");
if (lastAdvModesTimestamp < (System.currentTimeMillis()
- (THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES * 60 * 1000))) {
logger.debug("Ignoring after {} minutes.", THRESHOLD_INTERVAL_FOR_ADVANCED_MINUTES);
} else {
return (backOffCounter++ % 6 == 0);
}
} else if ((vehicleState.center_display_state != 0) && (!isInMotion())) {
logger.debug("Car is in camp, climate keep, dog, or other mode preventing sleep. Mode {}",
vehicleState.center_display_state);
return (backOffCounter++ % 6 == 0);
} else {
lastAdvModesTimestamp = System.currentTimeMillis();
}
}
if (vehicleState.homelink_nearby) {
computedInactivityPeriod = MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT;
logger.debug("Car is at home. Movement or drive state threshold is {} min.",
MOVE_THRESHOLD_INTERVAL_MINUTES_DEFAULT);
}
if (useDriveState) {
if (driveState.shift_state != null) {
logger.debug("Car drive state not null and not ready to sleep.");
return true;
} else {
status = lastDriveStateChangeToNullTimestamp > (System.currentTimeMillis()
- (computedInactivityPeriod * 60 * 1000));
if (status) {
logger.debug("Drivestate is null but has changed recently, therefore continuing to poll.");
return status;
} else {
logger.debug("Drivestate has changed to null after interval {} min and can now be put to sleep.",
computedInactivityPeriod);
return status;
}
}
} else {
status = lastLocationChangeTimestamp > (System.currentTimeMillis()
- (computedInactivityPeriod * 60 * 1000));
if (status) {
logger.debug("Car has moved recently and can not sleep");
return status;
} else {
logger.debug("Car has not moved in {} min, and can sleep", computedInactivityPeriod);
return status;
}
}
}
protected boolean allowQuery() {
@ -555,6 +632,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected void setActive() {
isInactive = false;
lastLocationChangeTimestamp = System.currentTimeMillis();
lastDriveStateChangeToNullTimestamp = System.currentTimeMillis();
lastLatitude = 0;
lastLongitude = 0;
}
@ -762,9 +840,6 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected void queryVehicleAndUpdate() {
vehicle = queryVehicle();
if (vehicle != null) {
parseAndUpdate("queryVehicle", null, vehicleJSON);
}
}
public void parseAndUpdate(String request, String payLoad, String result) {
@ -788,6 +863,16 @@ public class TeslaVehicleHandler extends BaseThingHandler {
lastLongitude = driveState.longitude;
lastLocationChangeTimestamp = System.currentTimeMillis();
}
logger.trace("Drive state: {}", driveState.shift_state);
if ((driveState.shift_state == null) && (lastValidDriveStateNotNull)) {
logger.debug("Set NULL shiftstate time");
lastValidDriveStateNotNull = false;
lastDriveStateChangeToNullTimestamp = System.currentTimeMillis();
} else if (driveState.shift_state != null) {
logger.trace("Clear NULL shiftstate time");
lastValidDriveStateNotNull = true;
}
break;
}
@ -817,6 +902,18 @@ public class TeslaVehicleHandler extends BaseThingHandler {
break;
}
case "queryVehicle": {
if (vehicle != null) {
logger.debug("Vehicle state is {}", vehicle.state);
} else {
logger.debug("Vehicle state is initializing or unknown");
break;
}
if (vehicle != null && "asleep".equals(vehicle.state)) {
logger.debug("Vehicle is asleep.");
break;
}
if (vehicle != null && !lastState.equals(vehicle.state)) {
lastState = vehicle.state;
@ -824,6 +921,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
if (isAwake()) {
logger.debug("Vehicle is now awake, updating all data");
lastLocationChangeTimestamp = System.currentTimeMillis();
lastDriveStateChangeToNullTimestamp = System.currentTimeMillis();
requestAllData();
}
@ -837,7 +935,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
setActive();
} else {
boolean wasInactive = isInactive;
isInactive = !isCharging() && !hasMovedInSleepInterval();
isInactive = !isCharging() && !notReadyForSleep();
if (!wasInactive && isInactive) {
lastStateTimestamp = System.currentTimeMillis();
@ -967,7 +1065,6 @@ public class TeslaVehicleHandler extends BaseThingHandler {
protected Runnable slowStateRunnable = () -> {
try {
queryVehicleAndUpdate();
boolean allowQuery = allowQuery();
if (allowQuery) {
@ -980,7 +1077,9 @@ public class TeslaVehicleHandler extends BaseThingHandler {
wakeUp();
} else {
if (isAwake()) {
logger.debug("Vehicle is neither charging nor moving, skipping updates to allow it to sleep");
logger.debug("slowpoll: Throttled to allow sleep, occupied/idle, or in a console mode");
} else {
lastAdvModesTimestamp = System.currentTimeMillis();
}
}
}
@ -1001,7 +1100,7 @@ public class TeslaVehicleHandler extends BaseThingHandler {
wakeUp();
} else {
if (isAwake()) {
logger.debug("Vehicle is neither charging nor moving, skipping updates to allow it to sleep");
logger.debug("fastpoll: Throttled to allow sleep, occupied/idle, or in a console mode");
}
}
}

View File

@ -23,12 +23,14 @@ 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;

View File

@ -132,6 +132,7 @@
<parameter name="allowWakeup" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up</label>
<advanced>true</advanced>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
@ -143,8 +144,28 @@
<parameter name="enableEvents" type="boolean" required="false">
<default>false</default>
<label>Enable Events</label>
<advanced>true</advanced>
<description>Enable the event stream for the vehicle</description>
</parameter>
<parameter name="inactivity" type="integer" min="5" required="false">
<label>Inactivity Interval</label>
<advanced>true</advanced>
<description>The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.</description>
<default>5</default>
</parameter>
<parameter name="useDriveState" type="boolean" required="false">
<default>false</default>
<label>Use Drive State for Inactivity</label>
<advanced>true</advanced>
<description>Use the drive state instead of location to determine vehicle inactivity.</description>
</parameter>
<parameter name="useAdvancedStatesForPolling" type="boolean" required="false">
<default>false</default>
<label>Use Console Modes and Occupancy for Inactivity</label>
<advanced>true</advanced>
<description>Use these states to help continue the fast polling of the API. Do not back off polling if in these
states.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -139,6 +139,7 @@
<parameter name="allowWakeup" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up</label>
<advanced>true</advanced>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
@ -150,8 +151,28 @@
<parameter name="enableEvents" type="boolean" required="false">
<default>false</default>
<label>Enable Events</label>
<advanced>true</advanced>
<description>Enable the event stream for the vehicle</description>
</parameter>
<parameter name="inactivity" type="integer" min="5" required="false">
<label>Inactivity Interval</label>
<advanced>true</advanced>
<description>The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.</description>
<default>5</default>
</parameter>
<parameter name="useDriveState" type="boolean" required="false">
<default>false</default>
<label>Use Drive State for Inactivity</label>
<advanced>true</advanced>
<description>Use the drive state instead of location to determine vehicle inactivity.</description>
</parameter>
<parameter name="useAdvancedStatesForPolling" type="boolean" required="false">
<default>false</default>
<label>Use Console Modes and Occupancy for Inactivity</label>
<advanced>true</advanced>
<description>Use these states to help continue the fast polling of the API. Do not back off polling if in these
states.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -139,6 +139,7 @@
<parameter name="allowWakeup" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up</label>
<advanced>true</advanced>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
@ -150,8 +151,28 @@
<parameter name="enableEvents" type="boolean" required="false">
<default>false</default>
<label>Enable Events</label>
<advanced>true</advanced>
<description>Enable the event stream for the vehicle</description>
</parameter>
<parameter name="inactivity" type="integer" min="5" required="false">
<label>Inactivity Interval</label>
<advanced>true</advanced>
<description>The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.</description>
<default>5</default>
</parameter>
<parameter name="useDriveState" type="boolean" required="false">
<default>false</default>
<label>Use Drive State for Inactivity</label>
<advanced>true</advanced>
<description>Use the drive state instead of location to determine vehicle inactivity.</description>
</parameter>
<parameter name="useAdvancedStatesForPolling" type="boolean" required="false">
<default>false</default>
<label>Use Console Modes and Occupancy for Inactivity</label>
<advanced>true</advanced>
<description>Use these states to help continue the fast polling of the API. Do not back off polling if in these
states.</description>
</parameter>
</config-description>
</thing-type>

View File

@ -134,6 +134,7 @@
<parameter name="allowWakeup" type="boolean" required="false">
<default>false</default>
<label>Allow Wake-Up</label>
<advanced>true</advanced>
<description>Allows waking up the vehicle. Caution: This can result in huge vampire drain!</description>
</parameter>
<parameter name="allowWakeupForCommands" type="boolean" required="false">
@ -145,8 +146,28 @@
<parameter name="enableEvents" type="boolean" required="false">
<default>false</default>
<label>Enable Events</label>
<advanced>true</advanced>
<description>Enable the event stream for the vehicle</description>
</parameter>
<parameter name="inactivity" type="integer" min="5" required="false">
<label>Inactivity Interval</label>
<advanced>true</advanced>
<description>The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.</description>
<default>5</default>
</parameter>
<parameter name="useDriveState" type="boolean" required="false">
<default>false</default>
<label>Use Drive State for Inactivity</label>
<advanced>true</advanced>
<description>Use the drive state instead of location to determine vehicle inactivity.</description>
</parameter>
<parameter name="useAdvancedStatesForPolling" type="boolean" required="false">
<default>false</default>
<label>Use Console Modes and Occupancy for Inactivity</label>
<advanced>true</advanced>
<description>Use these states to help continue the fast polling of the API. Do not back off polling if in these
states.</description>
</parameter>
</config-description>
</thing-type>