feat: add sprinkler support
This PR adds support for my irrigation api work in this other PR https://github.com/SecKatie/wyzeapy/pull/127 and related issue https://github.com/SecKatie/ha-wyzeapi/issues/230
Again, my first time adding to a home assistant component, but ive added my code to the sensor.py, switch.py and a new number.py.
Each irrigation device has multiple zones. The parent device has several sensors (RSSI, wifimac, ip address, etc), and then the zones are represented as switches. they have attributes as well (name, id, etc), but my thought in home assistant is to be able to turn them on and off like a switch. The number entity is how long the zone should run for (1-3600 seconds).
Happy to make corrections, but i need the api work merged before i can test much more here
thanks for the review. i agree on reducing the sensors. In fact, i commented out a ton of "zone" properties in the other library for this same reason. Ill address all this feedback tonight.
i believe i addressed all the feedback so far. i still have a question on some of the callbacks, specifically in the sensors.py. I think the rest of the callbacks looked ok. I needed to add a couple functions to the api to support what i was doing here. Sorry for the refactor of device and service, that made a bunch of line changes. I cant tell whats HA convention so irrigation instead of device seemed a little more clear.
I addressed all your feedback, thanks! I also took your tip of manually loading it into Home Assistant. I cleaned up names and icons and it seems like everything is updating and persisting as i expect. Ive restarted HA and im not seeing any surprises.
The only problem left is that pushing the buttons (my POST payloads back to wyze) are failing with a 'Signature2 is not valid'. I need to investigate that tomorrow, but the payload from HA shouldnt change so this might be done.
thanks again! i addressed all the feedback. I think we should not merge until i can figure out the Signature2 error. Ive seen how it makes the payload, i just dont understand why its failing yet. Lets leave this open in case i need to come back and make changes here.
fixed the signature errors in the other lib, but found one bug with the quickrun duration. sprinklers are turning on though!!
ok, this is working for me. Final bug was to make the button press use the home assistant number entity value instead of trying to use the Zone class attribute. @brg468 please review that logic because im not sure if there is a better way to get the number value from the button platform.
What i have implemented here is working, i just tested several zones and i can watch the changes appear in my phone app. so its "working" just want another pair of eyes on calling between platforms.
also, i wrote a home assistant automation now to run through all the zones once and then again (so the water can soak into the ground) and the automation will finish everything by sunrise. I could add that here as a reference file or maybe in the wiki.
i do miss my Rachio, but this is what we had at the new house. Its working for me now though, ran through a full cycle.
ok, this is working for me. Final bug was to make the button press use the home assistant number entity value instead of trying to use the Zone class attribute. @brg468 please review that logic because im not sure if there is a better way to get the number value from the button platform.
What i have implemented here is working, i just tested several zones and i can watch the changes appear in my phone app. so its "working" just want another pair of eyes on calling between platforms.
Good to hear its working! Let me think about an easier way we could pass the number to the button, what you have works but it seems overly complicated.
thanks. i also want to convert the number box from seconds to minutes. its tricky to constantly convert between the two so why not do it in the code
So why can't you just pass the value that is set in Zone quickrun_duration during the button press? That should be set by the number entity right?
to be clear, the quickrun_duration is not a wyzeapi stored parameter at all. It takes duration as a payload when you call quickrun. In this case, i was using home assistant as the sole storage for quickrun_duration. It gets assigned into the Button as an extended attribute because I originally figured it could just be a property of the button. From what i read, the extended attributes are meant to be read-only and there isnt a convenient way to have a user update them.
So then i created a number entity, and when you pushed the button, it pulls the value from the number entity and sends that.
maybe ideally, there is no number entity, and somehow the user could update that attribute.
But isn't this assigning a value to the quickrun_duration variable of the Zone class? Which could then be accessed by the button platform?
Sorry its tough to be exactly sure without having something to test with. Any chance you'd be up for sharing the device with my account so I could actually see it in action? I'd change the output so it wouldn't actually turn anything on..
async def async_set_native_value(self, value: float) -> None:
"""Set the value."""
await self._irrigation_service.set_zone_quickrun_duration(
self._device, self._zone.zone_number, int(value)
)
self._zone.quickrun_duration = int(value)
self.async_write_ha_state()
i think when i tried that it didnt work (back when the button had state. but i may have misunderstood state versus the extended attributes at that time. Let me try again now that ive spent more time in the code. if i cant make it work ill share with you. i have a disabled zone that you could test starting and it wont flood my yard 😂
looking closer, i think the issue is that the zone class is a different instance. the button platform gets its own irrigation device
button.py
irrigation_service = await client.irrigation_service # Get all irrigation devices irrigation_devices = await irrigation_service.get_irrigations() # Create a button entity for each zone in each irrigation device buttons = [] for device in irrigation_devices: # Update the device to get its zones device = await irrigation_service.update(device) for zone in device.zones: if zone.enabled: buttons.append(WyzeIrrigationZoneButton(irrigation_service, device, zone)) # Add a stop all schedules button for each irrigation device, not each zone buttons.append(WyzeIrrigationStopAllButton(irrigation_service, device))
number.py
irrigation_service = await client.irrigation_service # Get all irrigation devices irrigation_devices = await irrigation_service.get_irrigations() # Create a number entity for each zone in each irrigation device entities = [] for device in irrigation_devices: # Update the device to get its zones device = await irrigation_service.update(device) for zone in device.zones: if zone.enabled: entities.append(WyzeIrrigationQuickrunDuration(irrigation_service, device, zone))
since the wyze api doesnt actually have the value, the calls to irrigation_service.update() never update the device. whatever they pass in gets passed back. The number entity does update self._zone.quickstart_duration, but its updating its own copy of it.
Is there another way to keep a global state within HA? It seems like a weird scenario with the wyze api. I could make a totally new parent device type in HA but that feels more complicated that just having the button look at the number entity value, or having the number entity call a button service to update its attribute.
If it works it works I guess. It certainly seems like there'd be an easier way to pass the number to the button, but it's hard to visualize. I don't quite get why two instances of the device are being created either.
maybe the right way is to create a top level device. This is unique because its a device with several different platform types. currently i am building some buttons, numbers and sensors and relying on HA to link them together at the device level. It feels closer to a climate platform (set temp, sensor for temp, switches for actions) but climate has that built in.
Let me look around for some other HA examples of a device that might exposes multiple platform types
Did you make any progress on this?
I didnt find a great way to build an abstraction so ive just been using it as designed so far in this PR. There might be one or two small changes that I need to commit here, but its been running for a month and half with no issues. I still havent received any reviews on the api PR. Ill push the changes here later today to make it up to date with what ive been running
this PR now matches what ive been running at home for two months or so
@SecKatie let me know what to do (if anything in this PR). I also have some templates that have been helpful for running the sprinklers at my house. I dont see a place for documentation really. i could add the yaml as files in this repo, or not include them at all.
@SecKatie let me know what to do (if anything in this PR). I also have some templates that have been helpful for running the sprinklers at my house. I dont see a place for documentation really. i could add the yaml as files in this repo, or not include them at all.
@FeatherKing This PR is looking really good. I am thinking once we resolve that one copilot suggestion this will be good to go into the code base.
@SecKatie @brg468 ptal at the new button.py logic on L139. seems to be working for me with two controllers. I also tried some crazy special characters and weird names in the zones and it matched everything i threw at it.
The new changes look good to me 👍