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
Joakim Plate 2023-07-19 10:17:40 +02:00 committed by GitHub
parent 67e3203d00
commit 80a7447030
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 161 additions and 3 deletions

View File

@ -22,6 +22,7 @@ from .coordinator import Coordinator, DeviceUnavailable
PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.NUMBER,
Platform.SENSOR,
Platform.SWITCH,

View File

@ -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)

View File

@ -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"]
}

View File

@ -24,6 +24,11 @@
"name": "Valve connection"
}
},
"button": {
"factory_reset": {
"name": "Factory reset"
}
},
"number": {
"remaining_open_time": {
"name": "Remaining open time"

View File

@ -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

View File

@ -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

View File

@ -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',
})
# ---

View File

@ -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),
]