Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion homeassistant/components/cookidoo/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["cookidoo_api"],
"quality_scale": "silver",
"requirements": ["cookidoo-api==0.12.2"]
"requirements": ["cookidoo-api==0.14.0"]
}
10 changes: 5 additions & 5 deletions homeassistant/components/esphome/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,11 +564,11 @@ async def _on_connect(self) -> None:
)
entry_data.loaded_platforms.add(Platform.ASSIST_SATELLITE)

cli.subscribe_states(entry_data.async_update_state)
cli.subscribe_service_calls(self.async_on_service_call)
cli.subscribe_home_assistant_states(
self.async_on_state_subscription,
self.async_on_state_request,
cli.subscribe_home_assistant_states_and_services(
on_state=entry_data.async_update_state,
on_service_call=self.async_on_service_call,
on_state_sub=self.async_on_state_subscription,
on_state_request=self.async_on_state_request,
)

entry_data.async_save_to_store()
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/esphome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==37.2.2",
"aioesphomeapi==38.2.1",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.1.0"
],
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/hassio/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
ISSUE_KEY_SYSTEM_DOCKER_CONFIG,
ISSUE_KEY_ADDON_DETACHED_ADDON_MISSING,
ISSUE_KEY_ADDON_DETACHED_ADDON_REMOVED,
"issue_system_disk_lifetime",
}

_LOGGER = logging.getLogger(__name__)
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/components/hassio/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@
}
}
},
"issue_system_disk_lifetime": {
"title": "Disk lifetime exceeding 90%",
"description": "The data disk has exceeded 90% of its expected lifespan. The disk may soon malfunction which can lead to data loss. You should replace it soon and migrate your data."
},
"unhealthy": {
"title": "Unhealthy system - {reason}",
"description": "System is currently unhealthy due to {reason}. For troubleshooting information, select Learn more."
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/somfy_mylink/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
},
"step": {
"init": {
"title": "Configure MyLink Options",
"title": "Configure MyLink options",
"data": {
"target_id": "Configure options for a cover."
}
},
"target_config": {
"title": "Configure MyLink Cover",
"title": "Configure MyLink cover",
"description": "Configure options for `{target_name}`",
"data": {
"reverse": "Cover is reversed"
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/tuya/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
Platform.SIREN,
Platform.SWITCH,
Platform.VACUUM,
Platform.VALVE,
]


Expand Down Expand Up @@ -166,6 +167,14 @@ class DPCode(StrEnum):
CONTROL_BACK = "control_back"
CONTROL_BACK_MODE = "control_back_mode"
COUNTDOWN = "countdown" # Countdown
COUNTDOWN_1 = "countdown_1"
COUNTDOWN_2 = "countdown_2"
COUNTDOWN_3 = "countdown_3"
COUNTDOWN_4 = "countdown_4"
COUNTDOWN_5 = "countdown_5"
COUNTDOWN_6 = "countdown_6"
COUNTDOWN_7 = "countdown_7"
COUNTDOWN_8 = "countdown_8"
COUNTDOWN_LEFT = "countdown_left"
COUNTDOWN_SET = "countdown_set" # Countdown setting
CRY_DETECTION_SWITCH = "cry_detection_switch"
Expand Down Expand Up @@ -319,6 +328,7 @@ class DPCode(StrEnum):
STATUS = "status"
STERILIZATION = "sterilization" # Sterilization
SUCTION = "suction"
SUPPLY_FREQUENCY = "supply_frequency"
SWING = "swing" # Swing mode
SWITCH = "switch" # Switch
SWITCH_1 = "switch_1" # Switch 1
Expand Down
60 changes: 60 additions & 0 deletions homeassistant/components/tuya/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,66 @@
entity_category=EntityCategory.CONFIG,
),
),
# Smart Water Timer
"sfkzq": (
# Controls the irrigation duration for the water valve
NumberEntityDescription(
key=DPCode.COUNTDOWN_1,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "1"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_2,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "2"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_3,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "3"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_4,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "4"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_5,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "5"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_6,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "6"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_7,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "7"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
NumberEntityDescription(
key=DPCode.COUNTDOWN_8,
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": "8"},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
),
),
# Siren Alarm
# https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu
"sgbj": (
Expand Down
14 changes: 14 additions & 0 deletions homeassistant/components/tuya/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,13 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
TuyaSensorEntityDescription(
key=DPCode.SUPPLY_FREQUENCY,
translation_key="supply_frequency",
device_class=SensorDeviceClass.FREQUENCY,
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
),
TuyaSensorEntityDescription(
key=DPCode.PHASE_A,
translation_key="phase_a_current",
Expand Down Expand Up @@ -1346,6 +1353,13 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
complex_type=ElectricityTypeData,
subkey="power",
),
TuyaSensorEntityDescription(
key=DPCode.SUPPLY_FREQUENCY,
translation_key="supply_frequency",
device_class=SensorDeviceClass.FREQUENCY,
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
),
TuyaSensorEntityDescription(
key=DPCode.PHASE_A,
translation_key="phase_a_current",
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/tuya/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@
"heat_preservation_time": {
"name": "Heat preservation time"
},
"indexed_irrigation_duration": {
"name": "Irrigation duration {index}"
},
"feed": {
"name": "Feed"
},
Expand Down Expand Up @@ -740,6 +743,9 @@
},
"liquid_level": {
"name": "Liquid level"
},
"supply_frequency": {
"name": "Supply frequency"
}
},
"switch": {
Expand Down Expand Up @@ -899,6 +905,11 @@
"frost_protection": {
"name": "Frost protection"
}
},
"valve": {
"indexed_valve": {
"name": "Valve {index}"
}
}
},
"exceptions": {
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/tuya/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,15 @@
entity_category=EntityCategory.CONFIG,
),
),
# Smoke Detector
# https://developer.tuya.com/en/docs/iot/categoryywbj?id=Kaiuz3f6sf952
"ywbj": (
SwitchEntityDescription(
key=DPCode.MUFFLING,
translation_key="mute",
entity_category=EntityCategory.CONFIG,
),
),
# Smart Electricity Meter
# https://developer.tuya.com/en/docs/iot/smart-meter?id=Kaiuz4gv6ack7
"zndb": (
Expand Down
140 changes: 140 additions & 0 deletions homeassistant/components/tuya/valve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""Support for Tuya valves."""

from __future__ import annotations

from tuya_sharing import CustomerDevice, Manager

from homeassistant.components.valve import (
ValveDeviceClass,
ValveEntity,
ValveEntityDescription,
ValveEntityFeature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode
from .entity import TuyaEntity

# All descriptions can be found here. Mostly the Boolean data types in the
# default instruction set of each category end up being a Valve.
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
VALVES: dict[str, tuple[ValveEntityDescription, ...]] = {
# Smart Water Timer
"sfkzq": (
ValveEntityDescription(
key=DPCode.SWITCH_1,
translation_key="indexed_valve",
translation_placeholders={"index": "1"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_2,
translation_key="indexed_valve",
translation_placeholders={"index": "2"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_3,
translation_key="indexed_valve",
translation_placeholders={"index": "3"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_4,
translation_key="indexed_valve",
translation_placeholders={"index": "4"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_5,
translation_key="indexed_valve",
translation_placeholders={"index": "5"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_6,
translation_key="indexed_valve",
translation_placeholders={"index": "6"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_7,
translation_key="indexed_valve",
translation_placeholders={"index": "7"},
device_class=ValveDeviceClass.WATER,
),
ValveEntityDescription(
key=DPCode.SWITCH_8,
translation_key="indexed_valve",
translation_placeholders={"index": "8"},
device_class=ValveDeviceClass.WATER,
),
),
}


async def async_setup_entry(
hass: HomeAssistant,
entry: TuyaConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up tuya valves dynamically through tuya discovery."""
hass_data = entry.runtime_data

@callback
def async_discover_device(device_ids: list[str]) -> None:
"""Discover and add a discovered tuya valve."""
entities: list[TuyaValveEntity] = []
for device_id in device_ids:
device = hass_data.manager.device_map[device_id]
if descriptions := VALVES.get(device.category):
entities.extend(
TuyaValveEntity(device, hass_data.manager, description)
for description in descriptions
if description.key in device.status
)

async_add_entities(entities)

async_discover_device([*hass_data.manager.device_map])

entry.async_on_unload(
async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device)
)


class TuyaValveEntity(TuyaEntity, ValveEntity):
"""Tuya Valve Device."""

_attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE

def __init__(
self,
device: CustomerDevice,
device_manager: Manager,
description: ValveEntityDescription,
) -> None:
"""Init TuyaValveEntity."""
super().__init__(device, device_manager)
self.entity_description = description
self._attr_unique_id = f"{super().unique_id}{description.key}"

@property
def is_closed(self) -> bool:
"""Return if the valve is closed."""
return not self.device.status.get(self.entity_description.key, False)

async def async_open_valve(self) -> None:
"""Open the valve."""
await self.hass.async_add_executor_job(
self._send_command, [{"code": self.entity_description.key, "value": True}]
)

async def async_close_valve(self) -> None:
"""Close the valve."""
await self.hass.async_add_executor_job(
self._send_command, [{"code": self.entity_description.key, "value": False}]
)
3 changes: 3 additions & 0 deletions homeassistant/components/yolink/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"exceptions": {
"invalid_config_entry": {
"message": "Config entry not found or not loaded!"
},
"valve_inoperable_currently": {
"message": "The Valve cannot be operated currently."
}
},
"entity": {
Expand Down
Loading
Loading