manzanotti / geniushub-client

Python library to provide direct connectivity to Genius Hub.
MIT License
9 stars 5 forks source link

Smart Plug Override with Time #90

Open WiggyToo opened 6 months ago

WiggyToo commented 6 months ago

Hi - first of all many thanks for all the work here, I came by way of Home Assistant where I wanted to override a Smart Plug at Sunset for a period of time, I can't get it to work there so wanted to check the underlying solution.

Here's what I have found:

  1. I can connect to and override the zone to "off" ( python3 ghclient.py -u [blahblah] -p [blahblah] [HUB IP] -z 15 -m off)
  2. I cannot override the zone to "on" with a time ( python3 ghclient.py -u [blahblah] -p [blah] [HUB IP] -z 15 -m override -s 600)

There is no error and the zone does come on but the override time is whatever it was before (when trying this in Home Assistant I get an error (see image)

image.

There are a couple of things in ghclient.py that confuse me and this may be the root of my issue:

Examples: ghclient.py HUB_ID [Makes sense] Display information about the Hub.

ghclient.py HUB_ID zones -v [Makes sense] Display detailed information about all Zones.

ghclient.py HUB_ID -z 3 off [Assume this needs to be "-m off"] Turn Zone 3 off.

ghclient.py HUB_ID -z 12 -d 3600 -t 19.5 [Assume this needs to be -s 3600 and it would override for 3600 seconds] Set the override temperature for Zone 12 to 19.5C for 1 hour.

I can't get the override to work with Power Zone or Heating Zone - the mode changes OK to Override but the time and the temperature are not applied.

So in summary this is either user error or a bug, override works but the time and temperature settings don't seem to (for me).

I'm very happy to provide more information or try things out if it helps.

Regards, Gav

PS The Temperature Override in HA appears OK, but the duration does not seem to work.

WiggyToo commented 6 months ago

I think this is the relevant log entry - I don't know what format to put the duration in in HA

image

causes this

File "/usr/src/homeassistant/homeassistant/components/geniushub/switch.py", line 87, in async_turn_on await self._zone.set_override(1, kwargs.get(ATTR_DURATION, 3600)) File "/usr/local/lib/python3.12/site-packages/geniushubclient/zone.py", line 290, in set_override duration = int(duration) if duration else 3600 ^^^^^^^^^^^^^ TypeError: int() argument must be a string, a bytes-like object or a real number, not 'datetime.timedelta'

WiggyToo commented 6 months ago

Hi @GeoffAtHome - if by chance you see this and can point me in the right direction I'd be most grateful.

Many thanks, Gav

rbubley commented 6 months ago

@WiggyToo, based on the error message it looks like you should put in the duration in seconds.

WiggyToo commented 6 months ago

Yes, I tried a few different formats but can't find one that doesn't throw the error.

There's no error if you leave the duration blank, then it defaults to 3600 seconds / 1 hour.

Thanks for the comment though, all suggestions gratefully received.

Gav

WiggyToo commented 6 months ago

I did some digging into the API using Postman mainly to see if there was a problem with my setup which was leading to the error.

The API documentation does not seem to cover override of zones with Smart Plugs, but by trial and error the following seems true, it would be good if someone else was able to check this as I am not too experienced with APIs etc.

POST https://my.geniushub.co.uk/v1/zones/[zoneID]/override - will override the Smart Plug: BODY as follows duration: 7200 - is in seconds as @rbubley said, setting this to 0 sets the state to Off setpoint: 0 will be stored as false for the zone, i.e. Off, 1 will be stored as True i.e. On

PATCH https://my.geniushub.co.uk/v1/zones/[zoneID]/override - sets the override values as above but wont change the plus state

You can check the current state with https://my.geniushub.co.uk/v1/zones/[zoneid]/mode and the current values with https://my.geniushub.co.uk/v1/zones/[zoneid]/override

If you don't include setpoint in the payload you get a 400 error with the message "Invalid request payload input"

So the API works, I don't know if it is possible to see if the HA Service "Genius Hub: set_switch_override" is sending the setpoint data or not or if this is the root of the error.

I have set Genius Hub up as a Custom Component to allow for experiments, and just modified SWITCH.PY to turn on for 16 hours rather than 1 hour as default which works round my specific issue, but I'd rather revert to the core integration.

e.g. Line 87 "await self._zone.set_override(1, kwargs.get(ATTR_DURATION, 57600))"

Regards, Gav

WiggyToo commented 6 months ago

More from me I'm afraid - useful I hope, this has been a good way to learn about customer components and test changes to the "geniushubclient" and "geniushub" components.

Having worked out how to put these in as config and custom_components in order to try changes to work around the issue I was seeing I have found the following.

  1. When using the Switch Override Service in an Automation the Duration ends up as a "datetime.timedelta" type which then fails in zone.py which attempts to convert it to an "int", this is the call that fails.
  2. I have bodged round this by adding this to my zone.py just before the failing call
    `# Start Fix for TypeError: int() argument must be a string, a bytes-like object or a real number, not 'datetime.timedelta'        
        from datetime import time, timedelta  
        if not isinstance (duration,int):
            duration = timedelta.total_seconds(duration)
    # End Fix        `
  3. The check is required because in the standard Switch: Turn on service the duration turns up as an "int" so does not need to be converted by zone.py
  4. The original line 290 of zone.py then runs in these 2 cases duration = int(duration) if duration else 3600

I don't know enough about how the services work or why this might be to find the root cause or a proper elegant fix but maybe others here would be able to track it down,

It may be that the place in the HA UI where you type the duration in seconds is converting it to "datetime.timedelta" but I have not yet worked out how this bit works or how to fix it, it seems this is the place where the override duration should be properly saved as an "int".

Many thanks, Gav