Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for HA 2024.1.0 - replace deprecated unit constants #528

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
64b570e
Update zh-Hant.json
bluefoxlee Oct 20, 2021
0cb02e7
Test camera
a180285 Dec 26, 2021
708721a
Add chuangmi.camera.xiaobai to special
a180285 Dec 26, 2021
0f2b301
Add chuangmi.camera.xiaobai to special
a180285 Dec 26, 2021
75bed6e
Add chuangmi.camera.xiaobai to special
a180285 Dec 26, 2021
9776e4c
Add missing func async_setup_entry
a180285 Dec 26, 2021
443ac5a
Add camera type
a180285 Dec 26, 2021
a078bd0
Add access_tokens to camera
a180285 Dec 26, 2021
38936de
Refactor camera turn off/on code
a180285 Dec 26, 2021
f1ada04
Add is_on
a180285 Dec 27, 2021
48ddd68
replase _is_on with _status
a180285 Dec 27, 2021
ced2d6f
Test in-memoery camera
a180285 Dec 27, 2021
7f81b99
test
a180285 Dec 27, 2021
b5144da
use real camera
a180285 Dec 27, 2021
d2ef199
Check camera status
a180285 Dec 28, 2021
193d8bc
Add debug log
a180285 Dec 28, 2021
699c902
Add more debug log
a180285 Dec 28, 2021
9c50f1c
Change camera init status
a180285 Dec 28, 2021
b949e45
Add more log
a180285 Dec 28, 2021
8d9c63c
use update callback
a180285 Dec 28, 2021
bf02318
Remove some debug logs
a180285 Dec 28, 2021
6a94417
fix(toilet) support properties in function
chliny Feb 27, 2022
17b220c
Add files via upload
LeandroIssa May 22, 2022
3d3486a
Update fan.py
msmarks Jun 10, 2022
7445eeb
Add Catalan translation
dtalens Jul 22, 2022
11d88a4
modified: custom_components/xiaomi_miot_raw/cover.py
Aug 10, 2022
8c2dd34
Update all device tokens when update xiaomi user and password
alcarl May 1, 2023
f4d61b9
change api timeout 5s to 30s
alcarl May 1, 2023
e7248ea
请求api返回小米账号登录信息失效时,自动重新登陆
alcarl May 3, 2023
fdbfab6
Fix for HA 2024.1.0 - replace deprecated unit constants
Gerrett84 Jan 5, 2024
eca0b28
fix deprecated methods of NumberEntity
Gerrett84 Jan 6, 2024
3cf2144
Fix for Python 3.10
Gerrett84 Jan 6, 2024
bd3e1a4
Merge branch 'master' into pr/277
Gerrett84 Jan 6, 2024
22db4e9
Merge branch 'master' into pr/310
Gerrett84 Jan 6, 2024
723918a
Merge branch 'master' into pr/355
Gerrett84 Jan 6, 2024
0e62216
Merge branch 'master' into pr/413
Gerrett84 Jan 6, 2024
e7bdee1
Merge branch 'master' into pr/418
Gerrett84 Jan 6, 2024
0565fcc
Merge branch 'master' into pr/434
Gerrett84 Jan 6, 2024
dfed8dc
Merge branch 'master' into pr/443
Gerrett84 Jan 6, 2024
ef16c5a
Merge branch 'master' into pr/508
Gerrett84 Jan 6, 2024
81ec47b
Save the last status and modify the volume control
xiaolanglanglang Sep 19, 2021
d71da10
Merge branch 'pr/418'
Gerrett84 Jan 6, 2024
9aacb3f
Merge branch 'pr/253'
Gerrett84 Jan 6, 2024
fc91413
Merge branch 'pr/443'
Gerrett84 Jan 6, 2024
3b0de42
Merge branch 'pr/277'
Gerrett84 Jan 6, 2024
aaa01ca
Merge branch 'pr/310'
Gerrett84 Jan 6, 2024
f66cfd6
Merge branch 'pr/355'
Gerrett84 Jan 6, 2024
a307b7d
Merge branch 'pr/413'
Gerrett84 Jan 6, 2024
4400f44
Merge branch 'pr/434'
Gerrett84 Jan 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions custom_components/xiaomi_miot_raw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async def async_remove_entry(hass, entry):
async def _setup_micloud_entry(hass, config_entry):
"""Thanks to @AlexxIT """
data: dict = config_entry.data.copy()
hass.data[DOMAIN]['micloud_config'] = data
server_location = data.get('server_location') or 'cn'

session = aiohttp_client.async_create_clientsession(hass, auto_cleanup=False)
Expand Down
64 changes: 57 additions & 7 deletions custom_components/xiaomi_miot_raw/basic_dev_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
import time
import logging
from datetime import timedelta
from datetime import timedelta, datetime
from functools import partial
from dataclasses import dataclass

Expand Down Expand Up @@ -62,7 +62,9 @@

class GenericMiotDevice(Entity):
"""通用 MiOT 设备"""


lastAutoUpdateAccountTime=datetime.now()-timedelta(seconds=3600)

def __init__(self, device, config, device_info, hass = None, mi_type = None):
"""Initialize the entity."""

Expand Down Expand Up @@ -506,7 +508,56 @@ def pre_process_data(key, value):
statedict[key] = pre_process_data(key, dict1[value['siid']][value['piid']])

else:
pass
# auth err
# 小米账号登录信息失效
# 自动重新登录,间隔3600秒
lostTime=(datetime.now()-GenericMiotDevice.lastAutoUpdateAccountTime).total_seconds()
_LOGGER.debug("miaccount auth err:lostTime:%d" % (lostTime))
if (lostTime>3600):
_LOGGER.warning("auto update mi_account token")
GenericMiotDevice.lastAutoUpdateAccountTime=datetime.now()

config=self.hass.data[DOMAIN]['micloud_config']
#_LOGGER.debug(f"self.hass.data[DOMAIN]['config']: {json.dumps (config)}")
if 'username' in config:
cloud=self._cloud_instance
resp = await cloud.login(config['username'],
config['password'])
if resp == (0, None):
#让新 token 实时生效
for item in self.hass.data[DOMAIN]['cloud_instance_list']:
mc = item['cloud_instance']
mc.login_by_credientals(
cloud.auth["user_id"],
cloud.auth['service_token'],
cloud.auth['ssecurity']
)

if self.hass.config_entries.async_entries(DOMAIN): #更新每个设备的token
_LOGGER.warning("Found existing config entries")
for entry in self.hass.config_entries.async_entries(DOMAIN):
if (
entry.data.get("update_from_cloud")
):
_LOGGER.warning("Updating existing entry")
update_from_cloud=entry.data.get("update_from_cloud")
update_from_cloud_new={
"did": update_from_cloud["did"],
"userId": update_from_cloud["userId"],
"serviceToken": cloud.auth['service_token'],
"ssecurity": cloud.auth['ssecurity'],
"server_location": update_from_cloud["server_location"]
}
entry_data_new=dict(entry.data)
entry_data_new.update({"update_from_cloud":update_from_cloud_new})
entry_id = entry.entry_id
self.hass.data[DOMAIN]['configs'][entry_id] = entry_data_new
self.hass.config_entries.async_update_entry( #保存新token到文件
entry,
data=entry_data_new,
)
else:
_LOGGER.error("config.data no username")

self._fail_count = 0
self._state_attrs.update(statedict)
Expand Down Expand Up @@ -681,8 +732,7 @@ def _handle_coordinator_update(self) -> None:
def _handle_platform_specific_attrs(self):
pass

@asyncio.coroutine
def async_service_handler(self, service):
async def async_service_handler(self, service):
"""Map services to methods on XiaomiMiioDevice."""
method = SERVICE_TO_METHOD.get(service.service)
params = {
Expand All @@ -702,11 +752,11 @@ def async_service_handler(self, service):

update_tasks = []
for device in devices:
yield from getattr(device, method["method"])(**params)
yield getattr(device, method["method"])(**params)
update_tasks.append(device.async_update_ha_state(True))

if update_tasks:
yield from asyncio.wait(update_tasks, loop=self.hass.loop)
yield asyncio.wait(update_tasks, loop=self.hass.loop)

class ToggleableMiotDevice(GenericMiotDevice, ToggleEntity):
def __init__(self, device, config, device_info, hass = None, mi_type = None):
Expand Down
1 change: 0 additions & 1 deletion custom_components/xiaomi_miot_raw/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
}

# pylint: disable=unused-argument
@asyncio.coroutine
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
hass.data[DOMAIN]['add_handler'].setdefault(TYPE, {})
if 'config_entry' in config:
Expand Down
151 changes: 151 additions & 0 deletions custom_components/xiaomi_miot_raw/camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""Platform for camera integration."""
import asyncio
import logging
from functools import partial
import collections

from datetime import timedelta
import json
from collections import OrderedDict
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.components.camera import (
SUPPORT_ON_OFF, SUPPORT_STREAM,
PLATFORM_SCHEMA,
Camera
)
from homeassistant.const import *
from homeassistant.exceptions import PlatformNotReady
from homeassistant.util import color
from miio.exceptions import DeviceException
from .deps.miio_new import MiotDevice
import miio
import copy

from .basic_dev_class import (
GenericMiotDevice,
ToggleableMiotDevice,
MiotSubDevice,
MiotSubToggleableDevice,
MiotIRDevice,
)
from . import async_generic_setup_platform
from .deps.const import (
DOMAIN,
ATTR_SYSSTATUS,
CONF_UPDATE_INSTANT,
CONF_MAPPING,
CONF_CONTROL_PARAMS,
CONF_CLOUD,
CONF_MODEL,
ATTR_STATE_VALUE,
ATTR_MODEL,
ATTR_FIRMWARE_VERSION,
ATTR_HARDWARE_VERSION,
SCHEMA,
MAP,
DUMMY_IP,
DUMMY_TOKEN,
)

TYPE = 'camera'

_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=10)
DEFAULT_NAME = "Generic MIoT " + TYPE
DATA_KEY = TYPE + '.' + DOMAIN

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
SCHEMA
)

# pylint: disable=unused-argument
@asyncio.coroutine
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
await async_generic_setup_platform(
hass,
config,
async_add_devices,
discovery_info,
TYPE,
{'default': MiotCamera}
)


async def async_setup_entry(hass, config_entry, async_add_entities):
config = copy.copy(hass.data[DOMAIN]['configs'].get(config_entry.entry_id, dict(config_entry.data)))
await async_setup_platform(hass, config, async_add_entities)


class MiotCamera(GenericMiotDevice, Camera):
def enable_motion_detection(self) -> None:
pass

def disable_motion_detection(self) -> None:
pass

def __init__(self, device, config, device_info, hass, main_mi_type):
self._device: miio.chuangmi_camera.ChuangmiCamera = None # Just for type hint
self._state: bool = None
GenericMiotDevice.__init__(self, device, config, device_info, hass, main_mi_type)
Camera.__init__(self)
self.register_callback(self.update_callback)

@property
def should_poll(self):
return True

def update_callback(self):
device_status = self.get_devicestatus()
# sleep will return [{'sysstatus': 'sleep'}]
# otherwise will return all other status
self._state = (len(device_status) > 1)
_LOGGER.debug(f"camera.update_callback result: {self._state}")

def get_devicestatus(self):
return self._device.send('get_devicestatus', {
'alarmsensitivity': "",
'cameraprompt': "",
'flip': "",
'infraredlight': "",
'ledstatus': "",
'recordtype': "",
'wakeuplevel': "",
})

@property
def supported_features(self) -> int:
return SUPPORT_ON_OFF

@property
def is_recording(self) -> bool:
return self._state

@property
def is_streaming(self) -> bool:
return False

@property
def is_on(self) -> bool:
return True

async def async_turn_on(self) -> None:
await self.async_do_turn_on(True)

async def async_turn_off(self) -> None:
await self.async_do_turn_on(False)

async def async_do_turn_on(self, new_status) -> None:
_LOGGER.info(f"Start camera.async_do_turn_on( {new_status} )")

if new_status:
cmd = "normal"
else:
cmd = "sleep"
result = self._device.send("set_" + ATTR_SYSSTATUS, [cmd])
if result != ['ok']:
_LOGGER.warning("result for send {}, {}".format(cmd, result))
return

self._state = new_status
self.schedule_update_ha_state()
1 change: 0 additions & 1 deletion custom_components/xiaomi_miot_raw/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@

SCAN_INTERVAL = timedelta(seconds=10)
# pylint: disable=unused-argument
@asyncio.coroutine
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
hass.data[DOMAIN]['add_handler'].setdefault(TYPE, {})
if 'config_entry' in config:
Expand Down
37 changes: 37 additions & 0 deletions custom_components/xiaomi_miot_raw/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import re

import logging
import asyncio
from types import coroutine
from typing import OrderedDict
Expand Down Expand Up @@ -40,6 +41,8 @@
from .deps.special_devices import SPECIAL_DEVICES
from .deps.xiaomi_cloud_new import MiCloud

_LOGGER = logging.getLogger(__name__)

SERVERS = {
'cn': "China",
'de': "Europe",
Expand Down Expand Up @@ -735,6 +738,40 @@ async def async_step_update_xiaomi_account(self, user_input=None, error=None, hi
if resp == (0, None):
self._all_config.update(user_input)
self._all_config.update(cloud.auth)

#让新 token 实时生效
for item in self.hass.data[DOMAIN]['cloud_instance_list']:
mc = item['cloud_instance']
mc.login_by_credientals(
cloud.auth["user_id"],
cloud.auth['service_token'],
cloud.auth['ssecurity']
)

if self.hass.config_entries.async_entries(DOMAIN): #更新每个设备的token
_LOGGER.info("Found existing config entries")
for entry in self.hass.config_entries.async_entries(DOMAIN):
if (
entry.data.get("update_from_cloud")
):
_LOGGER.info("Updating existing entry")
update_from_cloud=entry.data.get("update_from_cloud")
update_from_cloud_new={
"did": update_from_cloud["did"],
"userId": update_from_cloud["userId"],
"serviceToken": cloud.auth['service_token'],
"ssecurity": cloud.auth['ssecurity'],
"server_location": update_from_cloud["server_location"]
}
entry_data_new=dict(entry.data)
entry_data_new.update({"update_from_cloud":update_from_cloud_new})
entry_id = entry.entry_id
self.hass.data[DOMAIN]['configs'][entry_id] = entry_data_new
self.hass.config_entries.async_update_entry( #保存新token到文件
entry,
data=entry_data_new,
)

self._steps.pop(0)
return await self._steps[0]
elif resp[0] == -2:
Expand Down
3 changes: 1 addition & 2 deletions custom_components/xiaomi_miot_raw/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
SCAN_INTERVAL = timedelta(seconds=2)
# pylint: disable=unused-argument

@asyncio.coroutine
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
hass.data[DOMAIN]['add_handler'].setdefault(TYPE, {})
if 'config_entry' in config:
Expand Down Expand Up @@ -121,7 +120,7 @@ def is_closed(self):
""" Most of Xiaomi covers does not report position as 0 when they are fully closed.
It can be 0, 1, 2... So we consider it closed when it is <= 3. The _current_position
has been converted so it is always percentage. (#227) """
return self.current_cover_position <= 3
return int(self.current_cover_position) <= 3

@property
def is_closing(self):
Expand Down
Loading