keshavdv / unifi-cam-proxy

Enable non-Ubiquiti cameras to work with Unifi NVR
MIT License
1.65k stars 230 forks source link

Unifi Protect Dream Machine Pro #6

Closed nixis closed 3 years ago

nixis commented 3 years ago

Hi,

thanks for the that nice piece of software.

I have some trouble to adopt a camera, because I cant create an adoption token in the Unifi protect settings / dashboard, there is no option to generate or show a token. Bildschirmfoto 2020-09-14 um 11 00 33

If I run the command at the first time: unifi-cam-proxy --host 192.168.XXX.1 --cert client.pem --mac 'AA:BB:CC:00:11:22' --verbose --token '' rtsp -s rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_175k.mov

I get this message: 2020-09-14 11:05:29 unifi-camera-proxy RTSPCam[936] INFO /tmp/tmp93ukHV 2020-09-14 11:05:29 unifi-camera-proxy RTSPCam[936] INFO ffmpeg -y -re -rtsp_transport tcp -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_175k.mov" -vf fps=1 -update 1 /tmp/tmp93ukHV/screen.jpg 2020-09-14 11:05:29 unifi-camera-proxy Core[936] INFO Creating ws connection to wss://192.168.XXX.1:7442/camera/1.0/ws?token= Traceback (most recent call last): File "/usr/local/bin/unifi-cam-proxy", line 11, in <module> sys.exit(main()) File "/usr/local/lib/python2.7/dist-packages/unifi/main.py", line 58, in main c.run() File "/usr/local/lib/python2.7/dist-packages/unifi/core.py", line 745, in run ws = websocket.create_connection(uri, sslopt=ssl_opts, header=headers) File "/usr/local/lib/python2.7/dist-packages/websocket/_core.py", line 515, in create_connection websock.connect(url, **options) File "/usr/local/lib/python2.7/dist-packages/websocket/_core.py", line 226, in connect self.handshake_response = handshake(self.sock, *addrs, **options) File "/usr/local/lib/python2.7/dist-packages/websocket/_handshake.py", line 80, in handshake status, resp = _get_resp_headers(sock) File "/usr/local/lib/python2.7/dist-packages/websocket/_handshake.py", line 165, in _get_resp_headers raise WebSocketBadStatusException("Handshake status %d %s", status, status_message, resp_headers) websocket._exceptions.WebSocketBadStatusException: Handshake status 403 Forbidden

Now I can manually adopt the camera at the Dashboard: Bildschirmfoto 2020-09-14 um 11 06 42 Bildschirmfoto 2020-09-14 um 11 08 10

Now I run the same command a second time unifi-cam-proxy --host 192.168.XXX.1 --cert client.pem --mac 'AA:BB:CC:00:11:22' --verbose --token '' rtsp -s rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_175k.mov

I get this message: 2020-09-14 11:12:00 unifi-camera-proxy RTSPCam[981] INFO /tmp/tmpwKcKgZ 2020-09-14 11:12:00 unifi-camera-proxy RTSPCam[981] INFO ffmpeg -y -re -rtsp_transport tcp -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_175k.mov" -vf fps=1 -update 1 /tmp/tmpwKcKgZ/screen.jpg 2020-09-14 11:12:00 unifi-camera-proxy Core[981] INFO Creating ws connection to wss://192.168.XXX.1:7442/camera/1.0/ws?token= 2020-09-14 11:12:01 unifi-camera-proxy Core[981] INFO Initiating adoption with token [] and mac [AA:BB:CC:00:11:22] 2020-09-14 11:12:01 unifi-camera-proxy Core[981] DEBUG Sending: {'from': 'ubnt_avclient', 'functionName': 'ubnt_avclient_hello', 'inResponseTo': 0, 'to': 'UniFiVideo', 'responseExpected': False, 'messageId': 1, 'payload': {'connectionHost': '192.168.XXX.1', 'connectionSecurePort': 7442, 'rebootTimeoutSec': 30, 'name': 'unifi-cam-proxy', 'adoptionCode': '', 'idleTime': 191.96, 'protocolVersion': 67, 'mac': 'AA:BB:CC:00:11:22', 'uptime': 0.04075288772583008, 'fwVersion': 'UVC.S2L.v4.14.14.67.037e886.190630.1017', 'semver': 'v4.4.8', 'ip': '192.168.1.10', 'upgradeTimeoutSec': 150, 'model': 'UVC G3', 'hwrev': 19, 'totalLoad': 0.5474}} 2020-09-14 11:12:01 unifi-camera-proxy Core[981] INFO Processing [ubnt_avclient_hello] message 2020-09-14 11:12:01 unifi-camera-proxy Core[981] DEBUG Message contents: {u'from': u'UniFiVideo', u'functionName': u'ubnt_avclient_hello', u'inResponseTo': 1, u'to': u'ubnt_avclient', u'messageId': 11280, u'payload': {u'controllerName': u'unifi', u'overrideUuid': True, u'protocolVersion': 67}} Traceback (most recent call last): File "/usr/local/bin/unifi-cam-proxy", line 11, in <module> sys.exit(main()) File "/usr/local/lib/python2.7/dist-packages/unifi/main.py", line 58, in main c.run() File "/usr/local/lib/python2.7/dist-packages/unifi/core.py", line 759, in run reconnect = self.process(ws, msg) File "/usr/local/lib/python2.7/dist-packages/unifi/core.py", line 666, in process if m["responseExpected"] == False and m["functionName"] not in [ KeyError: 'responseExpected'

In the message I found a IP that not belongs to me "192.168.1.10", I found out this is the default camera ip, I dont use this option, because I connect to my cam directly to the rtsp stream like the bunny video.

Please help! What can i Do to get this working?

nixis commented 3 years ago

Tokens can be generated like so: https://help.ui.com/hc/en-us/articles/204975924-UniFi-Video-How-to-Adopt-a-Remote-Camera-that-is-not-Displaying-in-the-NV But in my case, there is no option to generate a token :(

AaronWebster commented 3 years ago

Same issue here with UDM pro.

pmcnano commented 3 years ago

I assume we won't have a way of making this work with UDM Pro because there doesn't seem to be a token anymore

DReffects commented 3 years ago

I've just stumbled upton this project after realizing that the "NVR" within a UDM Pro is in fact not a NVR but simply a bullshit device to sell more Ubiquiti branded, low-res cameras :( Has anyone figured out how to adopt on a UDM Pro?

swilalaa commented 3 years ago

+1

DReffects commented 3 years ago

would it be an option to add a camera manually to the posgresql database? One can access the database in the SSH console with unifi-os shell psql -U postgres -d unifi-protect -p 5433 \d+ cameras SELECT * FROM cameras;

gives you a detailed description of the cameras table... if one would simply add a unifi camera, then change the mac address and IP to a non-unifi camera? Could someone test that for me please? 👍

ArmandH commented 3 years ago
Table "public.cameras"
   Column        |           Type           |          Modifiers          | Storage  | Stats target | Description 

---------------------+--------------------------+-----------------------------+----------+--------------+------------- mac | character varying(255) | | extended | | host | character varying(255) | | extended | | connectionHost | character varying(255) | | extended | | type | character varying(255) | | extended | | name | character varying(255) | | extended | | upSince | bigint | | plain | | lastSeen | bigint | | plain | | connectedSince | bigint | | plain | | authToken | character varying(255) | | extended | | hardwareRevision | character varying(255) | | extended | | firmwareVersion | character varying(255) | | extended | | firmwareBuild | character varying(255) | | extended | | isUpdating | boolean | | plain | | isAdopting | boolean | | plain | | isAdopted | boolean | | plain | | isAdoptedByOther | boolean | | plain | | isProvisioned | boolean | | plain | | isSshEnabled | boolean | | plain | | fingerprint | character varying(255) | | extended | | password | character varying(255) | | extended | | lastMotion | bigint | | plain | | micVolume | bigint | | plain | | isMicEnabled | boolean | | plain | | channels | json | not null default '[]'::json | extended | | ispSettings | json | not null default '{}'::json | extended | | talkbackSettings | json | not null default '{}'::json | extended | | osdSettings | json | not null default '{}'::json | extended | | ledSettings | json | not null default '{}'::json | extended | | speakerSettings | json | not null default '{}'::json | extended | | recordingSettings | json | not null default '{}'::json | extended | | smartDetectSettings | json | not null default '{}'::json | extended | | recordingScheduleId | character varying(255) | | extended | | motionZones | json | not null default '[]'::json | extended | | privacyZones | json | not null default '[]'::json | extended | | smartDetectZones | json | not null default '[]'::json | extended | | smartDetectLines | json | not null default '[]'::json | extended | | stats | json | not null default '{}'::json | extended | | phyRate | bigint | | plain | | hdrMode | boolean | | plain | | videoMode | character varying(255) | | extended | | featureFlags | json | not null default '{}'::json | extended | | apMac | character varying(255) | | extended | | apRssi | bigint | | plain | | elementInfo | character varying(255) | | extended | | chimeDuration | bigint | | plain | | pirSettings | json | not null default '{}'::json | extended | | lcdMessage | json | not null default '{}'::json | extended | | lastRing | bigint | | plain | | anonymousDeviceId | character varying(255) | | extended | | id | character varying(255) | not null | extended | | createdAt | timestamp with time zone | not null | plain | | updatedAt | timestamp with time zone | not null | plain | | Indexes: "cameras_pkey" PRIMARY KEY, btree (id) "cameras_host_key" UNIQUE CONSTRAINT, btree (host) Foreign-key constraints: "cameras_recordingScheduleId_fkey" FOREIGN KEY ("recordingScheduleId") REFERENCES "recordingSchedules"(id) ON UPDATE CASCADE Referenced by: TABLE "events" CONSTRAINT "events_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE CASCAD E TABLE "heatmaps" CONSTRAINT "heatmaps_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE CA SCADE TABLE "lights" CONSTRAINT "lights_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE SET NU LL TABLE ""packageThumbnails"" CONSTRAINT "packageThumbnails_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE CASCADE TABLE ""recordingFiles"" CONSTRAINT "recordingFiles_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCAD E ON DELETE CASCADE TABLE "sensors" CONSTRAINT "sensors_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE SET NULL TABLE ""smartDetectTracks"" CONSTRAINT "smartDetectTracks_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELETE CASCADE TABLE "thumbnails" CONSTRAINT "thumbnails_cameraId_fkey" FOREIGN KEY ("cameraId") REFERENCES cameras(id) ON UPDATE CASCADE ON DELET E CASCADE

ArmandH commented 3 years ago

got no cameras yet to test that, what i noticed it has authToken so maybe that is possible to copy to a non ubi camera, i'm not familiar with postgres and do not know if we can manipulate the table.

keshavdv commented 3 years ago

At the moment, this project doesn't work with Unifi Protect, only the now EOL'ed Unifi Video product.

keshavdv commented 3 years ago

A new version is published in this branch that has instructions for use with Protect, if people want to test it out.

pironic commented 3 years ago

Thanks for trying... def a bit farther! I've customized the entrypoint.sh to the following: exec unifi-cam-proxy --host 10.1.1.1 --token "$AIAKOS_TOKEN" --name "Aiakos (Garage)" --mac "A4:<removed>:BB" --cert /config/server.pem rtsp -s "rtsp://<removed admin:pass>@10.1.2.3/live"

What strikes me as odd is the error message with a 192.168.1.0/24 ip... my network is 10.1.0.0/20

4/8/2021 10:58:33 AMUsing RTSP streom from
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c RTSPCam[1] INFO /tmp/tmpF_rN4Q
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c RTSPCam[1] INFO ffmpeg -y -re -rtsp_transport tcp -i "rtsp://<removed admin:pass>@10.1.2.3/live" -vf fps=1 -update 1 /tmp/tmpF_rN4Q/screen.jpg
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Creating ws connection to wss://10.1.1.1:7442/camera/1.0/ws?token=GMo<removed>098
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Initiating adoption with token [GMo<removed>098] and mac [A4:<removed>:BB]
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] DEBUG Sending: {'from': 'ubnt_avclient', 'functionName': 'ubnt_avclient_hello', 'inResponseTo': 0, 'to': 'UniFiVideo', 'responseExpected': False, 'messageId': 1, 'payload': {'connectionHost': '10.1.1.1', 'connectionSecurePort': 7442, 'rebootTimeoutSec': 30, 'name': 'Aiakos (Garage)', 'adoptionCode': 'GMo<removed>098', 'idleTime': 191.96, 'protocolVersion': 67, 'mac': 'A4:<removed>:BB', 'uptime': 0.051367998123168945, 'fwVersion': 'UVC.S2L.v4.14.14.67.037e886.190630.1017', 'semver': 'v4.4.8', 'ip': '192.168.1.10', 'upgradeTimeoutSec': 150, 'model': 'UVC G3', 'hwrev': 19, 'totalLoad': 0.5474}}
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Processing [ubnt_avclient_hello] message
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] DEBUG Message contents: {u'from': u'UniFiVideo', u'functionName': u'ubnt_avclient_hello', u'inResponseTo': 1, u'to': u'ubnt_avclient', u'messageId': 1048705, u'payload': {u'controllerUuid': u'66b2937a-<removed>-e02c72b8cff7', u'overrideUuid': True, u'controllerName': u'Pagoda', u'controllerVersion': u'1.17.3', u'protocolVersion': 67}}
4/8/2021 10:58:34 AMTraceback (most recent call last):
4/8/2021 10:58:34 AM  File "/usr/local/bin/unifi-cam-proxy", line 8, in <module>
4/8/2021 10:58:34 AM    sys.exit(main())
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/main.py", line 58, in main
4/8/2021 10:58:34 AM    c.run()
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 759, in run
4/8/2021 10:58:34 AM    reconnect = self.process(ws, msg)
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 666, in process
4/8/2021 10:58:34 AM    if m["responseExpected"] == False and m["functionName"] not in [
4/8/2021 10:58:34 AMKeyError: 'responseExpected'

gonna see if i can work with this...

EDIT: https://github.com/keshavdv/unifi-cam-proxy/blob/unifi-protect/unifi/main.py#L31

pironic commented 3 years ago

maybe a dumb question ... i rebuilt but it's still got the pip install command in the Dockerfile. is that just pulling from the pip version, rather than this updated version here? could it just be that it's not getting the updated code in the /unifi directory? How do i alter the Dockerfile to use the local 'library' instead of the pip installed one?

pmcnano commented 3 years ago

Thanks for trying... def a bit farther! I've customized the entrypoint.sh to the following: exec unifi-cam-proxy --host 10.1.1.1 --token "$AIAKOS_TOKEN" --name "Aiakos (Garage)" --mac "A4:<removed>:BB" --cert /config/server.pem rtsp -s "rtsp://<removed admin:pass>@10.1.2.3/live"

What strikes me as odd is the error message with a 192.168.1.0/24 ip... my network is 10.1.0.0/20

4/8/2021 10:58:33 AMUsing RTSP streom from
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c RTSPCam[1] INFO /tmp/tmpF_rN4Q
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c RTSPCam[1] INFO ffmpeg -y -re -rtsp_transport tcp -i "rtsp://<removed admin:pass>@10.1.2.3/live" -vf fps=1 -update 1 /tmp/tmpF_rN4Q/screen.jpg
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Creating ws connection to wss://10.1.1.1:7442/camera/1.0/ws?token=GMo<removed>098
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Initiating adoption with token [GMo<removed>098] and mac [A4:<removed>:BB]
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] DEBUG Sending: {'from': 'ubnt_avclient', 'functionName': 'ubnt_avclient_hello', 'inResponseTo': 0, 'to': 'UniFiVideo', 'responseExpected': False, 'messageId': 1, 'payload': {'connectionHost': '10.1.1.1', 'connectionSecurePort': 7442, 'rebootTimeoutSec': 30, 'name': 'Aiakos (Garage)', 'adoptionCode': 'GMo<removed>098', 'idleTime': 191.96, 'protocolVersion': 67, 'mac': 'A4:<removed>:BB', 'uptime': 0.051367998123168945, 'fwVersion': 'UVC.S2L.v4.14.14.67.037e886.190630.1017', 'semver': 'v4.4.8', 'ip': '192.168.1.10', 'upgradeTimeoutSec': 150, 'model': 'UVC G3', 'hwrev': 19, 'totalLoad': 0.5474}}
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] INFO Processing [ubnt_avclient_hello] message
4/8/2021 10:58:34 AM2021-04-08 16:58:34 f79a8951575c Core[1] DEBUG Message contents: {u'from': u'UniFiVideo', u'functionName': u'ubnt_avclient_hello', u'inResponseTo': 1, u'to': u'ubnt_avclient', u'messageId': 1048705, u'payload': {u'controllerUuid': u'66b2937a-<removed>-e02c72b8cff7', u'overrideUuid': True, u'controllerName': u'Pagoda', u'controllerVersion': u'1.17.3', u'protocolVersion': 67}}
4/8/2021 10:58:34 AMTraceback (most recent call last):
4/8/2021 10:58:34 AM  File "/usr/local/bin/unifi-cam-proxy", line 8, in <module>
4/8/2021 10:58:34 AM    sys.exit(main())
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/main.py", line 58, in main
4/8/2021 10:58:34 AM    c.run()
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 759, in run
4/8/2021 10:58:34 AM    reconnect = self.process(ws, msg)
4/8/2021 10:58:34 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 666, in process
4/8/2021 10:58:34 AM    if m["responseExpected"] == False and m["functionName"] not in [
4/8/2021 10:58:34 AMKeyError: 'responseExpected'

gonna see if i can work with this...

EDIT: https://github.com/keshavdv/unifi-cam-proxy/blob/unifi-protect/unifi/main.py#L31

From the file and line you posted, it is clear that you are missing passing the camera's ip address through --ip 10.1.2.3

pironic commented 3 years ago

Thank you for the advice @pmcnano!

a little further:

4/8/2021 11:29:06 AMUsing RTSP streom from
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 RTSPCam[1] INFO /tmp/tmp2QNWYG
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 RTSPCam[1] INFO ffmpeg -y -re -rtsp_transport tcp -i "rtsp://<rem admin:pass>@10.1.2.3/live" -vf fps=1 -update 1 /tmp/tmp2QNWYG/screen.jpg
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 Core[1] INFO Creating ws connection to wss://10.1.1.1:7442/camera/1.0/ws?token=GMo<rem>098
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 Core[1] INFO Initiating adoption with token [GMo<rem>098] and mac [A4<rem>BB]
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 Core[1] DEBUG Sending: {'from': 'ubnt_avclient', 'functionName': 'ubnt_avclient_hello', 'inResponseTo': 0, 'to': 'UniFiVideo', 'responseExpected': False, 'messageId': 1, 'payload': {'connectionHost': '10.1.1.1', 'connectionSecurePort': 7442, 'rebootTimeoutSec': 30, 'name': 'Aiakos (Garage)', 'adoptionCode': 'GMo<rem>098', 'idleTime': 191.96, 'protocolVersion': 67, 'mac': 'A4<rem>BB', 'uptime': 0.04044604301452637, 'fwVersion': 'UVC.S2L.v4.14.14.67.037e886.190630.1017', 'semver': 'v4.4.8', 'ip': '10.1.2.3', 'upgradeTimeoutSec': 150, 'model': 'UVC G3', 'hwrev': 19, 'totalLoad': 0.5474}}
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 Core[1] INFO Processing [ubnt_avclient_hello] message
4/8/2021 11:29:07 AM2021-04-08 17:29:07 b27c0dce6698 Core[1] DEBUG Message contents: {u'from': u'UniFiVideo', u'functionName': u'ubnt_avclient_hello', u'inResponseTo': 1, u'to': u'ubnt_avclient', u'messageId': 1049486, u'payload': {u'controllerUuid': u'66b2937a-<rem>-e02c72b8cff7', u'overrideUuid': True, u'controllerName': u'Pagoda', u'controllerVersion': u'1.17.3', u'protocolVersion': 67}}
4/8/2021 11:29:07 AMTraceback (most recent call last):
4/8/2021 11:29:07 AM  File "/usr/local/bin/unifi-cam-proxy", line 8, in <module>
4/8/2021 11:29:07 AM    sys.exit(main())
4/8/2021 11:29:07 AM  File "/usr/local/lib/python2.7/site-packages/unifi/main.py", line 58, in main
4/8/2021 11:29:07 AM    c.run()
4/8/2021 11:29:07 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 759, in run
4/8/2021 11:29:07 AM    reconnect = self.process(ws, msg)
4/8/2021 11:29:07 AM  File "/usr/local/lib/python2.7/site-packages/unifi/core.py", line 666, in process
4/8/2021 11:29:07 AM    if m["responseExpected"] == False and m["functionName"] not in [
4/8/2021 11:29:07 AMKeyError: 'responseExpected'

based on that stack trace...

https://github.com/keshavdv/unifi-cam-proxy/blob/master/unifi/core.py#L666 vs https://github.com/keshavdv/unifi-cam-proxy/blob/unifi-protect/unifi/core.py#L666

... it's def pulling the non-protect branch. I'm gonna try to alter the Dockerfile/entrypoint.sh to use the new branch manually rather than the pip library.

keshavdv commented 3 years ago

The docker image is not updated since this is still in development. You'll need to check out the branch locally, create a virtualenv and run this by hand. Something like:

git clone https://github.com/keshavdv/unifi-cam-proxy.git
cd unifi-cam-proxy && git checkout unifi-protect
python3 -m virtualenv venv
source venv/bin/activate
pip install -e .
unifi-cam-proxy ....
pmcnano commented 3 years ago

Just tried it with a reolink camera, and while I was able to get it provisioned, it never loaded the feed and then went offline. No visible errors in the logs.

Do I need to set the encoding to something in particular?

keshavdv commented 3 years ago

Do you have ffmpeg installed? The following info would be handy:

  1. The full command you're running with personal info redacted and make/model of the camera you are using
  2. Output of tail -n 30 /srv/unifi-protect/logs/errors.log from UDMP/UNVR (you'll need to enable SSH) in a Gist
  3. Last 20-30 lines of unifi-cam-proxy output in a linked Gist
pironic commented 3 years ago

I got the docker container to work however there is still 'undesired results'

I've got two logs at https://gist.github.com/pironic/76b42e47c0a288b5f649864880655e41

EDIT: could it be that the protect software is looking to the camera's ip to provide the image, but it should be the ip of the proxy?

using a wyzecam 2 with rtsp firmware.

keshavdv commented 3 years ago

Assuming those are the last log lines you see from the proxy, I think the GetRequest is stuck waiting for the snapshot file to get created by the ffmpeg command (code here). Can you try the following manually within the container and verify that the /tmp/screen.jpg file is actually getting created?

ffmpeg -y -re -rtsp_transport tcp -i "rtsp://<YOUR_CREDS>@10.1.2.3/live" -vf fps=1 -update 1 /tmp/screen.jpg

The IP is not actually used for anything meaningful that I've seen, it's just what is shown to you in the UI.

pironic commented 3 years ago

2 notes:

Looks like it all works, provided we dont have shitty equipment ;-) Thank you very much for your work on this.

Is there a way we can customize the model? Are we limited to a subset of supported unifi devices?

keshavdv commented 3 years ago

Good to hear! The implementation can be pretty demanding (starts 3+ parallel RTSP streams), so the Wyze Cam might just not be able to keep up. For the device model, I can make it something you can edit, but it will indeed be limited to the existing Unifi video devices (G3 Dome, G4 bullet, etc).

pironic commented 3 years ago

wait to put the work in to see if anyone else wants it... i think it's fine the way it is. Thank you very much for all your work. this is awesome.

EDIT: @keshavdv have you got a paypal or anything if i wanna throw a few bucks your way? maybe update the project allow us to 'support' financially?

my Dockerfile and entrypoint.sh if anyone else wants are:

Dockerfile

FROM python:3
RUN apt-get -y update && apt-get install -y \
  ffmpeg \
  netcat-openbsd
COPY . /app/
WORKDIR /app
RUN pip install --upgrade virtualenv && \
    git clone https://github.com/keshavdv/unifi-cam-proxy.git && \
    cd unifi-cam-proxy && git checkout unifi-protect && \
    python3 -m virtualenv venv
RUN ["chmod", "+x", "/app/entrypoint.sh"]
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["unifi-cam-proxy"]

entrypoint.sh

#!/bin/bash
cd /app/unifi-cam-proxy && \
. venv/bin/activate && \
pip install -e . 
cd /app
echo "Using RTSP stream from Aiakos with token: $AIAKOS_TOKEN"
#exec unifi-cam-proxy --host 10.1.2.3 --name "${NAME:-unifi-cam-proxy}" --mac "${MAC:-'AA:BB:CC:00:11:22'}" --cert /config/client.pem --token "$TOKEN" rtsp -s "$RTSP_URL"
# hardcoded to support multiple devices.
exec unifi-cam-proxy --host 10.1.1.1 --ip "10.1.2.3" --token "$AIAKOS_TOKEN" --name "Aiakos (Garage)" --mac "A4D<rem>CBB" --cert /config/server.pem rtsp -s "rtsp://<rem>@10.1.2.3/live"

exec "$@"
DanPatten commented 3 years ago

I got it to work with my UDM PRO but it kills my other camera that I used the cert from (shows disconnected). Also the RTSP stream was very very slow and it just buffered the entire time. In comparison it worked great in VLC player.

keshavdv commented 3 years ago
  1. Are you making sure you're using a different MAC address than your existing cameras (with --mac)? I haven't seen issues reusing the same cert, but using an existing MAC will clobber the other device.
  2. Have you had luck using the sample stream from the README to rule out camera-related issues (rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_175k.mov)?

As mentioned earlier, the implementation can be demanding on the source device since it starts many identical streams in parallel, so please share the make/model of your camera in case it's relevant here.

DanPatten commented 3 years ago

@keshavdv You are right in both cases, I should read the documentation closer, I'm guessing my RTSP stream is the issue so may have to play around with that. Thanks for all your work!

pmcnano commented 3 years ago

Do you have ffmpeg installed? The following info would be handy:

  1. The full command you're running with personal info redacted and make/model of the camera you are using
  2. Output of tail -n 30 /srv/unifi-protect/logs/errors.log from UDMP/UNVR (you'll need to enable SSH) in a Gist
  3. Last 20-30 lines of unifi-cam-proxy output in a linked Gist

That was it, ffmpeg missing I mean.

I got it to work but really, I had the same results as Dan.

I'm using Reolink RLC-410.

DanPatten commented 3 years ago

I left my stream going for a bit and then it got better after a few minutes. I think my other camera (G4 doorbell) randomly disconnected may be an unrelated issue.

Edit: It appears to stream fine in the protect app but not in the web view. Tried changing quality and had no effect. get_snapshot does work on web. Sample video works fine on both.

keshavdv commented 3 years ago

Can you share the output of ffprobe <your RTSP stream>?

DanPatten commented 3 years ago

My camera is an Amcrest ASH-26, RTSP settings: https://i.imgur.com/glkHv3z.png

ffprobe output: Input #0, rtsp, from 'rtsp://admin:xx@192.168.0.26/cam/realmonitor?channel=1&subtype=0': Metadata: title : Media Server Duration: N/A, start: 0.094000, bitrate: N/A Stream #0:0: Video: h264 (Main), yuvj420p(pc, progressive), 1280x960, 100 tbr, 90k tbn, 180k tbc Stream #0:1: Audio: aac (LC), 16000 Hz, mono, fltp

keshavdv commented 3 years ago

@pironic You might be able to use a WyzeCam with the workaround in #13.

@DanPatten Nothing seems out of the ordinary from what you’ve shared. Does web streaming work when you’re not on the same local network as your UDMP/UNVR (e.g. mobile hotspot)?

pironic commented 3 years ago

I'll leave this running for a few days to see how stable it is, but upon first inspection it seems to work!

@keshavdv you still need to provide a paypal or something... this is great.

here is my files:

Dockerfile

FROM python:3
RUN apt-get -y update && apt-get install -y \
  ffmpeg \
  netcat-openbsd
COPY . /app/
WORKDIR /app
RUN pip install --upgrade virtualenv && \
  git clone https://github.com/keshavdv/unifi-cam-proxy.git && \
  cd unifi-cam-proxy && git checkout unifi-protect && \
  python3 -m virtualenv venv
RUN wget https://github.com/aler9/rtsp-simple-server/releases/download/v0.15.4/rtsp-simple-server_v0.15.4_linux_amd64.tar.gz && \
  tar -xvf rtsp-simple-server_v0.15.4_linux_amd64.tar.gz && \
  rm rtsp-simple-server_v0.15.4_linux_amd64.tar.gz && \
  chmod +x rtsp-simple-server
RUN { \
  echo "paths:";\
  echo "  aiakos:";\
  echo "    source: rtsp://user:pass@10.1.2.3/live";\
  echo "    sourceProtocol: tcp";\
} > /app/rtsp-simple-server.yml
RUN ["chmod", "+x", "/app/entrypoint.sh"]
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["unifi-cam-proxy"]

entrypoint.sh

#!/bin/bash
cd /app/unifi-cam-proxy && \
. venv/bin/activate && \
pip install -e . 
cd /app
echo "Starting RtspSimpleServer for aiakos"
exec ./rtsp-simple-server &
echo "Using RTSP stream from Aiakos with token: $AIAKOS_TOKEN"
#exec unifi-cam-proxy --host 10.1.2.3 --name "${NAME:-unifi-cam-proxy}" --mac "${MAC:-'AA:BB:CC:00:11:22'}" --cert /config/client.pem --token "$TOKEN" rtsp -s "$RTSP_URL"
# hardcoded to support multiple devices.
exec unifi-cam-proxy --host 10.1.1.1 --ip "10.1.2.3" --token "$AIAKOS_TOKEN" --name "Aiakos (Garage)" --mac "A4<rem>CBB" --cert /config/server.pem rtsp -s "rtsp://localhost:8554/aiakos"

exec "$@"

docker-compose.yml

version: '2'
services:
  cam-proxy:
    build: .
    environment:
      AIAKOS_TOKEN: 'bnd<rem>KZg'
      RTSP_PROTOCOLS: 'tcp'
    volumes:
    - /data/unifi/video:/config
    restart: always
    ports:
    - 8554:8554/tcp
pironic commented 3 years ago

hmm... it's gone and gotten itself stuck. The log if filled every 2 seconds with several messages of

2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232007, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232008, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232009, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232010, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232011, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232012, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232013, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232014, 'inResponseTo': 0, 'payload': {}}
2021-04-13 01:46:04 4bc5314d1e08 Core[1] INFO Processing [Reboot] message
2021-04-13 01:46:04 4bc5314d1e08 Core[1] DEBUG Message contents: {'from': 'UniFiVideo', 'to': 'ubnt_avclient', 'responseExpected': False, 'functionName': 'Reboot', 'messageId': 1232015, 'inResponseTo': 0, 'payload': {}}

and it shows as rebooting image

the stream is still visible from the RtspSimpleServer as well. Thoughts?

EDIT: might be important to point out that restarting the container also fixes everything... until it gets caught again. error log when it's dying at: https://gist.github.com/pironic/ca03034c21718cf1df8baf250f78f95e

keshavdv commented 3 years ago

This usually happens when the UDMP side sees something it doesn’t like and attempts to reboot the camera in an attempt to “fix” things. You can usually find the relevant issue in /srv/unifi-protect/logs/errors.log on the UDMP (usually it’s because of a bad video stream). For the moment, getting out of this state requires restarting the unifi-cam-proxy process.

pironic commented 3 years ago

is there a way to have it auto-restart the container if it detects a reboot message?

DanPatten commented 3 years ago

@keshavdv My stream works outside of the network fine so I'm guessing it's something with this camera's stream + ffmpeg . I even tried using rtsp-simple-server and it behaved the same way.

pironic commented 3 years ago

I've moved the rtsp-simple-server out of the container and it seems to be much more stable. I've had it running fine for the last few hours without issue.

I dont suppose there would be a way to trigger motion events? I feel like that's prob something that was triggered by the camera and then sent to the nvr? not something that was determined by the nvr directly... is my assumption correct?

DanPatten commented 3 years ago

For motion events if this service exposed an API you could use BlueIris to detect motion events and post to that endpoint.

pironic commented 3 years ago

Screenshot_20210415-161657 If we could have as healthcheck endpoint that determines if the proxy is in that reboot status or not would also be a way we could detect if we need to restart the service if it stalls.

As it is though, as long as I'm on top of it, it is really nice being able to see my non-unifi devices in there. Thank you!

keshavdv commented 3 years ago

The latest version of the branch should attempt to honor Reboot messages and handle network disruptions a bit better for when the UDMP restarts, etc. Still probably needs more work, but hopefully a bit better than before. I've never quite been able to make motion events work so far (even on UFV), so there's still some work to figure out how to make that functional before it could hook into anything external.

jurajs5 commented 3 years ago

@pironic looks great, is it possible to help me with setup? Would love add my 5MP hikvision cameras to unifi enviroment.

thank you in advance Juraj

keshavdv commented 3 years ago

Ton of refactoring and potential breakages, but the latest version of the branch includes functional motion alerts! You can use automation of your choice to hit the following HTTP endpoints to start and stop motion events which can also trigger push notifications.

$ unifi-cam-proxy --host <NVR IP> --token <token> rtsp -s <source rtsp stream> --http-api 8080
$ curl localhost:8080/start_motion && sleep 10 &&  curl localhost:8080/stop_motion 
DReffects commented 3 years ago

Help me out here please - how can i get the certificate file from a G3 Flex? I cannot connect via SSH to the camera.

scp ubnt@192.168.0.XX:/var/etc/persistent/server.pem client.pem
ssh: connect to host 192.168.0.168 port 22: Connection refused

The G3 Flex is already adopted into protect.

Sorry, I should read the documentation of unifi protect more closely.

To enable SSH to your cameras do this on your UDM Pro: unifi-os shell Enter the following command to update the system packages and install Nano: apt-get update && apt-get install nano -y Type the command below to open the Protect configuration file using Nano, then allow editing: nano /srv/unifi-protect/config.json Edit the configuration file to allow SSH access: If the file is empty, add the following lines to the file:

{
"enableSsh": true
}

If the file is not empty: Type a comma ( , ) at the end of the “mbToKeepFree” line. (Note: If you don’t end this line with a comma, the configuration will fail.) Type “enableSsh": true on the following line, as shown below.

{ "ssl": {
"crt": "/etc/ssl/private/cloudkey.crt",
"key": "/etc/ssl/private/cloudkey.key"
},
"mbToKeepFree": 32768,
"enableSsh": true
}
DReffects commented 3 years ago

Can report that I got the proxy working with a DAHUA IPC. :) It seems to work fine with a h264 stream but does not with a h265 encoded stream. Does the UDM pro not support x265?

DReffects commented 3 years ago

I've changed the audio processing a little bit in the base/cams.py file:

#default="-f lavfi -i aevalsrc=0  -vcodec copy -strict -2 -c:a aac",
#default="-c:v copy -ar 32000 -ac 2 -codec:a aac -b:a 32k",
default="-c:v copy -c:a copy",

Unifi Protect can handle ACC (stereo) Streams up to 48000khz. the first line is the original, second default= option converts audio into 32khz stereo aac audio @32kbit (for cameras that cannot output aac)

the last line simply copies the audio-stream (and reduces cpu load of ffmpeg)

Is it currently known why the UDM Protect web interface does not show the "enable speakers" button for the proxy-cameras? Audio is available on the app and in recordings but not via the web interface.

mannkind commented 3 years ago

@keshavdv this is awesome 🎉 thanks for all your work on the unifi-protect branch!

It’s only been 24h, but it seems to be working well with two hikvision cubes and some fanghacks cameras (combined with rtsp-simple-server).

DReffects commented 3 years ago

@keshavdv Splendid Work! Have it running for about a day as well and have to join @mannkind in saying THANK YOU!

keshavdv commented 3 years ago

@DReffects The latest fix in master should enable audio from the web UI as well. You can modify the specific args passed to ffmpeg via the --ffmpeg-args CLI option if you don't want to have to edit code on a per-camera basis. There's probably not a one-size fits all solution, but I'm interested in trying to find the best default that minimizes unnecessary transcoding but also works out of the box for most folks.

DReffects commented 3 years ago

@keshavdv Superb, thanks for the information!

I am not really well versed with linux, I've currently have a CentOS stream Hyper-V machine running with the unifi-cam-proxy "installed" in the \tmp directory.

Could you please provide a small guide on how to update/upgrade the installation and/or how to setup this docker thingy that everyone keeps talking about? ;-)

Regarding the --fmpeg-args: superb! I was not aware this option exists :)

As far as I can tell the ffmpeg instances currently occupy a lot of CPU and memory. Is it feaseable to only spawn 2 ffmpeg instances instead of three per camera?

There's probably not a one-size fits all solution,

Well, you could pass on ffmpeg parameters to simply recode the entire stream like this: -c:v libx264 -b:v 6M -minrate 1M -preset medium -vf scale=1920:1080 -c:a aac -b:a 64K but that would require tons of cpu power to run in realtime.

simonk1969 commented 3 years ago

A new version is published in this branch that has instructions for use with Protect, if people want to test it out.

HI, sorry if I'm missing something here but when I click on the link above I get a 404 error. Is the link above still working for anyone else?

Regards Simon

keshavdv commented 3 years ago

@DReffects With docker and docker-compose installed, the sample at https://github.com/keshavdv/unifi-cam-proxy/blob/master/docker/docker-compose.yaml should be enough to get you going. With respect to the ffmpeg args, a set of defaults that prefers transcoding doesn't quite balance the desire to minimize transcoding when the majority of cameras streams are probably h264 + AAC already. To try and minimize load on the camera, you can use the hack in #13, but that won't reduce the cost of ffmpeg locally. Usually, the most expensive instance is the one used for the periodic snapshots since it does still need to decode the stream as mentioned in #15.

@simonk1969 The unifi-protect branch has already been merged into the main branch, so you can just use the latest version on PyPi/Docker or clone the repo.

Given a few folks have had this version working for a few days, I'm going to close out this issue and we can create new ones for specific discussions.