{"id":1477,"date":"2014-08-14T23:01:38","date_gmt":"2014-08-15T06:01:38","guid":{"rendered":"https:\/\/surfrock66.com\/?p=1477"},"modified":"2019-10-07T10:19:13","modified_gmt":"2019-10-07T17:19:13","slug":"improving-the-motorola-blink-baby-monitorcamera","status":"publish","type":"post","link":"https:\/\/surfrock66.com\/?p=1477","title":{"rendered":"Improving the Motorola Blink Baby Monitor\/Camera"},"content":{"rendered":"<p>\n\nSo we recently purchased the <a href=\"http:\/\/www.bedbathandbeyond.com\/store\/product\/motorola-blink1-wi-fi-camera-in-silver\/1040669670?device=c&amp;network=g&amp;matchtype=&amp;mcid=PS_googlepla_nonbrand_electronicstoys_&amp;gclid=Cj0KEQjwmayfBRDo25CR9un4hvEBEiQAv9fBbfI2qDL9jx0SffW8Hl1DNTYCMUDbv0Lr3guLnGKR3LYaAqGw8P8HAQ\">Motorola Blink1 Wifi Baby Monitor<\/a> (Is this the first blog post acknowledging the baby?  He's due any day!) and it's neat hardware with SHIT software.  Straight up, it doesn't do most things you would want.  I'm working to reverse engineer this and make it workable...particularly on linux.\n\nBefore I start...MAD PROPS to Simon Aldrich, whose article laid the foundation to what I'm trying to do here.  This got me started: <a href=\"http:\/\/simon.aldrich.eu\/blog\/2013\/08\/motorola-blink1-hacking\/\">Hacking the Motorola Blink 1 Baby Monitor (Part 1)<\/a> and <a href=\"http:\/\/simon.aldrich.eu\/blog\/2014\/01\/hacking-the-motorola-blink-1-baby-monitor-part-2\/\">Hacking the Motorola Blink 1 Baby Monitor (Part 2)<\/a>\n\n<!--more-->\n\nSo, here's the goals for this product that we're trying to produce...I'll bold\/underline the ones that DON'T come out of the box:\n<ul>\n<ol>At-home video on a mobile device<\/ol>\n<ol>At-Home video on a PC<\/ol>\n<ol><b><u>At-home continuous audio on a mobile device<\/u><\/b><\/ol>\n<ol><b><u>At-home continuous audio on a PC<\/u><\/b><\/ol>\n<ol><b><u>At-home continuous audio\/video on a mobile device<\/u><\/b><\/ol>\n<ol><b><u>At-home continuous audio\/video on a PC<\/u><\/b><\/ol>\n<ol>At-home notifications of events in the room<\/ol>\n<ol>At-home motion control of the camera<\/ol>\n<ol><b><u>Remote viewing with access control<\/u><\/b><\/ol>\n<ol>Remote video on a mobile device<\/ol>\n<ol><b><u>Remote video on a PC<\/u><\/b><\/ol>\n<ol><b><u>Remote continuous audio on a mobile device<\/u><\/b><\/ol>\n<ol><b><u>Remote continuous audio on a PC<\/u><\/b><\/ol>\n<ol><b><u>Remote continuous audio\/video on a mobile device<\/u><\/b><\/ol>\n<ol><b><u>Remote continuous audio\/video on a PC<\/u><\/b><\/ol>\n<ol>Remote notifications of events in the room<\/ol>\n<ol>Remote motion control of the camera<\/ol>\n<ol><b><u>Remote 2-way communication with the baby on a mobile device<\/u><\/b><\/ol>\n<\/ul>\nI have a web server on my LAN, so I actually demo a lot of my changes on a supplemental web server (so I'm not modifying the actual web server on the device...for now).\n\nNow, if you look at the box...they'll tell you some of these exist.  But they don't.  For example, their web service has a way to view remotely, but it's either full access or no access, and it's to one account.  So if I wanted to let my mom log in and see the baby, she can now take over control of the camera, flash the firmware, etc.  As we'll find later...it has a SECRET web interface built in (LAN Only)...that has ABSOLUTELY NO ACCESS CONTROL FOR BOTH VIEWING AND CONTROLLING.  Badness.  Lastly, the video times out after 5 minutes.  The notifications happen still, which I think is nice, but wife wants constant-audio, which it cannot provide.\n\nSo, based on Simon's work above, the camera actually hosts a tiny little web interface.  It USED to have an index.html...but no longer does.  Maybe this was a security thing, as they intended to discontinue the web interface?  Either way, the URL for that is now blinkhome.html so you can get to it.  In this, there's 2 pages I've found so far, a \"video only\" page (blinkhome.html) and an audio\/video page (java.html).  BTW...a link to the \"video only\" page is still pointing to index.html, which lends credence to the idea that they just changed it and didn't think more about it.\n\nFirst, let's talk the \"video only\" page.  It's not video at all.  It loads a series of static images, 3 at a time, and layers them, then when the last one is finished loading it deletes the front one.  The IMPACT is it looks like a video.  It's all done with Javascript.  Now, it actually indexes the images, and uses the index as the layer.  This means, if you leave it running forever...it's POSSIBLE that the index number and layer go into the BILLIONS range or higher.  For all I know...this could actually eventually lead to a memory error.  The image is actually not an image per-se...it's called from a function in the root of the web server, with the address http:\/\/IP\/?action=snapshot .  Now...as a test, I port forwarded a random port to point to my camera on my router...I get a 501 error, \"Lacking Session Key\" which I'm working on understanding now.\n\nBelow are the code snippets for the brunt of the javascript work to make this go:\n\n<br \/>\n<code>function createImageLayer() {<br \/>\nvar img = new Image();<br \/>\nimg.style.position = \"absolute\";<br \/>\nimg.style.zIndex = -1;<br \/>\nimg.onload = imageOnload;<br \/>\nimg.onclick = imageOnclick;<br \/>\nimg.width = 640;<br \/>\nimg.height = 480;<br \/>\nimg.src = \"\/?action=snapshot&amp;n=\" + (++imageNr);<br \/>\nvar webcam = document.getElementById(\"webcam\");<br \/>\nwebcam.insertBefore(img, webcam.firstChild);<br \/>\n}<br \/>\n\/\/ Two layers are always present (except at the very beginning), to avoid flicker<br \/>\nfunction imageOnload() {<br \/>\nthis.style.zIndex = imageNr; \/\/ Image finished, bring to front!<br \/>\nwhile (1 &lt; finished.length) {<br \/>\nvar del = finished.shift(); \/\/ Delete old image(s) from document<br \/>\ndel.parentNode.removeChild(del);<br \/>\n}<br \/>\nfinished.push(this);<br \/>\ncurrent_time = new Date();<br \/>\ndelta = current_time.getTime() - previous_time.getTime();<br \/>\nfps   = (1000.0 \/ delta).toFixed(3);<br \/>\nprevious_time = current_time;<br \/>\nif (!paused) createImageLayer();<br \/>\n}<\/code><br \/>\n\n\nThis is done so that you're never waiting for a redraw.  You always have an image up, and the one loading is behind it.  You can see that imageNr variable gets out of hand...I'm thinking about implementing something like \"If imageNr gets to 10,000 then set it to 1\" which will set the number over.  It would create a single potential flicker for one frame...if we consider that it seems to run at about 25fps, that's 1 flicker, for 1\/25th of a second, every 7 minutes.  I think that's reasonable to achieve \"always on\" functionality for the monitor.\n\nThis \"video only\" page also has ALL the controls listed, and NO access control.  That's absurd.  I often leave on vacation and leave a camera on for my dog, and then my parents can look in (since they don't travel much).  I wanted to have this feature, but the only ways it seems to provide access are with an account (it's 1 account\/camera pair, so I'd have to give viewers my real login to plug into an app OR the Motorola web interface) or to point them to the totally unprotected URL on the LAN.  Did I mention you can talk to the baby and play music to the baby from the camera?  I don't want strangers doing that! My goal here is to use a supplemental web server to route content, where I can implement access control.\n\nNow, there's the 2nd page.  This is http:\/\/IP\/java.html.  This one actually has an embedded java player which plays streaming audio and video.  Now...I use chrome on linux, and since NPAPI is now depreciated I can't play the applet, but since wife uses windows, I was able to view it there.  Looking at the source, you see the following code block:\n\n<br \/>\n<code>&lt;applet code=\"com.charliemouse.cambozola.Viewer\" archive=\"\/cambozola.jar\" width=\"512px\" height=\"384px\" &gt;<br \/>\n&lt;param name=\"url\" value=\"\/?action=appletvastream\"\/&gt;<br \/>\n&lt;param name=\"watermarks\" value=\"\/favicon.png|left,top\"\/&gt;<br \/>\n&lt;\/applet&gt;<\/code><br \/>\n\n\nCambozola...a little googling, voila.  It's an open source embedded java video player: <a href=\"http:\/\/www.charliemouse.com\/code\/cambozola\/\">website.<\/a>  This tells me, if we can find the stream, maybe we can use an HTML5 player in a website to pass access.  This could be the holy grail.\n\nSo, I took the address for the stream and plugged it into VLC...BOOM video.  Viewing the codec information, it's a Motion JPEG Video (MJPG) that is decoded into Planar 4:2:0 YUV full scale.  In VLC...I get no audio whatsoever.  On a hunch, I plugged the following streams into VLC as well: \/?action=appletvstream and \/?action=appletastream Both resolve!  Now, the audio doesn't produce anything, but it seems there's 3 options for streams.  The audio stream is exactly what the wife is looking for, so this is where we need to focus the research.\n\nWhen I load the java applet on wife's windows computer, I get audio.  When I load the stream in VLC on the same computer, no audio.  Now, the links all resolve in VLC, so I have to assume that the reason it works in the java player is that they have baked some sort of custom codec into the Cambozola player.  I'll need to pull this out.\n\nSo, let's go back to Cambozola.  Technically, it's GPL v2, so the source should be available, right?  HMM NOT FINDING IT OOPS, Stallman is goan be PISSED.  Nevertheless, I have a Java decompiler, so I'm good.  It seems they baked in v0.80.  On cambozola's website, it doesn't link to it directly, but the code is there: <a href=\"http:\/\/www.charliemouse.com:8080\/code\/cambozola\/cambozola-0.80.tar.gz\">http:\/\/www.charliemouse.com:8080\/code\/cambozola\/cambozola-0.80.tar.gz<\/a> If we open up the .jar included with the camera, there's 2 suspicious classes which are not in the stock cambozola jar...ADPCM and ADPCM Decoder.  There's another one called \"PlayAudio\" which I'm interested in.  Since this is all GPLv2...let's dig in:\n\nPlayAudio.Class\n\n<br \/>\n<code>package com.charliemouse.cambozola.shared;<br \/>\nimport javax.sound.sampled.AudioFormat;<br \/>\nimport javax.sound.sampled.AudioSystem;<br \/>\nimport javax.sound.sampled.DataLine;<br \/>\nimport javax.sound.sampled.Line;<br \/>\nimport javax.sound.sampled.LineUnavailableException;<br \/>\nimport javax.sound.sampled.SourceDataLine;<br \/>\npublic class PlayAudio extends Thread<br \/>\n{<br \/>\nprivate AudioFormat m_audfm;<br \/>\nprivate SourceDataLine m_line;<br \/>\nprivate boolean m_bRunAudio;<br \/>\nprivate boolean m_bPlayAudio;<br \/>\nprivate int m_aud_idx;<br \/>\nprivate int m_audRec_idx;<br \/>\nprivate byte[][] m_AudBuf;<br \/>\nprivate int[] m_AudBufLen;<br \/>\nprivate int[] m_AudBufStatus;<br \/>\npublic PlayAudio()<br \/>\n{<br \/>\nthis.m_bRunAudio = true;<br \/>\nthis.m_bPlayAudio = true;<br \/>\nthis.m_aud_idx = 0;<br \/>\nthis.m_AudBuf = new byte[16][16160];<br \/>\nthis.m_AudBufLen = new int[16];<br \/>\nthis.m_AudBufStatus = new int[16];<br \/>\nthis.m_audRec_idx = 0;<br \/>\nthis.m_audfm = new AudioFormat(8000.0F, 16, 1, true, false);<br \/>\ntry<br \/>\n{<br \/>\nthis.m_line = AudioSystem.getSourceDataLine(this.m_audfm);<br \/>\nthis.m_line.open(this.m_audfm, 16160);<br \/>\n}<br \/>\ncatch (LineUnavailableException e)<br \/>\n{<br \/>\n}<br \/>\n}<br \/>\npublic void init()<br \/>\n{<br \/>\n}<br \/>\npublic void setPlayAudio(boolean bPlayAudio)<br \/>\n{<br \/>\nthis.m_bPlayAudio = false;<br \/>\nfor (int i = 0; i &lt; 16; i++)<br \/>\n{<br \/>\nif (this.m_AudBufStatus[i] != 0)<br \/>\n{<br \/>\nUtil.memSet(this.m_AudBuf[i], 1010, (byte)0);<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\npublic void getAudio(byte[] audioData, int audioLen) {<br \/>\nint i = 0;<br \/>\nif (!this.m_bPlayAudio) {<br \/>\nreturn;<br \/>\n}<br \/>\nif (audioLen &gt; 4040)<br \/>\n{<br \/>\nreturn;<br \/>\n}<br \/>\nwhile (i &lt; audioLen)<br \/>\n{<br \/>\nint len;<br \/>\nint len;<br \/>\nif (i + 16160 &lt;= audioLen)<br \/>\nlen = 16160;<br \/>\nelse {<br \/>\nlen = audioLen - i;<br \/>\n}<br \/>\nif (this.m_AudBufStatus[this.m_audRec_idx] == 0)<br \/>\n{<br \/>\nthis.m_AudBufStatus[this.m_audRec_idx] = 1;<br \/>\nSystem.arraycopy(audioData, i, this.m_AudBuf[this.m_audRec_idx], 0, len);<br \/>\nthis.m_AudBufLen[this.m_audRec_idx] = len;<br \/>\nthis.m_AudBufStatus[this.m_audRec_idx] = 2;<br \/>\ni += len;<br \/>\nthis.m_audRec_idx = ((this.m_audRec_idx + 1) % 16);<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\ntry<br \/>\n{<br \/>\nThread.sleep(100L);<br \/>\n} catch (InterruptedException ie) {<br \/>\nbreak;<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\npublic void run()<br \/>\n{<br \/>\nthis.m_line.start();<br \/>\nwhile (true) if (this.m_bRunAudio)<br \/>\n{<br \/>\nif (this.m_bPlayAudio == true)<br \/>\n{<br \/>\nif (this.m_AudBufStatus[this.m_aud_idx] != 2) {<br \/>\ntry<br \/>\n{<br \/>\nThread.sleep(20L);<br \/>\n} catch (InterruptedException ie) {<br \/>\nbreak label176;<br \/>\n}<br \/>\n}<br \/>\nthis.m_AudBufStatus[this.m_aud_idx] = 1;<br \/>\nif (this.m_AudBufLen[this.m_aud_idx] &gt; 0)<br \/>\n{<br \/>\nthis.m_line.write(this.m_AudBuf[this.m_aud_idx], 0, this.m_AudBufLen[this.m_aud_idx]);<br \/>\nthis.m_AudBufLen[this.m_aud_idx] = 0;<br \/>\nthis.m_AudBufStatus[this.m_aud_idx] = 0;<br \/>\nthis.m_aud_idx = ((this.m_aud_idx + 1) % 16); continue;<br \/>\n}<br \/>\nthis.m_AudBufStatus[this.m_aud_idx] = 0;<br \/>\nthis.m_aud_idx = ((this.m_aud_idx + 1) % 16); continue;<br \/>\n}<br \/>\ntry<br \/>\n{<br \/>\nThread.sleep(1000L);<br \/>\n}<br \/>\ncatch (InterruptedException ie)<br \/>\n{<br \/>\n}<br \/>\n}<br \/>\nlabel176: this.m_line.drain();<br \/>\nthis.m_line.flush();<br \/>\nthis.m_line.close();<br \/>\n}<br \/>\n}<br \/>\n<\/code>\n\nNow...I wanted to get some info about the actual web server this is running...so I ran this command:\n\n<br \/>\n<code>surfrock66@sr66-darter:~\/Downloads$ wget --save-headers 192.168.1.68\/blinkhome.html<br \/>\n--2014-08-16 13:43:34--  http:\/\/192.168.1.68\/blinkhome.html<br \/>\nConnecting to 192.168.1.68:80... connected.<br \/>\nHTTP request sent, awaiting response... 200 OK<br \/>\nLength: unspecified<br \/>\nSaving to: \u2018blinkhome.html\u2019<br \/>\n[ &lt;=&gt;                                                                                                                         ] 11,594      --.-K\/s   in 0.03s<br \/>\n2014-08-16 13:43:34 (416 KB\/s) - \u2018blinkhome.html\u2019 saved [11594]<br \/>\nsurfrock66@sr66-darter:~\/Downloads$ cat blinkhome.html<br \/>\nHTTP\/1.0 200 OK<br \/>\nContent-type: text\/html<br \/>\nConnection: close<br \/>\nServer: MJPG-Streamer\/0.2<br \/>\nCache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0<br \/>\nPragma: no-cache<br \/>\nExpires: Mon, 3 Jan 2000 12:34:56 GMT<br \/>\n<\/code>\n\nSo...this is \"MJPG-Streamer\" version 0.2.  Turns out, open source! GPLv3!  <a href=\"https:\/\/code.google.com\/p\/mjpg-streamer\/\">https:\/\/code.google.com\/p\/mjpg-streamer\/<\/a> Now we maybe can get into the API a bit.  Right off the bat, we see a new stream address...http:\/\/IP\/?action=stream which DOES resolve in VLC...but still no sound.  That I can tell, mjpg-streamer comes with no audio support...I imagine the stream calls to appletvastream and appletastream are custom by Motorola.\n\nIn digging through the source, I found this: <a href=\"https:\/\/code.google.com\/p\/mjpg-streamer\/source\/browse\/trunk\/mjpg-streamer-1.6.3\/plugins\/input_uvc\/dynctrl.c\">https:\/\/code.google.com\/p\/mjpg-streamer\/source\/browse\/trunk\/mjpg-streamer-1.6.3\/plugins\/input_uvc\/dynctrl.c<\/a>  If we could get the modified source from Motorola, we could probably identify the specific commands this camera can accept...including the audio in, playing lullabyes, etc.\n\nNow that we've identified the 2 open source components, which have both been heavily modified...I think it's time to chase Motorola down, as they're now legally obliged to provide us the modifications they made to these 2 utilities.  I opened the manual included...no info about the GPL v2 or v3 at all.  I submitted a ticket to Motorola...and pinged the FSF in case Motorola won't cough up the source.\n\nHere's a reference to the pages I've found on the device so far:\n<ul>\n \t<li>http:\/\/IP\/index2.html<\/li>\n \t<li>http:\/\/IP\/blinkhome.html<\/li>\n \t<li>http:\/\/IP\/java.html<\/li>\n \t<li>http:\/\/IP\/javascript.html<\/li>\n \t<li>http:\/\/IP\/routersetup.html<\/li>\n \t<li>http:\/\/IP\/wifisetup.html<\/li>\n \t<li>http:\/\/IP:8080\/fwupgrade.html<\/li>\n \t<li>http:\/\/IP:8080\/cgi-bin\/online_upgrade<\/li>\n \t<li>http:\/\/IP:8080\/cgi-bin\/upload<\/li>\n \t<li>http:\/\/IP:8080\/style.css<\/li>\n \t<li>http:\/\/IP:8080\/fix.css<\/li>\n \t<li>http:\/\/IP:8080\/functions.js<\/li>\n \t<li>http:\/\/IP:8080\/cambozola.jar<\/li>\n<\/ul>\nHere's the list of actions that you can pass to http:\/\/IP\/?action=__\n<ul>\n \t<li>snapshot - Take a picture<\/li>\n \t<li>stream - Stream video only<\/li>\n \t<li>command - Send a command<\/li>\n \t<li>appletvstream - Stream video only<\/li>\n \t<li>appletastream - Stream audio only<\/li>\n \t<li>appletvastream - Stream audio and video<\/li>\n<\/ul>\nHere's the list of Commands that you can pass to http:\/\/IP\/?action=command&amp;command=__ (Many of these were pulled from the source code for mjpg-streamer, and were probably depreciated with Motorola's modifications)\n<ul>\n \t<li>reset_pan_tilt - Reset Camera Position (NO EFFECT, returns -1)<\/li>\n \t<li>value_contract - Unknown<\/li>\n \t<li>value_contrast - Retrieve Contrast Value (NO EFFECT, returns -1)<\/li>\n \t<li>value_brightness - Retrieve Brightness<\/li>\n \t<li>value_temperature - Retrieve Temperature<\/li>\n \t<li>value_resolution - Retrieve Resolution<\/li>\n \t<li>contrast_plus - Increase Contrast<\/li>\n \t<li>contrast_minus - Decrease Contrast<\/li>\n \t<li>brightness_plus - Increase Brightness<\/li>\n \t<li>brightness_minus - Decrease Brightness<\/li>\n \t<li>fb_stop - Stop ongoing up-down tilt command<\/li>\n \t<li>move_backwardx.y - Tilt Up, amount x between -3 and 3, y between 0-9<\/li>\n \t<li>move_forwardx.y - Tilt Down, amount x between -3 and 3, y between 0-9<\/li>\n \t<li>lr_stop - Stop ongoing left-right tilt command<\/li>\n \t<li>move_leftx.y - Tilt Left, amount x between -3 and 3, y between 0-9<\/li>\n \t<li>move_rightx.y - Tilt Right, amount x between -3 and 3, y between 0-9<\/li>\n \t<li>VGA640_480 - Set resolution to 640x480<\/li>\n \t<li>QVGA320_240 - Set resolution to 320x240<\/li>\n \t<li>QQVGA160_120 - Set resolution to 160x120<\/li>\n \t<li>led_on - Turns the LED ON (NO EFFECT, returns -1)<\/li>\n \t<li>led_off - Turns the LED OFF (NO EFFECT, returns -1)<\/li>\n \t<li>led_auto - (NO EFFECT, returns -1)<\/li>\n \t<li>led_blink - Blinks the LED (NO EFFECT, returns -1)<\/li>\n \t<li>reset_factory - Factory Reset the camera<\/li>\n \t<li>pan_plus - Move Right (NO EFFECT, returns -1)<\/li>\n \t<li>pan_minus - Move Left (NO EFFECT, returns -1)<\/li>\n \t<li>pan_set&amp;value=## - Set Pan Position (NO EFFECT, returns -1)<\/li>\n \t<li>tilt_minus - Move Down (NO EFFECT, returns -1)<\/li>\n \t<li>tilt_plus - Move Up (NO EFFECT, returns -1)<\/li>\n \t<li>tilt_set&amp;value=## - Set Tilt Position (NO EFFECT, returns -1)<\/li>\n \t<li>setup_wireless_read - Unknown (NO EFFECT, returns -1)<\/li>\n \t<li>dummy_request - Unknown (NO EFFECT, error page)<\/li>\n \t<li>gain_plus - Increase Gain (NO EFFECT, returns -1)<\/li>\n \t<li>gain_minus - Decrease Gain (NO EFFECT, returns -1)<\/li>\n \t<li>focus_plus - Increase Focus (NO EFFECT, returns -1)<\/li>\n \t<li>focus_minus - Decrease Focus (NO EFFECT, returns -1)<\/li>\n \t<li>focus_set&amp;value=## - Set Focus Value (NO EFFECT, returns -1)<\/li>\n \t<li>saturation_minus - Decrease Saturation (NO EFFECT, returns -1)<\/li>\n \t<li>saturation_plus - Increase Saturation (NO EFFECT, returns -1)<\/li>\n \t<li>reset - Unknown (NO EFFECT, returns -1)<\/li>\n<\/ul>\nI tried futzing with just recreating the interface with the correct buttons...this doesn't work.  You're welcome to peek in <a href=\"http:\/\/hda.surfrock66.com\/babycam\/WANLiveImage.html\">here.<\/a>  So...turns out, it's a CORS thing...the web server on the camera would need to be updated to allow for cross-origin access, read more here: <a href=\"http:\/\/www.html5rocks.com\/en\/tutorials\/cors\/\">http:\/\/www.html5rocks.com\/en\/tutorials\/cors\/<\/a> For sure, we would need to modify the web server to continue on some of the things I'm trying to do.\n\nRelated Posts:\n<ul>\n \t<li><a href=\"https:\/\/surfrock66.com\/improving-the-motorola-blink-baby-monitorcamera-part-2\/\">Improving the Motorola Blink Baby Monitor\/Camera (Part 2)<\/a><\/li>\n \t<li><a href=\"https:\/\/surfrock66.com\/improving-the-motorola-blink-baby-monitorcamera-part-3\/\">Improving the Motorola Blink Baby Monitor\/Camera (Part 3)<\/a><\/li>\n \t<li><a href=\"https:\/\/surfrock66.com\/improving-the-motorola-blink-baby-monitorcamera-part-4\/\">Improving the Motorola Blink Baby Monitor\/Camera (Part 4)<\/a><\/li>\n \t<li><a href=\"https:\/\/surfrock66.com\/improving-the-motorola-blink-baby-monitorcamera-part-5-2\/\">Improving the Motorola Blink Baby Monitor\/Camera (Part 5)<\/a><\/li>\n<\/ul>\n<\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,3],"tags":[],"class_list":["post-1477","post","type-post","status-publish","format-standard","hentry","category-geek","category-projects"],"_links":{"self":[{"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/posts\/1477","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/surfrock66.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1477"}],"version-history":[{"count":38,"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/posts\/1477\/revisions"}],"predecessor-version":[{"id":1654,"href":"https:\/\/surfrock66.com\/index.php?rest_route=\/wp\/v2\/posts\/1477\/revisions\/1654"}],"wp:attachment":[{"href":"https:\/\/surfrock66.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1477"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/surfrock66.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1477"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/surfrock66.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1477"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}