-
-
Notifications
You must be signed in to change notification settings - Fork 34.4k
Add Fluss+ Button integration #139925
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
base: dev
Are you sure you want to change the base?
Add Fluss+ Button integration #139925
Conversation
Added some contextual names
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Josef Zweck <josef@zweck.dev>
Co-authored-by: Josef Zweck <josef@zweck.dev>
await self.async_set_unique_id(DOMAIN) | ||
|
||
if self._async_current_entries(): | ||
return self.async_abort(reason="single_instance_allowed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we only allow one instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user only needs to add it once since the api key is connect to their account which is able to get the devices they have access to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but why can't there be 2 users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point, removing the config for that.
await self.async_set_unique_id(DOMAIN) | ||
|
||
if self._async_current_entries(): | ||
return self.async_abort(reason="single_instance_allowed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but why can't there be 2 users?
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry that took a while
entities: list[FlussButton] = [] | ||
for device_id, device in devices.items(): | ||
entities.append(FlussButton(coordinator, device_id, device)) | ||
|
||
async_add_entities(entities) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entities: list[FlussButton] = [] | |
for device_id, device in devices.items(): | |
entities.append(FlussButton(coordinator, device_id, device)) | |
async_add_entities(entities) | |
async_add_entities(FlussButton(coordinator, device_id, device) for device_id, device in devices.items()) |
@property | ||
def available(self) -> bool: | ||
"""Return if the entity is available.""" | ||
return self.coordinator.last_update_success |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@property | |
def available(self) -> bool: | |
"""Return if the entity is available.""" | |
return self.coordinator.last_update_success |
is the default for coordinator entities
@property | ||
def available(self) -> bool: | ||
"""Return if the entity is available.""" | ||
return super().available and self.device_id in self.coordinator.data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@property | |
def available(self) -> bool: | |
"""Return if the entity is available.""" | |
return super().available and self.device_id in self.coordinator.data |
not used atm
self, | ||
coordinator: FlussDataUpdateCoordinator, | ||
device_id: str, | ||
device: dict | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why would the device even be None
, we probably shouldn't setup the entity if we don't have that device. That'll also simplify the code below
def name(self) -> str: | ||
"""Use the deviceName field for the entity name.""" | ||
return ( | ||
self.device.get("deviceName", super().name) if self.device else super().name | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably rather add a proper home assistant device to your entity _attr_device_info
. If that is the main entity of the device you can set _attr_name
to None, so it'll take the device's name
assert result["errors"] == {} | ||
|
||
|
||
async def test_step_user_success(config_flow: FlussConfigFlow) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
init your flows with
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
mock_client.return_value = None | ||
result = await config_flow.async_step_user(user_input) | ||
|
||
assert result["type"] == FlowResultType.CREATE_ENTRY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert result["type"] == FlowResultType.CREATE_ENTRY | |
assert result["type"] is FlowResultType.CREATE_ENTRY |
is
to compare enums
async def test_step_user_invalid_auth(config_flow: FlussConfigFlow) -> None: | ||
"""Test invalid authentication.""" | ||
user_input = {CONF_API_KEY: "invalid_api_key"} | ||
|
||
with patch("homeassistant.components.fluss.config_flow.FlussApiClient") as mock_client: | ||
mock_client.side_effect = FlussApiClientAuthenticationError | ||
result = await config_flow.async_step_user(user_input) | ||
|
||
assert result["type"] == FlowResultType.FORM | ||
assert result["step_id"] == "user" | ||
assert result["errors"] == {"base": "invalid_auth"} | ||
|
||
|
||
async def test_step_user_cannot_connect(config_flow: FlussConfigFlow) -> None: | ||
"""Test connection failure.""" | ||
user_input = {CONF_API_KEY: "some_api_key"} | ||
|
||
with patch("homeassistant.components.fluss.config_flow.FlussApiClient") as mock_client: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
those can be parametrized
def test_data_schema_validation(): | ||
"""Test that the data schema enforces required string field.""" | ||
# Valid input | ||
STEP_USER_DATA_SCHEMA({CONF_API_KEY: "test_key"}) | ||
|
||
# Missing key | ||
with pytest.raises(vol.error.MultipleInvalid): | ||
STEP_USER_DATA_SCHEMA({}) | ||
|
||
# Non-string value | ||
with pytest.raises(vol.error.MultipleInvalid): | ||
STEP_USER_DATA_SCHEMA({CONF_API_KEY: 123}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need to test that, HA takes care of that
@pytest.fixture | ||
async def mock_hass(): | ||
"""Mock Hass Environment.""" | ||
hass = AsyncMock(spec=HomeAssistant) | ||
hass.config_entries = AsyncMock() | ||
hass.config_entries.async_forward_entry_setups = AsyncMock() | ||
hass.config_entries.async_unload_platforms = AsyncMock() | ||
hass.data = {} | ||
return hass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move common fixtures to conftest.py
Type of change
Additional information
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
.To help with the load of incoming pull requests: