jeroenterheerdt / ring-hassio

A Home Assistant add-on for live streaming from Ring devices.
MIT License
131 stars 93 forks source link

Use docker without Hass.io #1

Closed robert-alfaro closed 4 years ago

robert-alfaro commented 4 years ago

What is the suggested image to build from? Can you add steps in the README for building the image and running container for those not using Hassio.

jeroenterheerdt commented 4 years ago

hmm, not sure. HASSIO uses alpine:3.11. There is also homeassistant/amd64-builder.

jeroenterheerdt commented 4 years ago

I doubt this repo is useful is you are not using Home Assistant. I would just take a look at the original work by dgreif (see this repos README).

robert-alfaro commented 4 years ago

I'm using Home Assistant, not Hass.io.

robert-alfaro commented 4 years ago

I'll give Alpine a shot right now

robert-alfaro commented 4 years ago

I hadn't delved into hassio addon build process...until now. I used BUILD_FROM=homeassistant/armv7-base which is the Alpine image for my machine/arch.

Here's what I've done..

  1. Build image docker build --build-arg BUILD_FROM='homeassistant/armv7-base:3.11' -t ring-hassio .
  2. Modify config.json for Ring username/password
  3. Run container docker run --init --rm --name="ring-livestream" -v <path to ring_hassio dir>/:/data/ -p 3000:3000 ring-hassio

At first /data was not mounting..not sure why. Anyways, when I run it I get:

(node:10) UnhandledPromiseRejectionWarning: Error: Failed to fetch oauth token from Ring. Verify that your refresh token is correct. invalid_grant
    at RingRestClient.<anonymous> (/ring-hassio/ring_hassio/node_modules/ring-client-api/lib/api/rest-client.js:129:23)
    at Generator.throw (<anonymous>)
    at rejected (/ring-hassio/ring_hassio/node_modules/ring-client-api/lib/api/rest-client.js:6:65)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:10) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:10) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Any idea @jeroenterheerdt ?

jeroenterheerdt commented 4 years ago

are you certain you have your username/password correct? be mindful of the escaping required when using special characters in your password in config.json.. If you have two-factor auth enabled not sure how that will work.

jes1417 commented 4 years ago

@robert-alfaro did you get this figured out? I don't run hassio Home Assistant I use Home Assistant Core in Docker and would love this feature.

robert-alfaro commented 4 years ago

Ok embarrassing, but I had a typo in config.json. All plain text, no escaping needed. I don't have two-factor enabled.

Back to my original issue that I accidentally masked:

jq: error: Could not open file /data/options.json: No such file or directory
robert-alfaro commented 4 years ago

@jes1417 I too am running Home Assistant Core (not Home Assistant [used to be called Hass.io]). I'm almost there I think.

I'm looking through hass.io repos to see where config.json::options gets translated and stuffed into options.json

I think I can simply craft my own options.json and then pass mount that file to /data/options.json. I am trying to get the JSON syntax right..currently have a parsing error.

robert-alfaro commented 4 years ago

I created file options.json with contents:

{
    "ring_username": "<username>",
    "ring_password": "<password>",
    "port": 3000
}

Then ran container:

docker run --init --rm --name="ring-livestream" -v <path to options.json>:/data/options.json -p 3000:3000 ring-hassio

The server starts up, logs in successfully (I got an e-mail notification from Ring that confirms this).

Started VLC and tried connecting to stream path: http://<device ip address>:3000/public/stream.m3u8

Progress, but still not working @jeroenterheerdt :

output directory: public/
Started server, listening on port 3000.
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.
(node:10) UnhandledPromiseRejectionWarning: Error: sip INVITE request failed with status 480
    at /ring-hassio/ring_hassio/node_modules/ring-client-api/lib/api/sip-session.js:169:28
    at searching (/ring-hassio/ring_hassio/node_modules/sip/sip.js:1316:5)
    at /ring-hassio/ring_hassio/node_modules/sip/sip.js:1297:41
    at Object.message (/ring-hassio/ring_hassio/node_modules/sip/sip.js:1116:7)
    at Object.signal (/ring-hassio/ring_hassio/node_modules/sip/sip.js:982:55)
    at /ring-hassio/ring_hassio/node_modules/sip/sip.js:1344:24
    at onMessage (/ring-hassio/ring_hassio/node_modules/sip/sip.js:558:9)
    at content (/ring-hassio/ring_hassio/node_modules/sip/sip.js:493:7)
    at headers (/ring-hassio/ring_hassio/node_modules/sip/sip.js:480:9)
    at TLSSocket.<anonymous> (/ring-hassio/ring_hassio/node_modules/sip/sip.js:504:27)
(node:10) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
(node:10) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

socket 0 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
sending file: public/stream.m3u8
socket 1 opened
requested uri: /public/stream0.ts
mapped filename: public/stream0.ts
sending file: public/stream0.ts
socket 0 closed
socket 1 closed
socket 2 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
sending file: public/stream.m3u8
socket 3 opened
requested uri: /public/stream0.ts
mapped filename: public/stream0.ts
sending file: public/stream0.ts
socket 3 closed
socket 2 closed
robert-alfaro commented 4 years ago

After running the first time I now get file not found errors when trying to serve the stream.

output directory: public/
Started server, listening on port 3000.
socket 0 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
file not found: public/stream.m3u8
socket 0 closed
socket 1 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
file not found: public/stream.m3u8
socket 1 closed
socket 2 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
file not found: public/stream.m3u8
socket 2 closed
socket 3 opened
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
file not found: public/stream.m3u8
socket 3 closed
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.
(node:10) UnhandledPromiseRejectionWarning: Error: sip INVITE request failed with status 480
    at /ring-hassio/ring_hassio/node_modules/ring-client-api/lib/api/sip-session.js:169:28
    at searching (/ring-hassio/ring_hassio/node_modules/sip/sip.js:1316:5)
    at /ring-hassio/ring_hassio/node_modules/sip/sip.js:1297:41
    at Object.message (/ring-hassio/ring_hassio/node_modules/sip/sip.js:1116:7)
    at Object.signal (/ring-hassio/ring_hassio/node_modules/sip/sip.js:982:55)
    at /ring-hassio/ring_hassio/node_modules/sip/sip.js:1344:24
    at onMessage (/ring-hassio/ring_hassio/node_modules/sip/sip.js:558:9)
    at content (/ring-hassio/ring_hassio/node_modules/sip/sip.js:493:7)
    at headers (/ring-hassio/ring_hassio/node_modules/sip/sip.js:480:9)
    at TLSSocket.<anonymous> (/ring-hassio/ring_hassio/node_modules/sip/sip.js:504:27)
(node:10) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
(node:10) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
robert-alfaro commented 4 years ago

I'd say the issue is related to https://github.com/dgreif/ring/issues/106 and perhaps an artifact of the server stopping and restarting too quickly because I'm not cycling it quickly at all.

jeroenterheerdt commented 4 years ago

yeah, I have seen that too. The underlying code is sometimes a bit buggy ;)

jeroenterheerdt commented 4 years ago

by the way, you can make an env file as well and pass that in.

robert-alfaro commented 4 years ago

I'm not familiar with javascript or typescript (I'm a firmware guy).. uh.. is this pulling "latest" or a pinned to some version of the ring api library -- does it need to be updated to prevent the serving part from being unstable?

jeroenterheerdt commented 4 years ago

it is pinned to a version that is from a month before. It works fine in HASS

robert-alfaro commented 4 years ago

I tried opening the browser to /index.html and can observe it loading.. then the socket error happens, then it restarts and then the 480 error. So perhaps the file not found error is related to docker volume / permissions?

jeroenterheerdt commented 4 years ago

not sure. I was able to run it in Docker just now without problems.

robert-alfaro commented 4 years ago

it is pinned to a version that is from a month before. It works fine in HASS

how can I test updating it? (assuming there are not really any mods needed in this repo)

not sure. I was able to run it in Docker just now without problems.

doing the same I've done (but for a different architecture)?

jeroenterheerdt commented 4 years ago

you would have to do some editing in the package*.json files :) good luck with that if you don't know what you're doing ;)

robert-alfaro commented 4 years ago

..and I'll need to modify the Dockerfile to adjust this since I see the npm install line pulling from there.

robert-alfaro commented 4 years ago

Ok.. adjusted the Dockerfile to COPY the local repo files. I updated only the ring-client-api package to v6.1.1. So far not getting "file not found" errors nor am I getting the 480 error upon server restart... but still no livestream. Sockets are closing almost immediately -- in browser and VLC.

output directory: public/
Started server, listening on port 3000.
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.
socket 0 opened
socket 1 opened
requested uri: /
requested uri: /public/stream.m3u8
mapped filename: public/stream.m3u8
sending file: public/stream.m3u8
socket 0 closed
socket 1 closed
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.
...
jeroenterheerdt commented 4 years ago

sockets being closed is expected since each file is just very short timespan.

jeroenterheerdt commented 4 years ago

can you at least open the index.html that is in the root?

robert-alfaro commented 4 years ago

I CAN open /index.html in browser. Browser console log shows HTTP404 for the stream url.

In VLC, I just ran with debug enabled and.. it essentially gets EOF immediately. See anything?

...
http stream debug: resolving 192.168.1.198 ...
[00007f5374001610] http stream debug: outgoing request:
GET /public/stream.m3u8 HTTP/1.1
Host: 192.168.1.198:3000
Accept: */*
Accept-Language: en_US
User-Agent: VLC/3.0.8 LibVLC/3.0.8
Range: bytes=0-

[00007f5374001610] http stream debug: incoming response:
HTTP/1.1 200 OK
Content-Type: application/vnd.apple.mpegurl
Date: Thu, 06 Feb 2020 02:40:03 GMT
Connection: keep-alive
Transfer-Encoding: chunked

...
[00007f5374002950] prefetch stream debug: using 16777216 bytes buffer, 16777216 bytes read
[00007f5374002950] main stream debug: using stream_filter module "prefetch"
[00007f5374002950] prefetch stream debug: end of stream
...
[00007f5374002d00] main stream debug: no stream_filter modules matched
[00007f5374013dc0] main stream_directory debug: looking for stream_directory module matching "any": 1 candidates
[00007f5374013dc0] main stream_directory debug: no stream_directory modules matched
[00007f5374000fa0] main input source debug: attachment of directory-extractor failed for http://192.168.1.198:3000/public/stream.m3u8
[00007f5374002d00] main stream debug: looking for stream_filter module matching "record": 26 candidates
[00007f5374002d00] main stream debug: using stream_filter module "record"
[00007f5374000fa0] main input source debug: creating demux: access='http' demux='any' location='192.168.1.198:3000/public/stream.m3u8' file='(null)'
[00007f5374001140] main demux debug: looking for demux module matching "any": 55 candidates
[00007f5374001140] adaptive demux debug: Period
[00007f5374001140] adaptive demux debug:  BaseAdaptationSet default_id#0
[00007f5374001140] adaptive demux debug:   Representation http://192.168.1.198:3000/public/stream.m3u8
[00007f5374001140] adaptive demux debug:    Segment #1 url=http://192.168.1.198:3000/public/stream0.ts duration 0
[00007f5374001140] adaptive demux debug: opening playlist file (192.168.1.198:3000/public/stream.m3u8)
...
[00007f5370000c40] main input debug: `http://192.168.1.198:3000/public/stream.m3u8' successfully opened
[00007f5374002d00] adaptive stream debug: Retrieving http://192.168.1.198:3000/public/stream0.ts @0
[00007f5374002d00] main stream debug: resolving 192.168.1.198 ...
[00007f5374002d00] main stream debug: connecting to 192.168.1.198 port 3000 ...
[00007f5374001140] adaptive demux error: Failed to create demuxer (nil) Unknown
[00007f5370000c40] main input debug: EOF reached
jeroenterheerdt commented 4 years ago

hmm, weird. I will need to debug this further if I am going to be of any help here. I am sorry. I cannot reproduce the problem on my end :(

robert-alfaro commented 4 years ago

I hear ya.. thanks for you help thus far.

robert-alfaro commented 4 years ago

I'll try this on a desktop next instead of on my odroid xu4.

Update: no luck on using amd64-base base image. Next I'll modify for ubuntu base.

jeroenterheerdt commented 4 years ago

@robert-alfaro did this help?

robert-alfaro commented 4 years ago

I'll try it all again right now

robert-alfaro commented 4 years ago

Same state as yesterday (after I upgraded ring-client-api to v6.1.1)... socket closes and server restarts.

requested uri: /public/stream0.ts
mapped filename: public/stream0.ts
sending file: public/stream0.ts
socket 0 closed
socket 1 closed
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.

@dgreif Thanks for the dependency updates..it does fix the 480 code and "file not found" issues. Do you have any thoughts on the outstanding issue regarding the socket closing immediately?

jeroenterheerdt commented 4 years ago

Hmm. What is the contents of stream.m3u8 when you open it in a browser instead of VLC? It seems like somehow the stream is never really started, since it only looking for stream0. There might be a network error somewhere, not sure. Can you confirm the Ring app works fine on the same network with the same credentials? No potential blockers anywhere?

robert-alfaro commented 4 years ago

Ring app works on Android devices and with Ring integration in Home Assistant core on this network. The Odroid xu4 I'm trying to run ring-hassio docker on is the same I'm running Home Assistant core in docker. Also tried on an Ubuntu amd64 desktop in docker. Both setups I've only tried using the Alpine base as to switch to ubuntu base I need to further modify the Dockerfile (just have not tried yet). Same network has several cameras streaming hls over rtsp. My ring doorbell is the Ring Elite (PoE variant).

robert-alfaro commented 4 years ago

What is the contents of stream.m3u8 when you open it in a browser instead of VLC?

$ cat stream.m3u8 
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:0
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:0.000000,
stream0.ts
#EXT-X-ENDLIST

Also, without requesting a stream after starting..about 30 second later I get Call has ended:

output directory: public/
Started server, listening on port 3000.
Call has ended
Restarting server
Server closed!
output directory: public/
Started server, listening on port 3000.
jeroenterheerdt commented 4 years ago

Yeah, so since this is sip based we keep the call open only for a short amount of time, hence the frequent restarts of the server. Now yes, I know this is clunky. What you're seeing is that somehow the stream cannot be started. Probably because of inability to talk to Rings endpoints somehow. Not sure about the Elite, I don't have that model.

jeroenterheerdt commented 4 years ago

But assuming the Ring-api works with the Elite then this should work as well, so I would encourage you to investigate getting that to work first.

robert-alfaro commented 4 years ago

Yea.. I understand what's happening, just not why. I'm pretty sure there is nothing different about the Elite model, especially since there's no cloudless communication. Any suggestions to isolate my testing?

dgreif commented 4 years ago

Elite shouldn't be any different than any other ring camera for live streaming. See https://github.com/dgreif/ring/wiki/Camera-Troubleshooting for the homebridge troubleshooting steps. Main thing would be making sure you have UPnP or NAT-PMP turned on in your router

robert-alfaro commented 4 years ago

I'm running pfsense..and yea I've got UPnP & NAT-PMP not enabled. (I didn't say "disabled" because I didn't turn it off, I just never turned it on for security reasons.) Let me mess with that and give it a shot.

@dgreif Are there other ports used besides 3000, internal/external, that need to be allowed for UPnP? Trying to figure out port/port-range for the ACL entry: image

robert-alfaro commented 4 years ago

I enabled both UPnP and NAT-PMP and left them wide-open.. still nothing. I don't see any upnp sessions/requests in pfsense.

UPDATE: success! Not sure what happened earlier, but after enabling both UPnP and NAT-PMP and using ACL entry allow 1024-65535 <host address> 1024-65535 to allow only this device access.

In summary

To get working without Hass.io, using docker straight up:

  1. ensure device connecting to ring api and serving the stream has UPnP/NAT-PMP enabled. To be more strict, possibly use explicit port forward rules -- ports documented here: Ring Ports

  2. clone this repo somewhere

  3. create options.json somewhere

    {
    "ring_username": "<username>",
    "ring_password": "<password>",
    "port": 3000
    }
  4. build docker image

    NOTE: substitute below 'armv7' with your machine architecture

    cd <path to this repo>
    docker build --build-arg BUILD_FROM='homeassistant/armv7-base:3.11' -t ring-hassio .
  5. run docker image

    docker run --init -d --name="ring-livestream" -v <path to options.json>:/data/options.json -p 3000:3000 ring-hassio

It is not working for me in Chrome web browser -- the stream does not play, however, the stream.m3u8 file does show various stream parts. VLC works like a charm..audio/video.

I have not yet actually tried adding this to home assistant, but I'm hopeful simply adding the camera as the README details will do.

Thanks for your help @jeroenterheerdt @dgreif

jeroenterheerdt commented 4 years ago

Awesome! The cameras should now be easy to add. Also, the video playback in browser will only work on Safari or in Chrono with an extension. That's why I recommend trying VLC. Great that you got it work. I will try to see to adding this to the readme.

jeroenterheerdt commented 4 years ago

readme updated!

robert-alfaro commented 4 years ago

As a brief update.. This works great for what it is, however, it creates tons and tons of live stream events in app, and causes alerts to not happen/detect, i.e motion and ding events/alerts don't occur since a live session is active. I've stopped use.

jeroenterheerdt commented 4 years ago

yes, I know - I found out that it blocks the alerts. One thing I am thinking of doing is somehow finding a way to trigger the livestream when there is motion and kill it after X period. Not sure.