y2kbug

Untitled

Mar 3rd, 2022 (edited)
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.30 KB | None | 0 0
  1. """Support for Sesame Japanese Version, by CANDY HOUSE."""
  2. from __future__ import annotations
  3.  
  4. import base64
  5. import datetime
  6. import pysesame2
  7. import requests
  8. import voluptuous as vol
  9. from Crypto.Cipher import AES
  10. from Crypto.Hash import CMAC
  11.  
  12. import homeassistant.helpers.config_validation as cv
  13. from homeassistant.components.lock import PLATFORM_SCHEMA, LockEntity
  14. from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_DEVICE_ID, CONF_NAME, CONF_API_KEY, CONF_DEVICE_ID, \
  15.     CONF_CLIENT_SECRET
  16. from homeassistant.core import HomeAssistant
  17. from homeassistant.helpers.entity_platform import AddEntitiesCallback
  18. from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
  19.  
  20. ATTR_SERIAL_NO = "serial"
  21.  
  22. PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
  23.     vol.Required(CONF_NAME): cv.string,
  24.     vol.Required(CONF_DEVICE_ID): cv.string,
  25.     vol.Required(CONF_API_KEY): cv.string,
  26.     vol.Required(CONF_CLIENT_SECRET): cv.string,
  27. })
  28.  
  29.  
  30. def setup_platform(
  31.     hass: HomeAssistant,
  32.     config: ConfigType,
  33.     add_entities: AddEntitiesCallback,
  34.     discovery_info: DiscoveryInfoType | None = None,
  35. ) -> None:
  36.     name = config.get(CONF_NAME)
  37.     device_id = config.get(CONF_DEVICE_ID)
  38.     api_key = config.get(CONF_API_KEY)
  39.     client_secret = config.get(CONF_CLIENT_SECRET)
  40.  
  41.     add_entities(
  42.         [SesameJPDevice(
  43.             name=name,
  44.             uuid=device_id,
  45.             api_key=api_key,
  46.             secret_key=client_secret,
  47.         )],
  48.         update_before_add=True,
  49.     )
  50.  
  51.  
  52. class SesameJPDevice(LockEntity):
  53.     def __init__(
  54.             self,
  55.             name,
  56.             uuid,
  57.             api_key,
  58.             secret_key,
  59.     ) -> None:
  60.         self._name: str = name
  61.         self._uuid: str = uuid
  62.         self._api_key: str = api_key
  63.         self._secret_key: str = secret_key
  64.         self._is_locked = False
  65.         self._responsive = False
  66.         self._battery = -1
  67.         self.update()
  68.  
  69.     @property
  70.     def name(self) -> str | None:
  71.         return self._name
  72.  
  73.     @property
  74.     def available(self) -> bool:
  75.         return self._responsive
  76.  
  77.     @property
  78.     def is_locked(self) -> bool:
  79.         return self._is_locked
  80.  
  81.     def lock(self, **kwargs) -> None:
  82.         self._sesame_command(action="LOCK")
  83.  
  84.     def unlock(self, **kwargs) -> None:
  85.         self._sesame_command(action="UNLOCK")
  86.  
  87.     def update(self) -> None:
  88.         response = requests.get(
  89.             "https://app.candyhouse.co/api/sesame2/{sesame2_uuid}".format(sesame2_uuid=self._uuid),
  90.             headers={
  91.                 "x-api-key": self._api_key,
  92.             },
  93.         )
  94.         state = response.json()
  95.  
  96.         if state:
  97.             self._responsive = True
  98.  
  99.             if state['CHSesame2Status'] == "locked":
  100.                 self._is_locked = True
  101.             else:
  102.                 self._is_locked = False
  103.             self._battery = state['batteryPercentage']
  104.         else:
  105.             self._responsive = False
  106.  
  107.     @property
  108.     def extra_state_attributes(self) -> dict:
  109.         return {}
  110.  
  111.     def _sesame_history(self) -> None:
  112.         response = requests.get(
  113.             "https://app.candyhouse.co/api/sesame2/{sesame2_uuid}/history?page=0&lg=1".format(sesame2_uuid=self._uuid),
  114.             headers={
  115.                 "x-api-key": self._api_key,
  116.             },
  117.         )
  118.         # return response.json()
  119.  
  120.     def _sesame_command(self, action) -> None:
  121.         if action == "LOCK":
  122.             cmd = 82
  123.         elif action != "UNLOCK":
  124.             cmd = 83
  125.         else:
  126.             return
  127.  
  128.         ts = int(datetime.datetime.now().timestamp())
  129.         message = ts.to_bytes(4, byteorder='little')
  130.         message = message.hex()[2:8]
  131.         cmac = CMAC.new(bytes.fromhex(secret_key), ciphermod=AES)
  132.         cmac.update(bytes.fromhex(message))
  133.         sign = cmac.hexdigest()
  134.  
  135.         response = requests.post(
  136.             "https://app.candyhouse.co/api/sesame2/{sesame2_uuid}/cmd".format(sesame2_uuid=self._uuid),
  137.             headers={
  138.                 "x-api-key": self._api_key,
  139.             },
  140.             json={
  141.                 "cmd": cmd,
  142.                 "history": base64.b64encode(bytes("Home-Assistant {action}".format(action=action), 'utf-8')).decode(),
  143.                 "sign": sign,
  144.             },
  145.         )
  146.         # return response.text
  147.  
Add Comment
Please, Sign In to add comment