-
-
Notifications
You must be signed in to change notification settings - Fork 33.9k
Add Gaposa integration #138754
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 Gaposa integration #138754
Conversation
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.
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up Gaposa from a config entry.""" | ||
|
||
hass.data.setdefault(DOMAIN, {}) | ||
hass.data[DOMAIN].setdefault(entry.entry_id, {}) |
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.
please extend the typing of ConfigEntry
and store the data you would store in hass.data
in entry.runtime_data
password = entry.data[CONF_PASSWORD] | ||
|
||
try: | ||
gaposa = Gaposa(api_key, loop=hass.loop, websession=websession) |
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 add the loop?
rules: | ||
action-setup: "done" | ||
appropriate-polling: "done" | ||
brands: "done" | ||
common-modules: "done" | ||
config-flow: "done" | ||
config-flow-test-coverage: "done" | ||
dependency-transparency: "done" | ||
docs-actions: "done" | ||
docs-high-level-description: "done" | ||
docs-installation-instructions: "done" | ||
docs-removal-instructions: "done" | ||
entity-event-setup: "done" | ||
entity-unique-id: "done" | ||
has-entity-name: "done" | ||
runtime-data: "done" | ||
test-before-configure: "done" | ||
test-before-setup: "done" | ||
unique-config-entry: "done" |
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.
Please add the full yaml file
coordinator = DataUpdateCoordinatorGaposa( | ||
hass, | ||
_LOGGER, | ||
gaposa, | ||
# Name of the data. For logging purposes. | ||
name=entry.title, | ||
# Polling interval. Will only be polled if there are subscribers. | ||
update_interval=timedelta(seconds=UPDATE_INTERVAL), | ||
) |
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 isn't this in the coordinator.py?
# Store runtime data that should persist between restarts | ||
entry.async_on_unload(entry.add_update_listener(update_listener)) |
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.
can be removed
await self.async_set_unique_id(DOMAIN) | ||
self._abort_if_unique_id_configured() |
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 set the domain as unique id?
# The supported features of a cover are done using a bitmask. Using the constants | ||
# imported above, we can tell HA the features that are supported by this entity. | ||
# If the supported features were dynamic (ie: different depending on the external | ||
# device it connected to), then this should be function with an @property decorator. | ||
@property | ||
def supported_features(self) -> CoverEntityFeature: | ||
"""Return supported features.""" | ||
return ( | ||
CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP | ||
) |
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.
This can be set to _attr_supported_features
instead
# Add device actions support | ||
@property | ||
def device_actions(self) -> list[dict[str, str]]: | ||
"""Return the available actions for this cover.""" | ||
return [ | ||
{ | ||
"name": "Open", | ||
"service": "cover.open_cover", | ||
}, | ||
{ | ||
"name": "Close", | ||
"service": "cover.close_cover", | ||
}, | ||
{ | ||
"name": "Stop", | ||
"service": "cover.stop_cover", | ||
}, | ||
] |
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?
# A unique_id for this entity with in this domain. This means for example if you | ||
# have a sensor on this cover, you must ensure the value returned is unique, | ||
# which is done here by appending "_cover". For more information, see: | ||
# https://developers.home-assistant.io/docs/entity_registry_index/#unique-id-requirements | ||
# Note: This is NOT used to generate the user visible Entity ID used in automations. | ||
self._attr_unique_id = self.id | ||
|
||
# This is the name for this *entity*, the "name" attribute from "device_info" | ||
# is used as the device name for device screens in the UI. This name is used on | ||
# entity screens, and used to build the Entity ID that's used is automations etc. | ||
self._attr_name = self.motor.name | ||
|
||
async def async_will_remove_from_hass(self) -> None: | ||
"""Entity being removed from hass.""" | ||
# The opposite of async_added_to_hass. Remove any registered call backs here. | ||
await super().async_will_remove_from_hass() | ||
|
||
# Information about the devices that is partially visible in the UI. | ||
# The most critical thing here is to give this entity a name so it is displayed | ||
# as a "device" in the HA UI. This name is used on the Devices overview table, | ||
# and the initial screen when the device is added (rather than the entity name | ||
# property below). You can then associate other Entities (eg: a battery | ||
A93C | # sensor) with this device, so it shows more like a unified element in the UI. | |
# For example, an associated battery sensor will be displayed in the right most | ||
# column in the Configuration > Devices view for a device. | ||
# To associate an entity with this device, the device_info must also return an | ||
# identical "identifiers" attribute, but not return a name attribute. | ||
# See the sensors.py file for the corresponding example setup. | ||
# Additional meta data can also be returned here, including sw_version (displayed | ||
# as Firmware), model and manufacturer (displayed as <model> by <manufacturer>) | ||
# shown on the device info screen. The Manufacturer and model also have their | ||
# respective columns on the Devices overview table. Note: Many of these must be | ||
# set when the device is first added, and they are not always automatically | ||
# refreshed by HA from it's internal cache. | ||
# For more information see: | ||
# https://developers.home-assistant.io/docs/device_registry_index/#device-properties | ||
@property | ||
def device_info(self) -> DeviceInfo: | ||
"""Information about this entity/device.""" |
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 have a whole paragraph here
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.
Remove so we can add in a separate PR
Fixes an issue where the UI state of Gaposa covers wasn't properly updating after actions: - When stop button is pressed, immediately request a refresh from the API and update UI - After open/close actions, refresh API state before updating UI when motion completes - Add tests to verify this behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix context parameter in GaposaCover initialization - Change log levels from INFO to DEBUG for routine operations - Improve test handling of coroutines to avoid warnings
- Remove loop parameter from Gaposa API initialization - Move API initialization to coordinator - Use entry.runtime_data instead of hass.data for storing data - Update quality_scale.yaml file - Remove device_actions property as it's not needed - Remove diagnostics.py for future PR - Cleanup code by removing excessive comments
There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days. |
Apologies for the lack of progress. I have push changes for the review comments, but unfortunately I have not had an opportunity to visit the property where my Gaposa blinds are installed in order to test with those changes. So the changes are not ready for review yet. I do expect to have that opportunity in the next month. |
Proposed change
This change introduces a new component for Gaposa blinds and shades (https://www.gaposa.it/eng). The component uses the cloud pull model, accessing the same server and API as the Gaposa RollApp mobile application (https://www.gaposa.it/eng/news/rollapp/). This cloud service communicates with the shades through their LinkIt hub (https://www.gaposa.it/eng/prod/?residential/electronics/control-units/home-automation/linkit).
The Gaposa blinds do not report position or battery level. The integration obtains position information from the cloud service. Motion status is inferred from elapsed time since last command and an assumed motion duration.
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: