Run homebridge as a service upon reboot


This post shows how to run homebridge automatically upon reboot using upstart. If you’re using systemd, the default initialization system these days, see Running Homebridge on Bootup (systemd).

Install upstart

sudo apt-get install upstart

Create configuration file /etc/init/homebridge.conf with

start on stopped rc
stop on shutdown

setuid pi

script
    export HOME="/home/pi"
    export NODE_PATH=$HOME/node_modules/
    gpio -g mode 27 out
    gpio -g mode 27 down
    gpio export 27 out
    exec /usr/local/bin/homebridge
end script

start on stopped rc ensures that avahi-daemon has been started by its SysV init script under /etc/init.d before homebridge is started.

Test the job by running it thus

sudo start homebridge

Use the following command to check the output of the job

sudo tail -f /var/log/upstart/homebridge.log

The following command can be used to verify that homebridge job has been started

sudo initctl list | grep homebridge

To stop the above job

sudo stop homebridge

To run job as a service that will run automatically at boot

sudo service homebridge start

To stop the service forever

sudo service homebridge stop

Toggle GPIO on Raspberry Pi using HomeKit


In this post, I take my HomeKit Raspberry Pi integration a step further, by turning on/off a LED using the homebridge-gpio-wpi plugin. With the ability to control the GPIO pins, I should be able to turn on/off much bigger things using solid state relays and such.

Install homebridge-gpio-wpi

The installation should be pretty straightforward. Assuming you are at the command line in the home folder, run

npm install homebridge-gpio-wpi

That should install all node modules under ~/node_modules/.

Configure homebridge by editing ~/.homebridge/config.json. Here’s mine

{
    "bridge": {
        "name": "Homebridge",
        "username": "CC:22:3D:E3:CE:32",
        "port": 51826,
        "pin": "031-45-155"
    },
    
    "description": "This has some fake accessories",

    "accessories": [
        {
            "accessory":      "FakeBulb",
            "name":           "Test lamp",
            "bulb_name":      "Lamp 1"
        },
        {
            "accessory": "GPIO",
            "name": "GPIO2",
            "pin": 27
        }
    ],

    "platforms": []
}

Configure GPIO2 using the gpio utility, and start homebridge

gpio -g mode 27 out
gpio -g mode 27 down
gpio export 27 out
export NODE_PATH=$HOME/node_modules/
homebridge

See also how to run homebridge as a service upon reboot.

Test with HomeKit

If you’ve configured the Homebridge peripheral in an iOS app such as Hesperus, it should now show you a new device called GPIO2, and allow you to switch it on/off.

LED

Hesperus allows you to create a schedule to turn on and off devices.

Schedule

Make things smart with HomeKit and Raspberry Pi


As an avid iOS user I have been keen on using HomeKit. That’s when I read about a new – and currently free – HomeKit app in the iOS App Store called Hesperus. I don’t have a HomeKit compatible thing at home, but a quick internet search revealed that I could run a HomeKit compatible service called homebridge on a Raspberry Pi. This post only goes so far as configuring a fictitious light bulb plugin that can be controlled remotely.

Setup Raspberry Pi Image

I decided to download a headless (console-only) version of Raspbian called RASPBIAN JESSIE LITE. Instructions for setting up an SD card appropriately can be found here. I use Win32 Disk Imager on Windows to write images.

Powering the Raspberry Pi

I didn’t want to use an HDMI display with the Raspberry Pi, and wanted to power it using my laptop. I have used a USB to serial adapter to do that in the past. This time, I went with Adafruit’s USB Serial TTL cable as described in this lesson. That done, I was able to power up and login to the Raspberry Pi using a serial terminal. I tend to use screen on Linux or Mac OS X

screen /dev/ttyUSB0

Configuring Wi-Fi

RASPBIAN JESSIE LITE lacks a full-fledged user interface, making Wi-Fi configuration slightly painful. I am using a Wi-Fi stick and had some issues getting the driver to work. Hopefully, you’ve got a Raspberry Pi 3, or a compatible Wi-Fi stick that does not require too much tinkering. You can also use Ethernet. The following can be used to check whether your network interface can be listed

ifconfig

Look for an interface called wlan0 if using Wi-Fi, or eth0 if using ethernet.

This is how you can create a configuration file for your Wi-Fi access point

wpa_passphrase your_SSID your_passphrase > your_SSID.conf

Copy the contents of your_SSID.conf and paste them into /etc/wpa_supplicant/wpa_supplicant.conf using any text editor. I used vi thus

sudo vi /etc/wpa_supplicant/wpa_supplicant.conf

Having done that, Wi-Fi was up and running. I had internet access, and could access the Raspberry Pi on the local network via ssh.

Installing packages

A few additional Linux packages and configuration steps are required before homebridge may be installed. Packages can be installed thus

sudo apt-get update
sudo apt install nodejs npm git libavahi-compat-libdnssd-dev

Updating Node.js

The version of Node.js installed by apt-get is rather dated, and will not work with homebridge. To update node, use the following commands

sudo npm install -g n
sudo n stable

Install homebridge

homebridge can be installed using npm thus

sudo npm install -g homebridge

Find and install plugins

To do anything interesting with homebridge you’ll require a plugin, and have it configured in ~/.homebridge/config.json. One simple plugin called homebridge-fakebulb can be installed thus

sudo npm install -g homebridge-fakebulb

Its sample configuration file can be used to create the config.json file mentioned above. This is what my config.json looks like

{
    "bridge": {
        "name": "Homebridge",
        "username": "CC:22:3D:E3:CE:32",
        "port": 51826,
        "pin": "031-45-155"
    },

    "description": "This has some fake accessories",

    "accessories": [
        {
            "accessory":      "FakeBulb",
            "name":           "Test lamp",
            "bulb_name":      "Lamp 1"
        }
    ],

    "platforms": []
}

Use with HomeKit

Apple’s HomeKit has been app-less since launch. Siri is the only way you were able to control HomeKit devices. HomeKit has a rich API and it didn’t take long for paid apps to appear in the App Store. Hesperus is a new free app that I opted to use to control homebridge.

Here’s Hesperus with the Homebridge peripheral paired and working, showing the Test lamp device’s status. I can control the Test lamp (turn it on/off) anywhere I have an internet connection because I have an Apple TV (generation 4 – but 3 should also work) at home. Apple TV needs to be signed into the same iCould account as the iOS device paired with the Homebridge peripheral.

IMG_1979

Handle custom CAs in iOS app


This post discusses how to handle custom CAs in a Swift 2 iOS app that uses Alamofire.

Certificates need to be in the DER encoded binary format. If they are in PEM (BASE64) encoded text format, you need to convert them to DER encoded format. This can be achieved with openssl, thus

openssl x509 -inform PEM -in infile.cer -outform DER -out outfile.cer

Then, just drag the certificate files into your Xcode project so that they are embedded as resources.

Next, we need to create a custom Alamofire manager with a custom ServerTrustPolicyManager

        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "example.com": .PinCertificates(
                certificates: ServerTrustPolicy.certificatesInBundle(),
                validateCertificateChain: true,
                validateHost: true
            )
        ]
        
        manager = Manager(
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )

All REST requests should then be created using manager.request instead of Alamofire.request.

In iOS 9, additional transport security exceptions are required to be set in info.plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>example.com</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSIncludesSubdomains</key>
                <true/>
                <!-- Optional: Specify minimum TLS version -->
                <key>NSTemporaryExceptionMinimumTLSVersion</key>
                <string>TLSv1.2</string>
            </dict>
        </dict>
    </dict>
...
</dict>
</plist>

Tackling OAuth 2.0 in iOS 9 with Swift 2


In an earlier post I discussed how to tackle OAuth 2.0 in an Android app. This post discusses how to do that in iOS 9 with Swift 2.

Step 1, in the post referenced above, is performed in a UIWebView. The view containing the UIWebView implements UIWebViewDelegate, intercepts all accessed URLs in webView:shouldStartLoadWithRequest:navigationType: function, and acquires the authorization code using regular expressions.

class ViewController: UIViewController, UIWebViewDelegate {
    @IBOutlet weak var webView: UIWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        webView.delegate = self;
        webView.loadRequest(loginURL) // initialize loginURL
    }

    func webView(webView: UIWebView, shouldStartLoadWithRequest: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        var continueToUrl = true
        do {
            let regex = try NSRegularExpression(pattern: "code=(.+?(?=&|$))", options: NSRegularExpression.Options())
            let url: String? = shouldStartLoadWithRequest.url?.absoluteString;
            let result: NSTextCheckingResult? = regex.firstMatch(in: url!, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, url!.characters.count))
            let codeNSRange = result?.rangeAt(1)
            if (codeNSRange != nil) {
                let startIndex = url?.index((url?.startIndex)!, offsetBy: (codeNSRange?.location)!)
                let endIndex = url?.index((url?.startIndex)!, offsetBy: (codeNSRange?.location)! + (codeNSRange?.length)!)
                let code = url?.substring(with: Range<String.Index>(startIndex!..<endIndex!))
                debugPrint(code)
                acquireAccessToken(code!)
                continueToUrl = false
            }
         } catch {
         }
         return continueToUrl;
     }

I found it challenging to use the interfaces for regular expression matching, and extracting substrings. They are quite different from those found in other popular languages, but should be familiar to Objective C developers. Step 2, to acquire the access token, can be performed thus

    func acquireAccessToken(code: String) {
        manager!.request(tokenURL, method: .post, parameters: ["code": code])
            .validate().responseJSON { response in
                switch response.result {
                case .Success:
                    if let value = response.result.value {
                        let json = JSON(value)
                        self.accessToken = json["access_token"].stringValue
                        debugPrint("Access Token: \(self.accessToken)")
                    }

                case .Failure(let error):
                    debugPrint(error)
                }
        }
    }

The code above utilizes Alamofire for performing REST calls, and SwiftyJSON to handle JSON. Obtain those two frameworks using Carthage. Create a Cartfile with

github "Alamofire/Alamofire" ~> 3.0
github "SwiftyJSON/SwiftyJSON"

Then, invoke carthage to build the frameworks

carthage update

Drag the .framework files under Carthage/Build/ into your Xcode project. The files are added by reference. Adjust project target settings to ensure that the frameworks are embedded, otherwise you’ll get an error such as

dyld: Library not loaded: @rpath/SwiftyJSON.framework/SwiftyJSON
  Referenced from: ...

If you use git for version control, remember to adjust .gitignore to exclude Carthage/ folder.

Common audio format between Android and iOS


If you need a common audio format between Android and iOS, try AAC codec with container format MP4. The file extension used is mp4.

On Android, record using encoding MediaRecorder.AudioEncoder.AAC and container format MediaRecorder.OutputFormat.MPEG_4. That should play all right on iOS 7, or better.

On iOS, record using the following settings

NSDictionary *recordSettings = 
    [NSDictionary
    dictionaryWithObjectsAndKeys:
    [NSNumber numberWithFloat:44100.0],AVSampleRateKey,
    [NSNumber numberWithInt: 2],AVNumberOfChannelsKey,
    [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
    [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
    [NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
    [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
    nil];

The resulting file should play all right on Android 4.3, or better.

Monthly news review


This post reviews news in the month that has passed.

Everything Google announced at Google I/O 2014 in one handy list

Google announced a lot in one long keynote at I/O. Android One, Android Auto, Android Wear, and Android TV, are probably the big announcements this year. Looks like Google is prefixing all mobile-oriented hardware with Android, web-oriented hardware with Chrome, and services with Google. Unless it is something coming out of Nest, who’ve just launched a developer program for the programmable home.

Aereo Lost. What Now?

TV broadcasters are celebrating while the tech industry is up in arms. Are customers the real losers? Why should we need airwaves to transmit TV in the era of mobile internet? Why hasn’t the TV business adopted on-demand programming more actively? It isn’t as if their business isn’t being slowly driven to the ground.

This is Microsoft’s first Android smartphone, the Nokia X2

Nokia could have hedged its bets with Android a long while back. So why now? It is a cheap but attractive Android Smartphone full of Microsoft software and services.

Amazon’s Fire phone launch: Hits, misses, and takeaways

From inexpensive tablets to a fairly expensive phone, Amazon as come a long way. Lack of Bluetooth 4.0 (especially Smart) is annoying. It does seem to sport universal LTE, like the Moto G 4G. Will the Fire Phone truly delight users?

Google Donates Mod_Spdy To The Apache Foundation

HTTP 2.0 is around the corner and changes one crucial aspect of HTTP 1.x. It will no longer be a text-based protocol. An important feature is that data will be multiplexed over a single connection a browser maintains with a server.

Docker hopes its container platform will ease the lives of developers

Will an open container help big companies and other providers overcome the dependency on and momentum of Amazon, Google, and Microsoft?

Turing Test breakthrough as super-computer becomes first to convince us it’s human

Not everybody is convinced though, but the implications are important nevertheless. How do you know an e-mail message wasn’t sent by a real person? Are we at the cusp of having to deal with endless amount of believable spam? Looking at the positive aspects, customer support, distance education, and other areas that depend on personal interaction, may benefit.

Skype Translator Will Change the World

Real-time voice translation is a hard problem. You have to translate speech to text. The text then needs to be translated to the target language. The translated text then needs to be converted to speech. Imagine doing all of that in real time. Imagine doing that wrong in a UN session discussing climate change.

Google’s secretive 3D-mapping project now has a tablet

Google is keen to map the indoors. I see huge potential for indoor mapping. Imagine your interior designer mapping your house so that she can show you exactly how your renovated indoors will look? A robot that can go about your house tidying it? Are we heading towards becoming Wall-E lazy?

Apple announces iOS 8 at WWDC 2014

Easily one of Apple’s best WWDC considering all the news. A new programming language called Swift, Mac OS X Yosemite, Metal, HomeKit, CloudKit, and extensions in iOS 8. For those eager to learn Swift, Apple has provided an iBook for it already. A good news for all Netflix viewers, Safari on Mac OS X Yosemite now allows streaming using HTML5, no Silverlight required.