Skip to content
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

Some API tweaking for openevse integration. #394

Closed
KipK opened this issue Nov 29, 2024 · 27 comments · Fixed by #406
Closed

Some API tweaking for openevse integration. #394

KipK opened this issue Nov 29, 2024 · 27 comments · Fixed by #406

Comments

@KipK
Copy link
Contributor

KipK commented Nov 29, 2024

Following up #402, I create an issue here as its more appropriated.

1/ If a claim or an override is already present, API should add the property on it, instead of creating a new claim/override with only the latest property.

example: EVSE is manually set to enabled, user change the charge_rate, it then just create a new override with only "charge_current" , state is removed.
should instead create a new override with "charge_current" and "state"

2/ Same as above, If a claim/override have more than one property ( but auto_release ), removing a property should keep the other properties but not delete the claim/override. If there's only one property, it then should remove the override/claim.

3/ setting charge rate to its max value ( aka "max_current_soft" ) should remove the charge_current property from the override if there's other properties, or remove the override if there's only the "charge_current" one.

In all cases, it should not consider "auto_release" if set to "true" , as this one is always added to a claim/override by default. You can just ignore this property like it does on OpenEVSE UI side as there's no use case for override. But probably better to test the boolean state and just ignore it if it's true.

@firstof9
Copy link
Owner

1/ If a claim or an override is already present, API should add the property on it, instead of creating a new claim/override with only the latest property.

As I understand it the override API is just a single setting, and calling it again should just add to the override that's in place currently. As for the claims, a similar thing as long as the client is the same. Please do correct me if I am wrong.

3/ setting charge rate to its max value ( aka "max_current_soft" ) should remove the charge_current property from the override if there's other properties, or remove the override if there's only the "charge_current" one.

This shouldn't be too hard.

@KipK
Copy link
Contributor Author

KipK commented Nov 29, 2024

/override endpoint is an abstraction of /claim endpoint but only for "manual override" service id.
It just works the same as claims, can have all the claim properties too. ( state, charge_current, max_current )

When you create an override you can see it in /claim endpoint too.

For the claims, yes it should only consider the properties of the same service ID you use of course.

@firstof9
Copy link
Owner

Looking at the code for make_claim

async def make_claim(
self,
state: str | None = None,
charge_current: int | None = None,
max_current: int | None = None,
auto_release: bool = True,
client: int = CLIENT,
) -> Any:
"""Make a claim."""
if not self._version_check("4.1.0"):
_LOGGER.debug("Feature not supported for older firmware.")
raise UnsupportedFeature
if state not in ["active", "disabled", None]:
_LOGGER.error("Invalid claim state: %s", state)
raise ValueError
url = f"{self.url}claims/{client}"
data: dict[str, Any] = {}
data["auto_release"] = auto_release
if state is not None:
data["state"] = state
if charge_current is not None:
data["charge_current"] = charge_current
if max_current is not None:
data["max_current"] = max_current
_LOGGER.debug("Claim data: %s", data)
_LOGGER.debug("Setting up claim on %s", url)
response = await self.process_request(
url=url, method="post", data=data
) # noqa: E501
return response

I'm only adjusting the claim the library makes and only adjusting whatever variables are passed, but that only piles on the current claim then I assume right or would it wipe what's currently in the claim and use what's been passed to it?

@KipK
Copy link
Contributor Author

KipK commented Nov 29, 2024

On OpenEvse each time you make a new claim with same service ID or an override, you have to resend all the properties yes.

@firstof9
Copy link
Owner

Thanks for confirming.

@KipK
Copy link
Contributor Author

KipK commented Jan 13, 2025

To illustrate, here is a short video of the consequencies of this issue:

openevse2.mp4

@KipK
Copy link
Contributor Author

KipK commented Feb 3, 2025

Hi @firstof9 ,

I saw your "fix_claims" branch, is it testable yet ?

@firstof9
Copy link
Owner

firstof9 commented Feb 3, 2025

That branch was because I forgot I had technically fixed it in the integration 😆

@KipK
Copy link
Contributor Author

KipK commented Feb 3, 2025

I thought it was to fix this , the lost properties when making a claim/override

@firstof9
Copy link
Owner

firstof9 commented Feb 3, 2025

I thought it was working correctly with the integration now? Is that not the case?

@KipK
Copy link
Contributor Author

KipK commented Feb 3, 2025

nope it still removes the previous properties.

To reproduce:

Send an override to set the state to Active or Disabled depending of your default state.
Then set the charge rate using number.openevse_charge_rate
The previous Active/Disabled state is removed then.

@firstof9
Copy link
Owner

firstof9 commented Feb 3, 2025

Ah ok then yes, the fix_claims branch will fix that.
Give me a moment to merge it.

@firstof9 firstof9 reopened this Feb 3, 2025
@firstof9
Copy link
Owner

firstof9 commented Feb 3, 2025

Ok you should be able to modify the manifest.json for the integration to 0.1.72 and that'll have the change in it.

@KipK
Copy link
Contributor Author

KipK commented Feb 4, 2025

Great, looks good here. 👍 :)

2 things:

  • When charge rate is manually set, if it's manually set back to the max value, it should remove the charge_current prop override.
  • When switching from Active/Disabled to Auto ( aka removing the state property from override, it actually remove the charge_current prop. Should keep it.

I still get the websocket error posted on the other thread when restarting HA, just posting it here as it's more related to the library than the integration I think.

Recorder: openevsehttp.__main__
Source: runner.py:154
First time appeared: 09:12:14 (244 occurrencies)
Last Recording: 09:12:14

Websocket to ws://192.168.1.8/ws failed, aborting [Error: '01JJ4VKJ7BGNTWN4BFD6PNF2MT']

Seems it tried to reconnect 244 times in 1 sec.

this one has only 1 occurencie:

Traceback (most recent call last):
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/websocket.py", line 92, in running
    await self.callback(msgtype, msg, None)
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/__main__.py", line 290, in _update_status
    await self.callback()  # pylint: disable=not-callable
    ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openevse/__init__.py", line 354, in websocket_update
    coordinator = self.hass.data[DOMAIN][self.config.entry_id][COORDINATOR]
                  ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
KeyError: '01JJ4VKJ7BGNTWN4BFD6PNF2MT'

Full debug log here: https://pastebin.com/GiBTQ6hX

@firstof9
Copy link
Owner

firstof9 commented Feb 4, 2025

I still get the websocket error posted on the other thread when restarting HA, just posting it here as it's more related to the library than the integration I think.

It's actually the integration, again, I'm not sure how you are reaching that message, I cannot reproduce it.

  • When charge rate is manually set, if it's manually set back to the max value, it should remove the charge_current prop override.

I'll see what I can do.

  • When switching from Active/Disabled to Auto ( aka removing the state property from override, it actually remove the charge_current prop. Should keep it.

I'll take a look at that too. What service are you calling to toggle these?

@KipK
Copy link
Contributor Author

KipK commented Feb 4, 2025

I'll take a look at that too. What service are you calling to toggle these?

I use set override for this.

I'm not sure how you are reaching that message, I cannot reproduce it.

I'm using dev builds but I don't see any changes on the API, will try with 5.1.2

@KipK
Copy link
Contributor Author

KipK commented Feb 4, 2025

Just tested, it's ok with 5.1.2 but not with dev builds.

edit: false alert. Got it with 5.1.2 also...

Calling set_override from dev tools / action throws this error:

websocket_api script: Error executing script. Unexpected error for call_service at pos 1: '01J7BSHM4CWTVBXH5978MGEAMR'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 526, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 764, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<9 lines>...
    )
    ^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 727, in _async_run_long_action
    return await long_task
           ^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2795, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2838, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openevse/services.py", line 202, in _set_override
    manager = self.hass.data[DOMAIN][config_id][MANAGER]
              ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
KeyError: '01J7BSHM4CWTVBXH5978MGEAMR'

@firstof9
Copy link
Owner

firstof9 commented Feb 4, 2025

This branch will catch the error: https://github.com/firstof9/openevse/tree/key-check

@KipK
Copy link
Contributor Author

KipK commented Feb 4, 2025

When calling set override I get this alert on UI:
failed action openevse/set_override. cannot access local variable 'manager' where it is not associated with a value

in the log:

2025-02-04 21:49:16.608 DEBUG (MainThread) [custom_components.openevse.services] Device ID: 1a8619b7019b8e42ea0f560a0c008fc0
2025-02-04 21:49:16.608 DEBUG (MainThread) [custom_components.openevse.services] Device_entry: DeviceEntry(area_id='garage', config_entries={'01JJ4VKJ7BGNTWN4BFD6PNF2MT', '01JC9Q0JN4GKXMN9K6VPGQFYW7'}, configuration_url='http://192.168.1.8/', connections={('openevse', '01J7BSHM4CWTVBXH5978MGEAMR'), ('openevse', '01JJ4VKJ7BGNTWN4BFD6PNF2MT')}, created_at=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), disabled_by=None, entry_type=None, hw_version=None, id='1a8619b7019b8e42ea0f560a0c008fc0', identifiers={('openevse', '9C9C1FD9D8E8')}, labels=set(), manufacturer='OpenEVSE', model='openevse_wifi_v1', model_id=None, modified_at=datetime.datetime(2025, 2, 4, 16, 58, 8, 505522, tzinfo=datetime.timezone.utc), name_by_user=None, name='openevse', primary_config_entry='01JJ4VKJ7BGNTWN4BFD6PNF2MT', serial_number=None, suggested_area=None, sw_version='master_d8a3474c', via_device_id=None, is_new=False, _cache={'json_repr': b'{"area_id":"garage","configuration_url":"http://192.168.1.8/","config_entries":["01JJ4VKJ7BGNTWN4BFD6PNF2MT","01JC9Q0JN4GKXMN9K6VPGQFYW7"],"connections":[["openevse","01J7BSHM4CWTVBXH5978MGEAMR"],["openevse","01JJ4VKJ7BGNTWN4BFD6PNF2MT"]],"created_at":0.0,"disabled_by":null,"entry_type":null,"hw_version":null,"id":"1a8619b7019b8e42ea0f560a0c008fc0","identifiers":[["openevse","9C9C1FD9D8E8"]],"labels":[],"manufacturer":"OpenEVSE","model":"openevse_wifi_v1","model_id":null,"modified_at":1738688288.505522,"name_by_user":null,"name":"openevse","primary_config_entry":"01JJ4VKJ7BGNTWN4BFD6PNF2MT","serial_number":null,"sw_version":"master_d8a3474c","via_device_id":null}'})
2025-02-04 21:49:16.609 DEBUG (MainThread) [custom_components.openevse.services] Config ID: 01J7BSHM4CWTVBXH5978MGEAMR
2025-02-04 21:49:16.609 ERROR (MainThread) [custom_components.openevse.services] Error locating configuration: '01J7BSHM4CWTVBXH5978MGEAMR'
2025-02-04 21:49:16.609 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [139906833999344] Unexpected exception
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 245, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<7 lines>...
    )
    ^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2795, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2838, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openevse/services.py", line 232, in _set_override
    response = await manager.set_override(
                     ^^^^^^^
UnboundLocalError: cannot access local variable 'manager' where it is not associated with a value

This line looks suspicious:

[custom_components.openevse.services] Device_entry: DeviceEntry(area_id='garage', config_entries={'01JJ4VKJ7BGNTWN4BFD6PNF2MT', '01JC9Q0JN4GKXMN9K6VPGQFYW7'}, configuration_url='http://192.168.1.8/', connections={('openevse', '01J7BSHM4CWTVBXH5978MGEAMR'), ('openevse', '01JJ4VKJ7BGNTWN4BFD6PNF2MT')}, created_at=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), disabled_by=None, entry_type=None, hw_version=None, id='1a8619b7019b8e42ea0f560a0c008fc0', identifiers={('openevse', '9C9C1FD9D8E8')}, labels=set(), manufacturer='OpenEVSE', model='openevse_wifi_v1', model_id=None, modified_at=datetime.datetime(2025, 2, 4, 16, 58, 8, 505522, tzinfo=datetime.timezone.utc), name_by_user=None, name='openevse', primary_config_entry='01JJ4VKJ7BGNTWN4BFD6PNF2MT', serial_number=None, suggested_area=None, sw_version='master_d8a3474c', via_device_id=None, is_new=False, _cache={'json_repr': b'{"area_id":"garage","configuration_url":"http://192.168.1.8/","config_entries":["01JJ4VKJ7BGNTWN4BFD6PNF2MT","01JC9Q0JN4GKXMN9K6VPGQFYW7"],"connections":[["openevse","01J7BSHM4CWTVBXH5978MGEAMR"],["openevse","01JJ4VKJ7BGNTWN4BFD6PNF2MT"]],"created_at":0.0,"disabled_by":null,"entry_type":null,"hw_version":null,"id":"1a8619b7019b8e42ea0f560a0c008fc0","identifiers":[["openevse","9C9C1FD9D8E8"]],"labels":[],"manufacturer":"OpenEVSE","model":"openevse_wifi_v1","model_id":null,"modified_at":1738688288.505522,"name_by_user":null,"name":"openevse","primary_config_entry":"01JJ4VKJ7BGNTWN4BFD6PNF2MT","serial_number":null,"sw_version":"master_d8a3474c","via_device_id":null}'})

Why would I have multiple config_entries ?
Could it be the native HA OpenEvse integration conflict with yours as they booth have the same name?

@firstof9
Copy link
Owner

firstof9 commented Feb 4, 2025

Custom components override built in, did you have the built in one installed at some point?

@KipK
Copy link
Contributor Author

KipK commented Feb 4, 2025

Yes when I've first installed HA and then saw it was the wrong integration and installed yours.

Do you know how I can clean this up ? Don't even know where is it stored.

edit: I've checked in .config/core.config_entries , but I see only one entry for Openevse:

{"created_at":"2025-01-21T16:37:21.771295+00:00","data":{"grid":"","host":"192.168.1.8","invert_grid":false,"name":"openevse","password":"","solar":"","username":"","voltage":""},"disabled_by":null,"discovery_keys":{},"domain":"openevse","entry_id":"01JJ4VKJ7BGNTWN4BFD6PNF2MT","minor_version":1,"modified_at":"2025-01-21T16:37:21.771298+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","title":"openevse","unique_id":null,"version":1}

I've found in core.device_registry:

{"area_id":"garage","config_entries":["01JJ4VKJ7BGNTWN4BFD6PNF2MT","01JC9Q0JN4GKXMN9K6VPGQFYW7"],"configuration_url":"http://192.168.1.8/","connections":[["openevse","01J7BSHM4CWTVBXH5978MGEAMR"],["openevse","01JJ4VKJ7BGNTWN4BFD6PNF2MT"]],"created_at":"1970-01-01T00:00:00+00:00","disabled_by":null,"entry_type":null,"hw_version":null,"id":"1a8619b7019b8e42ea0f560a0c008fc0","identifiers":[["openevse","9C9C1FD9D8E8"]],"labels":[],"manufacturer":"OpenEVSE","model":"openevse_wifi_v1","model_id":null,"modified_at":"2025-02-04T16:58:08.505522+00:00","name_by_user":null,"name":"openevse","primary_config_entry":"01JJ4VKJ7BGNTWN4BFD6PNF2MT","serial_number":null,"sw_version":"master_d8a3474c","via_device_id":null},

Doesn't seems to be because of native integration, because I see entities in core.entity_registry for booth 01JJ4VKJ7BGNTWN4BFD6PNF2MT and 01J7BSHM4CWTVBXH5978MGEAMR that are not present in native integration.

@KipK
Copy link
Contributor Author

KipK commented Feb 5, 2025

anyway, I've cleaned up my setup mess :) removed the integration, removed the hacs repo too, reinstalled it.
Now i only have one entry in core.device_registry, so seems good.

Was not this easy, no idea how it could happend. probably by testing dev branches over the hacs installation.

Thanks for your support.

About my previous comment:

When switching from Active/Disabled to Auto ( aka removing the state property from override, it actually remove the charge_current prop. Should keep it.

Forget this one. It seems Openevse firmware now do like this too, setting Auto clear the current limit so let's keep it this way.

edit: too bad, I still have a problem at startup or when reloading the integration.

set override commands works, but the websocket doesn't connect. It doesn't catch this error with the "key-check" branch.
It fixes magically itself after few minutes however.

Unexpected exception occurred: '01JK9QQKHP3EYBQR16MJDNBW8Z'
Traceback (most recent call last):
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/websocket.py", line 92, in running
    await self.callback(msgtype, msg, None)
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/__main__.py", line 290, in _update_status
    await self.callback()  # pylint: disable=not-callable
    ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openevse/__init__.py", line 354, in websocket_update
    coordinator = self.hass.data[DOMAIN][self.config.entry_id][COORDINATOR]
                  ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
KeyError: '01JK9QQKHP3EYBQR16MJDNBW8Z'

@firstof9
Copy link
Owner

firstof9 commented Feb 5, 2025

too bad, I still have a problem at startup or when reloading the integration.

I'll catch that one as well, I'll update it in the morning.
Thanks for all the testing.

@firstof9
Copy link
Owner

firstof9 commented Feb 5, 2025

Changes pushed.

@KipK
Copy link
Contributor Author

KipK commented Feb 5, 2025

Here is it:

diagnostic: https://pastebin.com/jcppc9xW

HA journal:

Recorder: openevsehttp.__main__
Source: runner.py:154
S'est produit pour la première fois: 16:01:30 (244 occurrences)
Dernier enregistrement: 16:01:30

Websocket to ws://192.168.1.8/ws failed, aborting [Error: cannot access local variable 'coordinator' where it is not associated with a value]

Recorder: openevsehttp.websocket
Source: /usr/local/lib/python3.13/site-packages/openevsehttp/websocket.py:128
S'est produit pour la première fois: 16:01:30 (1 occurrences)
Dernier enregistrement: 16:01:30

Unexpected exception occurred: cannot access local variable 'coordinator' where it is not associated with a value
Traceback (most recent call last):
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/websocket.py", line 92, in running
    await self.callback(msgtype, msg, None)
  File "/usr/local/lib/python3.13/site-packages/openevsehttp/__main__.py", line 290, in _update_status
    await self.callback()  # pylint: disable=not-callable
    ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openevse/__init__.py", line 359, in websocket_update
    coordinator.async_set_updated_data(self._data)
    ^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'coordinator' where it is not associated with a value
Recorder: custom_components.openevse
Source: custom_components/openevse/__init__.py:357
intégration: OpenEVSE (documentation, problèmes)
S'est produit pour la première fois: 16:01:30 (1 occurrences)
Dernier enregistrement: 16:01:30

Error locating configuration: '01JKAVTFJW9RQ0ZTCVAXY0V6R2'

complete debug log:

https://pastebin.com/k0TkxsCS

In the complete log, you can see it fails at startup, then after a while ws connects ok.

@firstof9
Copy link
Owner

firstof9 commented Feb 5, 2025

Thanks I see the problem, just an order of operations thing.
Changes pushed.

@KipK
Copy link
Contributor Author

KipK commented Feb 5, 2025

All good sir 👍 fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants