Add support for buttons in gardena bluetooth (#96871)
* Add button to gardena * Add tests for button * Bump gardena bluetooth to 1.0.2 --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>pull/96896/head
parent
67e3203d00
commit
80a7447030
|
@ -22,6 +22,7 @@ from .coordinator import Coordinator, DeviceUnavailable
|
|||
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.NUMBER,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
"""Support for button entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from gardena_bluetooth.const import Reset
|
||||
from gardena_bluetooth.parse import CharacteristicBool
|
||||
|
||||
from homeassistant.components.button import (
|
||||
ButtonEntity,
|
||||
ButtonEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import Coordinator, GardenaBluetoothDescriptorEntity
|
||||
|
||||
|
||||
@dataclass
|
||||
class GardenaBluetoothButtonEntityDescription(ButtonEntityDescription):
|
||||
"""Description of entity."""
|
||||
|
||||
char: CharacteristicBool = field(default_factory=lambda: CharacteristicBool(""))
|
||||
|
||||
|
||||
DESCRIPTIONS = (
|
||||
GardenaBluetoothButtonEntityDescription(
|
||||
key=Reset.factory_reset.uuid,
|
||||
translation_key="factory_reset",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
char=Reset.factory_reset,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up binary sensor based on a config entry."""
|
||||
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
entities = [
|
||||
GardenaBluetoothButton(coordinator, description)
|
||||
for description in DESCRIPTIONS
|
||||
if description.key in coordinator.characteristics
|
||||
]
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class GardenaBluetoothButton(GardenaBluetoothDescriptorEntity, ButtonEntity):
|
||||
"""Representation of a binary sensor."""
|
||||
|
||||
entity_description: GardenaBluetoothButtonEntityDescription
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Trigger button action."""
|
||||
await self.coordinator.write(self.entity_description.char, True)
|
|
@ -13,5 +13,5 @@
|
|||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/gardena_bluetooth",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["gardena_bluetooth==1.0.1"]
|
||||
"requirements": ["gardena_bluetooth==1.0.2"]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
"name": "Valve connection"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"factory_reset": {
|
||||
"name": "Factory reset"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"remaining_open_time": {
|
||||
"name": "Remaining open time"
|
||||
|
|
|
@ -820,7 +820,7 @@ fritzconnection[qr]==1.12.2
|
|||
gTTS==2.2.4
|
||||
|
||||
# homeassistant.components.gardena_bluetooth
|
||||
gardena_bluetooth==1.0.1
|
||||
gardena_bluetooth==1.0.2
|
||||
|
||||
# homeassistant.components.google_assistant_sdk
|
||||
gassist-text==0.0.10
|
||||
|
|
|
@ -642,7 +642,7 @@ fritzconnection[qr]==1.12.2
|
|||
gTTS==2.2.4
|
||||
|
||||
# homeassistant.components.gardena_bluetooth
|
||||
gardena_bluetooth==1.0.1
|
||||
gardena_bluetooth==1.0.2
|
||||
|
||||
# homeassistant.components.google_assistant_sdk
|
||||
gassist-text==0.0.10
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# serializer version: 1
|
||||
# name: test_setup
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock Title Factory reset',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.mock_title_factory_reset',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup.1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock Title Factory reset',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.mock_title_factory_reset',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
|
@ -0,0 +1,67 @@
|
|||
"""Test Gardena Bluetooth sensor."""
|
||||
|
||||
|
||||
from unittest.mock import Mock, call
|
||||
|
||||
from gardena_bluetooth.const import Reset
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import setup_entry
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_switch_chars(mock_read_char_raw):
|
||||
"""Mock data on device."""
|
||||
mock_read_char_raw[Reset.factory_reset.uuid] = b"\x00"
|
||||
return mock_read_char_raw
|
||||
|
||||
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_entry: MockConfigEntry,
|
||||
mock_switch_chars: dict[str, bytes],
|
||||
) -> None:
|
||||
"""Test setup creates expected entities."""
|
||||
|
||||
entity_id = "button.mock_title_factory_reset"
|
||||
coordinator = await setup_entry(hass, mock_entry, [Platform.BUTTON])
|
||||
assert hass.states.get(entity_id) == snapshot
|
||||
|
||||
mock_switch_chars[Reset.factory_reset.uuid] = b"\x01"
|
||||
await coordinator.async_refresh()
|
||||
assert hass.states.get(entity_id) == snapshot
|
||||
|
||||
|
||||
async def test_switching(
|
||||
hass: HomeAssistant,
|
||||
mock_entry: MockConfigEntry,
|
||||
mock_client: Mock,
|
||||
mock_switch_chars: dict[str, bytes],
|
||||
) -> None:
|
||||
"""Test switching makes correct calls."""
|
||||
|
||||
entity_id = "button.mock_title_factory_reset"
|
||||
await setup_entry(hass, mock_entry, [Platform.BUTTON])
|
||||
assert hass.states.get(entity_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mock_client.write_char.mock_calls == [
|
||||
call(Reset.factory_reset, True),
|
||||
]
|
Loading…
Reference in New Issue