diff --git a/CODEOWNERS b/CODEOWNERS
index d2c062713ece2..82fc3dfbe5b46 100755
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -371,6 +371,7 @@
/bundles/org.openhab.binding.tellstick/ @openhab/add-ons-maintainers
/bundles/org.openhab.binding.tesla/ @kgoderis
/bundles/org.openhab.binding.teslapowerwall/ @psmedley
+/bundles/org.openhab.binding.teslascope/ @psmedley
/bundles/org.openhab.binding.tibber/ @kjoglum
/bundles/org.openhab.binding.tivo/ @mlobstein
/bundles/org.openhab.binding.touchwand/ @roieg
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index a572a4b2a52ca..e95b1542ac8f5 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -1851,6 +1851,11 @@
org.openhab.binding.teslapowerwall${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.teslascope
+ ${project.version}
+ org.openhab.addons.bundlesorg.openhab.binding.tibber
diff --git a/bundles/org.openhab.binding.teslascope/NOTICE b/bundles/org.openhab.binding.teslascope/NOTICE
new file mode 100644
index 0000000000000..38d625e349232
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/NOTICE
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.binding.teslascope/README.md b/bundles/org.openhab.binding.teslascope/README.md
new file mode 100644
index 0000000000000..d532010d4e1cc
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/README.md
@@ -0,0 +1,242 @@
+# Teslascope Binding
+
+This binding integrates [Tesla Electrical Vehicles](https://www.tesla.com).
+The integration happens through the [Teslascope](https://www.teslascope.com) API.
+
+## Supported Things
+
+All Tesla vehicles supported by Teslascope are supported.
+Each vehicle is represented by its own `vehicle` Thing.
+
+## Discovery
+
+Auto-discovery is not currently supported.
+
+## Thing Configuration
+
+As a minimum, the apiKey and publicID are needed:
+| Thing Parameter | Default Value | Required | Advanced | Description |
+|-----------------|---------------|----------|----------|--------------------------------------------------------------------------------------|
+| apiKey | N/A | Yes | No | apiKey provided by Teslascope |
+| publicID | N/A | Yes | No | Vehicle Public ID listed in Teslascope |
+| refreshInterval | 60 | No | Yes | The frequency with which to refresh information from Teslascope specified in seconds |
+
+## Channels
+
+All vehicles support a huge number of channels - the following list shows the standard ones:
+
+| Channel ID | Item Type | Label | Description |
+|-------------------|----------------------|--------------------|---------------------------------------------------------------------------------------------|
+| auto-conditioning | Switch | Auto Conditioning | Turns on auto-conditioning (a/c or heating) |
+| battery-level | Number:Dimensionless | Battery Level | State of the battery in % |
+| charging-state | String | Charging State | “Starting”, “Complete”, “Charging”, “Disconnected”, “Stopped”, “NoPower” |
+| charge-port | Switch | Charge Port | Open the Charge Port (ON) or indicates the state of the Charge Port (ON/OFF if Open/Closed) |
+| climate | Switch | Climate | Climate status indicator |
+| door-lock | Switch | Door Lock | Lock or unlock the car |
+| inside-temp | Number:Temperature | Inside Temperature | Indicates the inside temperature of the vehicle |
+| location | Location | Location | The actual position of the vehicle |
+| odometer | Number:Length | Odometer | Odometer of the vehicle |
+| speed | Number:Speed | Speed | Vehicle speed |
+| vin | String | VIN | Vehicle Identification Number |
+| vehicle-name | String | Name | Vehicle Name |
+| vehicle-state | String | Vehicle State | Vehicle State |
+
+Additionally, these advanced channels are available (not all are available on all vehicle types, e.g., the sunroof):
+
+| Channel ID | Item Type | Label | Description |
+|-----------------------------|--------------------------|-------------------------------|----------------------------------------------------------------------------------------------------------|
+| battery-range | Number:Length | Battery Range | Range of the battery |
+| center-rear-seat-heater | Switch | Center Rear Seat Heater | Indicates if the center rear seat heater is switched on |
+| charge | Switch | Charge | Start (ON) or stop (OFF) charging |
+| charge-energy-added | Number:Energy | Charge Energy Added | Energy added, in kWh, during the last charging session |
+| charge-limit-soc-standard | Dimmer | Charge Limit SOC Standard | Standard charging limit of the vehicle, in % |
+| charge-rate | Number:Speed | Charge Rate | Distance per hour charging rate |
+| charger-power | Number:Power | Charger Power | Power actually delivered by the charger |
+| charger-voltage | Number:ElectricPotential | Charger Voltage | Voltage (V) actually presented by the charger |
+| driver-front-door | Contact | Driver Front Door | Indicates if the front door at the driver's side is open |
+| driver-rear-door | Contact | Driver Rear Door | Indicates if the rear door at the driver's side is open |
+| driver-temp | Number:Temperature | Driver Temperature | Indicates the auto conditioning temperature set at the driver's side |
+| estimated-battery-range | Number:Length | Estimated Battery Range | Estimated battery range |
+| fan | Number | Fan | Indicates the speed (0-7) of the fan |
+| flash-lights | Switch | Flash Lights | Flash the lights of the car (when ON is received) |
+| front-defroster | Switch | Front Defroster | Indicates if the front defroster is enabled |
+| front-trunk | Switch | Front Trunk | Indicates if the front trunk is opened, or open the front trunk when ON is received |
+| heading | Number:Angle | Heading | Indicates the (compass) heading of the car, in 0-360 degrees |
+| honk-horn | Switch | Honk the Horn | Honk the horn of the vehicle, when ON is received |
+| homelink | Switch | Homelink Nearby | Indicates if the Home Link is nearby |
+| left-temp-direction | Number | Left Temperature Direction | Not documented / To be defined |
+| location | Location | Location | The actual position of the vehicle |
+| left-seat-heater | Switch | Left Seat Heater | Indicates if the left seat heater is switched on |
+| left-rear-seat-heater | Switch | Left Rear Seat Heater | Indicates if the left rear seat heater is switched on |
+| left-rear-back-seat-heater | Number | Left Rear Backseat Heater | Indicates the level (0, 1, 2, or 3) of the left rear backseat heater |
+| min-available-temp | Number:Temperature | Minimum Temperature | Indicates the minimal inside temperature of the vehicle |
+| max-available-temp | Number:Temperature | Maximum Temperature | Indicates the maximum inside temperature of the vehicle |
+| outside-temp | Number:Temperature | Outside Temperature | Indicates the outside temperature of the vehicle |
+| passenger-temp | Number | Passenger Temperature | Indicates the auto conditioning temperature set at the passenger's side |
+| passenger-front-door | Contact | Passenger Front Door | Indicates if the front door at the passenger's side is opened |
+| passenger-rear-door | Contact | Passenger Rear Door | Indicates if the rear door at the passenger's side is opened |
+| power | Number:Power | Power | Net kW flowing in (+) or out (-) of the battery |
+| preconditioning | Switch | Preconditioning | Indicates if preconditioning is activated |
+| rear-defroster | Switch | Rear Defroster | Indicates if the rear defroster is enabled |
+| rear-trunk | Switch | Rear Trunk | Indicates if the rear trunk is opened, or open/close the rear trunk when ON/OFF is received |
+| right-seat-heater | Switch | Right Seat Heater | Indicates if the right seat heater is switched on |
+| right-rear-seat-heater | Switch | Right Rear Seat Heater | Indicates if the right rear seat heater is switched on |
+| right-rear-back-seat-heater | Number | Right Rear Backseat Heater | Indicates the level (0, 1, 2, or 3) of the right rear backseat heater |
+| right-temp-direction | Number | Right Temperature Direction | Not documented / To be defined |
+| scheduled-charging-pending | Switch | Scheduled Charging Pending | Indicates if a scheduled charging session is still pending |
+| scheduled-charging-start | DateTime | Scheduled Charging Start | Indicates when the scheduled charging session will start, in yyyy-MM-dd'T'HH:mm:ss format |
+| sentry-mode | Switch | Sentry Mode | Activates or deactivates sentry mode |
+| shift-state | String | Shift State | Indicates the state of the transmission, “P”, “D”, “R”, or “N” |
+| side-mirror-heaters | Switch | Side Mirror Heaters | Indicates if the side mirror heaters are switched on |
+| smart-preconditioning | Switch | Smart Preconditioning | Indicates if smart preconditioning is switched on |
+| software-update-available | Switch | Update Available | Car software or map update available, automatically generated on non-empty "update status" |
+| software-update-status | String | Update Status | Car software or map update status, e.g. "downloading_wifi_wait", "installing" |
+| software-update-version | String | Update Version | Car software or map version to update to, e.g. "2023.32.9", "EU-2023.32-14783" for map updates, or empty |
+| steering-wheel-heater | Switch | Steering Wheel Heater | Turns On/Off the steering wheel heater |
+| sunroof-state | String | Sunroof State | Valid states are “unknown”, “open”, “closed”, “vent”, “comfort”. Accepts commands "close" and "vent". |
+| sunroof | Dimmer | Sunroof | Indicates the opening state of the sunroof (0% closed, 100% fully open) |
+| time-to-full-charge | Number | Time To Full Charge | Number of hours to fully charge the battery |
+| tpms-pressure-fl | Number:Pressure | Tyre Pressure FL | Tyre Pressure Front Left in Bar |
+| tpms-pressure-fr | Number:Pressure | Tyre Pressure FR | Tyre Pressure Front Right in Bar |
+| tpms-pressure-rl | Number:Pressure | Tyre Pressure RL | Tyre Pressure Rear Left in Bar |
+| tpms-pressure-rr | Number:Pressure | Tyre Pressure RR | Tyre Pressure Rear Right in Bar |
+| tpms-soft-warning-fl | Switch | Tyre Pressure Soft Warning FL | Tyre Pressure Soft Warning Front Left |
+| tpms-soft-warning-fr | Switch | Tyre Pressure Soft Warning FR | Tyre Pressure Soft Warning Front Right |
+| tpms-soft-warning-rl | Switch | Tyre Pressure Soft Warning RL | Tyre Pressure Soft Warning Rear Left |
+| tpms-soft-warning-rr | Switch | Tyre Pressure Soft Warning RR | Tyre Pressure Soft Warning Rear Right |
+| usable-battery-level | Number | Usable Battery Level | Indicates the % of battery that can be used for vehicle functions like driving |
+| valet-mode | Switch | Valet Mode | Enable or disable Valet Mode |
+| wiper-blade-heater | Switch | Wiperblade Heater | Indicates if the wiperblade heater is switched on |
+
+## Full Example
+
+### `demo.things`:
+
+```java
+teslascope:vehicle:model3 [ apiKey="xxxx", publicID="aXb3" ]
+```
+
+### `example.items`:
+
+```java
+String TeslaVehicleName {channel="teslascope:vehicle:model3:vehicle-name"}
+String TeslaVehicleState {channel="teslascope:vehicle:model3:vehicle-state"}
+String TeslaVIN {channel="teslascope:vehicle:model3:vin"}
+Number TeslaSpeed {channel="teslascope:vehicle:model3:speed"}
+String TeslaShiftState {channel="teslascope:vehicle:model3:shift-state"}
+Number TeslaOdometer {channel="teslascope:vehicle:model3:odometer"}
+Number TeslaRange {channel="teslascope:vehicle:model3:range"}
+
+Number TeslaBatteryLevel {channel="teslascope:vehicle:model3:battery-level"}
+Number TeslaPower {channel="teslascope:vehicle:model3:power"}
+Number TeslaBatteryRange {channel="teslascope:vehicle:model3:battery-range"}
+Number TeslaEstBatteryRange {channel="teslascope:vehicle:model3:estimated-battery-range"}
+Switch TeslaPreconditioning {channel="teslascope:vehicle:model3:preconditioning"}
+
+Switch TeslaCharge {channel="teslascope:vehicle:model3:charge"}
+
+Dimmer TeslaChargeLimit {channel="teslascope:vehicle:model3:charge-limit"}
+Number TeslaChargeRate {channel="teslascope:vehicle:model3:charge-rate"}
+String TeslaChargingState {channel="teslascope:vehicle:model3:charging-state"}
+Number TeslaChargerPower {channel="teslascope:vehicle:model3:charger-power"}
+Number TeslaTimeToFullCharge {channel="teslascope:vehicle:model3:time-to-full-charge"}
+
+Number TeslaChargerVoltage {channel="teslascope:vehicle:model3:charger-voltage"}
+Number TeslaChargerPower {channel="teslascope:vehicle:model3:charger-power"}
+
+DateTime TeslaScheduledChargingStart {channel="teslascope:vehicle:model3:scheduled-charging-start"}
+
+Switch TeslaDoorLock {channel="teslascope:vehicle:model3:door-lock"}
+Switch TeslaHorn {channel="teslascope:vehicle:model3:honk-horn"}
+Switch TeslaSentry {channel="teslascope:vehicle:model3:sentry-mode"}
+Switch TeslaLights {channel="teslascope:vehicle:model3:flash-lights"}
+Switch TeslaValet {channel="teslascope:vehicle:model3:valet-mode"}
+
+Switch TeslaFrontDefrost {channel="teslascope:vehicle:model3:front-defroster"}
+Switch TeslaRearDefrost {channel="teslascope:vehicle:model3:rear-defroster"}
+Switch TeslaLeftSeatHeater {channel="teslascope:vehicle:model3:left-seat-heater"}
+Switch TeslaRightSeatHeater {channel="teslascope:vehicle:model3:right-seat-heater"}
+
+Switch TeslaHomelink {channel="teslascope:vehicle:model3:homelink"}
+Location TeslaLocation {channel="teslascope:vehicle:model3:location"}
+Number TeslaHeading {channel="teslascope:vehicle:model3:heading"}
+
+Switch TeslaAutoconditioning {channel="teslascope:vehicle:model3:auto-conditioning"}
+Number:Temperature TeslaTemperature {channel="teslascope:vehicle:model3:temperature"}
+Number:Temperature TeslaInsideTemperature {channel="teslascope:vehicle:model3:inside-temp"}
+Number:Temperature TeslaOutsideTemperature {channel="teslascope:vehicle:model3:outside-temp"}
+
+Number:Pressure TeslaTPMSPressureFL {channel="teslascope:vehicle:model3:tpms-pressure-fl"}
+Number:Pressure TeslaTPMSPressureFR {channel="teslascope:vehicle:model3:tpms-pressure-fr"}
+Number:Pressure TeslaTPMSPressureRL {channel="teslascope:vehicle:model3:tpms-pressure-rl"}
+Number:Pressure TeslaTPMSPressureRR {channel="teslascope:vehicle:model3:tpms-pressure-rr"}
+
+Switch TeslaTPMSSoftWarningFL {channel="teslascope:vehicle:model3:tpms-soft-warning-fl"}
+Switch TeslaTPMSSoftWarningFR {channel="teslascope:vehicle:model3:tpms-soft-warning-fr"}
+Switch TeslaTPMSSoftWarningRL {channel="teslascope:vehicle:model3:tpms-soft-warning-rl"}
+Switch TeslaTPMSSoftWarningRR {channel="teslascope:vehicle:model3:tpms-soft-warning-rr"}
+```
+
+### `example.sitemap`:
+
+```perl
+sitemap main label="Main"
+{
+ Text item=TeslaUsableBatteryLevel label="Car" icon="tesla" valuecolor=[<=20="red",>60="green"]
+ {
+ Frame
+ {
+ Text item=TeslaState label="State [%s]" icon=""
+ Text item=TeslaHomelink label="Homelink Available[%s]" icon=""
+ Text item=TeslaSpeed label="Speed [%.1f]"
+ Text item=TeslaShiftState label="Shift State [%s]" icon=""
+ Text item=TeslaShiftState
+ 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=TeslaPower
+ Text item=TeslaBatteryRange label="Battery Range [%.1f miles]"
+ Text item=TeslaEstBatteryRange label="Battery Est 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]"
+ }
+ Frame
+ {
+ Switch item=TeslaDoorLock label="Doorlock"
+ Switch item=TeslaHorn label="Horn"
+ Switch item=TeslaLights label="Lights"
+ Switch item=TeslaValet label="Valet Mode"
+ Switch item=TeslaSentry label="Sentry Mode"
+
+ 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
+ {
+ Mapview item=TeslaLocation height=10
+ }
+ }
+}
+```
diff --git a/bundles/org.openhab.binding.teslascope/pom.xml b/bundles/org.openhab.binding.teslascope/pom.xml
new file mode 100644
index 0000000000000..cccf5dbe7ae35
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/pom.xml
@@ -0,0 +1,17 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 4.3.0-SNAPSHOT
+
+
+ org.openhab.binding.teslascope
+
+ openHAB Add-ons :: Bundles :: Teslascope Binding
+
+
diff --git a/bundles/org.openhab.binding.teslascope/src/main/feature/feature.xml b/bundles/org.openhab.binding.teslascope/src/main/feature/feature.xml
new file mode 100644
index 0000000000000..a33f949564d68
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/feature/feature.xml
@@ -0,0 +1,9 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.binding.teslascope/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeAuthenticationException.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeAuthenticationException.java
new file mode 100644
index 0000000000000..483be4cef4338
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeAuthenticationException.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Exception for when an unexpected response is received from the Teslascope API.
+ *
+ * @author Paul Smedley - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class TeslascopeAuthenticationException extends Exception {
+ private static final long serialVersionUID = 529232811860854017L;
+
+ public TeslascopeAuthenticationException(String message) {
+ super(message);
+ }
+
+ public TeslascopeAuthenticationException(Throwable ex) {
+ super(ex);
+ }
+
+ public TeslascopeAuthenticationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeBindingConstants.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeBindingConstants.java
new file mode 100644
index 0000000000000..c3ca8c171dfc6
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeBindingConstants.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link TeslascopeBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Paul Smedley - Initial contribution
+ */
+@NonNullByDefault
+public class TeslascopeBindingConstants {
+
+ private static final String BINDING_ID = "teslascope";
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID TESLASCOPE_THING = new ThingTypeUID(BINDING_ID, "vehicle");
+
+ // List of all Channel ids
+ public static final String CHANNEL_VIN = "vin";
+ public static final String CHANNEL_VEHICLE_NAME = "vehicle-name";
+ public static final String CHANNEL_VEHICLE_STATE = "vehicle-state";
+ public static final String CHANNEL_ODOMETER = "odometer";
+ public static final String CHANNEL_BATTERY_LEVEL = "battery-level";
+ public static final String CHANNEL_CHARGING_STATE = "charging-state";
+ public static final String CHANNEL_TPMS_FL = "tpms-pressure-fl";
+ public static final String CHANNEL_TPMS_FR = "tpms-pressure-fr";
+ public static final String CHANNEL_TPMS_RL = "tpms-pressure-rl";
+ public static final String CHANNEL_TPMS_RR = "tpms-pressure-rr";
+ public static final String CHANNEL_TPMS_SOFT_WARNING_FL = "tpms-soft-warning-fl";
+ public static final String CHANNEL_TPMS_SOFT_WARNING_FR = "tpms-soft-warning-fr";
+ public static final String CHANNEL_TPMS_SOFT_WARNING_RL = "tpms-soft-warning-rl";
+ public static final String CHANNEL_TPMS_SOFT_WARNING_RR = "tpms-soft-warning-rr";
+ public static final String CHANNEL_SOFTWARE_UPDATE_AVAILABLE = "software-update-available";
+ public static final String CHANNEL_SOFTWARE_UPDATE_STATUS = "software-update-status";
+ public static final String CHANNEL_SOFTWARE_UPDATE_VERSION = "software-update-version";
+ public static final String CHANNEL_AUTOCONDITIONING = "auto-conditioning";
+ public static final String CHANNEL_BATTERY_RANGE = "battery-range";
+ public static final String CHANNEL_CENTER_REAR_SEAT_HEATER = "center-rear-seat-heater";
+ public static final String CHANNEL_CHARGE = "charge";
+ public static final String CHANNEL_CHARGE_ENERGY_ADDED = "charge-energy-added";
+ public static final String CHANNEL_CHARGE_LIMIT_SOC_STANDARD = "charge-limit-soc-standard";
+ public static final String CHANNEL_CHARGE_PORT = "charge-port";
+ public static final String CHANNEL_CHARGE_RATE = "charge-rate";
+ public static final String CHANNEL_CHARGER_POWER = "charger-power";
+ public static final String CHANNEL_CHARGER_VOLTAGE = "charger-voltage";
+ public static final String CHANNEL_CLIMATE = "climate";
+ public static final String CHANNEL_DOOR_LOCK = "door-lock";
+ public static final String CHANNEL_DRIVER_FRONT_DOOR = "driver-front-door";
+ public static final String CHANNEL_DRIVER_REAR_DOOR = "driver-rear-door";
+ public static final String CHANNEL_DRIVER_TEMP = "driver-temp";
+ public static final String CHANNEL_ESTIMATED_BATTERY_RANGE = "estimated-battery-range";
+ public static final String CHANNEL_FAN = "fan";
+ public static final String CHANNEL_FLASH_LIGHTS = "flash-lights";
+ public static final String CHANNEL_FRONT_DEFROSTER = "front-defroster";
+ public static final String CHANNEL_FRONT_TRUNK = "front-trunk";
+ public static final String CHANNEL_HEADING = "heading";
+ public static final String CHANNEL_HOMELINK = "homelink";
+ public static final String CHANNEL_HONK_HORN = "honk-horn";
+ public static final String CHANNEL_INSIDE_TEMP = "inside-temp";
+ public static final String CHANNEL_LEFT_REAR_SEAT_HEATER = "left-rear-seat-heater";
+ public static final String CHANNEL_LEFT_SEAT_HEATER = "left-seat-heater";
+ public static final String CHANNEL_LEFT_TEMP_DIRECTION = "left-temp-direction";
+ public static final String CHANNEL_LOCATION = "location";
+ public static final String CHANNEL_MIN_AVAILABLE_TEMP = "min-available-temp";
+ public static final String CHANNEL_MAX_AVAILABLE_TEMP = "max-available-temp";
+ public static final String CHANNEL_OUTSIDE_TEMP = "outside-temp";
+ public static final String CHANNEL_PASSENGER_FRONT_DOOR = "passenger-front-door";
+ public static final String CHANNEL_PASSENGER_REAR_DOOR = "passenger-rear-door";
+ public static final String CHANNEL_PASSENGER_TEMP = "passenger-temp";
+ public static final String CHANNEL_POWER = "power";
+ public static final String CHANNEL_PRECONDITIONING = "preconditioning";
+ public static final String CHANNEL_REAR_DEFROSTER = "rear-defroster";
+ public static final String CHANNEL_REAR_TRUNK = "rear-trunk";
+ public static final String CHANNEL_RIGHT_REAR_SEAT_HEATER = "right-rear-seat-heater";
+ public static final String CHANNEL_RIGHT_SEAT_HEATER = "right-seat-heater";
+ public static final String CHANNEL_RIGHT_TEMP_DIRECTION = "right-temp-direction";
+ public static final String CHANNEL_SCHEDULED_CHARGING_PENDING = "scheduled-charging-pending";
+ public static final String CHANNEL_SCHEDULED_CHARGING_START = "scheduled-charging-start";
+ public static final String CHANNEL_SENTRY_MODE = "sentry-mode";
+ public static final String CHANNEL_SHIFT_STATE = "shift-state";
+ public static final String CHANNEL_SIDE_MIRROR_HEATERS = "side-mirror-heaters";
+ public static final String CHANNEL_SMARTPRECONDITIONG = "smart-preconditioning";
+ public static final String CHANNEL_SPEED = "speed";
+ public static final String CHANNEL_STEERING_WHEEL_HEATER = "steering-wheel-heater";
+ public static final String CHANNEL_SUNROOF = "sunroof";
+ public static final String CHANNEL_SUNROOF_STATE = "sunroof-state";
+ public static final String CHANNEL_TIME_TO_FULL_CHARGE = "time-to-full-charge";
+ public static final String CHANNEL_USABLE_BATTERY_LEVEL = "usable-battery-level";
+ public static final String CHANNEL_VALET_MODE = "valet-mode";
+ public static final String CHANNEL_WIPER_BLADE_HEATER = "wiper-blade-heater";
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeCommunicationException.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeCommunicationException.java
new file mode 100644
index 0000000000000..ea95e21cf17f5
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeCommunicationException.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Exception for when an unexpected response is received from the Teslascope API.
+ *
+ * @author Paul Smedley - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class TeslascopeCommunicationException extends Exception {
+ private static final long serialVersionUID = 529232811860854017L;
+
+ public TeslascopeCommunicationException(String message) {
+ super(message);
+ }
+
+ public TeslascopeCommunicationException(Throwable ex) {
+ super(ex);
+ }
+
+ public TeslascopeCommunicationException(@Nullable String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeConfiguration.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeConfiguration.java
new file mode 100644
index 0000000000000..d948cfc467121
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeConfiguration.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link TeslascopeConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Paul Smedley - Initial contribution
+ */
+@NonNullByDefault
+public class TeslascopeConfiguration {
+
+ public String apiKey = "";
+ public String publicID = "";
+ public int refreshInterval = 60;
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandler.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandler.java
new file mode 100644
index 0000000000000..cc57dcfc470a9
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandler.java
@@ -0,0 +1,376 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import static org.openhab.binding.teslascope.internal.TeslascopeBindingConstants.*;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.teslascope.internal.api.DetailedInformation;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.OpenClosedType;
+import org.openhab.core.library.types.PointType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.ImperialUnits;
+import org.openhab.core.library.unit.MetricPrefix;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.types.Command;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link TeslascopeHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Paul Smedley - Initial contribution
+ */
+@NonNullByDefault
+public class TeslascopeHandler extends BaseThingHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(TeslascopeHandler.class);
+
+ private TeslascopeConfiguration config = new TeslascopeConfiguration();
+ private TeslascopeWebTargets webTargets;
+ private @Nullable ScheduledFuture> pollFuture;
+
+ private final Gson gson = new Gson();
+
+ public TeslascopeHandler(Thing thing, HttpClient httpClient) {
+ super(thing);
+ webTargets = new TeslascopeWebTargets(httpClient);
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ try {
+ switch (channelUID.getId()) {
+ case TeslascopeBindingConstants.CHANNEL_AUTOCONDITIONING:
+ if (command instanceof OnOffType onOffCommand) {
+ setAutoConditioning(onOffCommand == OnOffType.ON);
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_CHARGE:
+ if (command instanceof OnOffType onOffCommand) {
+ charge(onOffCommand == OnOffType.ON);
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_CHARGE_PORT:
+ if (command instanceof OnOffType onOffCommand) {
+ chargeDoor(onOffCommand == OnOffType.ON);
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_DOOR_LOCK:
+ if (command instanceof OnOffType onOffCommand) {
+ lock(onOffCommand == OnOffType.ON);
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_FLASH_LIGHTS:
+ if (command instanceof OnOffType onOffCommand) {
+ flashLights();
+ return;
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_FRONT_TRUNK:
+ if (command instanceof OnOffType onOffCommand) {
+ openFrunk();
+ return;
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_HONK_HORN:
+ if (command instanceof OnOffType onOffCommand) {
+ honkHorn();
+ return;
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_REAR_TRUNK:
+ if (command instanceof OnOffType onOffCommand) {
+ openTrunk();
+ return;
+ }
+ break;
+ case TeslascopeBindingConstants.CHANNEL_SENTRY_MODE:
+ if (command instanceof OnOffType onOffCommand) {
+ sentry(onOffCommand == OnOffType.ON);
+ }
+ break;
+ default:
+ logger.debug("Received command ({}) of wrong type for thing '{}' on channel {}", command,
+ thing.getUID().getAsString(), channelUID.getId());
+ }
+ } catch (TeslascopeAuthenticationException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+ } catch (TeslascopeCommunicationException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+ }
+ }
+
+ @Override
+ public void initialize() {
+ config = getConfigAs(TeslascopeConfiguration.class);
+ if (config.apiKey.isBlank()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "@text/offline.conf-error.no-api-key");
+ return;
+ }
+
+ updateStatus(ThingStatus.UNKNOWN);
+
+ schedulePoll();
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ stopPoll();
+ }
+
+ private void schedulePoll() {
+ logger.debug("Scheduling poll every {} s", config.refreshInterval);
+ this.pollFuture = scheduler.scheduleWithFixedDelay(this::pollStatus, 0, config.refreshInterval,
+ TimeUnit.SECONDS);
+ }
+
+ private void stopPoll() {
+ final Future> future = pollFuture;
+ if (future != null) {
+ future.cancel(true);
+ pollFuture = null;
+ }
+ }
+
+ private void pollStatus() {
+ String response = "";
+
+ try {
+ response = webTargets.getDetailedInformation(config.publicID, config.apiKey);
+ updateStatus(ThingStatus.ONLINE);
+ } catch (TeslascopeAuthenticationException e) {
+ logger.debug("Unexpected authentication error connecting to Teslascope API", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+ return;
+ } catch (TeslascopeCommunicationException e) {
+ logger.debug("Unexpected error connecting to Teslascope API", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+ return;
+ }
+
+ DetailedInformation detailedInformation = gson.fromJson(response, DetailedInformation.class);
+
+ if (detailedInformation != null) {
+ updateState(TeslascopeBindingConstants.CHANNEL_VIN, new StringType(detailedInformation.vin));
+ updateState(TeslascopeBindingConstants.CHANNEL_VEHICLE_NAME, new StringType(detailedInformation.name));
+ updateState(TeslascopeBindingConstants.CHANNEL_VEHICLE_STATE, new StringType(detailedInformation.state));
+ updateState(TeslascopeBindingConstants.CHANNEL_ODOMETER,
+ new QuantityType<>(detailedInformation.odometer, ImperialUnits.MILE));
+
+ // charge state
+ updateState(TeslascopeBindingConstants.CHANNEL_BATTERY_LEVEL,
+ new DecimalType(detailedInformation.chargeState.batteryLevel));
+ updateState(TeslascopeBindingConstants.CHANNEL_USABLE_BATTERY_LEVEL,
+ new DecimalType(detailedInformation.chargeState.usableBatteryLevel));
+ updateState(TeslascopeBindingConstants.CHANNEL_BATTERY_RANGE,
+ new QuantityType<>(detailedInformation.chargeState.batteryRange, ImperialUnits.MILE));
+ updateState(TeslascopeBindingConstants.CHANNEL_ESTIMATED_BATTERY_RANGE,
+ new QuantityType<>(detailedInformation.chargeState.estBatteryRange, ImperialUnits.MILE));
+ // charge_enable_request isn't the right flag to determine if car is charging or not
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGE,
+ OnOffType.from("Charging".equals(detailedInformation.chargeState.chargingState)));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGE_ENERGY_ADDED,
+ new QuantityType<>(detailedInformation.chargeState.chargeEnergyAdded, Units.KILOWATT_HOUR));
+ updateState(CHANNEL_CHARGE_LIMIT_SOC_STANDARD,
+ new DecimalType(detailedInformation.chargeState.chargeLimitSoc / 100));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGE_PORT,
+ OnOffType.from(1 == detailedInformation.chargeState.chargePortDoorOpen));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGE_RATE,
+ new QuantityType<>(detailedInformation.chargeState.chargeRate, ImperialUnits.MILES_PER_HOUR));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGER_POWER,
+ new QuantityType<>(detailedInformation.chargeState.chargerPower, MetricPrefix.KILO(Units.WATT)));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGER_VOLTAGE,
+ new QuantityType<>(detailedInformation.chargeState.chargerVoltage, Units.VOLT));
+ updateState(TeslascopeBindingConstants.CHANNEL_TIME_TO_FULL_CHARGE,
+ new QuantityType<>(detailedInformation.chargeState.timeToFullCharge, Units.HOUR));
+ updateState(TeslascopeBindingConstants.CHANNEL_CHARGING_STATE,
+ new StringType(detailedInformation.chargeState.chargingState));
+ updateState(TeslascopeBindingConstants.CHANNEL_SCHEDULED_CHARGING_PENDING,
+ OnOffType.from(1 == detailedInformation.chargeState.scheduledChargingPending));
+ updateState(TeslascopeBindingConstants.CHANNEL_SCHEDULED_CHARGING_START,
+ new StringType(detailedInformation.chargeState.scheduledChargingStartTime));
+
+ // climate state
+ updateState(TeslascopeBindingConstants.CHANNEL_AUTOCONDITIONING,
+ OnOffType.from(1 == detailedInformation.climateState.isAutoConditioningOn));
+ updateState(TeslascopeBindingConstants.CHANNEL_CLIMATE,
+ OnOffType.from(1 == detailedInformation.climateState.isClimateOn));
+ updateState(TeslascopeBindingConstants.CHANNEL_FRONT_DEFROSTER,
+ OnOffType.from(1 == detailedInformation.climateState.isFrontDefrosterOn));
+ updateState(TeslascopeBindingConstants.CHANNEL_PRECONDITIONING,
+ OnOffType.from(1 == detailedInformation.climateState.isPreconditioning));
+ updateState(TeslascopeBindingConstants.CHANNEL_REAR_DEFROSTER,
+ OnOffType.from(1 == detailedInformation.climateState.isRearDefrosterOn));
+ updateState(TeslascopeBindingConstants.CHANNEL_LEFT_SEAT_HEATER,
+ new DecimalType(detailedInformation.climateState.seatHeaterLeft));
+ updateState(TeslascopeBindingConstants.CHANNEL_CENTER_REAR_SEAT_HEATER,
+ new DecimalType(detailedInformation.climateState.seatHeaterRearCenter));
+ updateState(TeslascopeBindingConstants.CHANNEL_LEFT_REAR_SEAT_HEATER,
+ new DecimalType(detailedInformation.climateState.seatHeaterRearLeft));
+ updateState(TeslascopeBindingConstants.CHANNEL_RIGHT_REAR_SEAT_HEATER,
+ new DecimalType(detailedInformation.climateState.seatHeaterRearRight));
+ updateState(TeslascopeBindingConstants.CHANNEL_RIGHT_SEAT_HEATER,
+ new DecimalType(detailedInformation.climateState.seatHeaterRight));
+ updateState(TeslascopeBindingConstants.CHANNEL_SIDE_MIRROR_HEATERS,
+ OnOffType.from(1 == detailedInformation.climateState.sideMirrorHeaters));
+ updateState(TeslascopeBindingConstants.CHANNEL_SMARTPRECONDITIONG,
+ OnOffType.from(1 == detailedInformation.climateState.smartPreconditioning));
+ updateState(TeslascopeBindingConstants.CHANNEL_STEERING_WHEEL_HEATER,
+ OnOffType.from(1 == detailedInformation.climateState.steeringWheelHeater));
+ updateState(TeslascopeBindingConstants.CHANNEL_WIPER_BLADE_HEATER,
+ OnOffType.from(1 == detailedInformation.climateState.wiperBladeHeater));
+ updateState(TeslascopeBindingConstants.CHANNEL_DRIVER_TEMP,
+ new QuantityType<>(detailedInformation.climateState.driverTempSetting, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_INSIDE_TEMP,
+ new QuantityType<>(detailedInformation.climateState.insideTemp, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_OUTSIDE_TEMP,
+ new QuantityType<>(detailedInformation.climateState.outsideTemp, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_PASSENGER_TEMP,
+ new QuantityType<>(detailedInformation.climateState.passengerTempSetting, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_FAN,
+ new DecimalType(detailedInformation.climateState.fanStatus));
+ updateState(TeslascopeBindingConstants.CHANNEL_LEFT_TEMP_DIRECTION,
+ new DecimalType(detailedInformation.climateState.leftTempDirection));
+ updateState(TeslascopeBindingConstants.CHANNEL_MAX_AVAILABLE_TEMP,
+ new QuantityType<>(detailedInformation.climateState.maxAvailTemp, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_MIN_AVAILABLE_TEMP,
+ new QuantityType<>(detailedInformation.climateState.minAvailTemp, SIUnits.CELSIUS));
+ updateState(TeslascopeBindingConstants.CHANNEL_RIGHT_TEMP_DIRECTION,
+ new DecimalType(detailedInformation.climateState.rightTempDirection));
+
+ // drive state
+ updateState(TeslascopeBindingConstants.CHANNEL_HEADING,
+ new DecimalType(detailedInformation.driveState.heading));
+ updateState(TeslascopeBindingConstants.CHANNEL_LOCATION, new PointType(
+ detailedInformation.driveState.latitude + "," + detailedInformation.driveState.longitude));
+ updateState(TeslascopeBindingConstants.CHANNEL_POWER,
+ new QuantityType<>(detailedInformation.driveState.power, MetricPrefix.KILO(Units.WATT)));
+ updateState(TeslascopeBindingConstants.CHANNEL_SHIFT_STATE,
+ new StringType(detailedInformation.driveState.shiftState));
+ updateState(TeslascopeBindingConstants.CHANNEL_SPEED,
+ new QuantityType<>(detailedInformation.driveState.speed, ImperialUnits.MILES_PER_HOUR));
+
+ // vehicle state
+ updateState(TeslascopeBindingConstants.CHANNEL_DOOR_LOCK,
+ OnOffType.from(1 == detailedInformation.vehicleState.locked));
+ updateState(TeslascopeBindingConstants.CHANNEL_SENTRY_MODE,
+ OnOffType.from(1 == detailedInformation.vehicleState.sentryMode));
+ updateState(TeslascopeBindingConstants.CHANNEL_VALET_MODE,
+ OnOffType.from(1 == detailedInformation.vehicleState.valetMode));
+ updateState(TeslascopeBindingConstants.CHANNEL_SOFTWARE_UPDATE_AVAILABLE,
+ OnOffType.from(!"".equals(detailedInformation.vehicleState.softwareUpdateStatus)));
+ updateState(TeslascopeBindingConstants.CHANNEL_SOFTWARE_UPDATE_STATUS,
+ new StringType(detailedInformation.vehicleState.softwareUpdateStatus));
+ updateState(TeslascopeBindingConstants.CHANNEL_SOFTWARE_UPDATE_VERSION,
+ new StringType(detailedInformation.vehicleState.softwareUpdateVersion));
+ updateState(TeslascopeBindingConstants.CHANNEL_SUNROOF_STATE,
+ new StringType(detailedInformation.vehicleState.sunRoofState));
+ updateState(TeslascopeBindingConstants.CHANNEL_SUNROOF,
+ new DecimalType(detailedInformation.vehicleState.sunRoofPercentOpen));
+ updateState(TeslascopeBindingConstants.CHANNEL_HOMELINK,
+ OnOffType.from(1 == detailedInformation.vehicleState.homelinkNearby));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_FL,
+ new QuantityType<>(detailedInformation.vehicleState.tpmsPressureFL, Units.BAR));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_FR,
+ new QuantityType<>(detailedInformation.vehicleState.tpmsPressureFR, Units.BAR));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_RL,
+ new QuantityType<>(detailedInformation.vehicleState.tpmsPressureRL, Units.BAR));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_RR,
+ new QuantityType<>(detailedInformation.vehicleState.tpmsPressureRR, Units.BAR));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_SOFT_WARNING_FL,
+ OnOffType.from(1 == detailedInformation.vehicleState.tpmsSoftWarningFL));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_SOFT_WARNING_FR,
+ OnOffType.from(1 == detailedInformation.vehicleState.tpmsSoftWarningFR));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_SOFT_WARNING_RL,
+ OnOffType.from(1 == detailedInformation.vehicleState.tpmsSoftWarningRL));
+ updateState(TeslascopeBindingConstants.CHANNEL_TPMS_SOFT_WARNING_RR,
+ OnOffType.from(1 == detailedInformation.vehicleState.tpmsSoftWarningRR));
+ updateState(TeslascopeBindingConstants.CHANNEL_DRIVER_FRONT_DOOR,
+ (1 == detailedInformation.vehicleState.df) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ updateState(TeslascopeBindingConstants.CHANNEL_DRIVER_REAR_DOOR,
+ (1 == detailedInformation.vehicleState.dr) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ updateState(TeslascopeBindingConstants.CHANNEL_PASSENGER_FRONT_DOOR,
+ (1 == detailedInformation.vehicleState.pf) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ updateState(TeslascopeBindingConstants.CHANNEL_PASSENGER_REAR_DOOR,
+ (1 == detailedInformation.vehicleState.pr) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ updateState(TeslascopeBindingConstants.CHANNEL_FRONT_TRUNK,
+ OnOffType.from(1 == detailedInformation.vehicleState.ft));
+ updateState(TeslascopeBindingConstants.CHANNEL_REAR_TRUNK,
+ OnOffType.from(1 == detailedInformation.vehicleState.rt));
+ }
+
+ // virtual items
+ updateState(TeslascopeBindingConstants.CHANNEL_HONK_HORN, OnOffType.OFF);
+ updateState(TeslascopeBindingConstants.CHANNEL_FLASH_LIGHTS, OnOffType.OFF);
+ }
+
+ protected void setAutoConditioning(boolean b)
+ throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, b ? "startAC" : "stopAC");
+ }
+
+ protected void charge(boolean b) throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, b ? "startCharging" : "stopCharging");
+ }
+
+ protected void chargeDoor(boolean b) throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, b ? "openChargeDoor" : "closeChargeDoor");
+ }
+
+ protected void flashLights() throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, "flashLights");
+ updateState(TeslascopeBindingConstants.CHANNEL_FLASH_LIGHTS, OnOffType.OFF);
+ }
+
+ protected void honkHorn() throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, "honkHorn");
+ updateState(TeslascopeBindingConstants.CHANNEL_HONK_HORN, OnOffType.OFF);
+ }
+
+ protected void lock(boolean b) throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, b ? "lock" : "unlock");
+ }
+
+ protected void openFrunk() throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, "openFrunk");
+ }
+
+ protected void openTrunk() throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, "openTrunk");
+ }
+
+ protected void sentry(boolean b) throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ webTargets.sendCommand(config.publicID, config.apiKey, b ? "enableSentryMode" : "disableSentryMode");
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandlerFactory.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandlerFactory.java
new file mode 100644
index 0000000000000..26a0451f8b80a
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeHandlerFactory.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import static org.openhab.binding.teslascope.internal.TeslascopeBindingConstants.*;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link TeslascopeHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Paul Smedley - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.teslascope", service = ThingHandlerFactory.class)
+public class TeslascopeHandlerFactory extends BaseThingHandlerFactory {
+
+ private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(TESLASCOPE_THING);
+
+ private final HttpClient httpClient;
+
+ @Activate
+ public TeslascopeHandlerFactory(@Reference HttpClientFactory httpClientFactory, ComponentContext componentContext) {
+ super.activate(componentContext);
+ this.httpClient = httpClientFactory.getCommonHttpClient();
+ }
+
+ @Override
+ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+ return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+ }
+
+ @Override
+ protected @Nullable ThingHandler createHandler(Thing thing) {
+ ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+ if (TESLASCOPE_THING.equals(thingTypeUID)) {
+ return new TeslascopeHandler(thing, httpClient);
+ }
+
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeWebTargets.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeWebTargets.java
new file mode 100644
index 0000000000000..f0456149806d4
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/TeslascopeWebTargets.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles performing the actual HTTP requests for communicating with the TeslascopeAPI.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+@NonNullByDefault
+public class TeslascopeWebTargets {
+ private static final int TIMEOUT_MS = 30000;
+ private static final String BASE_URI = "https://teslascope.com/api/vehicle/";
+ private final Logger logger = LoggerFactory.getLogger(TeslascopeWebTargets.class);
+ private HttpClient httpClient;
+
+ public TeslascopeWebTargets(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ public String getDetailedInformation(String publicID, String apiKey)
+ throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ return invoke(BASE_URI + publicID + "/detailed?api_key=" + apiKey);
+ }
+
+ public void sendCommand(String publicID, String apiKey, String command)
+ throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ invoke(BASE_URI + publicID + "/command/" + command + "?api_key=" + apiKey);
+ return;
+ }
+
+ private String invoke(String uri) throws TeslascopeCommunicationException, TeslascopeAuthenticationException {
+ logger.debug("Calling url: {}", uri);
+ String jsonResponse = "";
+ int status = 0;
+ try {
+ Request request = httpClient.newRequest(uri).method(HttpMethod.GET).timeout(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ if (logger.isTraceEnabled()) {
+ logger.trace("{} request for {}", HttpMethod.GET, uri);
+ }
+ ContentResponse response = request.send();
+ status = response.getStatus();
+ jsonResponse = response.getContentAsString();
+ logger.trace("JSON response: '{}'", jsonResponse);
+ if (status == HttpStatus.UNAUTHORIZED_401) {
+ throw new TeslascopeAuthenticationException("Unauthorized");
+ }
+ if (!HttpStatus.isSuccess(status)) {
+ throw new TeslascopeCommunicationException(
+ String.format("Teslascope returned error <%d> while invoking %s", status, uri));
+ }
+ } catch (TimeoutException | ExecutionException | InterruptedException ex) {
+ throw new TeslascopeCommunicationException(ex.getLocalizedMessage(), ex);
+ }
+
+ return jsonResponse;
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ChargeState.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ChargeState.java
new file mode 100644
index 0000000000000..23cd5a6d7243e
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ChargeState.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for holding the set of parameters used to read the controller variables.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+@NonNullByDefault
+public class ChargeState {
+ @SerializedName("battery_level")
+ public int batteryLevel;
+
+ @SerializedName("usable_battery_level")
+ public int usableBatteryLevel;
+
+ @SerializedName("battery_range")
+ public float batteryRange;
+
+ @SerializedName("est_battery_range")
+ public float estBatteryRange;
+
+ @SerializedName("charge_enable_request")
+ public int chargeEnableRequest;
+
+ @SerializedName("charge_energy_added")
+ public float chargeEnergyAdded;
+
+ @SerializedName("charge_limit_soc")
+ public int chargeLimitSoc;
+
+ @SerializedName("charge_port_door_open")
+ public int chargePortDoorOpen;
+
+ @SerializedName("charge_rate")
+ public float chargeRate;
+
+ @SerializedName("charger_power")
+ public int chargerPower;
+
+ @SerializedName("charger_voltage")
+ public int chargerVoltage;
+
+ @SerializedName("charging_state")
+ public String chargingState = "";
+
+ @SerializedName("time_to_full_charge")
+ public float timeToFullCharge;
+
+ @SerializedName("scheduled_charging_pending")
+ public int scheduledChargingPending;
+
+ @SerializedName("scheduled_charging_start_time")
+ public String scheduledChargingStartTime = " ";
+
+ private ChargeState() {
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ClimateState.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ClimateState.java
new file mode 100644
index 0000000000000..5bb4750739178
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/ClimateState.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for holding the set of parameters used to read the controller variables.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+@NonNullByDefault
+public class ClimateState {
+ // climate_state
+ @SerializedName("is_auto_conditioning_on")
+ public int isAutoConditioningOn;
+
+ @SerializedName("is_climate_on")
+ public int isClimateOn;
+
+ @SerializedName("is_front_defroster_on")
+ public int isFrontDefrosterOn;
+
+ @SerializedName("is_preconditioning")
+ public int isPreconditioning;
+
+ @SerializedName("is_rear_defroster_on")
+ public int isRearDefrosterOn;
+
+ @SerializedName("seat_heater_left")
+ public int seatHeaterLeft;
+
+ @SerializedName("seat_heater_rear_center")
+ public int seatHeaterRearCenter;
+
+ @SerializedName("seat_heater_rear_left")
+ public int seatHeaterRearLeft;
+
+ @SerializedName("seat_heater_rear_right")
+ public int seatHeaterRearRight;
+
+ @SerializedName("seat_heater_right")
+ public int seatHeaterRight;
+
+ @SerializedName("side_mirror_heaters")
+ public int sideMirrorHeaters;
+
+ @SerializedName("smart_preconditioning")
+ public int smartPreconditioning;
+
+ @SerializedName("steering_wheel_heater")
+ public int steeringWheelHeater;
+
+ @SerializedName("wiper_blade_heater")
+ public int wiperBladeHeater;
+
+ @SerializedName("driver_temp_setting")
+ public float driverTempSetting;
+
+ @SerializedName("inside_temp")
+ public float insideTemp;
+
+ @SerializedName("outside_temp")
+ public float outsideTemp;
+
+ @SerializedName("passenger_temp_setting")
+ public float passengerTempSetting;
+
+ @SerializedName("fan_status")
+ public float fanStatus;
+
+ @SerializedName("left_temp_direction")
+ public int leftTempDirection;
+
+ @SerializedName("max_avail_temp")
+ public float maxAvailTemp;
+
+ @SerializedName("min_avail_temp")
+ public float minAvailTemp;
+
+ @SerializedName("right_temp_direction")
+ public int rightTempDirection;
+
+ private ClimateState() {
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DetailedInformation.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DetailedInformation.java
new file mode 100644
index 0000000000000..b8c49f106c76a
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DetailedInformation.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for holding the set of parameters used to read the controller variables.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+
+@NonNullByDefault
+public class DetailedInformation {
+ public String vin = "";
+ public String name = "";
+ public String state = "";
+ public double odometer;
+
+ @SerializedName("vehicle_state")
+ public @NonNullByDefault({}) VehicleState vehicleState;
+
+ @SerializedName("climate_state")
+ public @NonNullByDefault({}) ClimateState climateState;
+
+ @SerializedName("charge_state")
+ public @NonNullByDefault({}) ChargeState chargeState;
+
+ @SerializedName("drive_state")
+ public @NonNullByDefault({}) DriveState driveState;
+
+ private DetailedInformation() {
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DriveState.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DriveState.java
new file mode 100644
index 0000000000000..353f9afab6d07
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/DriveState.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for holding the set of parameters used to read the controller variables.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+@NonNullByDefault
+public class DriveState {
+ // drive state
+ public int heading;
+ public float latitude;
+ public float longitude;
+
+ @SerializedName("shift_state")
+ public String shiftState = "";
+
+ public float power;
+ public float speed = 0;
+
+ private DriveState() {
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/VehicleState.java b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/VehicleState.java
new file mode 100644
index 0000000000000..319eed664a09d
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/java/org/openhab/binding/teslascope/internal/api/VehicleState.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.teslascope.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class for holding the set of parameters used to read the controller variables.
+ *
+ * @author Paul Smedley - Initial Contribution
+ *
+ */
+@NonNullByDefault
+public class VehicleState {
+ // vehicle_state
+ public int locked;
+
+ @SerializedName("sentry_mode")
+ public int sentryMode;
+
+ @SerializedName("valet_mode")
+ public int valetMode;
+
+ @SerializedName("software_update_status")
+ public String softwareUpdateStatus = "";
+
+ @SerializedName("software_update_version")
+ public String softwareUpdateVersion = "";
+
+ @SerializedName("fd_window")
+ public int fdWindow;
+
+ @SerializedName("fp_window")
+ public int fpWindow;
+
+ @SerializedName("rd_window")
+ public int rdWindow;
+
+ @SerializedName("rp_window")
+ public int rpWindow;
+
+ @SerializedName("sun_roof_state")
+ public String sunRoofState = "";
+
+ @SerializedName("sunRoofPercentOpen")
+ public int sunRoofPercentOpen;
+
+ @SerializedName("homelink_nearby")
+ public int homelinkNearby;
+
+ @SerializedName("tpms_pressure_fl")
+ public double tpmsPressureFL;
+
+ @SerializedName("tpms_pressure_fr")
+ public double tpmsPressureFR;
+
+ @SerializedName("tpms_pressure_rl")
+ public double tpmsPressureRL;
+
+ @SerializedName("tpms_pressure_rr")
+ public double tpmsPressureRR;
+
+ @SerializedName("tpms_soft_warning_fl")
+ public int tpmsSoftWarningFL;
+
+ @SerializedName("tpms_soft_warning_fr")
+ public int tpmsSoftWarningFR;
+
+ @SerializedName("tpms_soft_warning_rl")
+ public int tpmsSoftWarningRL;
+
+ @SerializedName("tpms_soft_warning_rr")
+ public int tpmsSoftWarningRR;
+
+ public int df;
+ public int dr;
+ public int pf;
+ public int pr;
+ public int ft;
+ public int rt;
+
+ private VehicleState() {
+ }
+}
diff --git a/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/addon/addon.xml
new file mode 100644
index 0000000000000..6684560bb52cd
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/addon/addon.xml
@@ -0,0 +1,11 @@
+
+
+
+ binding
+ Teslascope
+ This is the binding for Teslascope.
+ cloud
+
+
diff --git a/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/i18n/teslascope.properties b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/i18n/teslascope.properties
new file mode 100644
index 0000000000000..c72a8a65ffc97
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/i18n/teslascope.properties
@@ -0,0 +1,179 @@
+# add-on
+
+addon.teslascope.name = Teslascope
+addon.teslascope.description = This is the binding for Teslascope.
+
+# thing types
+
+thing-type.teslascope.vehicle.label = Teslascope
+thing-type.teslascope.vehicle.description = Access to Tesla Vehicle data via the Teslascope developer API
+
+# thing types config
+
+thing-type.config.teslascope.vehicle.apiKey.label = apiKey
+thing-type.config.teslascope.vehicle.apiKey.description = apiKey provided by Teslascope
+thing-type.config.teslascope.vehicle.publicID.label = Vehicle Public ID
+thing-type.config.teslascope.vehicle.publicID.description = Vehicle public ID listed in Teslascope
+thing-type.config.teslascope.vehicle.refreshInterval.label = Refresh Interval
+thing-type.config.teslascope.vehicle.refreshInterval.description = Interval the API is polled in sec.
+
+# channel types
+
+channel-type.teslascope.auto-conditioning.label = Auto Conditioning
+channel-type.teslascope.auto-conditioning.description = Turns on auto-conditioning (a/c or heating)
+channel-type.teslascope.battery-level.label = Battery Level
+channel-type.teslascope.battery-level.description = Vehicle Battery Level
+channel-type.teslascope.battery-range.label = Battery Range
+channel-type.teslascope.battery-range.description = Range of the battery
+channel-type.teslascope.center-rear-seat-heater.label = Center Rear Seat Heater
+channel-type.teslascope.center-rear-seat-heater.description = Indicates if the center rear seat heater is switched on
+channel-type.teslascope.charge-energy-added.label = Charge Energy Added
+channel-type.teslascope.charge-energy-added.description = Energy added, in kWh, during the last charging session
+channel-type.teslascope.charge-limit-soc-standard.label = Charge Limit SOC Standard
+channel-type.teslascope.charge-limit-soc-standard.description = Standard charging limit of the vehicle, in %
+channel-type.teslascope.charge-port.label = Charge Port
+channel-type.teslascope.charge-port.description = Open the Charge Port (ON) or indicates the state of the Charge Port (ON/OFF if Open/Closed)
+channel-type.teslascope.charge-rate.label = Charge Rate
+channel-type.teslascope.charge-rate.description = Distance per hour charging rate
+channel-type.teslascope.charge.label = Charge
+channel-type.teslascope.charge.description = Start (ON) or stop (OFF) charging
+channel-type.teslascope.charger-power.label = Charger Power
+channel-type.teslascope.charger-power.description = Power actually delivered by the charger
+channel-type.teslascope.charger-voltage.label = Charger Voltage
+channel-type.teslascope.charger-voltage.description = Voltage (V) actually presented by the charger
+channel-type.teslascope.charging-state.label = Charging State
+channel-type.teslascope.charging-state.description = Charging State
+channel-type.teslascope.climate.label = Climate
+channel-type.teslascope.climate.description = Climate status indicator
+channel-type.teslascope.door-lock.label = Door Lock
+channel-type.teslascope.door-lock.description = Lock or unlock the car
+channel-type.teslascope.driver-front-door.label = Driver Front Door
+channel-type.teslascope.driver-front-door.description = Indicates if the front door at the driver's side is opened
+channel-type.teslascope.driver-rear-door.label = Driver Rear Door
+channel-type.teslascope.driver-rear-door.description = Indicates if the rear door at the driver's side is opened
+channel-type.teslascope.driver-temp.label = Driver Temperature
+channel-type.teslascope.driver-temp.description = Indicates the auto conditioning temperature set at the driver's side
+channel-type.teslascope.estimated-battery-range.label = Estimated Battery Range
+channel-type.teslascope.estimated-battery-range.description = Estimated battery range
+channel-type.teslascope.fan.label = Fan
+channel-type.teslascope.fan.description = Indicates the speed (0-7) of the fan
+channel-type.teslascope.flash-lights.label = Flash Lights
+channel-type.teslascope.flash-lights.description = Flash the lights of the car (when ON is received)
+channel-type.teslascope.front-defroster.label = Front Defroster
+channel-type.teslascope.front-defroster.description = Indicates if the front defroster is enabled
+channel-type.teslascope.front-trunk.label = Front Trunk
+channel-type.teslascope.front-trunk.description = Indicates if the front trunk is opened, or open the front trunk when ON is received
+channel-type.teslascope.heading.label = Heading
+channel-type.teslascope.heading.description = Indicates the (compass) heading of the car, in 0-360 degrees
+channel-type.teslascope.homelink.label = Homelink Nearby
+channel-type.teslascope.homelink.description = Indicates if the Home Link is nearby
+channel-type.teslascope.honk-horn.label = Honk the Horn
+channel-type.teslascope.honk-horn.description = Honk the horn of the vehicle, when ON is received
+channel-type.teslascope.inside-temp.label = Inside Temperature
+channel-type.teslascope.inside-temp.description = Indicates the inside temperature of the vehicle
+channel-type.teslascope.left-rear-seat-heater.label = Left Rear Seat Heater
+channel-type.teslascope.left-rear-seat-heater.description = Indicates if the left rear seat heater is switched on
+channel-type.teslascope.left-seat-heater.label = Left Seat Heater
+channel-type.teslascope.left-seat-heater.description = Indicates if the left seat heater is switched on
+channel-type.teslascope.left-temp-direction.label = Left Temperature Direction
+channel-type.teslascope.left-temp-direction.description = Not documented / To be defined
+channel-type.teslascope.location.label = Location
+channel-type.teslascope.location.description = The actual position of the vehicle
+channel-type.teslascope.max-available-temp.label = Maximum Temperature
+channel-type.teslascope.max-available-temp.description = Indicates the maximum inside temperature of the vehicle
+channel-type.teslascope.min-available-temp.label = Minimum Temperature
+channel-type.teslascope.min-available-temp.description = Indicates the minimal inside temperature of the vehicle
+channel-type.teslascope.odometer.label = Odometer
+channel-type.teslascope.odometer.description = Vehicle Odometer
+channel-type.teslascope.outside-temp.label = Outside Temperature
+channel-type.teslascope.outside-temp.description = Indicates the outside temperature of the vehicle
+channel-type.teslascope.passenger-front-door.label = Passenger Front Door
+channel-type.teslascope.passenger-front-door.description = Indicates if the front door at the passenger's side is opened
+channel-type.teslascope.passenger-rear-door.label = Passenger Rear Door
+channel-type.teslascope.passenger-rear-door.description = Indicates if the rear door at the passenger's side is opened
+channel-type.teslascope.passenger-temp.label = Passenger Temperature
+channel-type.teslascope.passenger-temp.description = Indicates the auto conditioning temperature set at the passenger's side
+channel-type.teslascope.power.label = Power
+channel-type.teslascope.power.description = Net kW flowing in (+) or out (-) of the battery
+channel-type.teslascope.preconditioning.label = Preconditioning
+channel-type.teslascope.preconditioning.description = Indicates if preconditioning is activated
+channel-type.teslascope.rear-defroster.label = Rear Defroster
+channel-type.teslascope.rear-defroster.description = Indicates if the rear defroster is enabled
+channel-type.teslascope.rear-trunk.label = Rear Trunk
+channel-type.teslascope.rear-trunk.description = Indicates if the rear trunk is opened, or open/close the rear trunk when ON/OFF is received
+channel-type.teslascope.right-rear-seat-heater.label = Right Rear Seat Heater
+channel-type.teslascope.right-rear-seat-heater.description = Indicates if the right rear seat heater is switched on
+channel-type.teslascope.right-seat-heater.label = Right Seat Heater
+channel-type.teslascope.right-seat-heater.description = Indicates if the right seat heater is switched on
+channel-type.teslascope.right-temp-direction.label = Right Temperature Direction
+channel-type.teslascope.right-temp-direction.description = Not documented / To be defined
+channel-type.teslascope.scheduled-charging-pending.label = Scheduled Charging Pending
+channel-type.teslascope.scheduled-charging-pending.description = Indicates if a scheduled charging session is still pending
+channel-type.teslascope.scheduled-charging-start.label = Scheduled Charging Start
+channel-type.teslascope.scheduled-charging-start.description = Indicates when the scheduled charging session will start, in yyyy-MM-dd'T'HH:mm:ss format
+channel-type.teslascope.sentry-mode.label = Sentry Mode
+channel-type.teslascope.sentry-mode.description = Activates or deactivates sentry mode
+channel-type.teslascope.shift-state.label = Shift State
+channel-type.teslascope.shift-state.description = Indicates the state of the transmission, “P”, “D”, “R”, or “N”
+channel-type.teslascope.side-mirror-heaters.label = Side Mirror Heaters
+channel-type.teslascope.side-mirror-heaters.description = Indicates if the side mirror heaters are switched on
+channel-type.teslascope.smart-preconditioning.label = Smart Preconditioning
+channel-type.teslascope.smart-preconditioning.description = Indicates if smart preconditioning is switched on
+channel-type.teslascope.software-update-available.label = Update Available
+channel-type.teslascope.software-update-available.description = Car software or map update available
+channel-type.teslascope.software-update-status.label = Update Status
+channel-type.teslascope.software-update-status.description = Car software or map update status
+channel-type.teslascope.software-update-version.label = Update Version
+channel-type.teslascope.software-update-version.description = Car software or map version to update to
+channel-type.teslascope.speed.label = Speed
+channel-type.teslascope.speed.description = Vehicle speed
+channel-type.teslascope.steering-wheel-heater.label = Steering Wheel Heater
+channel-type.teslascope.steering-wheel-heater.description = Turns On/Off the steering wheel heater
+channel-type.teslascope.sunroof-state.label = Sunroof State
+channel-type.teslascope.sunroof-state.description = Valid states are “unknown”, “open”, “closed”, “vent”, “comfort”. Accepts commands "close" and "vent".
+channel-type.teslascope.sunroof.label = Sunroof
+channel-type.teslascope.sunroof.description = Indicates the opening state of the sunroof (0% closed, 100% fully open)
+channel-type.teslascope.time-to-full-charge.label = Time To Full Charge
+channel-type.teslascope.time-to-full-charge.description = Number of hours to fully charge the battery
+channel-type.teslascope.tpms-pressure-fl.label = Tyre Pressure FL
+channel-type.teslascope.tpms-pressure-fl.description = Tyre Pressure Front Left
+channel-type.teslascope.tpms-pressure-fr.label = Tyre Pressure FR
+channel-type.teslascope.tpms-pressure-fr.description = Tyre Pressure Front Right
+channel-type.teslascope.tpms-pressure-rl.label = Tyre Pressure RL
+channel-type.teslascope.tpms-pressure-rl.description = Tyre Pressure Rear Left
+channel-type.teslascope.tpms-pressure-rr.label = Tyre Pressure RR
+channel-type.teslascope.tpms-pressure-rr.description = Tyre Pressure Rear Right
+channel-type.teslascope.tpms-soft-warning-fl.label = Tyre Pressure Warning FL
+channel-type.teslascope.tpms-soft-warning-fl.description = Tyre Pressure Front Left - warning for low pressure
+channel-type.teslascope.tpms-soft-warning-fr.label = Tyre Pressure Warning FR
+channel-type.teslascope.tpms-soft-warning-fr.description = Tyre Pressure Front Right - warning for low pressure
+channel-type.teslascope.tpms-soft-warning-rl.label = Tyre Pressure Warning RL
+channel-type.teslascope.tpms-soft-warning-rl.description = Tyre Pressure Rear Left - warning for low pressure
+channel-type.teslascope.tpms-soft-warning-rr.label = Tyre Pressure Warning RR
+channel-type.teslascope.tpms-soft-warning-rr.description = Tyre Pressure Rear Right - warning for low pressure
+channel-type.teslascope.usable-battery-level.label = Usable Battery Level
+channel-type.teslascope.usable-battery-level.description = Indicates the % of battery that can be used for vehicle functions like driving
+channel-type.teslascope.valet-mode.label = Valet Mode
+channel-type.teslascope.valet-mode.description = Enable or disable Valet Mode
+channel-type.teslascope.vehicle-name.label = Name
+channel-type.teslascope.vehicle-name.description = Vehicle Name
+channel-type.teslascope.vehicle-state.label = Vehicle State
+channel-type.teslascope.vehicle-state.description = Vehicle State
+channel-type.teslascope.vin.label = VIN
+channel-type.teslascope.vin.description = Vehicle Identification Number
+channel-type.teslascope.wiper-blade-heater.label = Wiperblade Heater
+channel-type.teslascope.wiper-blade-heater.description = Indicates if the wiperblade heater is switched on
+
+# thing types
+
+thing-type.teslascope.service.label = Teslascope
+thing-type.teslascope.service.description = Access to Tesla Vehicle data via the Teslascope developer API
+
+# thing types config
+
+thing-type.config.teslascope.service.apiKey.label = apiKey
+thing-type.config.teslascope.service.apiKey.description = apiKey provided by Teslascope
+thing-type.config.teslascope.service.publicID.label = Vehicle Public ID
+thing-type.config.teslascope.service.publicID.description = Vehicle public ID listed in Teslascope
+thing-type.config.teslascope.service.refreshInterval.label = Refresh Interval
+thing-type.config.teslascope.service.refreshInterval.description = Interval the API is polled in sec.
diff --git a/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644
index 0000000000000..f76aba92644d2
--- /dev/null
+++ b/bundles/org.openhab.binding.teslascope/src/main/resources/OH-INF/thing/thing-types.xml
@@ -0,0 +1,525 @@
+
+
+
+
+
+ Access to Tesla Vehicle data via the Teslascope developer API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ apiKey provided by Teslascope
+
+
+
+ Vehicle public ID listed in Teslascope
+
+
+
+ Interval the API is polled in sec.
+ 60
+ true
+
+
+
+
+
+ String
+
+ Vehicle Identification Number
+
+
+
+ String
+
+ Vehicle Name
+
+
+
+ String
+
+ Vehicle State
+
+
+
+ Number:Length
+
+ Vehicle Odometer
+
+
+
+ Number:Dimensionless
+
+ Vehicle Battery Level
+
+
+
+ String
+
+ Charging State
+
+
+
+ Switch
+
+ Car software or map update available
+
+
+
+ String
+
+ Car software or map update status
+
+
+
+ String
+
+ Car software or map version to update to
+
+
+
+ Switch
+
+ Turns on auto-conditioning (a/c or heating)
+
+
+ Number:Length
+
+ Range of the battery
+
+
+
+ Switch
+
+ Indicates if the center rear seat heater is switched on
+
+
+
+ Switch
+
+ Start (ON) or stop (OFF) charging
+
+
+ Number:Energy
+
+ Energy added, in kWh, during the last charging session
+
+
+
+ Dimmer
+
+ Standard charging limit of the vehicle, in %
+
+
+
+ Switch
+
+ Open the Charge Port (ON) or indicates the state of the Charge Port (ON/OFF if Open/Closed)
+
+
+ Number:Speed
+
+ Distance per hour charging rate
+
+
+
+ Number:Power
+
+ Power actually delivered by the charger
+
+
+
+ Number:ElectricPotential
+
+ Voltage (V) actually presented by the charger
+
+
+
+ Switch
+
+ Climate status indicator
+
+
+
+ Contact
+
+ Indicates if the front door at the driver's side is opened
+
+
+
+ Switch
+
+ Lock or unlock the car
+
+
+ Contact
+
+ Indicates if the rear door at the driver's side is opened
+
+
+
+ Number:Temperature
+
+ Indicates the auto conditioning temperature set at the driver's side
+
+
+
+ Number:Length
+
+ Estimated battery range
+
+
+
+ Number
+
+ Indicates the speed (0-7) of the fan
+
+
+
+ Switch
+
+ Flash the lights of the car (when ON is received)
+
+
+ Switch
+
+ Indicates if the front defroster is enabled
+
+
+
+ Switch
+
+ Indicates if the front trunk is opened, or open the front trunk when ON is received
+
+
+ Number:Angle
+
+ Indicates the (compass) heading of the car, in 0-360 degrees
+
+
+
+ Switch
+
+ Honk the horn of the vehicle, when ON is received
+
+
+ Switch
+
+ Indicates if the Home Link is nearby
+
+
+ Number:Temperature
+
+ Indicates the inside temperature of the vehicle
+
+
+
+ Number
+
+ Not documented / To be defined
+
+
+
+ Location
+
+ The actual position of the vehicle
+
+
+
+ Switch
+
+ Indicates if the left seat heater is switched on
+
+
+
+ Switch
+
+ Indicates if the left rear seat heater is switched on
+
+
+
+ Number:Temperature
+
+ Indicates the minimal inside temperature of the vehicle
+
+
+
+ Number:Temperature
+
+ Indicates the maximum inside temperature of the vehicle
+
+
+
+ Number:Temperature
+
+ Indicates the outside temperature of the vehicle
+
+
+
+ Number
+
+ Indicates the auto conditioning temperature set at the passenger's side
+
+
+
+ Contact
+
+ Indicates if the front door at the passenger's side is opened
+
+
+
+ Contact
+
+ Indicates if the rear door at the passenger's side is opened
+
+
+
+ Number:Power
+
+ Net kW flowing in (+) or out (-) of the battery
+
+
+
+ Switch
+
+ Indicates if preconditioning is activated
+
+
+
+ Switch
+
+ Indicates if the rear defroster is enabled
+
+
+
+ Switch
+
+ Indicates if the rear trunk is opened, or open/close the rear trunk when ON/OFF is received
+
+
+ Switch
+
+ Indicates if the right seat heater is switched on
+
+
+
+ Switch
+
+ Indicates if the right rear seat heater is switched on
+
+
+
+ Number
+
+ Not documented / To be defined
+
+
+
+ Switch
+
+ Indicates if a scheduled charging session is still pending
+
+
+
+ DateTime
+
+ Indicates when the scheduled charging session will start, in yyyy-MM-dd'T'HH:mm:ss format
+
+
+
+ Switch
+
+ Activates or deactivates sentry mode
+
+
+ String
+
+ Indicates the state of the transmission, “P”, “D”, “R”, or “N”
+
+
+
+ Switch
+
+ Indicates if the side mirror heaters are switched on
+
+
+
+ Switch
+
+ Indicates if smart preconditioning is switched on
+
+
+
+ Number:Speed
+
+ Vehicle speed
+
+
+
+ Switch
+
+ Turns On/Off the steering wheel heater
+
+
+
+ String
+
+ Valid states are “unknown”, “open”, “closed”, “vent”, “comfort”. Accepts commands "close" and "vent".
+
+
+
+ Dimmer
+
+ Indicates the opening state of the sunroof (0% closed, 100% fully open)
+
+
+
+ Number
+
+ Number of hours to fully charge the battery
+
+
+
+ Number:Pressure
+
+ Tyre Pressure Front Left
+
+
+
+ Number:Pressure
+
+ Tyre Pressure Front Right
+
+
+
+ Number:Pressure
+
+ Tyre Pressure Rear Left
+
+
+
+ Number:Pressure
+
+ Tyre Pressure Rear Right
+
+
+
+ Switch
+
+ Tyre Pressure Front Left - warning for low pressure
+
+
+
+ Switch
+
+ Tyre Pressure Front Right - warning for low pressure
+
+
+
+ Switch
+
+ Tyre Pressure Rear Left - warning for low pressure
+
+
+
+ Switch
+
+ Tyre Pressure Rear Right - warning for low pressure
+
+
+
+ Number
+
+ Indicates the % of battery that can be used for vehicle functions like driving
+
+
+
+ Switch
+
+ Enable or disable Valet Mode
+
+
+ Switch
+
+ Indicates if the wiperblade heater is switched on
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 49293ac78ea89..1f26e09f2c2d3 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -406,6 +406,7 @@
org.openhab.binding.tellstickorg.openhab.binding.teslaorg.openhab.binding.teslapowerwall
+ org.openhab.binding.teslascopeorg.openhab.binding.tibberorg.openhab.binding.tivoorg.openhab.binding.touchwand