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

Please Add ONVIF Support. - UniFi Protect 5.0 now Supports Third Party Camera's. #1355

Open
StoneLegion opened this issue Sep 17, 2024 · 65 comments
Labels
enhancement New feature or request

Comments

@StoneLegion
Copy link

Describe the bug

I'm wondering if anyone able to get it to work? It says any camera that uses ONVIF Support, not sure if we emulate or can emulate such a feature?

I have a Dream Machine Pro, and tbh I love to get away from Blue Iris.

Affected Bridge Version

0.0

Bridge type

Docker Run/Compose

Affected Camera(s)

No response

Affected Camera Firmware

No response

docker-compose or config (if applicable)

No response

@StoneLegion StoneLegion added the bug Something isn't working label Sep 17, 2024
@Dudleydogg
Copy link

The current known bug with unifi is you can't authenticate the onvif it fails even if you have correct credentials apparently they are aware but no fix date is posted yet

@StoneLegion
Copy link
Author

The current known bug with unifi is you can't authenticate the onvif it fails even if you have correct credentials apparently they are aware but no fix date is posted yet

I think still Wyze Docker would not work because it does not output or provide a working onvif protocol? Unless I'm not understanding that.

@StoneLegion StoneLegion changed the title UniFi Protect 5.0 now Supports Third Party Camera's. Please Add ONVIF Support. - UniFi Protect 5.0 now Supports Third Party Camera's. Sep 23, 2024
@mrlt8
Copy link
Owner

mrlt8 commented Sep 23, 2024

I have an old local build with some basic support for ONVIF - auto discovery only works on a linux host as it seems to require the host network_mode.

I don't have any ubiquiti gear to test it with, but I can try to clean up some of that code.

@StoneLegion
Copy link
Author

I have an old local build with some basic support for ONVIF - auto discovery only works on a linux host as it seems to require the host network_mode.

I don't have any ubiquiti gear to test it with, but I can try to clean up some of that code.

Thank you, I guess I will have to learn to set it up on Linux hehe. I think for me getting away from the costly Blue Iris would be a really nice deal and I already had a UDM Pro already so this is pretty cool. Thanks for looking into it.

@thereal-BLKMGK
Copy link

BI's new licensing where if you go out of support they stop recording is pushing me to look elsewhere too although I suspect it'll be something closer to Frigate that Unifi although I run some of their hardware (not their NVR). The Wyze-bridge runs GREAT in a container on Linux!

Wish something like this was available for the Ring lights I inherited - grr!

mrlt8 added a commit that referenced this issue Sep 29, 2024
@mrlt8 mrlt8 added enhancement New feature or request and removed bug Something isn't working labels Sep 29, 2024
@mrlt8
Copy link
Owner

mrlt8 commented Sep 29, 2024

I pushed a new onvif image that should have some basic support for ONVIF. I decided to disable to ws-discovery stuff for now, but it should still work without the auto discovery if you point your client to your bridge and work on all platforms even without host mode.

This is still very basic and doesn't support any auth stuff yet, so you may have to set WB_AUTH=false.

@idaband
Copy link

idaband commented Sep 30, 2024

I pushed a new onvif image that should have some basic support for ONVIF. I decided to disable to ws-discovery stuff for now, but it should still work without the auto discovery if you point your client to your bridge and work on all platforms even without host mode.

This is still very basic and doesn't support any auth stuff yet, so you may have to set WB_AUTH=false.

sorry still reading through the code ...did you have a separate port / url that will be used to stream a particular camera ect?

@mrlt8
Copy link
Owner

mrlt8 commented Sep 30, 2024

You should be able to point it to your bridge on port 5000.

@idaband
Copy link

idaband commented Oct 1, 2024

Looking into seeing if its a firewall issue now. Does anyone else out been able to test this too?

https://help.ui.com/hc/en-us/articles/26301104828439-Third-Party-Cameras-in-UniFi-Protect

Preparing a Third-Party Camera

  1. Reference the OEM user manual for instructions on how to set up a specific camera. Generic steps are provided below.
  2. Connect the camera to the network and lookup the camera IP address in the UniFi Network app.
  3. In your browser, navigate to the camera’s local web server.
  4. Log in to the camera with default credentials and configure a username and password.
  5. Check if the camera requires a firmware update. Apply any updates available.
  6. Enable ONVIF in the camera and configure an ONVIF username and password. This is enabled automatically on some cameras and the global username and password are used.
  7. Configure the date, time, and timezone on the camera. Some cameras will fail authentication if the time is not set correctly.
    7a If applicable, ensure the authentication is set to Digest&ws-username token

@StoneLegion
Copy link
Author

As far as I know mrlr8 said discovery is disabled so Unifi is not going pickup anything till that is added.
"I decided to disable to ws-discovery stuff for now"

So I assume, not sure if it's correct, but it should not work on the unifi stuff yet.

@mrlt8
Copy link
Owner

mrlt8 commented Oct 1, 2024

Most of the ONVIF clients that I've been testing have an option to "manually" add a camera.

I can enable the WS discovery, but it will require the host network mode in Docker. AFAIK, the ONVIF auto discovery is only used for finding/adding the camera and is not used after that.

Edit: latest wyze-bridge:onvif image should have support for authentication if WB_AUTH is enabled. The username will be wb and the password will be the api key listed at the bottom of the WebUI.

@StoneLegion
Copy link
Author

Yeah currently the ubiquity one can only find it via discovery no manual adding yet. But this is their very first iteration so they might add more over time.

mrlt8 added a commit that referenced this issue Oct 1, 2024
@mrlt8
Copy link
Owner

mrlt8 commented Oct 1, 2024

Latest onvif image should have a WS_DISCOVERY option:

services:
    wyze-bridge:
        container_name: wyze-bridge
        restart: unless-stopped
        image: mrlt8/wyze-bridge:onvif # onvif image
        network_mode: host # host mode
        environment:
            - WS_DISCOVERY=true # enable discovery
            ....

@Nayruden
Copy link

Nayruden commented Oct 1, 2024

@StoneLegion I've got a Ubiquity UNVR, and you can add cameras manually, though they didn't make it easy to find. See the screenshot below.

github

However, I can't authenticate to the bridge. I tried username of wb and the API key shown at the bottom of the page (same as what I set via WB_API) but Unifi tells me "Invalid Credentials" and I get the following in the logs for the bridge.

[WyzeBridge] Onvif auth failed
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 21:54:09] "POST /onvif/media_service HTTP/1.1" 200 -

@mrlt8 I tried reviewing the authentication code for this but nothing stands out to me. Any ideas?

@StoneLegion
Copy link
Author

Wow this is great work and thanks @Nayruden I will have to try this when I have time. Please keep us updated with it.

@Nayruden
Copy link

Nayruden commented Oct 1, 2024

Something is up with the authentication code, I believe. Even with authentication disabled WB_AUTH=False, it's still failing auth.

[WyzeBridge] [AUTH] WB_AUTH=False
[WyzeBridge] 🔍 Could not find local cache for 'cameras'
[WyzeBridge] ☁️ Fetching 'cameras' from the Wyze API...
[WyzeBridge] [API] Fetched [6] cameras
[WyzeBridge] 💾 Saving 'cameras' to local cache...
<SNIP>
[WyzeBridge] [MTX] starting MediaMTX 1.9.0
[WyzeBridge] 🎬 6 streams enabled
[WyzeBridge] 10.42.0.128 - - [01/Oct/2024 22:37:54] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] Onvif auth failed

@idaband
Copy link

idaband commented Oct 2, 2024

I agree. Something with auth if failing. I went to auth = false and turned off network host and then i could log in.
(although my network host is not working as expected. I'm getting a 65 subnet instead of 1 and i'm not using any mask )

I did want to say THANK YOU THANK YOU for your help working this. If it doesn't happen any time soon or at all ..its ok. It's just going to be pretty crazy fun if it does end up working.

@mrlt8
Copy link
Owner

mrlt8 commented Oct 2, 2024

I made some changes to disable validating the authentication headers when WB_AUTH is set to false since some clients will still send security related headers.

Still not sure why authentication is failing when WB_AUTH is enabled though...

@idaband
Copy link

idaband commented Oct 2, 2024

which tag? i see three? or should we just pull the code and build the image locally?

mrlt8 added a commit that referenced this issue Oct 2, 2024
@mrlt8
Copy link
Owner

mrlt8 commented Oct 2, 2024

All the onvif related stuff should be in the onvif tag or you can build the image from the onvif branch locally.

The latest onvif image should show the 92a38e9 SHA on startup like this: 🚀 DOCKER-WYZE-BRIDGE ... 92a38e9

@Nayruden
Copy link

Nayruden commented Oct 2, 2024

With WB_AUTH=True now I see...

[WyzeBridge] [ONVIF] Auth failed for action='GetSystemDateAndTime' with creds=None
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/device_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/media_service HTTP/1.1" 200 -
[WyzeBridge] 10.42.0.128 - - [02/Oct/2024 11:10:03] "POST /onvif/media_service HTTP/1.1" 200 -

It still fails with "authentication failed" with WB_AUTH=False though. @mrlt8 send me an email at nayruden@gmail.com and I'll send you a pcap. I think that it's never sending creds with GetSystemDateAndTime but otherwise the creds are working and it's failing on something else.

@Nayruden
Copy link

Nayruden commented Oct 3, 2024

It works with WB_AUTH in either state. However, it does not work with multiple cameras. Here's how the UNVR sees the camera after import...

{
  "device": {
    "manufacturer": "Wyze Bridge",
    "model": "onvif Build [X86_64]",
    "firmwareVersion": "v2.10.3",
    "serialNumber": 0,
    "hardwareId": "X86_64 ONVIF BUILD [2024-10-02t15:44:22.474z] 44c1fc6"
  },
  "snapshotUri": "http://192.168.1.74:5000/snapshot/test2.jpg",
  "streams": [
    {
      "resolution": {
        "width": 1920,
        "height": 1080
      },
      "encoding": "H264",
      "bitrate": 5120,
      "uri": "rtsp://192.168.1.74:8554/test2"
    },
    {
      "resolution": {
        "width": 1920,
        "height": 1080
      },
      "encoding": "H264",
      "bitrate": 5120,
      "uri": "rtsp://192.168.1.74:8554/test"
    }
  ],
  "camera": {},
  "profiles": [
    {
      "$": {
        "token": "test2",
        "fixed": true
      },
      "name": "test2",
      "videoSourceConfiguration": {
        "$": {
          "token": "VideoSourceConfig_1"
        },
        "sourceToken": "VideoSource_1",
        "bounds": {
          "$": {
            "x": 0,
            "y": 0,
            "width": 1920,
            "height": 1080
          }
        }
      },
      "videoEncoderConfiguration": {
        "$": {
          "token": "VideoEncoderConfig_1"
        },
        "encoding": "H264",
        "resolution": {
          "width": 1920,
          "height": 1080
        },
        "rateControl": {
          "bitrateLimit": 5120
        }
      }
    },
    {
      "$": {
        "token": "test",
        "fixed": true
      },
      "name": "test",
      "videoSourceConfiguration": {
        "$": {
          "token": "VideoSourceConfig_1"
        },
        "sourceToken": "VideoSource_1",
        "bounds": {
          "$": {
            "x": 0,
            "y": 0,
            "width": 1920,
            "height": 1080
          }
        }
      },
      "videoEncoderConfiguration": {
        "$": {
          "token": "VideoEncoderConfig_1"
        },
        "encoding": "H264",
        "resolution": {
          "width": 1920,
          "height": 1080
        },
        "rateControl": {
          "bitrateLimit": 5120
        }
      }
    }
  ]
}

From UNVR's perspective, it's one camera with multiple streams. It picked the first stream for me.

@mrlt8 we need a way to pick which specific stream we want ONVIF to pick up. Maybe add an endpoint like /onvif/<CAM_NAME>? EG, I would manually add two ONVIF devices in this case, 192.168.1.74:5000/onvif/test and 192.168.1.74:5000/onvif/test2 and each endpoint would contain only the stream for that camera.

To get this far, my change was simply to add BitrateLimit to get_profiles. I picked 5MP for the bitrate but I'm not sure if that's the optimal value.

def get_profiles(streams):
    resp = """<trt:GetProfilesResponse>
            """
    for stream in streams:
        resp += f"""<trt:Profiles token="{stream}" fixed="true">
                <tt:Name>{stream}</tt:Name>
                <tt:VideoSourceConfiguration token="VideoSourceConfig_1">
                    <tt:SourceToken>VideoSource_1</tt:SourceToken>
                    <tt:Bounds x="0" y="0" width="1920" height="1080"/>
                </tt:VideoSourceConfiguration>
                <tt:VideoEncoderConfiguration token="VideoEncoderConfig_1">
                    <tt:Encoding>H264</tt:Encoding>
                    <tt:Resolution>
                        <tt:Width>1920</tt:Width>
                        <tt:Height>1080</tt:Height>
                    </tt:Resolution>
                    <tt:RateControl>
                        <tt:BitrateLimit>5000</tt:BitrateLimit>
                    </tt:RateControl>
                </tt:VideoEncoderConfiguration>
            </trt:Profiles>
            """
    return resp + "</trt:GetProfilesResponse>"

@Nayruden
Copy link

Nayruden commented Oct 3, 2024

Actually, I discovered that it is recording from both my devices even though it shows up as one camera. One of them is under the "high quality" recording, the other is under the "low quality" recording. 🤣

@Nayruden
Copy link

Nayruden commented Oct 3, 2024

I got the snapshot URI working by passing it the creds for wbadmin in the SOAP return. It makes the integration a lot nicer in the UNVR.

@StoneLegion
Copy link
Author

If you can share you setup with screenshots later I love to see them. Sadly been away so I have not had the pleasure of messing around with it, but I love to see it in action.

Once the kinks are worked on posting this on wyze / ubnt subreddits/facebook will really help bring more people to this project. Buying a single time investment into the UNVR or Dream Machine vs none stop license fee of Blue Iris is going make this amazing.

Thanks for everyone hard work on testing and of course mrlt8 for making this into reality.

@Nayruden
Copy link

Nayruden commented Oct 3, 2024

If you can share you setup with screenshots later I love to see them. Sadly been away so I have not had the pleasure of messing around with it, but I love to see it in action.

Once the kinks are worked on posting this on wyze / ubnt subreddits/facebook will really help bring more people to this project. Buying a single time investment into the UNVR or Dream Machine vs none stop license fee of Blue Iris is going make this amazing.

Thanks for everyone hard work on testing and of course mrlt8 for making this into reality.

It works just like my Ubiquiti camera now as far as I can tell. It's only missing the ability to scrub (playback only updates when you pick a time instead of updating on the fly as you scroll back) and events.

mrlt8 added a commit that referenced this issue Oct 4, 2024
Co-Authored-By: Brett Smith <16591+nayruden@users.noreply.github.com>
@mrlt8
Copy link
Owner

mrlt8 commented Oct 4, 2024

Thank you @Nayruden, I added BitrateLimit to the profiles response.

@mrlt8 we need a way to pick which specific stream we want ONVIF to pick up. Maybe add an endpoint like /onvif/<CAM_NAME>? EG, I would manually add two ONVIF devices in this case, 192.168.1.74:5000/onvif/test and 192.168.1.74:5000/onvif/test2 and each endpoint would contain only the stream for that camera.

Unfortunately, I don't think most onvif clients will allow you to specify the path like that, however, I believe you can keep adding the "same" device multiple times and just select the appropriate profile for each camera.

@idaband
Copy link

idaband commented Oct 4, 2024

Crazy idea....what about a port range to open up. Like port 6000s. Then each onvif stream gets it's own port that would proxy to the correct camera

@jpriganc
Copy link

jpriganc commented Oct 4, 2024

@mrlt8 and @Nayruden -Great work on getting this working!!! I have it showing up in Protect now. I have 4 Wyze cams, so getting them to show as individual cams in Protect would still be preferred. With the current setup, any idea if we can modify which one is showing in Protect? Right now, it is picking up my "side" camera, but I really want my "Driveway" camera to be the one recording.

@mrlt8
Copy link
Owner

mrlt8 commented Oct 4, 2024

@idaband That could work, but would also add a lot of complexity.

I believe "real" onvif servers with multiple cameras do something similar to what we're doing now and use a profile for each camera.

@Nayruden do you know if onvif supports adding cameras with a custom path?

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

@mrlt8 Unfortunately, you are right -- it does not accept a path. It only accepts an IP or hostname with a port. The way I got around this was that I added a bunch of alias domains on my network (EG kitchen.cam.local, hallway.cam.local, etc) that all point to the IP address of the Wyze bridge. When I added these different domains to the Protect, I used FILTER_NAMES on the Wyze bridge side so that it would only present a profile of my choice to the UNVR during that initial negotiation. Obviously not ideal but it's been working 100% since the initial registration and I am very happy with it so far.

So, as far as the initial registration, our only options are to vary the hostname / IP or the port as idaband suggested. I suspect most people would find the hostname registration straightforward enough (can do it from their router or PiHole, etc). In order to ease registration with that, maybe we could have a drop down selector on the Wyze bridge admin UI for which camera it will present to ONVIF? The camera adoption flow would then be as follows....

  • User sets up hostname for camera 1 -- cam-1.my.house (points to IP for Wyze bridge)
  • User selects "cam 1" in the Wyze bridge web UI ONVIF drop down
  • User adopts camera in their NVR, pointing it at cam-1.my.house:5000
  • User sets up hostname for camera 2 -- cam-2.my.house
  • User selects "cam 2" in the Wyze bridge web UI ONVIF drop down
  • User adopts camera in their NVR, pointing it at cam-2.my.house:5000

The hostnames are different so the NVR treats them as separate devices. Here's an example of how UNVR sees the devices at the end of this. (I modified the SOAP return so the snapshots would work in these examples)

Cam 1

{
  "device": {
    "manufacturer": "Wyze Bridge",
    "model": "onvif Build [X86_64]",
    "firmwareVersion": "v2.10.3",
    "serialNumber": 0,
    "hardwareId": "X86_64 ONVIF BUILD [2024-10-02t15:44:22.474z] 44c1fc6"
  },
  "snapshotUri": "http://wbadmin:pass@cam1.wyze.my.house:5000/snapshot/cam1.jpg",
  "streams": [
    {
      "resolution": {
        "width": 1920,
        "height": 1080
      },
      "encoding": "H264",
      "bitrate": 5000,
      "uri": "rtsp://wb:pass@cam1.wyze.my.house:8554/cam1"
    }
  ],
  "camera": {},
  "profiles": [
    {
      "$": {
        "token": "cam1",
        "fixed": true
      },
      "name": "cam1",
      "videoSourceConfiguration": {
        "$": {
          "token": "VideoSourceConfig_1"
        },
        "sourceToken": "VideoSource_1",
        "bounds": {
          "$": {
            "x": 0,
            "y": 0,
            "width": 1920,
            "height": 1080
          }
        }
      },
      "videoEncoderConfiguration": {
        "$": {
          "token": "VideoEncoderConfig_1"
        },
        "encoding": "H264",
        "resolution": {
          "width": 1920,
          "height": 1080
        },
        "rateControl": {
          "bitrateLimit": 5000
        }
      }
    }
  ]
}

Cam2

{
  "device": {
    "manufacturer": "Wyze Bridge",
    "model": "onvif Build [X86_64]",
    "firmwareVersion": "v2.10.3",
    "serialNumber": 0,
    "hardwareId": "X86_64 ONVIF BUILD [2024-10-02t15:44:22.474z] 44c1fc6"
  },
  "snapshotUri": "http://wbadmin:pass@cam2.wyze.my.house:5000/snapshot/cam2.jpg",
  "streams": [
    {
      "resolution": {
        "width": 1920,
        "height": 1080
      },
      "encoding": "H264",
      "bitrate": 5000,
      "uri": "rtsp://wb:pass@cam2.wyze.my.house:8554/cam2"
    }
  ],
  "camera": {},
  "profiles": [
    {
      "$": {
        "token": "cam2",
        "fixed": true
      },
      "name": "cam2",
      "videoSourceConfiguration": {
        "$": {
          "token": "VideoSourceConfig_1"
        },
        "sourceToken": "VideoSource_1",
        "bounds": {
          "$": {
            "x": 0,
            "y": 0,
            "width": 1920,
            "height": 1080
          }
        }
      },
      "videoEncoderConfiguration": {
        "$": {
          "token": "VideoEncoderConfig_1"
        },
        "encoding": "H264",
        "resolution": {
          "width": 1920,
          "height": 1080
        },
        "rateControl": {
          "bitrateLimit": 5000
        }
      }
    }
  ]
}

Since the NVR remembers the full path to the correct device after the initial registration, it doesn't matter if Wyze bridge is advertising another camera on ONVIF later.

@idaband
Copy link

idaband commented Oct 4, 2024

@Nayruden
is there a PR for the soap changes? I didn't see some of what your talking about in code. I'm still pulling the onvif branch.
ahh yes... I could use nginx proxy manager to sort out the ips with host names.

@mrlt8
Copy link
Owner

mrlt8 commented Oct 4, 2024

Another option could be to use WS-Discovery to advertise a path for each of the cameras? I believe most clients will accept whatever path the auto discovery returns e.g. /onvif/cam1/device_service, /onvif/cam2/device_service, etc.

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

@idaband I hard coded the creds because I'm lazy. I'm sure @mrlt8 can come up with a better solution for this. Use the code below to replace get_snapshot_uri in onvif.py. Change pass to your wbadmin password.

def get_snapshot_uri(profile):
    hostname = env_bool("DOMAIN", urlparse(request.root_url).hostname or "localhost")
    if WbAuth.enabled:
        hostname = f"wbadmin:pass@{hostname}"
    return f"""<trt:GetSnapshotUriResponse>
            <trt:MediaUri>
                <tt:Uri>http://{hostname}:5000/snapshot/{profile}.jpg</tt:Uri>
                <tt:InvalidAfterConnect>false</tt:InvalidAfterConnect>
                <tt:InvalidAfterReboot>false</tt:InvalidAfterReboot>
                <tt:Timeout>PT0S</tt:Timeout>
            </trt:MediaUri>
        </trt:GetSnapshotUriResponse>"""

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

@mrlt8 to be honest I didn't look at the discovery option. If it requires host networking and the same subnet it wouldn't have worked in my case anyway.

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

Based on some basic research, I think playback scrubbing (where you can see the camera feed fly by as you scroll back and forth in time) would be supported in the UNVR if there was a lower quality substream. I'm not sure what bitrate quality the official cameras use, but here's an example from mine while scrubbing. I'm not sure if this is something that would be supported by the Wyze bridge though. Might have to use something like go2rtc -- but that would require serving up completely different SOAP responses.

image

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

Nevermind... I'm a big dummy. I just saw that Wyze bridge does support lower quality substreams with SUBSTREAM=True. However, since both streams are giving UNVR the same hard-coded bitrate, it picks one at random to be high quality and the other to be low quality. I have scrubbing working for a test camera now, but the high quality and low quality are reversed of what they should be. @mrlt8 if you could change Wyze bridge to give a lower value bitrate for the lower quality substream, I think this would be fixed.

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

Nope -- doesn't matter what the bitrate is set to. It seems like UNVR will always take the first stream as "high quality" and the second as "low quality".

@Nayruden
Copy link

Nayruden commented Oct 4, 2024

Awesome! I've got scrubbing working now. I have SUBSTREAM=True and SUB_QUALITY=SD30 along with the following ugly hack replacement function in onvif.py. I wasn't sure what type of collection/iterable streams was and I didn't want to debug/trace it so I took a very brute force approach. 🤣

def get_profiles(streams):
    resp = """<trt:GetProfilesResponse>
            """
    resp_high = ""
    resp_low = ""
    for stream in streams:
        bitrate = 200 if "-sub" not in stream else 100
        resp_add = f"""<trt:Profiles token="{stream}" fixed="true">
                <tt:Name>{stream}</tt:Name>
                <tt:VideoSourceConfiguration token="VideoSourceConfig_1">
                    <tt:SourceToken>VideoSource_1</tt:SourceToken>
                    <tt:Bounds x="0" y="0" width="1920" height="1080"/>
                </tt:VideoSourceConfiguration>
                <tt:VideoEncoderConfiguration token="VideoEncoderConfig_1">
                    <tt:Encoding>H264</tt:Encoding>
                    <tt:Resolution>
                        <tt:Width>1920</tt:Width>
                        <tt:Height>1080</tt:Height>
                    </tt:Resolution>
                    <tt:RateControl>
                        <tt:BitrateLimit>{bitrate}</tt:BitrateLimit>
                    </tt:RateControl>
                </tt:VideoEncoderConfiguration>
            </trt:Profiles>
            """
        if "-sub" in stream:
            resp_low += resp_add
        else:
            resp_high += resp_add
    return resp + resp_high + resp_low + "</trt:GetProfilesResponse>"

@StoneLegion
Copy link
Author

It's been a week since the last reply. Is it running solid and well for yo guys? Worth migrating from Blue Iris to it or is there some stuff that needs to be fixed either UBNT side of things on the Hack?

@bdog4life
Copy link

I would like to test this, How would i Enable ONVIF in a Portainer config? Or is that not supported?

@Nayruden
Copy link

It's been a week since the last reply. Is it running solid and well for yo guys? Worth migrating from Blue Iris to it or is there some stuff that needs to be fixed either UBNT side of things on the Hack?

It's been working rock-solid for me! I've got four Wyze cameras streaming to UNVR now and they work just like the official Unifi cameras, except there's no motion detection.

@jpriganc
Copy link

@mrlt8 Unfortunately, you are right -- it does not accept a path. It only accepts an IP or hostname with a port. The way I got around this was that I added a bunch of alias domains on my network (EG kitchen.cam.local, hallway.cam.local, etc) that all point to the IP address of the Wyze bridge. When I added these different domains to the Protect, I used FILTER_NAMES on the Wyze bridge side so that it would only present a profile of my choice to the UNVR during that initial negotiation. Obviously not ideal but it's been working 100% since the initial registration and I am very happy with it so far.

So, as far as the initial registration, our only options are to vary the hostname / IP or the port as idaband suggested. I suspect most people would find the hostname registration straightforward enough (can do it from their router or PiHole, etc). In order to ease registration with that, maybe we could have a drop down selector on the Wyze bridge admin UI for which camera it will present to ONVIF? The camera adoption flow would then be as follows....

  • User sets up hostname for camera 1 -- cam-1.my.house (points to IP for Wyze bridge)
  • User selects "cam 1" in the Wyze bridge web UI ONVIF drop down
  • User adopts camera in their NVR, pointing it at cam-1.my.house:5000
  • User sets up hostname for camera 2 -- cam-2.my.house
  • User selects "cam 2" in the Wyze bridge web UI ONVIF drop down
  • User adopts camera in their NVR, pointing it at cam-2.my.house:5000

@Nayruden - sorry if this is a dumb question, but where did you put the "Filter_Names" option? Is that in the Docker settings or in the onvif.py file? I am running this on UnRAID, using the pre-built package. Also, I can't find the onvif.py file anywhere to modify. I need to keep looking for that. I have been recording one camera for the last week, but it is bringing in two different streams for that one camera.

@Nayruden
Copy link

FILTER_NAMES is an env var -- https://github.com/mrlt8/docker-wyze-bridge/wiki/Camera-Filtering

onvif.py needs to be added via a Dockerfile build or by a volume mount into the container. Here are instructions on how to do both of those options -- https://chatgpt.com/share/670e8461-4458-8010-a0bb-a9fea35e0cf1 . The container path is /app/wyzebridge/onvif.py

@MNewman
Copy link

MNewman commented Oct 16, 2024

@Nayruden I follow the idea of having multiple hostnames pointing to the same IP, but I'm missing how we get wyze-bridge to present the single filtered camera on each host name. Are you running multiple copies of wyze bridge, each filtered to a single camera?

@Nayruden
Copy link

@Nayruden I follow the idea of having multiple hostnames pointing to the same IP, but I'm missing how we get wyze-bridge to present the single filtered camera on each host name. Are you running multiple copies of wyze bridge, each filtered to a single camera?

No, I'm only running one copy. ONVIF is a one-time setup process. ONVIF hands back the RTSP stream URI and the NVR only ever cares about that URI that was handed back going forward. The wyze-bridge hands back RTSP streams that include the name of the camera and it doesn't matter what ONVIF passes to other clients in the future since it only ever grabs the data once. EG, see #1355 (comment) for how it stores the camera data after getting it from ONVIF -- it has the RTSP stream saved and that's all it ever cares about going forward.

At least, that's how UNVR works. I'm assuming others would be the same.

@idaband
Copy link

idaband commented Oct 16, 2024

i have 8 cameras...i'm getting ready to use a new PI for all the work. @Nayruden does the onvif image have hardware acceleration in it?

@Nayruden
Copy link

i have 8 cameras...i'm getting ready to use a new PI for all the work. @Nayruden does the onvif image have hardware acceleration in it?

Unless you're doing something unusual, my understanding is that wyze-bridge does a stream copy (no additional processing with CPU or GPU required).

@Toei79
Copy link

Toei79 commented Oct 28, 2024

wish know how work this , understanding its for cameras with onvif type? i have a few brands, use other method to able to play on synology surveillance, but its possible do on bridge great. understanding need inject onvif.py and how its on the chapgpt chat file with the info about my cameras? thats a python file ?

image
image

it gives a link address but after you shutdown camera or open app it gives a new address. no fully sure about this exactly but do some like that , no checked again just now

it gives something like this , rtsp://192.168.2.208:554/live/1jxxxxxjzaxa_p0_UFDWJJDBIHUE , then change last letters ramdomly

@Toei79
Copy link

Toei79 commented Nov 6, 2024

ok i figure out this lol . i did in the past cant remember before. one above give a different token? on the link ,

then go2rtc its able to get a permanent link

onvif://email:password@192.168.2.208:80?subtype=SubProfileToken

go2rtc discover camera with some data, and generate this one above, and you use to get m3u8 links there

so how i can use any of this for use onvif? i have already running onvif docker with this
version: '3'

services:

wyze-bridge:
container_name: wyze-bridge
image: mrlt8/wyze-bridge:onvif # onvif image
network_mode: host # Use host network mode
restart: unless-stopped # Restart policy
environment:
- WS_DISCOVERY=true # Enable ONVIF discovery
# Add additional environment variables as needed
# - WYZE_EMAIL=email
# - WYZE_PASSWORD=pass
# - RTSP_PORT=8554

but not discovers any camera onvif.

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

No branches or pull requests

10 participants