Skip to content

Commit

Permalink
Update to version 0.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
PlusPlus-ua committed Apr 26, 2023
1 parent 057ea7a commit b367c76
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 49 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning].

- Initial release


## [0.1.1] - 2023-04-26

### Added
Expand All @@ -22,3 +23,10 @@ and this project adheres to [Semantic Versioning].
### Changed

- Updated strings.json


## [0.1.2] - 2023-04-26

### Changed

- Changed a way to obtain device credentials from Tuya IOT cloud, possible fix to (#2)
68 changes: 34 additions & 34 deletions custom_components/tuya_ble/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from dataclasses import dataclass
import json
from typing import Any
from typing import Any, Iterable

from homeassistant.const import CONF_ADDRESS
from homeassistant.components.tuya.const import (
Expand Down Expand Up @@ -36,6 +36,7 @@
from .tuya_ble import AbstaractTuyaBLEDeviceManager, TuyaBLEDevice, TuyaBLEDeviceCredentials

from .const import (
CONF_PRODUCT_MODEL,
CONF_UUID,
CONF_LOCAL_KEY,
CONF_DEVICE_ID,
Expand All @@ -44,6 +45,7 @@
CONF_DEVICE_NAME,
CONF_PRODUCT_NAME,
DOMAIN,
TUYA_API_DEVICES_URL,
TUYA_API_FACTORY_INFO_URL,
TUYA_FACTORY_INFO_MAC,
)
Expand Down Expand Up @@ -77,6 +79,7 @@ class TuyaCloudCacheItem:
CONF_PRODUCT_ID,
CONF_DEVICE_NAME,
CONF_PRODUCT_NAME,
CONF_PRODUCT_MODEL,
]

_cache: dict[str, TuyaCloudCacheItem] = {}
Expand Down Expand Up @@ -164,39 +167,35 @@ async def login(self, add_to_cache: bool = False) -> dict[Any, Any]:
return await self._login(self._data, add_to_cache)

async def _fill_cache_item(self, item: TuyaCloudCacheItem) -> None:
openmq = TuyaOpenMQ(item.api)
openmq.start()

device_manager = TuyaDeviceManager(item.api, openmq)
await self._hass.async_add_executor_job(
device_manager.update_device_list_in_smart_home
devices_response = await self._hass.async_add_executor_job(
item.api.get,
TUYA_API_DEVICES_URL % (item.api.token_info.uid),
)

for tuya_device in device_manager.device_map.values():
response = await self._hass.async_add_executor_job(
item.api.get,
"%s=%s" % (
TUYA_API_FACTORY_INFO_URL,
tuya_device.id,
),
)
factory_info = response[TUYA_RESPONSE_RESULT][0]
if TUYA_FACTORY_INFO_MAC in factory_info:
mac = ':'.join(
factory_info[TUYA_FACTORY_INFO_MAC][i:i + 2]
for i in range(0, 12, 2)
).upper()
item.credentials[mac] = {
CONF_ADDRESS: mac,
CONF_UUID: tuya_device.uuid,
CONF_LOCAL_KEY: tuya_device.local_key,
CONF_DEVICE_ID: tuya_device.id,
CONF_CATEGORY: tuya_device.category,
CONF_PRODUCT_ID: tuya_device.product_id,
CONF_DEVICE_NAME: tuya_device.name,
CONF_PRODUCT_NAME: tuya_device.product_name,
}
openmq.stop()
if devices_response.get(TUYA_RESPONSE_SUCCESS):
devices = devices_response.get(TUYA_RESPONSE_RESULT)
if isinstance(devices, Iterable):
for device in devices:
fi_response = await self._hass.async_add_executor_job(
item.api.get,
TUYA_API_FACTORY_INFO_URL % (device.get("id")),
)
factory_info = fi_response[TUYA_RESPONSE_RESULT][0]
if TUYA_FACTORY_INFO_MAC in factory_info:
mac = ':'.join(
factory_info[TUYA_FACTORY_INFO_MAC][i:i + 2]
for i in range(0, 12, 2)
).upper()
item.credentials[mac] = {
CONF_ADDRESS: mac,
CONF_UUID: device.get("uuid"),
CONF_LOCAL_KEY: device.get("local_key"),
CONF_DEVICE_ID: device.get("id"),
CONF_CATEGORY: device.get("category"),
CONF_PRODUCT_ID: device.get("product_id"),
CONF_DEVICE_NAME: device.get("name"),
CONF_PRODUCT_MODEL: device.get("model"),
CONF_PRODUCT_NAME: device.get("product_name"),
}

async def build_cache(self) -> None:
global _cache
Expand Down Expand Up @@ -274,6 +273,7 @@ async def get_device_credentials(
credentials.get(CONF_CATEGORY, ""),
credentials.get(CONF_PRODUCT_ID, ""),
credentials.get(CONF_DEVICE_NAME, ""),
credentials.get(CONF_PRODUCT_MODEL, ""),
credentials.get(CONF_PRODUCT_NAME, ""),
)
_LOGGER.debug("Retrieved: %s", result)
Expand All @@ -283,7 +283,7 @@ async def get_device_credentials(
self._data.update(credentials)

return result

@property
def data(self) -> dict[str, Any]:
return self._data
4 changes: 3 additions & 1 deletion custom_components/tuya_ble/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
CONF_CATEGORY: Final = "category"
CONF_PRODUCT_ID: Final = "product_id"
CONF_DEVICE_NAME: Final = "device_name"
CONF_PRODUCT_MODEL: Final = "product_model"
CONF_PRODUCT_NAME: Final = "product_name"

TUYA_API_FACTORY_INFO_URL: Final = "/v1.0/iot-03/devices/factory-infos?device_ids"
TUYA_API_DEVICES_URL: Final = "/v1.0/users/%s/devices"
TUYA_API_FACTORY_INFO_URL: Final = "/v1.0/iot-03/devices/factory-infos?device_ids=%s"
TUYA_FACTORY_INFO_MAC: Final = "mac"

BATTERY_STATE_LOW: Final = "low"
Expand Down
10 changes: 7 additions & 3 deletions custom_components/tuya_ble/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,12 @@ def get_device_info(device: TuyaBLEDevice) -> DeviceInfo | None:
product_info = get_product_info_by_ids(
device.category,
device.product_id
)
product_name = product_info.name if product_info else device.name
)
product_name : str
if product_info:
product_name = product_info.name
else:
product_name = device.name
result = DeviceInfo(
connections={(dr.CONNECTION_BLUETOOTH, device.address)},
hw_version=device.hardware_version,
Expand All @@ -279,7 +283,7 @@ def get_device_info(device: TuyaBLEDevice) -> DeviceInfo | None:
DEVICE_DEF_MANUFACTURER
),
model=("%s (%s)") % (
product_name,
device.product_model or product_name,
device.product_id,
),
name=("%s %s") % (
Expand Down
2 changes: 1 addition & 1 deletion custom_components/tuya_ble/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
"documentation": "https://www.home-assistant.io/integrations/tuya_ble",
"requirements": ["tuya-iot-py-sdk==0.6.6", "pycountry"],
"iot_class": "local_push",
"version": "0.1.1"
"version": "0.1.2"
}
3 changes: 3 additions & 0 deletions custom_components/tuya_ble/tuya_ble/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class TuyaBLEDeviceCredentials:
category: str
product_id: str
device_name: str | None
product_model: str | None
product_name: str | None

def __str__(self):
Expand All @@ -23,11 +24,13 @@ def __str__(self):
"category: %s, "
"product_id: %s, "
"device_name: %s, "
"product_model: %s, "
"product_name: %s"
) % (
self.category,
self.product_id,
self.device_name,
self.product_model,
self.product_name,
)

Expand Down
64 changes: 54 additions & 10 deletions custom_components/tuya_ble/tuya_ble/tuya_ble.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def __init__(
self._connect_lock = asyncio.Lock()
self._client: BleakClientWithServiceCache | None = None
self._expected_disconnect = False
self._connected_callbacks: list[Callable[[], None]] = []
self._connected_callbacks: list[Callable[[], None]] = []
self._callbacks: list[Callable[[list[TuyaBLEDataPoint]], None]] = []
self._disconnected_callbacks: list[Callable[[], None]] = []
self._current_seq_num = 1
Expand Down Expand Up @@ -409,6 +409,13 @@ def product_id(self) -> str:
else:
return ""

@property
def product_model(self) -> str:
if self._device_info is not None:
return self._device_info.product_model
else:
return ""

@property
def product_name(self) -> str:
if self._device_info is not None:
Expand Down Expand Up @@ -621,6 +628,8 @@ async def _ensure_connected(self) -> None:
exc_info=True
)
continue
else:
continue

if self._client and self._client.is_connected:
_LOGGER.debug(
Expand All @@ -646,6 +655,8 @@ async def _ensure_connected(self) -> None:
exc_info=True
)
continue
else:
continue

if self._client and self._client.is_connected:
_LOGGER.debug(
Expand All @@ -671,10 +682,34 @@ async def _ensure_connected(self) -> None:
exc_info=True
)
continue
else:
continue

break

self._fire_connected_callbacks()

if self._client:
if self._client.is_connected:
if self._is_paired:
_LOGGER.debug(
"%s: Successfully connected",
self.address
)
self._fire_connected_callbacks()
else:
_LOGGER.error(
"%s: Connected but not paired",
self.address
)
else:
_LOGGER.error(
"%s: Not connected",
self.address
)
else:
_LOGGER.error(
"%s: No client device",
self.address
)

async def _reconnect(self, use_delay: bool = True) -> None:
"""Attempt a reconnect"""
Expand Down Expand Up @@ -805,7 +840,7 @@ async def _send_packets_locked(self, packets: list[bytes]) -> None:
ex,
)
await self._execute_disconnect()
raise
raise BleakError from ex
except BleakError as ex:
# Disconnect so we can reset state and try again
_LOGGER.debug(
Expand Down Expand Up @@ -869,12 +904,21 @@ async def _send_packet_while_connected(
future = asyncio.Future()
self._input_expected_responses[seq_num] = future

_LOGGER.debug(
"%s: Sending packet: #%s %s",
self.address,
seq_num,
code.name,
)
if response_to > 0:
_LOGGER.debug(
"%s: Sending packet: #%s %s in response to #%s",
self.address,
seq_num,
code.name,
response_to,
)
else:
_LOGGER.debug(
"%s: Sending packet: #%s %s",
self.address,
seq_num,
code.name,
)
packets: list[bytes] = self._build_packets(
seq_num, code, data, response_to
)
Expand Down

0 comments on commit b367c76

Please sign in to comment.