Clover, Handoff and Continuity in Yosemite

01 April, 2015

In the Hackintosh realm, there are two prominent and extensively covered methods for installing OS X:
Clover and Chameleon At a very high level, both methods are created with the intent of installing OS X on PCs while using a combination of kext patches in case of Clover and/or kext injection in case of Chameleon.

Assuming that you have done your research on the most compatible hardware, you will still be hard-pressed to get everything working out of the box. With the constantly changing landscape of Hackintosh development, you will always need to stay on top of the different ways to get your components working.

This post focuses on a couple of new features introduced in OS X Yosemite called Handoff, Continuity and Facetime calling. Handoff allows you to transfer the state of activity in certain applications from your iPhone or iPad to your Mac and vice versa. Continuity refers to the ability of forwarding phone calls to your Mac or Macbook. You can also make calls from your Mac/Macbook using your iPhone connection. This way, if your phone is in another room, you can still take the call or even make a call.

Needless to say, unless you are using a first-party, Apple-certified WiFi/Bluetooth card, you have to configure Clover to make your card appear first-party. This post focuses on the Azurewave CE123H mini PCIe WiFi/Bluetooth combo card.

In spite of the fact that I document the steps for a specific card, the concept applies to all supported1 cards. There is an excellent thread located here that covers a complete list of cards that will support Handoff and Continuity.

Before you venture any further in the process of applying kext patches in Clover, it is very important to make sure that your network interfaces are configured correctly so that en0 refers to the first built-in network interface. This is vital to get many OS X services such as Mac App Store, iTunes and Messages among others.

Past this, you need the following kexts in your EFI Partition > CLOVER > kexts > 10.10:

  1. BcrmPatchRAM.kext
  2. BTFirmwareUploader.kext
  3. FakePCIID_BCM943552Z_as_BCM94360CS2.kext
  4. FakePCIID.kext

You need these kexts to firstly, enable uploading of custom firmware, and present your card to OS X as a first-party card. Once you have these in place, you need to correct the locale in order to enable all WiFi frequencies.
To achieve that, open Clover Configurator, mount your EFI partition and import your config.plist file.

Then, in the Kernel and Kext Patches section add an entry:
For the US/FCC fix, apply the following to AirPortBcrm4360
+ Find: 41 83 FC FF 74 2C 48
+ Replace: 66 C7 06 55 53 EB 2B

For the Handoff/Continuity, apply this patch to IOBluetoothFamily:
+ Find: 48 85 C0 74 5C 0F B7 48
+ Replace: 41 BE 0F 00 00 00 EB 59

Save the config.plist file and then rebuild your kext cache using Kext Wizard
Reboot, and then log out of your iCloud account on your Hackintosh as well as your iPhone or iPad and log back in.

You should have Handoff and Continuity enabled.


  1. There is a specific set of cards that work with this approach. Research your selection before you purchase. 

My FreeNAS box is down. Currently investigating. Could be hardware failure. Lost about 2TB of data.

Fruitr got DDoSed pretty badly. It will be down till I rewrite it in Python and re-deploy.

Messages, Clover and Yosemite 10.10.2

22 February, 2015

I built myself a mini-ITX Hackintosh for design and coding, as well as a little audio production.

This particular combination of hardware components can be quite functional and productive once you get everything working. You may find this information on other sites.1 I researched the forums on the said sites and collated information that might serve as a reference for others, with a similar configuration or help someone make a decision.

I am currently running Yosemite 10.10.2 with UEFI Clover.
Messages is working along with Handoff, Continuity, Instant hotspot and the ability to connect to my 5Ghz WiFi network.


Hackintosh with a Focusrite Scarlett 2i2 audio interface

Specifications
Motherboard Gigabyte GA-H97-WiFi
Processor Intel Core i3 4350 3.6Ghz
Case Cooler Master HAF 915R
Graphics nVidia GTX 760 2GB
WiFi/Bluetooth Azurewave CE123H (based on Broadcom BCM4352 reference chipset)

I had to order the Azurewave CE123H card separately, because the included Intel WiFi/Bluetooth combo card does not work with OS X. This card is confirmed to support the Bluetooth 4.0 LE (Low Energy) standard that is used by Handoff and Airdrop features.

Using Clover, installing OS X Yosemite is relatively painless, if you do your research2.

Once you install Yosemite, you will notice that you cannot log into Messages using your iCloud account. Either that or you will encounter an activation error. Additionally, Bluetooth won't be functional, and you won't be able to see your 5GHz WiFi network. Some additional steps are required to get that functional.

I had the following kexts in my EFI > Clover > kexts > 10.10 to get Bluetooth and 5Ghz working. Apparently, these kexts enable the uploading of custom firmware and fake a PCI ID for OS X, so that it thinks that you are using a first-party card.

BrcmPatchRAM.kext, BTFirmwareUploader.kext, FakePCIID_BCM94352Z_as_BCM94360CS2.kext and FakePCIID.kext

  1. In preparation, you must first ensure that your Ethernet card is recognized as en0 in System Profiler. The true reason behind this is to follow the BSD convention. OS X services such as Mac App Store, iTunes Store and Messages as well as iCloud all require that en0 refer to the first, built-in network interface.

  2. Secondly, you need valid MLB and ROM values. These are invariably essential to getting Messages to work. MLB stands for Main Logic Board; and all Mac computers - laptops and desktops have a MLB, which is uniquely identified using a number. This MLB along with a valid ROM value is used for authentication by Messages. ROM here, refers to, or rather used to refer to the Mac's Firewire MAC address. You can use your network interface's MAC address, by going to System Preferences > Network > [Interface: WiFi or Ethernet] > Advanced

  3. Then, open Clover Configurator and mount your EFI partition. Import your config.plist file.

  4. In the SMBIOS section, click the magic wand and generate a SMBIOS that is closest to the configuration of your hackintosh. For example, my hackintosh has a Haswell Core i3, so I went with a iMac13,2. Make sure that you "shake" the values for the week of manufacture and the unit number fields. This will generate a random serial number, which you should check against Apple's database here. The serial number must be invalid, which indicates that it is unique.

  5. Past that, you must take care of the Board-ID, Board Serial Number, Serial Number and SmUUID

  6. In the Rt Variables section, paste the MAC address (without colons) that you obtained in step 2, into the ROM field. In the MLB field, enter the serial number you generated in step 4, and append 5 random hexadecimal letters, so your entire serial number is seventeen digits.

  7. Run the command uudigen in Terminal and paste that value in SMBIOS > SmUUID

  8. Board Serial Number should be the same as MLB

  9. With this, you should enter the appropriate kext patches in Clover's Kext and Kernel Patches to enable the correct locale for WiFi and enable 5Ghz support. I will recommend that you peruse the excellent and comprehensive guide for finding the correct patch for your wireless card here

  10. Run nvram -p in your Terminal and make a note of the values. These should remain persistent even after your restart. This essentially means that the MLB and ROM values, which are used to authenticate Messages will persist ensuring that Messages will be functional across multiple reboots.

  11. Save your config.plist and reboot.

XBMC/Kodi, you are awesome, but good god your skins need some work.

Playing voice memos in the background

02 December, 2014

I recently discovered a way to play voice memos in the background on my iPhone. Why they don't display this behavior by default is baffling to say the least.

There are several published hacks to do this, and most of them involve sharing the memo with yourself via Messages.

My method is somewhat similar to this one1 and involves the least amount of intrusion.

  1. Open Voice memos and play the memo.
  2. Lock the screen.
  3. Wake the phone using the power button.
  4. Slide up to go into the Camera app.
  5. Press the home button to return to home screen and you will notice that the memo is playing in the background.

If you have your own method that works for you, but involves more steps, you can add this one to your list. I tested this on iOS 8.1.1 (12B435)

I will just assume that Willem Dafoe is the lead singer for Powderfinger. That is my happy place.

mongoose, Mongo and JSON

23 October, 2014

I am working on a reporting app that is built on the Quickbooks Online API. It pulls in reporting information that needs to be saved to a local database. I am using Mongo as the data store and using the mongoose ODM with node.js

That said, I have a schema already defined like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = mongoose.model('vbDetail', {

    company_name: String,
    rowsdata: {vals:
                {
                    date: Date,
                    transaction_type: String,
                    transaction_num: String,
                    due_date: Date,
                    amount: Number,
                    open_balance: Number,
                    balance: Number
                }
            },

    meta_rows: [{
        identifier: String,
        processing_date: Date,
        processing_amount :Date,
        notes: String
    }]
})

Saving the JSON to this is straightforward. It does look tricky to loop over certain nested objects1. But it is a matter of just getting the loops right.

The JSON response itself looks like this (truncated):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{ Header: 
           { ColData: 
              [ { value: 'GunnChamberlain PL' },
                { value: '' },
                { value: '' },
                { value: '' },
                { value: '' },
                { value: '' },
                { value: '' } ] },
          Rows: 
           { Row: 
              [ { ColData: 
                   [ { value: '03/10/2014' },
                     { value: 'Bill' },
                     { value: '2341' },
                     { value: '03/10/2014' },
                     { value: '500.0' },
                     { value: '500.0' },
                     { value: '500.0' } ],
                  type: 'Data' },
                { ColData: 
                   [ { value: '04/30/2014' },
                     { value: 'Bill' },
                     { value: '4663' },
                     { value: '04/30/2014' },
                     { value: '450.0' },
                     { value: '450.0' },
                     { value: '950.0' } ],
                  type: 'Data' },
                { ColData: 
                   [ { value: '05/31/2014' },
                     { value: 'Bill' },
                     { value: '4878' },
                     { value: '05/31/2014' },
                     { value: '875.0' },
                     { value: '875.0' },
                     { value: '1825.0' } ],
                  type: 'Data' },
                { ColData: 
                   [ { value: '06/30/2014' },
                     { value: 'Bill' },
                     { value: '5115' },
                     { value: '06/30/2014' },
                     { value: '680.0' },
                     { value: '680.0' },
                     { value: '2505.0' } ],
                  type: 'Data' } ] },
          Summary: 
           { ColData: 
              [ { value: 'Total for GunnChamberlain PL' },
                { value: '' },
                { value: '' },
                { value: '' },
                { value: '2505.0' },
                { value: '2505.0' },
                { value: '' } ] },
          type: 'Section' }

The concept is to loop over the Rows object that corresponds to individual companies. Then, for each nested Row objects loop over the ColData object and save the values to the database.

Here's what the code for it looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   //test
  for (var row in report["Rows"]["Row"]) {
      while (count < companies) {
          // save the rows corresponding to each client
          for (var rowdata in report.Rows.Row[count].Rows.Row) {
              for (var coldata in report.Rows.Row[count].Rows.Row[rowdata]
                  // save company name
                  var vbd = new vbDetail({
                      company_name: report.Rows.Row[count].Header.ColDat
                  });

                  // save the row data per company
                  vbd.rowsdata = ({
                      vals: {
                          date: report.Rows.Row[count].Rows.Row[rowdata].ColData[0].value,
                          transaction_type: report.Rows.Row[count].Rows.Row[rowdata].ColData[1].value,
                          transaction_num: report.Rows.Row[count].Rows.Row[rowdata].ColData[2].value,
                          due_date: report.Rows.Row[count].Rows.Row[rowdata].ColData[3].value,
                          amount: report.Rows.Row[count].Rows.Row[rowdata].ColData[4].value,
                          open_balance: report.Rows.Row[count].Rows.Row[rowdata].ColData[5].value,
                          balance: report.Rows.Row[count].Rows.Row[rowdata].ColDat
                      }
                  }) console.log(vbd);

                  // Save the record to DB
                  vbd.save(function(err) {
                      if (err) console.log(err);
                  })
                }
              count++;
            }
      }
}

First run with node.js and Express

07 October, 2014

I began a project using node.js just to get a feel of it. I am writing this post so that it serves as a development log and reference for myself. It could also help you if you work with Quickbooks and node.js.

The objective is to create an interface for viewing reports from Quickbooks.

The code lives here: Finance App
The premise is simple enough for me to start using a framework and there is already an API wrapper for me to experiment with.1 Based on the requirements of the project, I broke down it's implementation into the following parts:

Part I
1. Connect to the API
2. Retrieve the report data
3. Display it

Part II
1. Add custom fields to the report
2. Save the customized report to a local database
3. Sync the custom report data with the online report

Part III
1. Add the ability to add/remove date ranges for forecast reports
2. Add custom filters to get specific views of the reports
3. Writing the report data back to Quickbooks

I am currently focussing on Part I, as it is sufficiently involved. I started off with all the code in one file, following this guide2 step-by-step. This guide helped me organize my project files better. The project is still nowhere near organized as it should be, but it gave me a place to start.

I am using Jade as my template engine and Express framework for Node.js

Getting connected to the API was easy. You need a developer account with Intuit Partner Platform3. Then you are asked to create an app and enter the URLs for the landing page, callback and authentication. Quickbooks Online uses OAuth for authentication. Upon providing a consumerKey and a consumerSecret, the API will give you an accessToken and accessTokenSecret that you will have to store locally so it is available to the app session-wide.

Once connection is established, I instantiate a QuickBooks object like so:

1
2
3
4
5
6
qbo = new QuickBooks(creds.consumerKey,
                         creds.consumerSecret,
                         accessToken.oauth_token,
                         accessToken.oauth_token_secret,
                         postBody.oauth.realmId,
                         true); 

Now, I have access to the various API endpoints to send/receive data.
I make calls to the API by writing routes that correspond to specific reports that I want the data for.

Here's an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.get('/vendorbalancedetail', express.bodyParser(), function(req, res) {
    qbo.reportVendorBalanceDetail({
        date_macro: 'This Month-to-date',
        appaid: 'Unpaid'
    }, function(_, report) {

        //console.log(report)
        res.render('vendorbalancedetail.jade', {
            title: "Report Detail",
            reportname: report["Header"]['ReportName'],
            daterange: "From:" + report["Header"]["StartPeriod"] + " to: " + report["Header"]["EndPeriod"],
            alldata: report,
            columns: report["Columns"],
            rowsperclient: report["Rows"]
        });
    })
})

Let's break it down.

1
2
3
4
5
6
app.get('/vendorbalancedetail', express.bodyParser(), function(req, res) {
            qbo.reportVendorBalanceDetail({
                        date_macro: 'This Month-to-date',
                        appaid: 'Unpaid'
                    }, function(_, report)

I initiate a GET request invoked as a method on the app variable which is a reference to an instance of the express server. I want this request to be made if the user navigates to the /vendorbalancedetail location of the app.

1
2
3
4
5
qbo.reportVendorBalanceDetail({
            date_macro: 'This Month-to-date',
            appaid: 'Unpaid'
        }, function(_, report))

This is an API call that requests the VendorBalanceDetail report for this month to date. It also returns only those transactions that have been marked as 'unpaid.' The call also makes the report object available so I can pass JSON to the view.

That is done like so:

1
2
3
4
5
6
7
8
res.render('vendorbalancedetail.jade', {
    title: "Report Detail",
    reportname: report["Header"]['ReportName'],
    daterange: "From:" + report["Header"]["StartPeriod"] + " to:     " + report["Header"]["EndPeriod"],
    alldata: report,
    columns: report["Columns"],
    rowsperclient: report["Rows"]
});

This is self-explanatory. I render the response from the API call to a view called vendorbalancedetail.jade and make all the variables available inside it.

The tricky part is working with the JSON returned by the API and displaying it in a row/column format. I have used tables for my approach. If you think of a better solution, do let me know. The code for the view would be too much for this post. You can check it out on the Github page.

More to come.

Fruitr is on Rails 4

22 September, 2014

I have a side project that I am very passionate about.
It lives at fruitr.rishighan.com

It was originally developed on an older version of Rails. Since I revamped this site on Rails 4, I felt I should do the same for the project that deserves to be shown to the world.

It was relatively easy to upgrade it to Rails 4. Aside from the usual broken gem dependencies, there was nothing strange or extraordinary stopping the upgrade. I did have the Echonest API impose a rate limit on me; and the none of my API requests returned any response. This baffled me for a whole 15 minutes till I figured out that there is an option for developers to 'upgrade' their account. It is free, provided you tell them what your app does and they will remove that ridiculous rate limit.

As soon as I told Echonest that my app is not doing anything to threaten their existence, they upgraded my rate-limit and the app started working. I thought of writing a quick how-to on deploying the rails app using Capistrano.

I use the excellent hosting service provided by Linode. It runs an instance of Ubuntu 14.04. Now, on to the good stuff. Bear in mind, this assumes that you have already set up your server environment with rvm, passenger and the appropriate directives in nginx.conf

1
2
3
4
gem 'capistrano'
gem 'capistrano-recipes'
gem 'capistrano-rvm'
gem 'capistrano-bundler' 

Then install your capistrano files.

1
cap install

This generates the following:

1
2
3
4
5
6
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
Capified

Past this, ssh into the server and create the app directory. In this case, mkdir fruitr and set the appropriate ownership and permissions chown -R rishi:rishi fruitr and chmod -R 755 fruitr

Once this is done, modify your Capfile, production.rb and deploy.rb
In your Capfile, set the required gems. I needed

1
2
3
require 'capistrano/rvm'
require 'capistrano/deploy'
require 'capistrano/bundler'

My production.rb defines the hostname and the roles.

1
2
3
4
5
set :stage, :production
server 'rishighan.com', user: 'rishi', roles: %w{web app}

#RVM stuff
set :rvm_type, :user

Finally, my deploy.rb looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# config valid only for Capistrano 3.1
lock '3.2.1'

set :application, 'fruitr'
set :repo_url, 'git@github.com:rishighan/fruitr.git'

# Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

# Default deploy_to directory is /var/www/my_app
set :deploy_to, '/home/rishi/fruitr'

# Default value for :scm is :git
set :scm, :git

This configuration is specific for my project. However, you can use this if you have Linode as your host and are using git as your SCM.