Compare commits

..

6 Commits

Author SHA1 Message Date
d91b3edb40 Use unique_id instead of mac address for #22 2023-04-15 22:05:02 +02:00
83c5e3479e Add hob support #22 2023-04-15 04:34:12 +02:00
b0cd020941 Bump versions 2023-04-15 00:32:47 +02:00
593842144a Add zip release for download count 2023-04-12 23:59:09 +02:00
9a6e1155f9 Add useful links 2023-04-12 23:58:10 +02:00
365a3af171 Clean up sessions correct, fixes #19 2023-04-12 19:28:04 +02:00
13 changed files with 201 additions and 29 deletions

25
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Release
on:
release:
types: [published]
jobs:
release-zip:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ZIP Component Dir
run: |
cd ${{ github.workspace }}/custom_components/hon
zip -r haier_hon.zip ./
- name: Upload zip to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ github.workspace }}/custom_components/hon/haier_hon.zip
asset_name: haier_hon.zip
tag: ${{ github.ref }}
overwrite: true

View File

@ -9,7 +9,7 @@ Home Assistant integration for Haier hOn: support for Haier/Candy/Hoover home ap
- Washer Dryer - Washer Dryer
- Washing Machine - Washing Machine
- Oven - Oven
- Hob
## Installation ## Installation
**Method 1:** [![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=Andre0512&repository=hon&category=integration) **Method 1:** [![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=Andre0512&repository=hon&category=integration)

View File

@ -104,14 +104,14 @@ BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = {
"OV": ( "OV": (
HonBinarySensorEntityDescription( HonBinarySensorEntityDescription(
key="attributes.lastConnEvent.category", key="attributes.lastConnEvent.category",
name="Online", name="Connection",
device_class=BinarySensorDeviceClass.CONNECTIVITY, device_class=BinarySensorDeviceClass.CONNECTIVITY,
on_value="CONNECTED", on_value="CONNECTED",
icon="mdi:wifi", icon="mdi:wifi",
), ),
HonBinarySensorEntityDescription( HonBinarySensorEntityDescription(
key="attributes.parameters.remoteCtrValid", key="attributes.parameters.remoteCtrValid",
name="On", name="Remote Control",
device_class=BinarySensorDeviceClass.CONNECTIVITY, device_class=BinarySensorDeviceClass.CONNECTIVITY,
on_value="1", on_value="1",
icon="mdi:remote", icon="mdi:remote",
@ -124,6 +124,41 @@ BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = {
icon="mdi:power-cycle", icon="mdi:power-cycle",
), ),
), ),
"IV": (
HonBinarySensorEntityDescription(
key="attributes.lastConnEvent.category",
name="Connection",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
on_value="CONNECTED",
icon="mdi:wifi",
),
HonBinarySensorEntityDescription(
key="attributes.parameters.remoteCtrValid",
name="Remote Control",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
on_value="1",
icon="mdi:remote",
),
HonBinarySensorEntityDescription(
key="attributes.parameters.onOffStatus",
name="On",
device_class=BinarySensorDeviceClass.RUNNING,
on_value="1",
icon="mdi:power-cycle",
),
HonBinarySensorEntityDescription(
key="hotStatus",
name="Hot Status",
device_class=BinarySensorDeviceClass.HEAT,
on_value="1",
),
HonBinarySensorEntityDescription(
key="hobLockStatus",
name="Hob Lock",
device_class=BinarySensorDeviceClass.LOCK,
on_value="0",
),
),
} }
@ -132,11 +167,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := BINARY_SENSORS.get(device.appliance_type): if descriptions := BINARY_SENSORS.get(device.appliance_type):

View File

@ -25,7 +25,14 @@ BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = {
name="Stop Program", name="Stop Program",
icon="mdi:power-off", icon="mdi:power-off",
), ),
) ),
"IV": (
ButtonEntityDescription(
key="startProgram",
name="Start Program",
icon="mdi:pot-steam",
),
),
} }
@ -34,11 +41,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := BUTTONS.get(device.appliance_type): if descriptions := BUTTONS.get(device.appliance_type):

View File

@ -22,12 +22,12 @@ class HonEntity(CoordinatorEntity):
self._hass = hass self._hass = hass
self._device = device self._device = device
self._attr_unique_id = self._device.mac_address self._attr_unique_id = self._device.unique_id
@property @property
def device_info(self): def device_info(self):
return DeviceInfo( return DeviceInfo(
identifiers={(DOMAIN, self._device.mac_address)}, identifiers={(DOMAIN, self._device.unique_id)},
manufacturer=self._device.get("brand", ""), manufacturer=self._device.get("brand", ""),
name=self._device.nick_name name=self._device.nick_name
if self._device.nick_name if self._device.nick_name
@ -43,7 +43,7 @@ class HonCoordinator(DataUpdateCoordinator):
super().__init__( super().__init__(
hass, hass,
_LOGGER, _LOGGER,
name=device.mac_address, name=device.unique_id,
update_interval=timedelta(seconds=30), update_interval=timedelta(seconds=30),
) )
self._device = device self._device = device

View File

@ -6,6 +6,6 @@
"documentation": "https://github.com/Andre0512/hon/", "documentation": "https://github.com/Andre0512/hon/",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"issue_tracker": "https://github.com/Andre0512/hon/issues", "issue_tracker": "https://github.com/Andre0512/hon/issues",
"requirements": ["pyhOn==0.7.2"], "requirements": ["pyhOn==0.8.0b3"],
"version": "0.5.0" "version": "0.6.0-beta.2"
} }

View File

@ -106,6 +106,20 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = {
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
), ),
), ),
"IV": (
NumberEntityDescription(
key="startProgram.temp",
name="Temperature",
entity_category=EntityCategory.CONFIG,
icon="mdi:thermometer",
),
NumberEntityDescription(
key="startProgram.powerManagement",
name="Power Management",
entity_category=EntityCategory.CONFIG,
icon="mdi:timelapse",
),
),
} }
@ -114,11 +128,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := NUMBERS.get(device.appliance_type): if descriptions := NUMBERS.get(device.appliance_type):

View File

@ -68,6 +68,7 @@ SELECTS = {
key="startProgram.program", key="startProgram.program",
name="Program", name="Program",
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
translation_key="programs",
), ),
SelectEntityDescription( SelectEntityDescription(
key="startProgram.preheatStatus", key="startProgram.preheatStatus",
@ -75,6 +76,14 @@ SELECTS = {
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
), ),
), ),
"IV": (
SelectEntityDescription(
key="startProgram.program",
name="Program",
entity_category=EntityCategory.CONFIG,
translation_key="programs",
),
),
} }
@ -83,11 +92,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := SELECTS.get(device.appliance_type): if descriptions := SELECTS.get(device.appliance_type):

View File

@ -221,6 +221,22 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = {
icon="mdi:thermometer", icon="mdi:thermometer",
), ),
), ),
"IV": (
SensorEntityDescription(
key="remainingTimeMM",
name="Remaining Time",
icon="mdi:timer",
native_unit_of_measurement=UnitOfTime.MINUTES,
),
SensorEntityDescription(
key="temp",
name="Temperature",
icon="mdi:thermometer",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
),
SensorEntityDescription(key="errors", name="Error", icon="mdi:math-log"),
),
} }
@ -229,11 +245,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := SENSORS.get(device.appliance_type): if descriptions := SENSORS.get(device.appliance_type):

View File

@ -97,11 +97,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non
coordinators = hass.data[DOMAIN]["coordinators"] coordinators = hass.data[DOMAIN]["coordinators"]
appliances = [] appliances = []
for device in hon.appliances: for device in hon.appliances:
if device.mac_address in coordinators: if device.unique_id in coordinators:
coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id]
else: else:
coordinator = HonCoordinator(hass, device) coordinator = HonCoordinator(hass, device)
hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
if descriptions := SWITCHES.get(device.appliance_type): if descriptions := SWITCHES.get(device.appliance_type):

View File

@ -402,7 +402,64 @@
"wool": "Wool", "wool": "Wool",
"wool_and_delicates_49": "Wool and Delicates 49'", "wool_and_delicates_49": "Wool and Delicates 49'",
"wool_dry": "Wool Dry", "wool_dry": "Wool Dry",
"wool_soft_care": "Wool and Soft Car" "wool_soft_care": "Wool and Soft Car",
"bakery": "Pasta and Pastries",
"bakery_steam": "Steam-baked bread",
"bottom_heating": "Bottom Heating",
"bottom_heating_fan": "Bottom Heating + Fan",
"bread": "Bread",
"bread_steam": "Steam-baked pastries",
"combi": "Combi",
"convection_fan": "Convection + Fan",
"convection_fan_turnspit": "Convection + Fan + Turnspit",
"conventional": "Conventional",
"conventional_turnspit": "Convection + Turnspit",
"defrost": "Defrost",
"descaling": "Descaling",
"fish": "Fish",
"fish_steam": "Steam-cooked fish",
"grill_cata": "Grill",
"grill_fan_cata": "Grill fan",
"grill_fan_pyro": "Grill + Fan",
"grill_pyro": "Grill",
"h20_clean": "H2O-Clean",
"iot_bread": "Bread",
"iot_h20_clean": "h2O clean",
"leavening": "Leavening",
"light_fan": "Light Fan",
"low_temp_cooking": "Low Temperature Cooking",
"low_temp_cooking_fish": "Low Temperature Cooking - Fish",
"low_temp_cooking_fish_steam": "Low Temperature Steam Cooking - Fish",
"low_temp_cooking_meat": "Low Temperature Cooking - Meat",
"low_temp_cooking_meat_steam": "Low Temperature Steam Cooking - Meat",
"low_temp_cooking_steam": "Low Temperature Steam Cooking",
"meat": "Meat",
"meat_steam": "Steam-cooked meat",
"multi_level": "Multi-Level",
"paella": "Paella",
"pasta_and_bakery": "Pasta and Bakery",
"pizza": "Pizza",
"pyrolysis": "Pyrolysis",
"pyrolysis_plus": "Pyrolysis +",
"red_meat": "Red Meat",
"red_meat_steam": "Steam-cooked red meat",
"regenerate": "Regeneration",
"soft_plus": "Soft+",
"super_grill": "Super Grill",
"tailor_bake": "Tailor bake",
"tailor_bake_cata": "Tailor Bake",
"tailor_bake_pyro": "Tailor Bake",
"vegetables": "Vegetables",
"vegetables_cata": "Vegetables",
"vegetables_pyro": "Vegetables",
"water_discharge": "Water Drain",
"white_meat": "White Meat",
"white_meat_steam": "Steam-cooked white meat",
"iot_standard_boiling": "Boiling",
"iot_standard_frying": "Frying",
"iot_standard_keep_warm": "Keep Warm",
"iot_standard_melting": "Melting",
"iot_standard_simmering": "Simmering"
} }
} }
} }

View File

@ -1,4 +1,6 @@
{ {
"name": "Haier hOn", "name": "Haier hOn",
"homeassistant": "2023.2.0" "homeassistant": "2023.2.0",
"zip_release": true,
"filename": "haier_hon.zip"
} }

View File

@ -9,6 +9,7 @@ Support for home appliances of Haier's mobile app hOn.
- Washer Dryer - Washer Dryer
- Washing Machine - Washing Machine
- Oven - Oven
- Hob
## Tested Appliances ## Tested Appliances
- Haier WD90-B14TEAM5 - Haier WD90-B14TEAM5
@ -29,5 +30,11 @@ _If the integration is not in the list, you need to clear the browser cache._
Want to help us to support more appliances? Or add more sensors? Or help with translating? Or beautify some icons or captions? Want to help us to support more appliances? Or add more sensors? Or help with translating? Or beautify some icons or captions?
Check out the [project on GitHub](https://github.com/Andre0512/hon), every contribution is welcome! Check out the [project on GitHub](https://github.com/Andre0512/hon), every contribution is welcome!
## Useful Links
* [GitHub repository](https://github.com/Andre0512/hon) (please add a star if you like this integration!)
* [pyhOn library](https://github.com/Andre0512/pyhOn)
* [Release notes](https://github.com/Andre0512/hon/releases)
* [Discussion and help](https://github.com/Andre0512/hon/discussions)
* [Issues](https://github.com/Andre0512/hon/issues)