Major improvement refactor#56
Conversation
* Refactor to use the common HA approach for entities * Make it much simpler to make new entities * Add ZaptecBaseEntity for heavy lifting * Added ZaptecUpdateCoordinator to centrally manage API updates * Added new protocols: binary sensor, button, number in addition to sensor and switch * Added support for "download diagnostics" * Add unique id on component * General: Added type hints User changes: * Entity naming is completely changed. Entity names are read from Zaptec Portal. * Entities are grouped into devices and devices reflect structure * Remove services "start_charging" and "stop_charging" (not available in HW) * Add services "authorize_charging" and "deauthorize_charging" * Many new entities/sensors/buttons instead of relying on attrs and templates * Services also available as buttons which doesn't require `charger_id` API changes: * Made ZaptecBase an ABC base class * Cleaned up ZaptecBase.set_attributes() * Fixed infinite authentication failed loop * Cleaned up stream message reception * Fixed error handling in stream reception * Added MC-NBFX data decoder for stream messages * Set all Zaptec API facing methods as private methods * Provide proper exception on fails * Structurize build() and state() for init and updating * Added properties (e.g. `Charger.operating_mode`) that translates Zaptec API internal numbers to strings
|
@sveinse I have granted you write permission to the repo. |
|
@Hellowlol Thank you very much! Even with this privilege, I definitely would like your input on the design of this. One question I'd like to find out eventually is what entities and control the users of this really needs. FYI I'm actively working on some improvements based on some early feedback that I think should be included into this PR. One of the changes is to revert back some of the more controversial changes with |
* Improved API and interface. Added data validation. Added type conversion. * Added several new HA entities * Fix bugs and smaller improvements
|
@Hellowlol I have updated the PR, where I improved the API interfaces added some entities I was missing in my own home setup. Removed the I'm going to create a new issue where I can invite users to beta-test it. Since I don't have access to the server side of the Zaptec API, it is very hard to test the Zaptec component. We need input from others on how it works in their setup. I've released a zaptec-dev at https://github.com/sveinse/zaptec which is installable in HACS that can be used for testing. edit |
|
@Hellowlol is it ok if we bump the version of zaptec when the beta testing of this PR is done and we merge it in? |
|
Not sure if this is the right place to post, but how do I access the ZAPTEC sense information and show it in HA? |
* Fix failure to start if zaptec user have no extra privileges, sveinse/zaptec#10 * Ensure entities are marked as "Unavailable" if not available in Zaptec * Fix text of binary sensor "charger.is_authorization_required" * Fix more user friendly error messages
* Fix sveinse/zaptec#2, sveinse/zaptec#10, sveinse/zaptec#15
* Handle starting zaptec with non-privileged user
* Fix "unavailable" state on entities
* Fix non-working buttons and commands
* Fix error reporting and logging
* Fix unity bug in "total_charge_power"
* Added "total_charge_power_session"
* Update API data validators
|
@sveinse I think we are far from 1.0 until it has been appropriately tested against all the chargers. I suggest you merge the PR bump to 0.0.7, release it as a beta, and write whats breaking in the release notes. After a testing period of X weeks no real new issues have arisen. Bump the 0.0.7 to 1.0 as a normal release |
| MIT License | ||
|
|
||
| Copyright (c) 2021 Hellowlol and contributers | ||
| Copyright (c) 2023 Svein Seldal, @sveinse |
There was a problem hiding this comment.
Lets just have one copywrite line:
.... 2023 @Hellowlol , @sveinse and contributers
There was a problem hiding this comment.
Agreed. I had them separate because I alone can't make the copyright 2023 claim on your behalf.
| # Add names. | ||
| obs.update({value: key for key, value in v.items()}) | ||
| class AuthorizationError(ZaptecApiError): | ||
| '''Authenatication failed''' |
There was a problem hiding this comment.
Run black and fixup so ' -> "
There was a problem hiding this comment.
I haven't run black on anything. I didn't know if you did. So I'll run everything through black and update the PR.
| self.__class__.__name__, | ||
| ) | ||
| def set_attributes(self, data: TDict) -> bool: | ||
| """Set the class attributes from the given data""""" |
| """Set a limit now how many amps the installation can use | ||
| # Get the hierarchy of circurits and chargers | ||
| try: | ||
| hierarchy = await self._account._request(f"installation/{self.id}/hierarchy") |
There was a problem hiding this comment.
Why isnt hirarchy used directly?
There was a problem hiding this comment.
It is. If you look in line 172.
| '''Raw request for installation data''' | ||
|
|
||
| # Get the installation data | ||
| data = await self._account._request(f"installation/{self.id}") |
There was a problem hiding this comment.
Same for this one? Why not use the api?
There was a problem hiding this comment.
There is currently no method in class Account for this as the only consumer of this request is in the class Interface.
|
Thank you for the review and feedback!
@Hellowlol I agree that in the current state we're far from 1.0. I was thinking ahead. Personally I find the double zero |
|
@Hellowlol I'd like to talk about the architecture of
Shall we make it that PS! A notable downside to this is that the code below is bloated if there is only one caller of it -- the high-level classes. Since this is the low-level interface, the user should never need to interact with the low-level methods directly. # Method in class Account
async def installation_info(self, inst_id: str):
return await self._request(f"installation/{inst_id}")edit |
|
@Hellowlol PR updated with black, fix your comments on copyright, fix diagnostics anonymization error. The only remaining issue is the comments on the API. Is it ok as it is in the PR, or should I refactor to change into the proposed structure presented in https://gist.github.com/sveinse/c98a39fba92dc328fc017da956cd8063 ? What is the next steps? Should you approve this merge, or can I do it? How do we proceed? Please advice. I think there a a few users waiting on this making it into the official channels. |
* Fix timeout issues, sveinse/zaptec#19 * Fix sensor stateclass, making it possible to use kwh from zaptec in HA energy, sveinse/zaptec#16
|
The entire point is to have an object api. If i wanted to just use data method i might just use a swagger client. I dont care how it implementedbut there should be logic do so the data is connected to the correct object. Account example account get the live connection details but the rest of the logic should be in install class, charger class etc. Nice work👍 Feel free to bump to whatever version you feel is appropriate for the state the repo is in, merge and release it as a prerelease |
| _LOGGER.error("Could not get info from %s: %s", full_url, err) | ||
| # Validate the incoming json data | ||
| # FIXME: This raise pydantic.ValidationError if the json is unexpected. How to handle this? | ||
| validate(json_result, url=url) |
There was a problem hiding this comment.
Because we cannot assume that the data from the Zaptec API is formatted correctly, one should always validate incoming data. What if Zaptec changes something?
We rely on certain data being present, e.g. for data in installations["Data"]: assumes Data is there. If it isn't then the resulting error can be very hard to link to the incoming data being malformed. Validation ensures that one gets a clear "I don't understand the data I just got"-type errors, which is a lot easier to deal with.
There is normally another dimension to validation and that is deserialization into named objects (see validation.py). But given the way this API is constructed with the special attribute handling, this feature isn't used.
| _LOGGER.debug("Calling %s", cmd) | ||
| return await self._account._request(cmd, method="post") | ||
|
|
||
| async def update(self, data): |
There was a problem hiding this comment.
Comment out, don’t remove this method.
There was a problem hiding this comment.
I can add it back if you want @Hellowlol. I'm sorry, I deleted the function because it doesn't do anything, and it is messy to have have useless methods included. What is the intent of the function?
There was a problem hiding this comment.
Honestly, I can’t remember. I just remember that I needed it for something. I’ll get back to it when I have time
There was a problem hiding this comment.
I propose that we leave it out for now (since it does nothing) and add it later when you have time to look at it.
The object api is a high-level interface which sits on top of the Zaptec cloud API and returns python objects, e.g. The low-level interface communicates the data from the cloud as-is. E.g. say we have a These two interfaces are very different and have different usages. It is very common in py apis to hide the low-level methods and only present the high-level methods. This was the path I was pursuing and probably the cause for these discussions. We can have both interfaces if that is what's wanted. |
Thank you for the trust! 🥇 I suggest PS! You execute merges as regular merges, no squash or rebase, right? |
|
I have no fixed rule for how i do merges, it depends in the situasion. Generally i prefer merge |
* Add support for selecting which chargers to add, sveinse/zaptec#5 * Add support for adding optional prefix, sveinse/zaptec#4 * Adding API timeout to 60 secs, sveinse/zaptec#19 * Updated UI messages * Fixup general error handling * Change API to allow for supporting selecting which chargers to use
Based on the latest version of https://github.com/ludeeus/integration_blueprint
* API: Make requests more robust by introducing a retry mechanism, sveinse/zaptec#19 * API: Fix set_limit_current bug, sveinse/zaptec#27 * Fix coordinator update when calling services
|
So close but no cigar. Come on guys, you can do it! |
|
@svenakela close indeed. Testing is what remains. Have you tested the zaptec-dev implementation? |
I am on 0.7.0 now. Go charger, if anything can be tested let me know. |
|
@svenakela sure. Run it, test it, use it. Getting some real-life experience with it. The more experience we get with 0.7.0 the faster it can be released to a production version. |
Charge limiting and balancing as we speak. |
This is a considerable PR that contains a major refactor and contribution to the zaptec component. The intent is to improve the overall usability, feature availability and code structure of the integration. See below for a full list of features.
ℹ️ NOTE: This PR is available for beta-testing. Go to https://github.com/sveinse/zaptec for instructions on how to install with HACS.
zaptec-charger-xxxxx*is replaced by entities named using the name set in the Zaptec Portal, e.g.Sol Charger mode.The following binary sensors (for being connected) includes all attributes if that's needed for any manual templates:
<name> Installation<name> Circuit<name> ChargerUser changes
charger_idTechnical features
ZaptecBaseEntityfor heavy liftingZaptecUpdateCoordinatorto centrally manage API updatesAPI changes
Known issues