mrlt8 / docker-wyze-bridge

WebRTC/RTSP/RTMP/LL-HLS bridge for Wyze cams in a docker container
GNU Affero General Public License v3.0
2.61k stars 161 forks source link

Bring more Commands to MQTT discovered entities #921

Open jhansche opened 1 year ago

jhansche commented 1 year ago

Current commands: https://github.com/mrlt8/docker-wyze-bridge/wiki/Camera-Commands Entities exposed via discovery: https://github.com/mrlt8/docker-wyze-bridge/blob/main/app/wyzebridge/mqtt.py#L184

A few things that would be helpful:

In the case of "Pan Cruise waypoints", as an MQTT Select entity, the bridge can do the heavy lifting by:

  1. During discovery and/or GET cruise_points, publish discovery config for that camera, with the list of options: ["Waypoint 1", "2", .. "4"] depending on the number of configured waypoints. Optionally: periodically, or in response to other GET or SET requests of cruise_points, re-publish the updated discovery config with the updated options list, if it changed.
  2. When selecting one of the options in the select entity, which will be one of "waypoint 1" .. "4", re-query cruise_points (or cache/retain the last known configured waypoints from the last GET request), and then send the ptz_position command for that waypoint's coordinates. This is what was mentioned in https://github.com/mrlt8/docker-wyze-bridge/issues/835#issuecomment-1584763601 but with the new proposal being that we can support it natively in the add-on, without having to reimplement that functionality via external helpers/scripts to do it. This becomes even harder to do manually, as a result of the weird non-json value reported in https://github.com/mrlt8/docker-wyze-bridge/issues/835#issuecomment-1637137370

Others that could be supported, but may not add much value?

jhansche commented 1 year ago

A simplified idea for the Cruise Waypoints - we wouldn't even have to maintain an updated list of configured waypoints, if the Select entity's discovery config just includes the max number of configurable waypoints (which I believe is up to 4 waypoints max):

options: ["", "Waypoint 1", "2", "3", "4"]

And then when the waypoint is selected, look up cruise_points, select the right index, and either send the configured ptz_position if that waypoint is configured, or do nothing (or respond with an error) if the selected index is out of bounds.

There would also need to be some testing involved, in order to avoid issues with retaining state of the Select entity, which can't really be retained, because it may change after selecting a waypoint 🤔 In reality is probably makes more sense to treat these as 4 buttons, since buttons would not have a retained state that we have to deal with, and it's really just a one-time action to tell it to move to that position.

On the other hand, we could easy do this kind of "point the camera at $X" functionality manually, just by maintaining our own manual set of ptz coordinates somewhere. I was just looking for a way to make it work natively in the HA entity without having to augment those entities with our own helpers. But the more I think of it, maintaining our own list of ptz coordinates actually expands the functionality of the app's waypoints, because we would not be restricted to only 4 to choose from. Since we can have our own configuration of buttons or scripts or whatever, to make it snap to a specific viewport, and independently have a built-in "Pan Cruise" switch that will cycle through the cruise_points.

jhansche commented 1 year ago

It looks like we don't currently cache the resolved list of supported_commands on a per-cam basis. I think we would need to load that for each camera and save it with the cam in order to detect whether each camera supports various features, especially for determining whether the PTZ/Cruise features should be included in discovery or not.

mrlt8 commented 1 year ago

A couple of these are a little tricky..

We can technically SET/change "Res", but it tends to cause issues if we switch the resolution midstream, so that's why I've left this one out. We can't query the value directly, but it should update when requesting param_info or camera_info. See #825 for all the key-values.

Signal is another weird one that only get returned on authentication with the camera and there doesn't seem to be a way to update the value without reconnecting. Potential workaround may be to poll the data from the web api?

Snapshot is only active when discovery is enabled to avoid spamming the MQTT server with data, but we could make this optional.

Audio is more diagnostic and only gets published at setup. We may be able to enable/disable audio in the future.

jhansche commented 1 year ago

Makes sense. I was just noting the overlap and differences between MQTT entities and the Commands list, and trying to identify some that could be candidates for MQTT discovery (though some may not be worth the effort). What you've just added so far is a great start and may be good enough for the majority of users.

jhansche commented 1 year ago

In v2.3.11, I see the new entities on both my pan and non-pan cameras (with pan features correctly appearing only in the pan cameras) 🎉

This is great, thank you!

mrlt8 commented 1 year ago

@jhansche Added some more entities to the dev branch. Would appreciate some testing and feedback.

jhansche commented 1 year ago

I see the updated entities.


The new select for choosing the cruise waypoint, does not seem to work. It might be because of options being a list of ints, when they should be strings? From the logs:

   File "/usr/src/homeassistant/homeassistant/components/select/__init__.py", line 105, in async_select_option
       raise ValueError(f"Option {option} not valid for {entity.entity_id}")
   ValueError: Option 1 not valid for select.wyze_cam_pan_1_cruise_point
                "payload": {
                    "state_topic": f"{base_topic}cruise_point",
                    "command_topic": f"{base_topic}cruise_point/set",
                    "options": [1, 2, 3, 4],
                    "icon": "mdi:map-marker-multiple",
                },

There may also be some usability issues with the last selected option remaining selected inside the UI, even if the camera has since moved on - for example, if you select waypoint 1, and then motion tracking causes it to pan somewhere else. The UI will still have 1 selected, which may make it harder to to RE-select 1 later, if the frontend doesn't see it as a change 🤔 Instead you would have to change the value (i.e. from 1 to 2), and then change it back, in order to get back to waypoint 1.

One option might be to add an empty "" parked value to the options, and whenever the waypoint value is set, publish an update to the waypoint state to switch it back to "". This would not only fix the re-select issue, but also acts as a kind of visual confirmation in the entity UI that the request was received/acknowledged/handled. And it frees it back up to allow re-selecting an actual value.

But that might be a hack, and it may even be better to just make them buttons? Not sure.


I tried to test the REBOOT button also, but it didn't seem to do anything. It's possible that it just took a long time to respond, and it's hard to keep an eye on 4 things at once (between logs in 2 places, add-on web ui, device info entity in HA, and watching the camera itself), but I notice it responds much more quickly to commands like power-off, which is why it makes me think maybe it's just not working 🤷‍♂️ EDIT: never mind ... it does just take a long time to reboot, but confirmed it is working. I can hear the speaker click when I press it.


Minor issue: changing ALARM from switch to siren results in 2 entities now, because the old entity is still in the entity registry ... not sure how much you care about that?

Screenshot 2023-07-22 at 11 39 42 AM

If you do want to take care of removing it, you can do that with an empty discovery payload:

Subsequent messages on a topic where a valid payload has been received will be handled as a configuration update, and a configuration update with an empty payload will cause a previously discovered device to be deleted.

However, because they both have the same topic (/alarm), but different platform (switch vs siren), the MQTT discovery won't differentiate between them, and therefore an empty payload on alarm will delete the new siren as well. And sending the empty payload first, followed by real payload, could cause it to delete and readd the entity each time. Another option could be to store some kind of one-time flag, to cause it to send the empty payload first, one time only, and then repopulate with the updated discovery payload.

According to the docs, the topic segment before /config is the object-id, and best practice would be that it match the unique_id if there is one. It doesn't look like the discovery payloads currently set a unique_id, which may be part of the problem, but also highlights that it would not be safe to switch the platform while retaining the same unique_id. 🤔

Maybe it's not a big deal, if the original switch hasn't been released yet (but I think it was in 2.3.11?)

jhansche commented 1 year ago

Unrelated - I did notice that my "Docker Wyze Bridge (dev)" add-on didn't start up when I tried it, to test these. I had to completely uninstall and then reinstall the add-on, which also means I lost all my configs (mostly stock anyway, especially for the dev tests, so it's really just having to re-enter email/pass). I don't know why it would just fail to start. Maybe the image it was looking for no longer exists, so it has to be uninstalled?

This seems to be related to https://github.com/mrlt8/edge-repo/issues/1

mrlt8 commented 1 year ago

Been playing around with the select option for cruise_point, but it seems to be very optimistic even when the optimistic flag is set to false. The empty payload kind of works, but it sometimes just ends up clearing out the topic without updating the selection. Using - as the placeholder also works and will reset the value, but the HA GUI will usually just ignore it and keep the optimistic value even though the actual value is - when refreshing the page.

Any thoughts on handling the PTZ/Rotary Degree commands? Are buttons the only option?

jhansche commented 1 year ago

For rotary, is it ok for the axes to be set separately? Cause two number sliders would probably be easiest. You might be able to throttle sending the command to see if a second coordinate is going to be received 🤔 but that sounds like more effort than it's worth.

I've never seen any kind of 2D or 3D controls that would let you pick from that kind of coordinate space at one time. Maybe eventually HA will come up with a way to control this.

If you're more interested in directing the camera than absolute positioning, I've only seen D-pad style controls, which would basically be a series of buttons.

jhansche commented 1 year ago

Tested v2.3.12, and the waypoint selection is working great now! I also only see one ALARM entity now (the siren platform).

mrlt8 commented 1 year ago

@jhansche MQTT Cover seems to have an up/down and "rotate" that might be usable for the ptz.

I can't seem to get rid of the "stop" button for rotation, but I don't think the button does anything so it shouldn't be an issue.

jhansche commented 1 year ago

That's an interesting use.. so you're thinking open/close position for one axis, and tilt position for the other axis?

It would look odd with the native controls, but most people who would be using it probably wouldn't mind that, and would either use scripts for what they need, or some other Lovelace card to make it look the way they want.

Could be a useful way to implement it as an all in one entity.

jhansche commented 1 year ago

Got a chance to try out the new Cover entity for pan and tilt. Gotta say it's pretty slick 😎

I'm a little confused about the initial control that appears, before switching it to the d-pad style controls. I'm not really sure what that slider is doing. It really just caused it to kind of shift left and right maybe a few degrees, but never beyond those few degrees in either direction, no matter how far the slider is moved.

But the tilt control is definitely intuitive, and the stop button in the center is hardly noticeable.

joeblack2k commented 1 year ago

Is it possible to add "Privacy mode" toggle for the Pan camera?

i would like to create a flow where the camera goes off when i'm home and on when i'm not.

thanks!

jhansche commented 1 year ago

@joeblack2k as explained earlier in this issue, "Privacy mode" is nothing more than "power off". That switch already exists. EDIT: was not this issue, was #799, #841. Also replied to you directly at https://github.com/mrlt8/docker-wyze-bridge/issues/913#issuecomment-1633253442

tensiondriven commented 11 months ago

Not sure if this has been discussed, or if perhaps i missed it; I have a few cameras with Wyze Spotlights attached, and it would be jim-dandy to be able to turn the light on/off via REST API or MQTT.

My use case: The cameras are monitoring biological cultures which are supposed to stay in the dark, but I want to be able to monitor them remotely. (I'm already using Wyze cams and docker-wyze-bridge to monitor other things in the lab.) I was hoping to use a Wyze Spotlight and write an automation in Home Assistant (MQTT entity or script via REST if necessary) to turn on the light, take a snapshot, and turn the light off.

mrlt8 commented 11 months ago

Will look into it! There seem to be several floodlight related commands available in the app, so we may be able to add some support:

k12050_getFloodLightInfo
k12052_setFloodLightMode
k12054_setFloodLightType
k12060_setFloodLightSwitch
k12064_setFloodLightRestart
k12066_getFloodLightPIREnhanceMobileFilter
k12068_setFloodLightPIREnhanceMobileFilter
mrlt8 commented 11 months ago

@tensiondriven I added some commands for the WYZEC3L spotlight.

Would appreciate if you could try to set spotlight to on/off and see if any of the get values are working for the following endpoints:

ralacher commented 11 months ago

@mrlt8 here are the get values from my spotlight

$ curl http://192.168.0.201:5001/api/laundry-room/floodlight
{"command":"floodlight","payload":"","response":null,"status":"success","value":null}

$ curl http://192.168.0.201:5001/api/laundry-room/accessories
{"command":"accessories","payload":"","response":null,"status":"success","value":null}

$ curl http://192.168.0.201:5001/api/laundry-room/whitelight
{"command":"whitelight","payload":"","response":null,"status":"success","value":null}

Similar responses for the whitelight and floodlight endpoints on my floodlight accessory, but the /accessories endpoint produced this response.

$ curl http://192.168.0.201:5001/api/flood-light/accessories
{"command":"accessories","payload":"","response":"123,34,97,99,99,101,115,115,111,114,105,101,115,73,110,102,111,34,58,123,34,115,116,97,116,117,115,34,58,34,49,34,44,34,116,121,112,101,34,58,34,51,34,44,34,70,105,114,109,83,117,98,80,108,117,103,80,114,111,116,111,99,111,108,86,101,114,115,105,111,110,34,58,34,50,34,44,34,100,101,118,105,99,101,76,105,115,116,34,58,91,123,34,109,97,99,34,58,34,55,55,68,52,54,49,51,68,34,44,34,115,111,102,116,118,101,114,34,58,34,49,46,48,46,48,46,53,53,34,44,34,114,101,97,108,83,119,105,116,99,104,34,58,34,49,34,44,34,98,114,105,103,104,116,110,101,115,115,34,58,34,50,53,53,34,44,34,109,111,100,101,34,58,34,51,34,44,34,80,73,82,34,58,34,49,34,44,34,101,110,118,68,97,114,107,34,58,34,49,34,44,34,109,111,110,116,105,111,110,68,97,114,107,34,58,34,50,34,44,34,115,111,117,110,100,68,97,114,107,34,58,34,50,34,44,34,100,117,114,97,116,105,111,110,115,34,58,34,54,48,34,44,34,80,73,82,83,101,110,115,105,116,105,118,105,116,121,34,58,34,49,55,54,34,44,34,80,73,82,83,105,108,101,110,116,84,105,109,101,34,58,34,49,34,44,34,80,73,82,67,104,111,111,115,101,34,58,34,50,50,52,34,44,34,97,108,97,114,109,76,105,103,104,116,84,121,112,101,34,58,34,50,34,44,34,97,108,97,114,109,86,111,108,117,109,101,84,121,112,101,34,58,34,49,34,44,34,97,99,99,101,115,115,111,114,105,101,115,86,111,108,117,109,101,34,58,34,52,34,44,34,97,108,97,114,109,83,119,105,116,99,104,34,58,34,49,34,44,34,80,73,82,70,105,108,116,101,114,34,58,34,50,34,44,34,80,73,82,77,111,116,105,111,110,70,105,108,116,101,114,34,58,34,50,34,44,34,115,105,114,101,110,65,108,97,114,109,34,58,34,50,34,125,93,125,125","status":"success","value":"123,34,97,99,99,101,115,115,111,114,105,101,115,73,110,102,111,34,58,123,34,115,116,97,116,117,115,34,58,34,49,34,44,34,116,121,112,101,34,58,34,51,34,44,34,70,105,114,109,83,117,98,80,108,117,103,80,114,111,116,111,99,111,108,86,101,114,115,105,111,110,34,58,34,50,34,44,34,100,101,118,105,99,101,76,105,115,116,34,58,91,123,34,109,97,99,34,58,34,55,55,68,52,54,49,51,68,34,44,34,115,111,102,116,118,101,114,34,58,34,49,46,48,46,48,46,53,53,34,44,34,114,101,97,108,83,119,105,116,99,104,34,58,34,49,34,44,34,98,114,105,103,104,116,110,101,115,115,34,58,34,50,53,53,34,44,34,109,111,100,101,34,58,34,51,34,44,34,80,73,82,34,58,34,49,34,44,34,101,110,118,68,97,114,107,34,58,34,49,34,44,34,109,111,110,116,105,111,110,68,97,114,107,34,58,34,50,34,44,34,115,111,117,110,100,68,97,114,107,34,58,34,50,34,44,34,100,117,114,97,116,105,111,110,115,34,58,34,54,48,34,44,34,80,73,82,83,101,110,115,105,116,105,118,105,116,121,34,58,34,49,55,54,34,44,34,80,73,82,83,105,108,101,110,116,84,105,109,101,34,58,34,49,34,44,34,80,73,82,67,104,111,111,115,101,34,58,34,50,50,52,34,44,34,97,108,97,114,109,76,105,103,104,116,84,121,112,101,34,58,34,50,34,44,34,97,108,97,114,109,86,111,108,117,109,101,84,121,112,101,34,58,34,49,34,44,34,97,99,99,101,115,115,111,114,105,101,115,86,111,108,117,109,101,34,58,34,52,34,44,34,97,108,97,114,109,83,119,105,116,99,104,34,58,34,49,34,44,34,80,73,82,70,105,108,116,101,114,34,58,34,50,34,44,34,80,73,82,77,111,116,105,111,110,70,105,108,116,101,114,34,58,34,50,34,44,34,115,105,114,101,110,65,108,97,114,109,34,58,34,50,34,125,93,125,125"}

Converting the integers values in the response attribute got me this (repeated twice).

{"accessoriesInfo":{"status":"1","type":"3","FirmSubPlugProtocolVersion":"2","deviceList":[{"mac":"77D4613D","softver":"1.0.0.55","realSwitch":"1","brightness":"255","mode":"3","PIR":"1","envDark":"1","montionDark":"2","soundDark":"2","durations":"60","PIRSensitivity":"176","PIRSilentTime":"1","PIRChoose":"224","alarmLightType":"2","alarmVolumeType":"1","accessoriesVolume":"4","alarmSwitch":"1","PIRFilter":"2","PIRMotionFilter":"2","sirenAlarm":"2"}]}}
mrlt8 commented 11 months ago

Thank you @ralacher! Does the spotlight respond to http://192.168.0.201:5001/api/laundry-room/floodlight/on or http://192.168.0.201:5001/api/laundry-room/floodlight/off

ralacher commented 11 months ago

@mrlt8 it does not -- here are the results.

$ curl http://192.168.0.201:5001/api/laundry-room/floodlight/on
{"command":"floodlight","payload":"on","response":"invalid command","status":"error","value":null}
$ curl http://192.168.0.201:5001/api/laundry-room/floodlight/off
{"command":"floodlight","payload":"off","response":"invalid command","status":"error","value":null}
mrlt8 commented 11 months ago

@ralacher My bad, I meant:

http://192.168.0.201:5001/api/laundry-room/spotlight/on 
http://192.168.0.201:5001/api/laundry-room/spotlight/off
ralacher commented 11 months ago

@mrlt8 ah yeah, that does work. Saw the spotlight itself turn on/off and saw the updates occur in the Wyze app.

$ curl http://192.168.0.201:5001/api/laundry-room/spotlight/on
{"command":"spotlight","payload":"on","response":1,"status":"success","value":"1"}
$ curl http://192.168.0.201:5001/api/laundry-room/spotlight/off
{"command":"spotlight","payload":"off","response":1,"status":"success","value":"2"}

Should the floodlight accessory work as well? I get an error message when I try my flood light camera and accessory.

$ curl http://192.168.0.201:5001/api/flood-light/floodlight/on
{"command":"floodlight","payload":"on","response":"invalid command","status":"error","value":null}
mrlt8 commented 11 months ago

Awesome! No, I haven't added the set commands for the floodlight yet. Will look into it when I have a chance!

ralacher commented 11 months ago

Thanks so much! Really appreciate all your work on this project.