vinteo / hass-opensprinkler

OpenSprinkler Integration for Home Assistant
MIT License
204 stars 40 forks source link

HA Web API returning 'hour must be in 0..23' randomly on some Opensprinkler entities #292

Open hplato opened 2 months ago

hplato commented 2 months ago

I've been working to migrate my opensprinkler interface over to Home Assistant. I've been able to send a program like [[100,-1,-1,-1],[1,2,3,4,5]], to the appropriate HA entities. This mostly works, however I am really puzzled why sometimes HA throws an error thinking that the entity is a time item. This has happened on both offset and duration items. For example:

sending data to ha: {"domain":"number","service_data":{"value":"210"},"id":39,"service":"set_value","type":"call_service","target":{"entity_id":"number.e2_start_time_offset"}}

Received FAILURE on request 39: $VAR1 = { 'error' => { 'message' => 'hour must be in 0..23', 'code' => 'unknown_error' }, 'id' => 39, 'type' => 'result' };

sending data to ha: {"target": {"entity_id":"number.e2_station_7"},"type":"call_service","service":"set_value","service_data":{"value":"9"},"domain":"number","id":51} Received FAILURE on request 51: $VAR1 = { 'id' => 51, 'type' => 'result', 'error' => { 'code' => 'unknown_error', 'message' => 'hour must be in 0..23' } };

The integration works, and the values are set, but I'd like to address this weird error as I don't know the underlying problem. If anyone has any suggestions, would be greatly appreciated.

I also saw the pull request from July 2023 where durations are locked to minutes. Is there any other methods to add some seconds to durations?

EdLeckert commented 2 months ago

I suspect your program start type was set to Sunset, and your current time of sunset is less than 210 minutes from midnight. I can reproduce the error with those conditions. And I suppose when you tried to set durations the start time was already in error. I can recreate that as well.

The reason a time entity is getting involved is because time.<program>_start_time gets updated when any of the start time parameters change, and it's getting set outside of the valid range for a single day. So if you need to change from a Sunset start type to Midnight, for example, set that first and then set the offset minutes. Going the other direction, you may have to reduce the minutes first. In any case, the start time needs to fit within a day at all times.

There is currently no way to set durations with the integration other than by minutes. This was by design to keep sliders and other UI components from having to show numbers that were unreasonably large and difficult to comprehend at a glance.

hplato commented 2 months ago

Thank you for the response (again!). All the offsets are all definitely set to midnight. I go through the four possible start times and check if it's a -1 and then set the offset_type to Disabled. If it's a positive number, I set offset_type to Midnight. I'm not quite sure what to do if the first value is -1, as start_time_offset_type doesn't have a disabled function. I could disable the overall program if a -1 value exists, but then it would enable the program if a positive number occurs (and I like to be able to override right on the OSP program for things like water restriction days).

I'll print out more debug before setting objects. Seems like a safer approach is to zero out the durations, then set the start time(s), then set the proper durations to avoid any intermediate math issues.

I still am a bit puzzled, as these are the program test strings that I'm using (in seconds, but they are converted to minutes in my code)

"[[210,-1,-1,-1],[600,650,1100,197,434,650,493,1550,1150,374,137]]"; Start 3:30am, and run for 122 minutes. (no where near midnight) "[[400,800,-1,-1],[61,61,61,61,61,61,61,61,61,61,61]]"; Start at 6:40am and run for 22 minutes (I round up seconds), start at 1:20pm and run for 22 minutes

hplato commented 1 month ago

I've also noticed now that I have a lot of these errors in the logs. Is there any way to have some diagnostic information output so I can see what the actual issue is? I'm running firmware 219

2024-07-16 13:15:02.206 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved (None) Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 255, in _handle_refresh_interval await self._async_refresh(log_failures=True, scheduled=True) File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 411, in _async_refresh self.async_update_listeners() File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 165, in async_update_listeners update_callback() File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1007, in async_write_ha_state self._async_write_ha_state() File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1133, in _async_write_ha_state state, attr, capabilities, shadowed_attr = self.async_calculate_state() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1068, in async_calculate_state state = self._stringify_state(available) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1013, in _stringify_state if (state := self.state) is None: ^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/components/time/init.py", line 95, in state if self.native_value is None: ^^^^^^^^^^^^^^^^^ File "/config/custom_components/opensprinkler/time.py", line 95, in native_value return datetime.time(trunc(minutes / 60), minutes % 60, 0) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: hour must be in 0..23