Ring doorbell

Yes ffmpeg can read and write h264.ts and mpeg2.ts as it is more about the contents of the file and not the container.

1 Like

what format is provided by the backend?
if itā€˜s an regular video format a browser should support it
so itā€˜s just reading the stream and writing into a file (spin of a dedicated thread to make it asynchronous)
Iā€˜ll provide you the timezone code I use in the Shelly binding when getting home or tomorrow

Here we are:

  1. Get local time, timezone of the PC (systemDefault)
   public static DateTimeType getTimestamp() {
        return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(now()), ZoneId.systemDefault()));
    }
  1. With given timezone
    public static DateTimeType getTimestamp(String zone, long timestamp) {
        ZoneId zoneId = ZoneId.of(zone);
        ZonedDateTime zdt = LocalDateTime.now().atZone(zoneId);
        int delta = zdt.getOffset().getTotalSeconds();
        return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp - delta), zoneId));
    }

This can be used if you are able to retrieve the timezone from the api service.

Reading a stream from a given URL

           String imageUrl = SERVLET_IMAGE_URL_BASE + uri;
            logger.debug("RachioImage: {} image '{}' from '{}'", request.getMethod(), uri, imageUrl);
            setHeaders(resp);
            URL url = new URL(imageUrl);
            URLConnection conn = url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            reader = conn.getInputStream();
            writer = resp.getOutputStream();

            // read data in 4k chunks
            byte[] data = new byte[4096];
            int n;
            while (((n = reader.read(data)) != -1)) {
                writer.write(data, 0, n);
            }

With the rachio binding I had a problem that their code service doesnā€™t set the correct content type. What I did was creating a servlet, which runs on the OH system and redirects the requested so I could fix the image type and return the browser the correct media type

  • The Api return the media url, which will be rewritten to point to the local system (127.0.0.1)

  • The rewritten url becomes the channel value

  • so the browser will open this one, which in fact generates a request to the bindingā€™s servlet

  • inside the binding I load the remote media and sends it to the browser, which then display the correct media fule

  • In your case you could do something similar. Store the file in a sub folder under /html so itā€™s accessible via http.

  • rewrite the url to point to that uri and update the channel with that value

  • the browser or other app opens this url, the binding catches the request and returns the file data to the client

  • some kind of round robin or timeline makes sure that your are not queuing endless video file

This is the servlet code: https://github.com/markus7017/org.openhab.binding.rachio/blob/master/src/main/java/org/openhab/binding/rachio/internal/api/RachioImageServlet.java

Awesome, thanks for the pointers. Some great ideas I hadnā€™t thought of for sure. The actual Ring video is mp4 and used to be able to be retrieved via simple wget, itā€™s just new authentication that was getting in the way. Hopefully I can make some time in the next few days to bang on this for a bit and get something done, itā€™s been an unusually busy time lately for some reason.

This should work the same way (in fact every format, which is supported by the browser/client app)
I would place the download folder somewhere under conf/html so you could rewrite the url with something like ā€œhttp://127.0.0.1/static/&lt;ring folder>/<filename>ā€ - keep the same file name, which should be unique.

fyi: there is also HttpUtil. downloadImage(), but Iā€™m not sure if this also handled video files

I installed the ring binding 2.5.1 and have the same problem with a delay of about 30 to 60 seconds. Polling interval is set to 3 seconds. So i would expect to get an event after a ring notification with a max delay of 3 seconds and not 30 seconds. The delay is not caused by rule compilation. Using IFTTT i never had a delay but the service is not usable anymore with myopenhab cloud service.
I hope that anybody has a solution for this problem.

Did you set the polling delay on the device (doorbell, etc) thing, the account thing, or both?

I set the polling intervall on the device and account thing to 3 seconds. Location is Germany if this is relevant.

@markus7017 HttpUtil. downloadImage() unfortunately didnā€™t work, but your servlet idea seems to be bearing some fruit. I hope to have something up very soon with the video working via a servlet!

@fuslwusl I took a look at things and so far I donā€™t see anything in the binding that could be causing this, every time the poll interval is reached, it does a request to Ringā€™s server and if there is a new event then it updates the channels. Unfortunately this means that we are at the mercy of the ring side to post the event in a timely manner on that interface. I suspect IFTTT didnā€™t have that issue because they might be using a subscription type connection to an interface instead of polling the rest interface. It may be part of the perks of being in their ā€œpartnerā€ program if thatā€™s the case. Unfortunately as soon as I replied to the email thread I had with them that I was finally able to connect and poll data and asked if there was any way we could discuss getting into their partner program, they went from timely responses to radio silence.

I will keep digging into it though to see if thereā€™s something we can do once I get a release with the video link put out.

Thanx for checking this again. I really hope Ring will open their system for basic features like motion and ring notifications. Amazon Echo devices are able to get the ring notifications since a few weeks. Perhaps there is a way to get these notifications from there or from IFTTT? The best way was IFTTT for me. But openhab doesnā€™t support it anymore. So it would be great to get realtime events using this binding.

Iā€™ve put a new version of the binding here: org.openhab.binding.ring-2.5.1-SNAPSHOT.jar . This one should fix the time zone and time formatting, and includes providing a link to the last event video again. The binding puts up a servlet that runs at http://:8080/ring/video/ to provide an .mp4 of the video and will put that url in the channel. Iā€™ve also cleaned up the logging to not include sensitive information in debug (only trace). Hopefully this one works for everyone.

1 Like

@zolakk,

I am clearly confused as to how the servlet for the ring video is suppose to workā€¦ do you have a walkthrough as to how it is set up? I have the URL showing as:

http://10.0.1.25:8080/ring/video/[Bunch of numbers here]

I put this URL in a browser and I get the play icon with a slash through it. I am at a loss, I just canā€™t seem to follow the documents that @markus7017 linked. I have a very limited knowledge base for coding.

~John

Whilst direct access is the holy grail, Iā€™m getting an almost instantaneous doorbell press event into openHAB by using an Alexa routine.

Iā€™ve exposed a ā€œDoor Bellā€ Switch item to Alexa, and on the Doorbell event from Ring, Iā€™m setting this openHAB Switch to ON. Iā€™ve then set up a Rule that when the ā€œDoor Bellā€ switch is set to ON, it plays ā€˜doorbell.mp3ā€™ via openHAB into my multi-room audio setup. The Switch item is then set to OFF a second later.

This actually starts playing the sound through openHAB quicker than my Ring Chime and Echo devices do!

2 Likes

Hey Zolakk,

Installed your lastest binding and it works along with the streaming video. What I canā€™t figure out is the file actually gets created in /ring/video folder for a split second and then it disappears. The reason I know this is because I have DropBox monitoring /ring/video folder and I see it trying to make a copy to the cloud when it happens but it actually doesnā€™t grab it because it disappears so quickly.

Where are you putting this .MP4 file once its dropped in the /ring/video folder?

Is there anyway you can leave it there so it can be referenced in the future?

If you can keep the file there; is it possible to add another field to the binding which is just the filename itself? This way I can reference the file name from a virtual web directory so I can play the video remotely from OH.

Keep up the great work!

Best, Jay

Clicking on URL after an hour

Hereā€™s the dump I get when you click on a URL that existed an hour ago. Iā€™m guessing Ring is not allowing the API to look at OLD videoā€™s without their premium service which allows you to go back in time.

I did this a few times and the same dump occurs. May want to catch this exception and log it as Video No Longer Accessible.

2020-02-06 13:32:18.917 [ERROR] [nding.ring.internal.RingVideoServlet] - RingVideo: Unable to process request: null
2020-02-06 13:32:19.205 [ERROR] [hab.binding.ring.internal.RestClient] - Authentication exception in getRecordingURL
org.openhab.binding.ring.internal.errors.AuthenticationException: Invalid request
	at org.openhab.binding.ring.internal.RestClient.getRequest(RestClient.java:222) ~[288:org.openhab.binding.ring:2.5.1.202002051924]
	at org.openhab.binding.ring.internal.RestClient.getRecordingURL(RestClient.java:627) [288:org.openhab.binding.ring:2.5.1.202002051924]
	at org.openhab.binding.ring.internal.RingVideoServlet.service(RingVideoServlet.java:90) [288:org.openhab.binding.ring:2.5.1.202002051924]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [29:javax.servlet-api:3.1.0]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865) [85:org.eclipse.jetty.servlet:9.4.11.v20180605]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535) [85:org.eclipse.jetty.servlet:9.4.11.v20180605]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [186:org.ops4j.pax.web.pax-web-jetty:7.2.3]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) [82:org.eclipse.jetty.security:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1317) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) [186:org.ops4j.pax.web.pax-web-jetty:7.2.3]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) [85:org.eclipse.jetty.servlet:9.4.11.v20180605]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1219) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [186:org.ops4j.pax.web.pax-web-jetty:7.2.3]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.Server.handle(Server.java:531) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260) [84:org.eclipse.jetty.server:9.4.11.v20180605]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281) [75:org.eclipse.jetty.io:9.4.11.v20180605]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) [75:org.eclipse.jetty.io:9.4.11.v20180605]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) [75:org.eclipse.jetty.io:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680) [87:org.eclipse.jetty.util:9.4.11.v20180605]
	at java.lang.Thread.run(Thread.java:748) [?:?]
2020-02-06 13:32:19.207 [ERROR] [nding.ring.internal.RingVideoServlet] - RingVideo: Unable to process request: null

Best, Jay

The binding doesnā€™t put an mp4 file anywhere that iā€™m aware of, perhaps in a temp directory somewhere. All it does is take that long string of numbers (the ā€œding idā€ as they put it) and adds the requisite authentication token, etc which is needed for every request and streams that out to the browser. You are also correct with your follow up post, IIRC if you donā€™t have the premium service, they donā€™t save any videos at all on their end and after that one link expires itā€™s gone forever. It seems the only way to get video working reliably is to also be signed up for their premium service that I have experienced.

As far as responsiveness, iā€™ve found the same that @Confused did (I suspect also because itā€™s a ā€œpartnerā€ situation, they get the luxury of a push interface) and thatā€™s actually the approach I currently use myself because it so much more responsive and it integrates with my Alexas more directly. Ring still has not yet replied to me on getting a ā€œpartner likeā€ situation set up or even any formal documentation, but initially they did say something along the lines of that because this is an open source project getting issued a partner ID (and thus access to partner APIs and documentation) was not possible because that ID would have to be published and so they wouldnā€™t be able to control it.

@zolakk,
I installed the binding and everything appears to be working except for the video. I have the premium service and have not enabled two factor authentication yet. I am not getting the video, when I try to open the URL in a new tab, my log shows:

2020-02-07 06:16:52.386 [ERROR] [nding.ring.internal.RingVideoServlet] - RingVideo: Unable to process request: null
2020-02-07 06:29:23.683 [ERROR] [hab.binding.ring.internal.RestClient] - Authentication exception in getRecordingURL
org.openhab.binding.ring.internal.errors.AuthenticationException: Invalid request
	at org.openhab.binding.ring.internal.RestClient.getRequest(RestClient.java:222) ~[bundleFile:?]
	at org.openhab.binding.ring.internal.RestClient.getRecordingURL(RestClient.java:627) [bundleFile:?]
	at org.openhab.binding.ring.internal.RingVideoServlet.service(RingVideoServlet.java:90) [bundleFile:?]

When I try to wget the video from the URL, I get a file, but it is 0 kb in size. Any help would be appreciated.

~John

EDIT - to add more of the error

Suddeny tonight im getting ā€œOFFLINE - COMMUNICATION_ERROR Initialization failed: nullā€ under the ring account binding?

EDIT never mind - for some reason my server got an IPV6 address and my homeplugs dont like that. :-/

Also i cant get the link to work (cannot click it in the habpanel dummy widget) also when copied from the paperui to a new tab noting is displayed.

i have gotten this to work now but when an event is triggereed the video changes but does not lay until i refresh the habpanel. its like the video is getting pulled to fast, before my ring account has had a chance to create the video?