-
-
Notifications
You must be signed in to change notification settings - Fork 45
Simplify the V1 methods by using single re-usable base methods #125
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: master
Are you sure you want to change the base?
Conversation
|
Thanks for adding mix support! However, I have a concern about the API design: Passing inverter_type as a parameter to every method call creates unnecessary coupling and repetition. As I wrote in previous feedback (even though AI helped me phrase it): Inverter type is a property of the inverter, not a parameter of each operation. It should be determined once and reused internally, not passed around repeatedly. Here is how you could do it: |
@johanzander thanks for your comments, but there is no need to pass the type at all did you see |
examples/min_example_dashboard.py
Outdated
| raise Exception("No MIN_TLX device found to get energy data from.") | ||
|
|
||
| # energy data does not contain epvToday for some reason, so we need to calculate it | ||
| epv_today = energy_data["epv1Today"] + energy_data["epv2Today"] |
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.
great to add this to the library. But I have up to 4 individual PVs, so please use something more dynamic, taking into account the sum of up to 4 if present.
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.
@johanzander are they all of the same type or do you have a mix? that might be a interesting scenario
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.
added a sum
|
but you have modified min_example.py to take device type parameter. is this a mistake? |
examples/min_example.py
Outdated
| inverter_data = api.min_detail(inverter_sn) | ||
| inverter_data = api.device_details( | ||
| device_sn=inverter_sn, | ||
| device_type=device_type |
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.
passing device_type?
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.
let me check , but I believe I have 3 different ways to call the same methods , device_details() is the base method with sn and device type https://github.com/indykoning/PyPi_GrowattServer/pull/125/files#diff-12865f9986e5f28194397aae0efed2b7abc9137d18c0a09197682e6c7e65cd01R484-R511, the details() https://github.com/indykoning/PyPi_GrowattServer/pull/125/files#diff-12865f9986e5f28194397aae0efed2b7abc9137d18c0a09197682e6c7e65cd01R1225-R1227 where the sn and device type are set on the object, so not needed as params , I will roll back my changes in examples/min_example.py to use a backwards compatible min_detail(sn) which will just call device_details(sn, device_type=7 )
revert changes in min_* example and add backwards compatible wrapper …
johanzander
left a comment
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.
Backward compatibility with MIN inverters using V1 seem to work...
Will test the new harmonized V1 APIs later...
growattServer/open_api_v1.py
Outdated
| if DEBUG >= 1: | ||
| print(f"Saving {self.slugify(operation_name)}_data.json") # noqa: T201 | ||
| with open(f"{self.slugify(operation_name)}_data.json", "w") as f: # noqa: PTH123 | ||
| json.dump(response, f, indent=4, sort_keys=True) |
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 remove debug code from prod version.
Im testing the library and I see these:
Saving getting_MIN_TLX_details_data.json
Saving getting_MIN_TLX_settings_data.json
Saving getting_MIN_TLX_energy_data_data.json
growattServer/open_api_v1.py
Outdated
| """Enumeration of Growatt device types.""" | ||
|
|
||
| MIX_SPH = 5 # MIX/SPH devices | ||
| MIN_TLX = 7 # MIN/TLX devices |
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.
For consistency, should you call the enum
MiX_SPH for SPH_MIX instead (<DEVICE_TYPE>)
consider adding all types in the enum:
INVERTER = 1
STORAGE = 2
OTHER = 3
MAX = 4
SPH_MIX = 5
SPA = 6
MIN_TLX = 7
PCS = 8
HPS = 9
PBD = 10
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 only thing consistent with their naming convention, is the inconsistency
|
@indykoning I have pulled the upstream changes in and fixed as many ruff errors as possible |
Concerns with This PRI really appreciate the effort to add MIX/SPH support, but I have concerns about the approach. 1. Breaking Changes Will Break Home Assistant IntegrationThe PR changes existing public method signatures: Before (current): api.min_read_parameter(device_sn, parameter_id, start_address=None, end_address=None)
api.min_write_time_segment(device_sn, segment_id, batt_mode, start_time, end_time, enabled=True)After (this PR): api.min_read_parameter(device_sn, params: dict)
api.min_write_time_segment(device_sn, params: TimeSegmentParams)Impact: This will immediately break existing code including the Home Assistant Growatt integration which relies on this library. We need to maintain backward compatibility. 2. The "Generic" Methods Don't Actually Solve a Real ProblemThe new Current (clear and concise)api.min_read_parameter(device_sn, 'discharge_power')Proposed (verbose and exposes implementation details)api.common_read_parameter(device_sn, DeviceType.MIN_TLX, 'discharge_power')There's minimal code duplication being eliminated - just URL routing logic. MIN and SPH devices call completely different API endpoints (device/tlx/* vs device/mix/*, readMinParam vs readMixParam) with different parameters. The "generic" methods just add an abstraction layer that exposes device-type implementation details at every call. 3. RecommendationTo add SPH support while maintaining backward compatibility:
# Settings
def sph_settings(self, device_sn):
"""Get settings for an SPH inverter."""
# SPH-specific implementation
# Read/Write Parameters
def sph_read_parameter(self, device_sn, parameter_id, start_address=None, end_address=None):
"""Read parameter from SPH inverter."""
# SPH-specific implementation
def sph_write_parameter(self, device_sn, parameter_id, parameter_values=None):
"""Write parameter to SPH inverter."""
# SPH-specific implementation
# Time Segments
def sph_read_time_segments(self, device_sn, settings_data=None):
"""Read time segments from SPH inverter."""
# SPH-specific implementation
def sph_write_time_segment(self, device_sn, segment_id, batt_mode, start_time, end_time, enabled=True):
"""Write time segment to SPH inverter."""
# SPH-specific implementationThis approach:
The MIN and SPH implementations can share internal helper methods like 4. Alternative: If Truly Generic Methods Are DesiredIf the goal is to have generic methods for parameter operations, a better approach would cache device types internally: Usage: # Device types are auto-registered when calling device_list
devices = api.device_list(plant_id)
# Then use truly generic methods for parameters (no device_type parameter!)
api.read_parameter(device_sn, 'discharge_power')
api.write_parameter(device_sn, 'ac_charge', 1)Implementation approach:
Benefits:
This would provide a genuinely generic interface for parameter read/write operations while maintaining all existing functionality. Would you be open to refactoring along these lines? |
|
@johanzander so why did you not say this months ago, when you first looked at this? |
|
@johanzander also saying it would break the HA integration, should not happen if the dependency is using correct SemVer dependency requirements right? |
|
@GraemeDBlue I did provide feedback months ago about the API design concerns - specifically about passing device_type as a parameter to every method call rather than caching it internally. However, I'll be honest: I didn't anticipate that existing min_* method signatures would be changed in a way that breaks backward compatibility. I assumed we'd be adding new functionality rather than modifying existing public APIs that downstream projects like Home Assistant depend on. Looking back at the PR history, it appears some of the breaking signature changes (like min_read_parameter and min_write_time_segment taking params objects instead of individual arguments) may have been introduced since my earlier comments. My feedback remains focused on two main points:
I'm happy to discuss how we can add SPH support in a way that doesn't break existing integrations. The work you've done on the underlying implementation is valuable - it's really just about how we expose it as a public API. |
|
@johanzander yeah I'm open to working together, but thought you had ghosted me, so stopped asking you for feedback. |
Yes, it wouldn't break immediately because of these changes were commited or even this library released, but if the HA integration would be updated from current 1.7.1 to a newer version it would break. In theory one could update the library version and the method calls in HA at the same time, but HA project don't allow this - they bump libraries in separate PRs from code updates. |
No, I have been busy with the Home Assistant Growatt integration and finally all major changes I needed (reading / writing TOU settings, etc.) have been accepted and will be released in the 2026.1 update. So now I will have more time to spend on this library update. |
|
@GraemeDBlue - I'd like to help get this merged. If you're open to it, I can collaborate on updating the PR to:
Would you be open to that? I can push changes to your branch or create a collaborative branch - whatever works best for you. |
@johanzander my idea had been to get the Growatt library to control and validate the params sent , rather than the HA implementation by calling specific library method like johanzander/growatt_server_upstream@master...GraemeDBlue:growatt_server_upstream:master#diff-814821c0de54a55c25b8b789f81ed1edcf1486fa245f99748de316999e503fc4R551 |
@johanzander yeah I can add you as a collaborator on my branch |
|
@johanzander aah its not protected anyway so maybe we should just create a new branch and have some sort of plan rather than working cross purposes |
Summary
Checklist