Project Idea: Eric’s Magic Window

This is a project idea that I have to turn a single board computer, LCD monitor, and a few other parts into a Magic Window. I’m hoping to actually work this idea and document it in this space, as I get parts/funding (funding is me saving up my fun money, I’m not looking for crowdsourcing). When it’s complete, I’ll probably share photos/video of the final product, system images, instructions, etc for anyone else looking to build one.

The Concept

Eric’s Magic Window is a framed LCD screen mounted to the wall. It looks sort of like a window. It is controlled by a remote control, and has the following operating modes:

1. The Digital Window – in this mode, it will stream one of several live camera feeds from around the world. In this mode, it will look most like a window. A number of live camera feeds are broadcast on sites such as earthcam.com.

2. The Digital Frame – in this mode, family photos are shown slow slideshow style from a photo collection, either stored locally or in the cloud.

3. The Digital Gallery – same as digital frame mode, except we see landscape photos and paintings instead of family photos.

4. The Wall Calendar – in this mode, you see a month view of Google Calendar.

5. Weather Center – The current weather report. Stretch: figures out current location from IP address.

Parts Needed

1. Single Board Computer (e.g. Imagine Tech Creator CI20, Raspberry Pi B+, Banana Pi M2, or BeagleBone Black)
2. SD or MicroSD for storage, 16+ GB
3. WiFi dongle if board doesn’t have it built it
4. Remote control + receiver of some sort, possibly a mini-keyboard or maybe just a basic remote
5. LCD display w/ HDMI connector in the neighborhood of 13″ – 17″ + HDMI cable
6. Hardware to mount LCD on the wall
7. clever way to attach the board out of site behind the monitor
8. Custom cut wooden frame
9. I need some solution that will save me from having a power cable hang down my wall.

The Plan

My plan is to get enough parts to develop this and to get the proof of concept working. I’ll then tweak it until I’m happy, and only then tackle the mounting, framing, etc.

Resources and Challenges

I’ve been working with Linux for 20 years now, including some systems administration experience. I’ve been a professional software developer for 16 years and currently work as a web developer on a LAMP/js stack. I have the skills needed to make all the software do what it needs to do.

The biggest challenges for me will be on the mounting/building side of the project. Luckily, that comes last, which will give me time to figure it out I hope. If the challenge of this part of the project looks like it’ll be too much, I’ll just put the monitor on top of one of our bookcases and punt on the wall mounting.

Summary

As soon as I have what I need to get started, I’ll start the project and start blogging a developer’s diary here. I’ll take this as an opportunity to provide review information from any computer hardware I use for the project. Follow me on Twitter at @ericwburns if you want to keep tabs on this.

Comments

comments

Powered by Facebook Comments

Why your fonts don’t look right on the Chrome app

chrome

So, fun fact: the Chrome app for Android or iOS tries to help you SOOOO MUCH. In fact, it will hijack the CSS styles of text on your web site and tweak them to be more readable. It tweaks them by as much as 300%. It tweaks only some of the text elements and leave other ones alone. So yeah, HUUUUUUGE form labels next to teeny tiny form elements for example. Ugh.

Chrome calls this “font boosting”. I call this “stress boosting”.

If you’re like me (and I know I am), you find this annoying because it makes your web site look like garbage.

Do you want to tell the Chrome to disable font boosting? Luckily, it’s easy to do so. Just apply this style to some root element of your page like this:

#page_wrapper {
max-height: 999999px;
}

if you have a page wrapper. If not, do this instead:

html * {
max-height: 999999px;
}

The style will cascade down, and Chrome will stop being such a control freak helpy helperton. You’ll have control to style your css as you see fit.

Comments

comments

Powered by Facebook Comments

Facebook Login, My Old Nemesis

An Alternative Login with Facebook Implementation

So every app of sufficient complexity has one feature that always seems to break in odd ways. You tweak it, duct tape it, adjust it, but it just breaks, breaks, breaks. When this happens enough, you tear it down and rebuild the silly thing from scratch. This is what happened with my Facebook login implementation for babynamester.com

Facebook-My-Nemesis

I used to have an implementation based on this: https://developers.facebook.com/docs/facebook-login/getting-started-web/

This default implementation runs on event listeners. For whatever reason, this version of Facebook login proved to be really fragile for me. After many hours trying to shore it up, I spent some quality time with the Facebook API documentation and built the version below instead.

My version works by passing callbacks to the FB.login function to perform an app login on success.

1. Create a Facebook app

Just follow the instructions here under section 1 of this page: https://developers.facebook.com/docs/facebook-login/getting-started-web/

2. Initialize the Facebook SDK on your page

Next, make sure your page initializes with Facebook’s API correctly. There’s no need to nest any of the javascript in a document ready function.

<div id="fb-root"></div>

<script type="text/javascript">
(function(d){
   var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
   if (d.getElementById(id)) {return;}
   js = d.createElement('script'); js.id = id; js.async = true;
   js.src = "//connect.facebook.net/en_US/all.js";
   ref.parentNode.insertBefore(js, ref);
}(document));
  
window.fbAsyncInit = function() {
   FB.init({
      appId      : '123456789123456789', // replace this with your appId
      channelUrl : '//'+window.location.hostname+'/channel.php', // Path to your Channel File
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
   });
}
</script>

3. Write a function to handle success

Let’s skip to the end before circling back. After we have a successful Facebook login, we’ll need to tell our app that we’ve validated a Facebook login for a specific user and create the appropriate session. At this stage we’ll have a Facebook user object to work with, ‘me’. We’ll see how we get that in step 4 below – just go with it for now.

Let’s make sure this object is valid (i.e. has an id). If it is, I hit an endpoint in the app to get a signature for that id. This is to prevent people from spoofing my app’s facebook login form and creating bogus accounts and sessions in the app. Once we get the signature (‘key’) back from the app’s endpoint, we enter the id, the signature, and some basic user information (found on the user object) into the login with facebook form and submit it. The form submits to an action that will validate the id against the signature. If it checks out, it will see if a user exists in the app. If not, we create one. And then either way we create a session.

The code I’m showing you is everything in the view layer. I leave the signature endpoint and login endpoint to your imagination. Those will be specific to your app anyway. This code also does not need to be in a wait for document ready.

<script type="text/javascript">

// this is the function to login to our app once the Facebook login
// is successful and we have a Facebook user object
function login_with_facebook(me) {
   // this is the endpoint in my app that I get a validation signature from
   url = '/facebook/jskey';

   if ('id' in me && me.id) {
      $.post(url, { 
         'id': me.id 
      }, function(response) {
         // use the user object data and jskey signature to post the #fb_form form
         if (me.name) {
            $('#fb_form input.fb_name').val(me.name);
         }
         if (me.id) {
            $('#fb_form input.fb_id').val(me.id);
         }
         if (me.gender) {
            $('fb_form input.fb_gender').val(me.gender);
         }

         var data = jQuery.parseJSON(response);
         $('#fb_form input.fb_key').val(data['key']);
         $('#fb_form').submit();
      });
   }
}
</script>

4. Hook up a login button or link and a logout link

Finally, we create a button or a link with the class ‘login_with_facebook’ somewhere on our page and another link with the ‘fb_logout’ class. To make it functional, we use this code.

<script type="text/javascript">
$(document).ready(function() {
   $('.login_with_facebook').click(function(e){
      e.preventDefault();

      // Get the login status, perform actions accordingly
      FB.getLoginStatus(function(response) {
         if (response.status === 'connected') {
            // user is logged into Facebook and has already authorized your
            // app. request a user object and call our app login function
            // with it
            FB.api('/me', function(me) {
               if ('id' in me) {
                  login_with_facebook(me);
               }
            });
         }
         else if (response.status === 'not_authorized') {
            // user is logged into Facebook, but has not authorized your app.
            // Facebook login, passing in a callback to fetch the user object
            // and perform an app login on success
            FB.login(function(response) {
               if (response.authResponse) {
                  FB.api('/me', function(me){
                     login_with_facebook(me);
                  });
               }
            });
         } else {
            // not logged in to Facebook. We do a Facebook login, passing in
            // a callback that fetches the user object and fires an app login
            // on success. The same actions as the previous case, but I'm
            // keeping them separate to more clearly show the three possible 
            // states you can be in relation to Facebook. You also may want
            // to handle these cases differently.
            FB.login(function(response) {
               if (response.authResponse) {
                  FB.api('/me', function(me){
                     login_with_facebook(me);
                  });
               }
            });
         }
      });
   });

   // who said breaking up is hard to do?
   $('a.fb_logout').click(function(e){
      // preventing default to make sure our logout request fires and
      // then redirects to where the link points
      e.preventDefault();
      FB.logout();
      window.location = $(this).attr('href');
   });
});

</script>

5. Knit it into your web app
The parts that I haven’t shown you are on the backend of my app. You’ll need to figure out what makes sense for your app. Specifically, the parts of my app I’m not showing you are:
1. the /facebook/jskey endpoint that creates a signature for an id. For best security, the signature for a given id should change over time.
2. the endpoint that the form submits to. This endpoint validates the id against the signature. If valid, it checks to see if the user exists yet for that Facebook id in our app. If so, it just creates a session and redirects back to the page. If not, it will also create a new user.

Also, I leave my #fb_form form, login button, and logout link html to your imagination.

We’re not handling failure with much sophistication, just ignoring it. In the places where failure is detected, you could easily add some code to flash the user a helpful message if you desire.

That’s it, I hope you find this useful.

Comments

comments

Powered by Facebook Comments

tagtacular.js

tagtacular.js

tagtacular.js is a jQuery plugin for tag management that I just released as an open source project. My project goals are:

  • very easy to setup with default behavior
  • very flexible customization options
  • minimal requirements and minimal assumptions about your technology stack and architecture

Check it out and let me know what you think:

 

Comments

comments

Powered by Facebook Comments