Skip to content

Commit

Permalink
Merge pull request #181 from zabuldon/dev
Browse files Browse the repository at this point in the history
2021-04-01
  • Loading branch information
alandtse committed Apr 2, 2021
2 parents 813da15 + 69599db commit 060b3be
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pytest==6.2.2; python_version >= "3.6"
pytz==2021.1; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.5"
pyyaml==5.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
regex==2021.3.17; python_version >= "3.6"
requests==2.15.1; python_version >= "3.5"
requests==2.20.0; python_version >= "3.5"
six==1.15.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0"
snowballstemmer==2.1.0; python_version >= "3.6"
soupsieve==2.2.1; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.6"
Expand Down
6 changes: 6 additions & 0 deletions teslajsonpy/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from teslajsonpy.homeassistant.lock import ChargerLock, Lock
from teslajsonpy.homeassistant.sentry_mode import SentryModeSwitch
from teslajsonpy.homeassistant.trunk import FrunkLock, TrunkLock
from teslajsonpy.homeassistant.heated_seats import HeatedSeatSwitch

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -545,6 +546,11 @@ def _add_components(self, car):
self.__components.append(TrunkLock(car, self))
self.__components.append(FrunkLock(car, self))
self.__components.append(UpdateSensor(car, self))
self.__components.append(HeatedSeatSwitch(car, self, 'left'))
self.__components.append(HeatedSeatSwitch(car, self, 'right'))
self.__components.append(HeatedSeatSwitch(car, self, 'rear_left'))
self.__components.append(HeatedSeatSwitch(car, self, 'rear_center'))
self.__components.append(HeatedSeatSwitch(car, self, 'rear_right'))

async def _wake_up(self, car_id):
car_vin = self._id_to_vin(car_id)
Expand Down
93 changes: 93 additions & 0 deletions teslajsonpy/homeassistant/heated_seats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# SPDX-License-Identifier: Apache-2.0
"""
Python Package for controlling Tesla API.
For more details about this api, please refer to the documentation at
https://github.com/zabuldon/teslajsonpy
"""
import time

from teslajsonpy.homeassistant.vehicle import VehicleDevice

seat_id_map = {
"left": 0,
"right": 1,
"rear_left": 2,
"rear_center": 4,
"rear_right": 5,
}


class HeatedSeatSwitch(VehicleDevice):
"""Home-assistant heated seat class for Tesla vehicles.
This is intended to be partially inherited by a Home-Assitant entity.
"""

def __init__(self, data, controller, seat_name):
"""Initialize a heated seat for the vehicle.
Parameters
----------
data : dict
The base state for a Tesla vehicle.
https://tesla-api.timdorr.com/vehicle/state/data
controller : teslajsonpy.Controller
The controller that controls updates to the Tesla API.
seat_name : string
The name of the seat to control.
One of "left", "right", "rear_left", "rear_center", "rear_right."
Returns
-------
None
"""
super().__init__(data, controller)
self.__manual_update_time = 0
self.__seat_heat_level = data['climate_state'][f'seat_heater_{seat_name}']
self.__seat_name = seat_name

self.type = f"heated seat {seat_name}"
self.hass_type = "switch"

self.name = self._name()

self.uniq_name = self._uniq_name()
self.bin_type = 0x7

async def async_update(self, wake_if_asleep=False, force=False) -> None:
"""Update the seat state."""
await super().async_update(wake_if_asleep=wake_if_asleep)
self.refresh()

def refresh(self) -> None:
"""Refresh data.
This assumes the controller has already been updated
"""
super().refresh()
last_update = self._controller.get_last_update_time(self._id)
if last_update >= self.__manual_update_time:
data = self._controller.get_climate_params(self._id)
self.__seat_heat_level = data[f'seat_heater_{self.__seat_name}'] if data else None

async def set_seat_heat_level(self, level):
"""Set heated seat level."""
data = await self._controller.command(
self._id, "remote_seat_heater_request", data={
'heater': seat_id_map[self.__seat_name],
'level': level
}, wake_if_asleep=True
)
if data and data["response"]["result"]:
self.__seat_heat_level = level
self.__manual_update_time = time.time()

def get_seat_heat_level(self):
"""Return current heated seat level."""
return self.__seat_heat_level

@staticmethod
def has_battery():
"""Return whether the device has a battery."""
return False
95 changes: 95 additions & 0 deletions tests/unit_tests/homeassistant/test_heated_seat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""Test door HeatedSeatSwitch."""

import pytest

from teslajsonpy.controller import Controller
from teslajsonpy.homeassistant.heated_seats import HeatedSeatSwitch

from tests.tesla_mock import TeslaMock


def test_has_battery(monkeypatch):
"""Test has_battery()."""

_mock = TeslaMock(monkeypatch)
_controller = Controller(None)

_data = _mock.data_request_vehicle()
_seat = HeatedSeatSwitch(_data, _controller, 'left')

assert not _seat.has_battery()


def test_get_seat_heat_level_on_init(monkeypatch):
"""Test get_seat_heat_level() after initialization."""

_mock = TeslaMock(monkeypatch)
_controller = Controller(None)

_data = _mock.data_request_vehicle()
_seat = HeatedSeatSwitch(_data, _controller, 'left')

assert not _seat is None
assert _seat.get_seat_heat_level() == 3 # 3 is mocked initial level for left seat from tesla_mock.py


@pytest.mark.asyncio
async def test_get_seat_heat_level_after_update(monkeypatch):
"""Test get_seat_heat_level() after an update."""

_mock = TeslaMock(monkeypatch)
_controller = Controller(None)

NEW_LEVEL = 1

_data = _mock.data_request_vehicle()
_data["climate_state"]['seat_heater_left'] = NEW_LEVEL
_seat = HeatedSeatSwitch(_data, _controller, 'left')

await _seat.async_update()

assert not _seat is None
assert _seat.get_seat_heat_level() == NEW_LEVEL


@pytest.mark.asyncio
async def test_set_get_seat_heat_level(monkeypatch):
"""Test HeatedSeatSwitch()."""

_mock = TeslaMock(monkeypatch)
_controller = Controller(None)

ORIG_LEVEL = 1
NEW_LEVEL = 2

_data = _mock.data_request_vehicle()
_data["climate_state"]["seat_heater_left"] = ORIG_LEVEL
_seat = HeatedSeatSwitch(_data, _controller, 'left')

await _seat.async_update()

await _seat.set_seat_heat_level(NEW_LEVEL)

assert not _seat is None
assert _seat.get_seat_heat_level() == NEW_LEVEL


@pytest.mark.asyncio
async def test_seat_same_level(monkeypatch):
"""Test set_seat_heat_level to same level."""

_mock = TeslaMock(monkeypatch)
_controller = Controller(None)

ORIG_LEVEL = 1

_data = _mock.data_request_vehicle()
_data["climate_state"]["seat_heater_left"] = ORIG_LEVEL
_seat = HeatedSeatSwitch(_data, _controller, 'left')

await _seat.async_update()

await _seat.set_seat_heat_level(ORIG_LEVEL)

assert not _seat is None
assert _seat.get_seat_heat_level() == ORIG_LEVEL

0 comments on commit 060b3be

Please sign in to comment.