[tesla] Adapt binding to changed API from Tesla backend (#14924)

* Adapt binding to changed API from Tesla backend
* Add new translations and vehicle thing type

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer 2023-05-03 20:39:05 +02:00 committed by GitHub
parent 91450d0708
commit bf2ce7b418
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 881 additions and 762 deletions

View File

@ -22,10 +22,11 @@ Access is established through a Tesla account as a bridge.
The account cannot be automatically discovered, but has to be created manually.
Once an account is configured, it is automatically queried for associated vehicles and an Inbox entry is created for each of them.
Note: Vehicles that are asleep might not be discovered, so you might want to wake it up through the Tesla app first.
Once an account is configured, it is queried for associated vehicles and an Inbox entry is created for each of them.
Note: Vehicles that are asleep are discovered and put into the Inbox, but their model cannot be determined.
As an effect, their channels are missing until the vehicle wakes up and can be fully queried.
A vehicle can be manually woken up by opening the Tesla app and checking the vehicle status in there.
## Bridge Configuration
@ -40,7 +41,6 @@ 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 Parameters
The vehicle Thing requires the vehicle's VIN as a configuration parameter `vin`.
@ -52,8 +52,7 @@ Additionally, the follow optional parameters may be defined.
| 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.
For further flexibility and experimentation, the following advanced parameters may also be set.
| Parameter Name | Label | Default Value | Description |
|-----------------------------|------------------------------------------------|---------------|----------------------------------------------------------------------------------------------------|
@ -64,13 +63,12 @@ For further flexibility and experimentation, the following advanced parameters m
| 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).
This setting is not recommended as it will result in a significant vampire drain (i.e. energy consumption although the vehicle is parking).
`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
All vehicles support a huge number of channels - the following list shows the standard ones:
@ -88,7 +86,6 @@ All vehicles support a huge number of channels - the following list shows the st
| odometer | Number:Length | Odometer | Odometer of the vehicle |
| speed | Number:Speed | Speed | Vehicle speed |
Additionally, these advanced channels are available (not all are available on all vehicle types, e.g., the sunroof):
| Channel ID | Item Type | Label | Description |
@ -100,7 +97,7 @@ Additionally, these advanced channels are available (not all are available on al
| batteryheaternopower | Switch | Battery Heater Power | Indicates if there is enough power to use the battery heater |
| batteryrange | Number:Length | Battery Range | Range of the battery |
| calendarenabled | Switch | Calendar Enabled | Indicates if access to a remote calendar is enabled |
| centerdisplay | Number | Central Display State | Indicates the state of the central display in the vehicle, see [here](https://tesla-api.timdorr.com/vehicle/state/vehiclestate) for valid values |
| centerdisplay | Number | Central Display State | Indicates the state of the central display in the vehicle, see [here](https://tesla-api.timdorr.com/vehicle/state/vehiclestate) for valid values |
| centerrearseatheater | Switch | Center Rear Seat Heater | Indicates if the center rear seat heater is switched on |
| charge | Switch | Charge | Start (ON) or stop (OFF) charging |
| chargecable | String | Charge Cable | Undocumented / To be defined |
@ -195,13 +192,11 @@ Additionally, these advanced channels are available (not all are available on al
| wakeup | Switch | Wake Up | Wake up the vehicle from a (deep) sleep |
| wiperbladeheater | Switch | Wiperblade Heater | Indicates if the wiperblade heater is switched on |
## Example
demo.Things:
```
```java
Bridge tesla:account:myaccount "My Tesla Account" [ refreshToken="xxxx" ] {
model3 mycar "My favorite car" [ vin="5YJSA7H25FFP53736"]
}
@ -209,70 +204,70 @@ Bridge tesla:account:myaccount "My Tesla Account" [ refreshToken="xxxx" ] {
demo.items:
```
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"}
```java
DateTime TeslaEventstamp {channel="account:model3:myaccount:mycar:eventstamp"}
String TeslaState {channel="account:model3:myaccount:mycar:state"}
Number TeslaSpeed {channel="account:model3:myaccount:mycar:speed"}
String TeslaShiftState {channel="account:model3:myaccount:mycar:shiftstate"}
Number TeslaOdometer {channel="account:model3:myaccount:mycar:odometer"}
Number TeslaRange {channel="account: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"}
Number TeslaBatteryLevel {channel="account:model3:myaccount:mycar:batterylevel"}
Number TeslaPower {channel="account:model3:myaccount:mycar:power"}
Number TeslaBatteryCurrent {channel="account:model3:myaccount:mycar:batterycurrent"}
Number TeslaBatteryRange {channel="account:model3:myaccount:mycar:batteryrange"}
Number TeslaEstBatteryRange {channel="account:model3:myaccount:mycar:estimatedbatteryrange"}
Number TeslaIdealBatteryRange {channel="account:model3:myaccount:mycar:idealbatteryrange"}
Number TeslaUsableBatteryLevel {channel="account:model3:myaccount:mycar:usablebatterylevel"}
Switch TeslaPreconditioning {channel="account:model3:myaccount:mycar:preconditioning"}
Switch TeslaCharge {channel="model3:myaccount:mycar:charge"}
Switch TeslaChargeToMax {channel="model3:myaccount:mycar:chargetomax"}
Switch TeslaCharge {channel="account:model3:myaccount:mycar:charge"}
Switch TeslaChargeToMax {channel="account: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"}
Dimmer TeslaChargeLimit {channel="account:model3:myaccount:mycar:chargelimit"}
Number TeslaChargeRate {channel="account:model3:myaccount:mycar:chargerate"}
String TeslaChargingState {channel="account:model3:myaccount:mycar:chargingstate"}
Number TeslaChargerPower {channel="account:model3:myaccount:mycar:chargerpower"}
Number TeslaTimeToFullCharge {channel="account:model3:myaccount:mycar:timetofullcharge"}
Number TeslaMaxCharges {channel="account: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"}
Number TeslaChargerVoltage {channel="account:model3:myaccount:mycar:chargervoltage"}
Number TeslaChargerPower {channel="account:model3:myaccount:mycar:chargerpower"}
Number TeslaChargerCurrent {channel="account:model3:myaccount:mycar:chargercurrent"}
DateTime TeslaScheduledChargingStart {channel="model3:myaccount:mycar:scheduledchargingstart"}
Dimmer TeslaSoC {channel="model3:myaccount:mycar:soc"}
DateTime TeslaScheduledChargingStart {channel="account:model3:myaccount:mycar:scheduledchargingstart"}
Dimmer TeslaSoC {channel="account: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 TeslaDoorLock {channel="account:model3:myaccount:mycar:doorlock"}
Switch TeslaHorn {channel="account:model3:myaccount:mycar:honkhorn"}
Switch TeslaStart {channel="account:model3:myaccount:mycar:remotestart"}
Switch TeslaSentry {channel="account:model3:myaccount:mycar:sentrymode"}
Switch TeslaLights {channel="account:model3:myaccount:mycar:flashlights"}
Switch TeslaValet {channel="account:model3:myaccount:mycar:valetmode"}
Switch TeslaWakeup {channel="model3:myaccount:mycar:wakeup"}
Switch TeslaWakeup {channel="account: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 TeslaBatteryHeater {channel="account:model3:myaccount:mycar:batteryheater"}
Switch TeslaFrontDefrost {channel="account:model3:myaccount:mycar:frontdefroster"}
Switch TeslaRearDefrost {channel="account:model3:myaccount:mycar:reardefroster"}
Switch TeslaLeftSeatHeater {channel="account:model3:myaccount:mycar:leftseatheater"}
Switch TeslaRightSeatHeater {channel="account: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 TeslaHomelink {channel="account:model3:myaccount:mycar:homelink"}
Location TeslaLocation {channel="account:model3:myaccount:mycar:location"}
Number TeslaHeading {channel="account:model3:myaccount:mycar:heading"}
DateTime TeslaLocationTime {channel="account: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"}
Switch TeslaAutoconditioning {channel="account:model3:myaccount:mycar:autoconditioning"}
Number:Temperature TeslaTemperature {channel="account:model3:myaccount:mycar:temperature"}
Number:Temperature TeslaTemperatureCombined {channel="account:model3:myaccount:mycar:combinedtemp"}
Number:Temperature TeslaInsideTemperature {channel="account:model3:myaccount:mycar:insidetemp"}
Number:Temperature TeslaOutsideTemperature {channel="account:model3:myaccount:mycar:outsidetemp"}
```
demo.sitemap:
```
```perl
sitemap main label="Main"
{
Text item=TeslaUsableBatteryLevel label="Car" icon="tesla" valuecolor=[<=20="red",>60="green"]
@ -342,23 +337,7 @@ sitemap main label="Main"
}
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
Mapview item=TeslaLocation height=10
}
}
}
@ -366,7 +345,7 @@ sitemap main label="Main"
demo.rule (for graphing online status in sitemap above)
```
```java
rule "Tesla State Changed"
when
Item TeslaState changed

View File

@ -28,7 +28,7 @@ public class TeslaBindingConstants {
public static final String API_NAME = "Tesla Client API";
public static final String API_VERSION = "api/1/";
public static final String PATH_COMMAND = "command/{cmd}";
public static final String PATH_DATA_REQUEST = "data_request/{cmd}";
public static final String PATH_DATA_REQUEST = "vehicle_data";
public static final String PATH_VEHICLE_ID = "/{vid}/";
public static final String PATH_WAKE_UP = "wake_up";
public static final String PATH_ACCESS_TOKEN = "oauth/token";
@ -71,19 +71,11 @@ public class TeslaBindingConstants {
public static final String COMMAND_WAKE_UP = "wake_up";
public static final String DATA_THROTTLE = "datathrottle";
// Tesla REST API vehicle states
public static final String CHARGE_STATE = "charge_state";
public static final String CLIMATE_STATE = "climate_state";
public static final String DRIVE_STATE = "drive_state";
public static final String GUI_STATE = "gui_settings";
public static final String MOBILE_ENABLED_STATE = "mobile_enabled";
public static final String VEHICLE_STATE = "vehicle_state";
public static final String VEHICLE_CONFIG = "vehicle_config";
public static final String BINDING_ID = "tesla";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
public static final ThingTypeUID THING_TYPE_VEHICLE = new ThingTypeUID(BINDING_ID, "vehicle");
public static final ThingTypeUID THING_TYPE_MODELS = new ThingTypeUID(BINDING_ID, "models");
public static final ThingTypeUID THING_TYPE_MODEL3 = new ThingTypeUID(BINDING_ID, "model3");
public static final ThingTypeUID THING_TYPE_MODELX = new ThingTypeUID(BINDING_ID, "modelx");

View File

@ -48,10 +48,10 @@ public class TeslaChannelSelectorProxy {
AUTO_COND("is_auto_conditioning_on", "autoconditioning", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -64,10 +64,10 @@ public class TeslaChannelSelectorProxy {
BATTERY_HEATER("battery_heater_on", "batteryheater", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -76,10 +76,10 @@ public class TeslaChannelSelectorProxy {
BATTERY_HEATER_NO_POWER("battery_heater_no_power", "batteryheaternopower", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -97,10 +97,10 @@ public class TeslaChannelSelectorProxy {
CALENDAR_SUPPORTED("calendar_supported", "calendarsupported", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -109,10 +109,10 @@ public class TeslaChannelSelectorProxy {
CALENDAR_ENABLED("calendar_enabled", "calendarenabled", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -123,10 +123,10 @@ public class TeslaChannelSelectorProxy {
CHARGE(null, "charge", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -138,10 +138,10 @@ public class TeslaChannelSelectorProxy {
CHARGE_ENABLE_REQUEST("charge_enable_request", "chargeenablerequest", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -184,10 +184,10 @@ public class TeslaChannelSelectorProxy {
CHARGE_TO_MAX("charge_to_max_range", "chargetomax", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -197,10 +197,10 @@ public class TeslaChannelSelectorProxy {
CHARGEPORT("charge_port_door_open", "chargeport", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -214,10 +214,10 @@ public class TeslaChannelSelectorProxy {
CLIMATE_ON("is_climate_on", "climate", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -229,10 +229,10 @@ public class TeslaChannelSelectorProxy {
DARK_RIMS("dark_rims", "darkrims", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -242,10 +242,10 @@ public class TeslaChannelSelectorProxy {
DF("df", "driverfrontdoor", OpenClosedType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("OPEN");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("CLOSED");
}
return super.getState(s);
@ -254,10 +254,10 @@ public class TeslaChannelSelectorProxy {
DOOR_LOCK("locked", "doorlock", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -266,10 +266,10 @@ public class TeslaChannelSelectorProxy {
DR("dr", "driverreardoor", OpenClosedType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("OPEN");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("CLOSED");
}
return super.getState(s);
@ -319,10 +319,10 @@ public class TeslaChannelSelectorProxy {
EU_VEHICLE("eu_vehicle", "european", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -332,10 +332,10 @@ public class TeslaChannelSelectorProxy {
FAST_CHARGER("fast_charger_present", "fastcharger", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -346,10 +346,10 @@ public class TeslaChannelSelectorProxy {
FLASH(null, "flashlights", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -358,10 +358,10 @@ public class TeslaChannelSelectorProxy {
FRONT_DEFROSTER("is_front_defroster_on", "frontdefroster", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -370,10 +370,10 @@ public class TeslaChannelSelectorProxy {
FT("ft", "fronttrunk", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -397,10 +397,10 @@ public class TeslaChannelSelectorProxy {
HAS_SPOILER("has_spoiler", "spoiler", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -417,10 +417,10 @@ public class TeslaChannelSelectorProxy {
HONK_HORN(null, "honkhorn", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -429,10 +429,10 @@ public class TeslaChannelSelectorProxy {
HOMELINK_NEARBY("homelink_nearby", "homelink", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -491,10 +491,10 @@ public class TeslaChannelSelectorProxy {
MANAGED_CHARGING("managed_charging_active", "managedcharging", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true")) {
if ("true".equals(s)) {
return super.getState("ON");
}
if (s.equals("false")) {
if ("false".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -504,23 +504,23 @@ public class TeslaChannelSelectorProxy {
false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true")) {
if ("true".equals(s)) {
return super.getState("ON");
}
if (s.equals("false")) {
if ("false".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
}
},
MANAGED_CHARGING_START("managed_charging_start_time", "managedchargingstart", StringType.class, false),
MOBILE_ENABLED(TeslaBindingConstants.MOBILE_ENABLED_STATE, "mobileenabled", OnOffType.class, false) {
MOBILE_ENABLED("mobile_enabled", "mobileenabled", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true")) {
if ("true".equals(s)) {
return super.getState("ON");
}
if (s.equals("false")) {
if ("false".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -529,10 +529,10 @@ public class TeslaChannelSelectorProxy {
MOTORIZED_CHARGE_PORT("motorized_charge_port", "motorizedchargeport", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -555,10 +555,10 @@ public class TeslaChannelSelectorProxy {
NATIVE_LOCATION_SUPPORTED("native_location_supported", "nativelocationsupported", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -568,10 +568,10 @@ public class TeslaChannelSelectorProxy {
NOT_ENOUGH_POWER_TO_HEAT("not_enough_power_to_heat", "notenoughpower", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -580,10 +580,10 @@ public class TeslaChannelSelectorProxy {
NOTIFICATIONS_ENABLED("notifications_enabled", "notificationsenabled", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -592,10 +592,10 @@ public class TeslaChannelSelectorProxy {
NOTIFICATIONS_SUPPORTED("notifications_supported", "notificationssupported", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -612,10 +612,10 @@ public class TeslaChannelSelectorProxy {
OPEN_FRUNK(null, "openfrunk", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -624,10 +624,10 @@ public class TeslaChannelSelectorProxy {
OPEN_TRUNK(null, "opentrunk", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -645,10 +645,10 @@ public class TeslaChannelSelectorProxy {
PARSED_CALENDAR("parsed_calendar_supported", "parsedcalendar", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -666,10 +666,10 @@ public class TeslaChannelSelectorProxy {
PF("pf", "passengerfrontdoor", OpenClosedType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("OPEN");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("CLOSED");
}
return super.getState(s);
@ -679,10 +679,10 @@ public class TeslaChannelSelectorProxy {
PR("pr", "passengerreardoor", OpenClosedType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("OPEN");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("CLOSED");
}
return super.getState(s);
@ -691,10 +691,10 @@ public class TeslaChannelSelectorProxy {
PRECONDITIONING("is_preconditioning", "preconditioning", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -705,7 +705,7 @@ public class TeslaChannelSelectorProxy {
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
State someState = super.getState(s);
BigDecimal value = ((DecimalType) someState).toBigDecimal();
if (properties.containsKey("distanceunits") && properties.get("distanceunits").equals("km/hr")) {
if (properties.containsKey("distanceunits") && "km/hr".equals(properties.get("distanceunits"))) {
return new QuantityType<>(value, MetricPrefix.KILO(SIUnits.METRE));
} else {
return new QuantityType<>(value, ImperialUnits.MILE);
@ -715,10 +715,10 @@ public class TeslaChannelSelectorProxy {
REAR_DEFROSTER("is_rear_defroster_on", "reardefroster", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -727,10 +727,10 @@ public class TeslaChannelSelectorProxy {
REAR_SEAT_HEATERS("rear_seat_heaters", "rearseatheaters", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -739,10 +739,10 @@ public class TeslaChannelSelectorProxy {
REMOTE_START("remote_start", "remotestart", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -751,10 +751,10 @@ public class TeslaChannelSelectorProxy {
REMOTE_START_ENABLED("remote_start_enabled", "remotestartenabled", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -763,10 +763,10 @@ public class TeslaChannelSelectorProxy {
REMOTE_START_SUPPORTED("remote_start_supported", "remotestartsupported", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -775,10 +775,10 @@ public class TeslaChannelSelectorProxy {
RESET_VALET_PIN(null, "resetvaletpin", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -787,10 +787,10 @@ public class TeslaChannelSelectorProxy {
RHD("rhd", "rhd", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -801,10 +801,10 @@ public class TeslaChannelSelectorProxy {
RT("rt", "reartrunk", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -821,10 +821,10 @@ public class TeslaChannelSelectorProxy {
SCHEDULED_CHARGING_PENDING("scheduled_charging_pending", "scheduledchargingpending", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -844,10 +844,10 @@ public class TeslaChannelSelectorProxy {
SENTRY_MODE("sentry_mode", "sentrymode", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -856,10 +856,10 @@ public class TeslaChannelSelectorProxy {
SENTRY_MODE_AVAILABLE("sentry_mode_available", "sentrymodeavailable", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -869,10 +869,10 @@ public class TeslaChannelSelectorProxy {
SIDEMIRROR_HEATING("side_mirror_heaters", "sidemirrorheaters", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -881,10 +881,10 @@ public class TeslaChannelSelectorProxy {
SMART_PRECONDITIONING("smart_preconditioning", "smartpreconditioning", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -907,10 +907,10 @@ public class TeslaChannelSelectorProxy {
STEERINGWHEEL_HEATER("steering_wheel_heater", "steeringwheelheater", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -919,10 +919,10 @@ public class TeslaChannelSelectorProxy {
SUN_ROOF_PRESENT("sun_roof_installed", "sunroofinstalled", OnOffType.class, true) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -942,7 +942,7 @@ public class TeslaChannelSelectorProxy {
TIMESTAMP("timestamp", "eventstamp", DateTimeType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
Date date = new Date(Long.valueOf(s));
Date date = new Date(Long.parseLong(s));
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
return super.getState(dateFormatter.format(date));
}
@ -950,10 +950,10 @@ public class TeslaChannelSelectorProxy {
TRIP_CARGING("trip_charging", "tripcharging", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -970,10 +970,10 @@ public class TeslaChannelSelectorProxy {
VALET_MODE("valet_mode", "valetmode", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -982,10 +982,10 @@ public class TeslaChannelSelectorProxy {
VALET_PIN("valet_pin_needed", "valetpin", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -995,10 +995,10 @@ public class TeslaChannelSelectorProxy {
WAKEUP(null, "wakeup", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -1007,10 +1007,10 @@ public class TeslaChannelSelectorProxy {
WIPERBLADE_HEATER("wiper_blade_heater", "wiperbladeheater", OnOffType.class, false) {
@Override
public State getState(String s, TeslaChannelSelectorProxy proxy, Map<String, String> properties) {
if (s.equals("true") || s.equals("1")) {
if ("true".equals(s) || "1".equals(s)) {
return super.getState("ON");
}
if (s.equals("false") || s.equals("0")) {
if ("false".equals(s) || "0".equals(s)) {
return super.getState("OFF");
}
return super.getState(s);
@ -1059,10 +1059,8 @@ public class TeslaChannelSelectorProxy {
if (state != null) {
return state;
}
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException
| InvocationTargetException e) {
}
return null;

View File

@ -27,6 +27,7 @@ import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.io.net.http.WebSocketFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeMigrationService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
@ -50,21 +51,24 @@ public class TeslaHandlerFactory extends BaseThingHandlerFactory {
private static final int EVENT_STREAM_CONNECT_TIMEOUT = 3;
private static final int EVENT_STREAM_READ_TIMEOUT = 200;
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ACCOUNT, THING_TYPE_MODELS,
THING_TYPE_MODEL3, THING_TYPE_MODELX, THING_TYPE_MODELY);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ACCOUNT, THING_TYPE_VEHICLE,
THING_TYPE_MODELS, THING_TYPE_MODEL3, THING_TYPE_MODELX, THING_TYPE_MODELY);
private final ClientBuilder clientBuilder;
private final HttpClientFactory httpClientFactory;
private final WebSocketFactory webSocketFactory;
private final ThingTypeMigrationService thingTypeMigrationService;
@Activate
public TeslaHandlerFactory(@Reference ClientBuilder clientBuilder, @Reference HttpClientFactory httpClientFactory,
final @Reference WebSocketFactory webSocketFactory) {
final @Reference WebSocketFactory webSocketFactory,
final @Reference ThingTypeMigrationService thingTypeMigrationService) {
this.clientBuilder = clientBuilder //
.connectTimeout(EVENT_STREAM_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(EVENT_STREAM_READ_TIMEOUT, TimeUnit.SECONDS);
this.httpClientFactory = httpClientFactory;
this.webSocketFactory = webSocketFactory;
this.thingTypeMigrationService = thingTypeMigrationService;
}
@Override
@ -77,7 +81,8 @@ public class TeslaHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_ACCOUNT)) {
return new TeslaAccountHandler((Bridge) thing, clientBuilder.build(), httpClientFactory);
return new TeslaAccountHandler((Bridge) thing, clientBuilder.build(), httpClientFactory,
thingTypeMigrationService);
} else {
return new TeslaVehicleHandler(thing, webSocketFactory);
}

View File

@ -81,8 +81,10 @@ public class TeslaVehicleDiscoveryService extends AbstractDiscoveryService
@Override
public void vehicleFound(Vehicle vehicle, VehicleConfig vehicleConfig) {
ThingTypeUID type = identifyModel(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, handler.getThing().getUID(), vehicle.vin);
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(vehicle.display_name)
.withBridge(handler.getThing().getUID()).withProperty(TeslaBindingConstants.VIN, vehicle.vin)
@ -90,22 +92,4 @@ public class TeslaVehicleDiscoveryService extends AbstractDiscoveryService
thingDiscovered(discoveryResult);
}
}
private ThingTypeUID identifyModel(VehicleConfig vehicleConfig) {
logger.debug("Found a {} vehicle", vehicleConfig.car_type);
switch (vehicleConfig.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:
logger.debug("Found unknown vehicle type '{}' - ignoring it.", vehicleConfig.car_type);
return null;
}
}
}

View File

@ -32,9 +32,11 @@ import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
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.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
@ -43,6 +45,7 @@ import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeMigrationService;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
@ -66,7 +69,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
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")
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
private final Logger logger = LoggerFactory.getLogger(TeslaAccountHandler.class);
@ -80,6 +83,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
final WebTarget wakeUpTarget;
private final TeslaSSOHandler ssoHandler;
private final ThingTypeMigrationService thingTypeMigrationService;
// Threading and Job related variables
protected ScheduledFuture<?> connectJob;
@ -96,10 +100,12 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
private TokenResponse logonToken;
private final Set<VehicleListener> vehicleListeners = new HashSet<>();
public TeslaAccountHandler(Bridge bridge, Client teslaClient, HttpClientFactory httpClientFactory) {
public TeslaAccountHandler(Bridge bridge, Client teslaClient, HttpClientFactory httpClientFactory,
ThingTypeMigrationService thingTypeMigrationService) {
super(bridge);
this.teslaTarget = teslaClient.target(URI_OWNERS);
this.ssoHandler = new TeslaSSOHandler(httpClientFactory.getCommonHttpClient());
this.thingTypeMigrationService = thingTypeMigrationService;
this.vehiclesTarget = teslaTarget.path(API_VERSION).path(VEHICLES);
this.vehicleTarget = vehiclesTarget.path(PATH_VEHICLE_ID);
@ -143,7 +149,7 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
}
public void scanForVehicles() {
scheduler.execute(() -> queryVehicles());
scheduler.execute(this::queryVehicles);
}
public void addVehicleListener(VehicleListener listener) {
@ -179,7 +185,6 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
ThingStatusInfo authenticationResult = authenticate();
updateStatus(authenticationResult.getStatus(), authenticationResult.getStatusDetail(),
authenticationResult.getDescription());
return false;
} else {
apiIntervalErrors++;
if (immediatelyFail || apiIntervalErrors >= API_MAXIMUM_ERRORS_IN_INTERVAL) {
@ -221,11 +226,11 @@ 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, 0);
if (responseString == null || responseString.isBlank()) {
continue;
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;
}
VehicleConfig vehicleConfig = gson.fromJson(responseString, VehicleConfig.class);
for (VehicleListener listener : vehicleListeners) {
listener.vehicleFound(vehicle, vehicleConfig);
}
@ -233,6 +238,14 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
if (vehicle.vin.equals(vehicleThing.getConfiguration().get(VIN))) {
TeslaVehicleHandler vehicleHandler = (TeslaVehicleHandler) vehicleThing.getHandler();
if (vehicleHandler != null) {
if (TeslaBindingConstants.THING_TYPE_VEHICLE.equals(vehicleThing.getThingTypeUID())
&& vehicleConfig != null) {
// Seems the type of this vehicle has not been identified before, so let's switch the
// thing type of it
thingTypeMigrationService.migrateThingType(vehicleThing, vehicleConfig.identifyModel(),
vehicleThing.getConfiguration());
break;
}
logger.debug("Querying the vehicle: VIN {}", vehicle.vin);
String vehicleJSON = gson.toJson(vehicle);
vehicleHandler.parseAndUpdate("queryVehicle", null, vehicleJSON);
@ -256,13 +269,13 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
TokenResponse token = logonToken;
boolean hasExpired = true;
logger.debug("Current authentication time {}", dateFormatter.format(Instant.now()));
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);
logger.debug("Found a request token from {}", dateFormatter.format(tokenCreationInstant));
logger.debug("Access token expiration time {}", dateFormatter.format(tokenExpiresInstant));
logger.debug("Found a request token from {}", DATE_FORMATTER.format(tokenCreationInstant));
logger.debug("Access token expiration time {}", DATE_FORMATTER.format(tokenExpiresInstant));
if (tokenExpiresInstant.isBefore(Instant.now())) {
logger.debug("The access token has expired");
@ -308,15 +321,13 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
.header("Authorization", "Bearer " + logonToken.access_token)
.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();
} else {
if (command != null) {
response = target.resolveTemplate("cmd", command).resolveTemplate("vid", vehicleId)
.request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Bearer " + logonToken.access_token).get();
} else {
response = target.resolveTemplate("vid", vehicleId).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Bearer " + logonToken.access_token).get();
}
response = target.resolveTemplate("vid", vehicleId).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Bearer " + logonToken.access_token).get();
}
if (!checkResponse(response, false)) {
@ -330,7 +341,6 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
logger.debug("Retrying to send the command {}.", command);
return invokeAndParse(vehicleId, command, payLoad, target, noOfretries - 1);
} catch (InterruptedException e) {
return null;
}
}
return null;
@ -353,8 +363,9 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
lock.lock();
ThingStatusInfo status = getThing().getStatusInfo();
if (status.getStatus() != ThingStatus.ONLINE
&& status.getStatusDetail() != ThingStatusDetail.CONFIGURATION_ERROR) {
if ((status.getStatus() != ThingStatus.ONLINE
&& status.getStatusDetail() != ThingStatusDetail.CONFIGURATION_ERROR)
|| hasUnidentifiedVehicles()) {
logger.debug("Setting up an authenticated connection to the Tesla back-end");
ThingStatusInfo authenticationResult = authenticate();
@ -394,19 +405,16 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
}
}
}
} else {
if (response != null) {
logger.error("Error fetching the list of vehicles : {}:{}", response.getStatus(),
response.getStatusInfo());
updateStatus(ThingStatus.OFFLINE);
}
} else if (response != null) {
logger.error("Error fetching the list of vehicles : {}:{}", response.getStatus(),
response.getStatusInfo());
updateStatus(ThingStatus.OFFLINE);
}
} else if (authenticationResult.getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR) {
// make sure to set thing to CONFIGURATION_ERROR in case of failed authentication in order not to
// hit request limit on retries on the Tesla SSO endpoints.
updateStatus(ThingStatus.OFFLINE, authenticationResult.getStatusDetail());
}
}
} catch (Exception e) {
logger.error("An exception occurred while connecting to the Tesla back-end: '{}'", e.getMessage(), e);
@ -415,6 +423,11 @@ public class TeslaAccountHandler extends BaseBridgeHandler {
}
};
private boolean hasUnidentifiedVehicles() {
return getThing().getThings().stream()
.anyMatch(vehicle -> TeslaBindingConstants.THING_TYPE_VEHICLE.equals(vehicle.getThingTypeUID()));
}
protected class Request implements Runnable {
private static final int NO_OF_RETRIES = 3;

View File

@ -22,7 +22,6 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.websocket.api.Session;
@ -32,6 +31,7 @@ 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.core.io.net.http.WebSocketFactory;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -54,7 +54,6 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
private String endpointId;
protected WebSocketFactory webSocketFactory;
private static final AtomicInteger INSTANCE_COUNTER = new AtomicInteger();
private WebSocketClient client;
private ConnectionState connectionState = ConnectionState.CLOSED;
@ -62,11 +61,12 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
private EventHandler eventHandler;
private final Gson gson = new Gson();
public TeslaEventEndpoint(WebSocketFactory webSocketFactory) {
public TeslaEventEndpoint(ThingUID uid, WebSocketFactory webSocketFactory) {
try {
this.endpointId = "TeslaEventEndpoint-" + INSTANCE_COUNTER.incrementAndGet();
this.endpointId = "TeslaEventEndpoint-" + uid.getAsString();
client = webSocketFactory.createWebSocketClient(endpointId);
String name = ThingWebClientUtil.buildWebClientConsumerName(uid, null);
client = webSocketFactory.createWebSocketClient(name);
this.client.setConnectTimeout(TIMEOUT_MILLISECONDS);
this.client.setMaxIdleTimeout(IDLE_TIMEOUT_MILLISECONDS);
} catch (Exception e) {
@ -74,6 +74,16 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
}
}
public void close() {
try {
if (client.isRunning()) {
client.stop();
}
} catch (Exception e) {
logger.warn("An exception occurred while stopping the WebSocket client : {}", e.getMessage());
}
}
public void connect(URI endpointURI) {
if (connectionState == ConnectionState.CONNECTED) {
return;
@ -113,7 +123,7 @@ public class TeslaEventEndpoint implements WebSocketListener, WebSocketPingPongL
this.session = session;
}
public void close() {
public void closeConnection() {
try {
connectionState = ConnectionState.CLOSING;
if (session != null && session.isOpen()) {

View File

@ -46,7 +46,7 @@ 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")
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
public TeslaSSOHandler(HttpClient httpClient) {
@ -74,7 +74,7 @@ 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
logger.debug("Access token expires in {} seconds at {}", tokenResponse.expires_in, DATE_FORMATTER
.format(Instant.ofEpochMilli((tokenResponse.created_at + tokenResponse.expires_in) * 1000)));
return tokenResponse;
} else {

View File

@ -0,0 +1,67 @@
/**
* Copyright (c) 2010-2022 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.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ThingUID;
/**
* {@link ThingWebClientUtil} provides an utility method to create a valid consumer name for web clients.
*
* @author Laurent Garnier - Initial contribution
*/
@NonNullByDefault
public class ThingWebClientUtil {
private static final int MAX_CONSUMER_NAME_LENGTH = 20;
/**
* Build a valid consumer name for HTTP or WebSocket client.
*
* @param uid thing UID for which to associate HTTP or WebSocket client
* @param prefix a prefix to consider for the name; can be null
* @return a valid consumer name
*/
public static String buildWebClientConsumerName(ThingUID uid, @Nullable String prefix) {
String pref = prefix == null ? "" : prefix;
String name = pref + uid.getAsString().replace(':', '-');
if (name.length() > MAX_CONSUMER_NAME_LENGTH) {
// Try to use only prefix + binding ID + thing ID
name = pref + uid.getBindingId();
if (name.length() > (MAX_CONSUMER_NAME_LENGTH / 2)) {
// Truncate the binding ID to keep enough place for thing ID
name = name.substring(0, MAX_CONSUMER_NAME_LENGTH / 2);
}
// Add the thing ID
String id = uid.getId();
int maxIdLength = MAX_CONSUMER_NAME_LENGTH - 1 - name.length();
if (id.length() > maxIdLength) {
// If thing ID is too big, use a hash code of the thing UID instead of thing id
// and truncate it if necessary
id = buildHashCode(uid, maxIdLength);
}
name += "-" + id;
}
return name;
}
// Make the method public just to be able to call it inside the tests
static String buildHashCode(ThingUID uid, int maxLength) {
String result = Integer.toHexString(uid.hashCode());
if (result.length() > maxLength) {
result = result.substring(result.length() - maxLength);
}
return result;
}
}

View File

@ -12,6 +12,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;
@ -21,12 +23,14 @@ import org.openhab.binding.tesla.internal.protocol.VehicleConfig;
*
* @author Kai Kreuzer - Initial contribution
*/
@NonNullByDefault
public interface VehicleListener {
/**
* This method is called by the {@link TeslaAccountHandler}, if a vehicle is identified.
*
* @param vehicle a vehicle that was found within an account.
* @param vehicleConfig vehicle configuration that was read from the vehicle or null, if not available.
*/
void vehicleFound(Vehicle vehicle, VehicleConfig vehicleConfig);
void vehicleFound(Vehicle vehicle, @Nullable VehicleConfig vehicleConfig);
}

View File

@ -12,6 +12,9 @@
*/
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
@ -41,4 +44,20 @@ public class VehicleConfig {
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;
}
}
}

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2022 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() {
}
}

View File

@ -18,12 +18,12 @@ package org.openhab.binding.tesla.internal.throttler;
* @author Karel Goderis - Initial contribution
*/
public interface TimeProvider {
public static final TimeProvider SYSTEM_PROVIDER = new TimeProvider() {
static final TimeProvider SYSTEM_PROVIDER = new TimeProvider() {
@Override
public long getCurrentTimeInMillis() {
return System.currentTimeMillis();
}
};
public long getCurrentTimeInMillis();
long getCurrentTimeInMillis();
}

View File

@ -15,6 +15,8 @@ thing-type.tesla.modelx.label = Tesla Model X
thing-type.tesla.modelx.description = A Tesla Model X Vehicle
thing-type.tesla.modely.label = Tesla Model Y
thing-type.tesla.modely.description = A Tesla Model Y Vehicle
thing-type.tesla.vehicle.label = Tesla
thing-type.tesla.vehicle.description = A Tesla Vehicle
# thing types config
@ -24,6 +26,14 @@ 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.enableEvents.label = Enable Events
thing-type.config.tesla.model3.enableEvents.description = Enable the event stream for the vehicle
thing-type.config.tesla.model3.inactivity.label = Inactivity Interval
thing-type.config.tesla.model3.inactivity.description = The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.
thing-type.config.tesla.model3.useAdvancedStatesForPolling.label = Use Console Modes and Occupancy for Inactivity
thing-type.config.tesla.model3.useAdvancedStatesForPolling.description = Use these states to help continue the fast polling of the API. Do not back off polling if in these states.
thing-type.config.tesla.model3.useDriveState.label = Use Drive State for Inactivity
thing-type.config.tesla.model3.useDriveState.description = Use the drive state instead of location to determine vehicle inactivity.
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
@ -32,6 +42,14 @@ 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.enableEvents.label = Enable Events
thing-type.config.tesla.models.enableEvents.description = Enable the event stream for the vehicle
thing-type.config.tesla.models.inactivity.label = Inactivity Interval
thing-type.config.tesla.models.inactivity.description = The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.
thing-type.config.tesla.models.useAdvancedStatesForPolling.label = Use Console Modes and Occupancy for Inactivity
thing-type.config.tesla.models.useAdvancedStatesForPolling.description = Use these states to help continue the fast polling of the API. Do not back off polling if in these states.
thing-type.config.tesla.models.useDriveState.label = Use Drive State for Inactivity
thing-type.config.tesla.models.useDriveState.description = Use the drive state instead of location to determine vehicle inactivity.
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
@ -40,6 +58,14 @@ 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.enableEvents.label = Enable Events
thing-type.config.tesla.modelx.enableEvents.description = Enable the event stream for the vehicle
thing-type.config.tesla.modelx.inactivity.label = Inactivity Interval
thing-type.config.tesla.modelx.inactivity.description = The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.
thing-type.config.tesla.modelx.useAdvancedStatesForPolling.label = Use Console Modes and Occupancy for Inactivity
thing-type.config.tesla.modelx.useAdvancedStatesForPolling.description = Use these states to help continue the fast polling of the API. Do not back off polling if in these states.
thing-type.config.tesla.modelx.useDriveState.label = Use Drive State for Inactivity
thing-type.config.tesla.modelx.useDriveState.description = Use the drive state instead of location to determine vehicle inactivity.
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
@ -48,10 +74,34 @@ 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.enableEvents.label = Enable Events
thing-type.config.tesla.modely.enableEvents.description = Enable the event stream for the vehicle
thing-type.config.tesla.modely.inactivity.label = Inactivity Interval
thing-type.config.tesla.modely.inactivity.description = The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.
thing-type.config.tesla.modely.useAdvancedStatesForPolling.label = Use Console Modes and Occupancy for Inactivity
thing-type.config.tesla.modely.useAdvancedStatesForPolling.description = Use these states to help continue the fast polling of the API. Do not back off polling if in these states.
thing-type.config.tesla.modely.useDriveState.label = Use Drive State for Inactivity
thing-type.config.tesla.modely.useDriveState.description = Use the drive state instead of location to determine vehicle inactivity.
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
thing-type.config.tesla.modely.vin.description = VIN of the vehicle
thing-type.config.tesla.vehicle.allowWakeup.label = Allow Wake-Up
thing-type.config.tesla.vehicle.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain!
thing-type.config.tesla.vehicle.allowWakeupForCommands.label = Allow Wake-Up For Commands
thing-type.config.tesla.vehicle.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.vehicle.enableEvents.label = Enable Events
thing-type.config.tesla.vehicle.enableEvents.description = Enable the event stream for the vehicle
thing-type.config.tesla.vehicle.inactivity.label = Inactivity Interval
thing-type.config.tesla.vehicle.inactivity.description = The inactivity period in minutes, after which the binding stops for 20 minutes to let the car sleep.
thing-type.config.tesla.vehicle.useAdvancedStatesForPolling.label = Use Console Modes and Occupancy for Inactivity
thing-type.config.tesla.vehicle.useAdvancedStatesForPolling.description = Use these states to help continue the fast polling of the API. Do not back off polling if in these states.
thing-type.config.tesla.vehicle.useDriveState.label = Use Drive State for Inactivity
thing-type.config.tesla.vehicle.useDriveState.description = Use the drive state instead of location to determine vehicle inactivity.
thing-type.config.tesla.vehicle.valetpin.label = Valet PIN
thing-type.config.tesla.vehicle.valetpin.description = PIN to use when enabling Valet Mode
thing-type.config.tesla.vehicle.vin.label = Vehicle Identification Number
thing-type.config.tesla.vehicle.vin.description = VIN of the vehicle
# channel types
@ -206,7 +256,7 @@ channel-type.tesla.minavailabletemp.label = Minimum Temperature
channel-type.tesla.minavailabletemp.description = Indicates the minimal inside temperature of the vehicle
channel-type.tesla.mobileenabled.label = Mobile Enabled
channel-type.tesla.mobileenabled.description = Indicates whether the vehicle can be remotely controlled
channel-type.tesla.notenoughpower.label = Not Enought Power
channel-type.tesla.notenoughpower.label = Not Enough Power
channel-type.tesla.notenoughpower.description = Indicates if not enough power (ON) is available to heat the vehicle
channel-type.tesla.notificationsenabled.label = Notifications Enabled
channel-type.tesla.notificationsenabled.description = Not documented / To be defined

View File

@ -421,7 +421,7 @@
</channel-type>
<channel-type id="notenoughpower" advanced="true">
<item-type>Switch</item-type>
<label>Not Enought Power</label>
<label>Not Enough Power</label>
<description>Indicates if not enough power (ON) is available to heat the vehicle</description>
<state readOnly="true"></state>
</channel-type>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tesla"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="vehicle">
<supported-bridge-type-refs>
<bridge-type-ref id="account"/>
</supported-bridge-type-refs>
<label>Tesla</label>
<description>A Tesla Vehicle</description>
<config-description>
<parameter name="vin" type="text" required="true">
<label>Vehicle Identification Number</label>
<description>VIN of the vehicle</description>
</parameter>
<parameter name="valetpin" type="integer" min="0" max="9999" required="false">
<context>password</context>
<label>Valet PIN</label>
<description>PIN to use when enabling Valet Mode</description>
</parameter>
<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">
<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>
<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>
</thing:thing-descriptions>