So here is a video demonstration of my Tappt system.  Tappt is something I have been working on that consists of beer, Arduino, Android (soon Windows Phone 8), and a web server. The entire project is open source aside from the web server so you can hook up your kegerator to my website once this is out of alpha. I will be posting a tutorial as well as a parts list so you too can have your own. Keep your beer secure from your foes and track the stats on your kegerator.

Today I decided to recreate the iOS 7 parallax effect which is shown here.

ku-xlarge

This was fairly easy to do and did not require much time to implement. I had to use a second blurred background image for the icon panel since using the CSS3 blur brought the browser to a crawl on an iPhone. The main issue left in the demo is gimbal lock when you approach 90 degrees on the x-axis. This can probably be remedied by using a quaternion storing the gyroscope’s rotation to find the translation for the background image. I may come back to this project and fix this by using three.js or something similar. For this demo, I simply wanted to see what the new UI would feel like.

If you have a device with a gyroscope and a browser that supports it,
you can view the demo here.

Fork the project on github

This is a project I have been working on a while called Tappt.  Tappt is a frontend for your kegerator which tracks temperature and the beer in your keg.

The hardware is built using an Arduino Uno, a NFC shield, and a WiFi shield. For the app I am using Android but I will port this to iOS and windows phone.  The backend and website were written using ASP.Net MVC 4 and WebApi as well as Angular.js.

The Arduino and Android portions of this prototype can be found on github at https://github.com/jlkalberer/Tappt-Kegerator and https://github.com/jlkalberer/Tappt-Android.

** Update **
Someone has already started work on the library.  You can read about it here.  You can view the library on github (as of this writing) here.

So if you like me wanted to do a project using NFC peer-to-peer (P2P) between Android and Arduino (the P532 chip) there is no doubt that you have spent countless hours searching for libraries or examples which have already implemented this feature.  You may have even built test application for Android (I used this one) and a sketch for your Arduino (I started with this sketch).  I at least saw that the NFC was communicating between the devices so it’s a start.  It took me a few days of searching before I even got to this point.  Now I needed to figure out why I wasn’t actually sending the NDEF message from Android — the breakpoint at createNdefMessage is never reached. Continue reading

So I am writing this post mostly to help people get up to speed who like myself, had never programmed Android before and need to set up their Nexus 7 device.

Through a simple google search you probably end up at the Using Hardware Devices page on the Android site.  The instructions here are pretty straight forward but I wanted to include a few gotchas in my guide. Continue reading

For many of my projects I use MediaElementJS. This is an awesome library for HTML5 video with a fallback to Flash or Silverlight. Anyway, I had a client request to add google analytics for all their videos. I found the following code which adds the events to each player in order to start tracking events.   The code is a great start but I needed a deeper dive than simply the play, pause, and completed counts for each video.  I decided to track which parts of the videos were viewed by bucketing the videos into 30 second chunks.

google analytics mediaelementjs example

*I was tweaking the code while working on it so the last three buckets (8,9,10) should be merged with 4,5,6 but you get the idea.

The code is fairly straight forward but I thought I would post it as it may help someone out who needs to accomplish the same task.

$.extend(mejs.MepDefaults, {
    googleAnalyticsTitle: '',
    googleAnalyticsCategory: 'Videos',
    googleAnalyticsEventPlay: 'Play',
    googleAnalyticsEventPause: 'Pause',
    googleAnalyticsEventEnded: 'Ended',
    googleAnalyticsEventTime: 'Time'
});

var formatTime = function (timeInSeconds) {
    var sec_numb = parseInt(timeInSeconds);
    var hours = Math.floor(sec_numb / 3600);
    var minutes = Math.floor((sec_numb - (hours * 3600)) / 60) + hours * 60;
    var seconds = sec_numb - (hours * 3600) - (minutes * 60);

    if (seconds < 10) { seconds = "0" + seconds; }
    return minutes + ':' + seconds;
};

$.extend(MediaElementPlayer.prototype, {
    buildgoogleanalytics: function (player, controls, layers, media) {
        var timeInterval = 30, counter = 1, time, currentInterval = 0;
        media.addEventListener('play', function () {
            if (typeof _gaq != 'undefined') {
                _gaq.push(['_trackEvent',
					player.options.googleAnalyticsCategory,
					player.options.googleAnalyticsEventPlay,
					(player.options.googleAnalyticsTitle === '') ? player.currentSrc : player.options.googleAnalyticsTitle,
                    parseInt(player.getCurrentTime())
				]);
            }

            time = parseInt(player.getCurrentTime());
            counter = 1;
            while (timeInterval * counter < time) {
                counter += 1;
            }
        }, false);

        media.addEventListener('pause', function () {
            if (typeof _gaq != 'undefined') {
                _gaq.push(['_trackEvent',
					player.options.googleAnalyticsCategory,
					player.options.googleAnalyticsEventPause,
					(player.options.googleAnalyticsTitle === '') ? player.currentSrc : player.options.googleAnalyticsTitle,
                    parseInt(player.getCurrentTime())
				]);
            }
        }, false);

        media.addEventListener('ended', function () {
            if (typeof _gaq != 'undefined') {
                time = parseInt(player.getCurrentTime());
                currentInterval = timeInterval * counter;
                _gaq.push(['_trackEvent',
                        player.options.googleAnalyticsCategory,
                        player.options.googleAnalyticsEventEnded,
                        (player.options.googleAnalyticsTitle === '') ? player.currentSrc : player.options.googleAnalyticsTitle,
                        time
                    ]);
                _gaq.push(['_trackEvent',
                    player.options.googleAnalyticsCategory,
                    formatTime(currentInterval - timeInterval) + " - " + formatTime(time),
                    (player.options.googleAnalyticsTitle === '') ? player.currentSrc : player.options.googleAnalyticsTitle
                ]);
            }
        }, false);

        media.addEventListener('timeupdate', function () {
            if (typeof _gaq != 'undefined') {
                time = parseInt(player.getCurrentTime());
                currentInterval = timeInterval * counter;
                if (time > currentInterval) {
                    counter += 1;
                    _gaq.push(['_trackEvent',
                        player.options.googleAnalyticsCategory,
                        formatTime(currentInterval - timeInterval) + " - " + formatTime(currentInterval),
                        (player.options.googleAnalyticsTitle === '') ? player.currentSrc : player.options.googleAnalyticsTitle
                    ]);
                }
            }
        }, true);
    }
});

Just a quick diversion between company projects at work.  This is our company holiday card.  I used ImpactJS to write it — the library had some compatibility issues here and there with various mobile devices but overall it is a good framework.

P.S.  I am back in the land of Appcelerator for the time being so I should have a large update to the Mvc framework at some point.

So as promised, I am diving deeper into my Appcelerator Mvc framework. In this post I will give more complex examples on how to use my framework in conjunction with joli so you can truely see how to integrate my framework in a complex, data-driven application. If you haven’t read over the basics or how the routing module works, I recommend you do so. You may also want to read my post on jsAutomapper. Continue reading