1. Beer Alchemy Integration

    As I mentioned in my previous post, my beer recipes are now online.

    I've had several people ask me how this is done, so I think a post is in order.

    While it's entirely possible to brew beer at home without any fancy gadgets, there are several tools I use (such as my refractometer) that make the process easier, more controlled, or both. Brewing software is one of the few instruments that I'm not sure I'd want to brew without. I use a Mac, primarily, so Beer Alchemy (BA) is the obvious choice for recipe formulation, calculation, and logging.

    BA has its own HTML export mechanism for recipes, and I used this for quite a long time, but I was never really satisfied with the results. The markup was hard to style, contained a lot of clutter (occasionally useful, but often redundant information such as style parameters), and simply didn't fit well with the rest of my site.

    Beer Alchemy HTML Output

    You can also export from BA in PDF (not suitable for web publishing), ProMash's binary recipe format (a pain to convert, although there do seem to be some tools to help with this), BeerXML (normally the most accessible, but in my opinion, a poorly-designed XML format), or in BA's native .bar ("Beer Alchemy Recipe") format, which is what I chose.

    Beer Alchemy Recipe Export Dialog

    The bar format contains a property list, similar to those found throughout Apple systems. Property lists are either binary or XML (but the XML is very difficult to work with using traditional tools because of the way it employs element peering instead of a hierarchy to manage relationships). Luckily, I found a project called CFPropertyList that allows for easy plist handling in PHP. (I even contributed a minor change to this project, a while ago.)

    Once you've run the .bar file's contents through CFPropertyList, layout is very simple. Here's most of the code I use to generate my recipes:

    <?php
    $beerPath = __DIR__ . '/../resources/beer/';
     
    $recipes = apc_fetch('seancoates_recipes');
    $fromCache = true;
    if ($recipes === false) {
    	$fromCache = false;
    	foreach (new DirectoryIterator($beerPath) as $f) {
    		if ($f->isDot()) {
    			continue;
    		}
    		if (substr($f->getFilename(), -4) != '.bar') {
    			continue;
    		}
    		$cfpl = new CFPropertyList($beerPath . '/' . $f->getFilename());
    		$recipe = $cfpl->toArray();
    		$title = $recipe['RecipeTitle'];
    		$recipes[self::slugify($title)] = array(
    			'title' => $title,
    			'content' => $recipe,
    		);
    	}
    	asort($recipes);
    	if ($recipes) {
    		apc_store('seancoates_recipes', $recipes, 3600); // 1h
    	}
    }

    In addition to displaying the recipe's data, I also wanted to show the approximate (calculated) beer colour. Normally, beer recipes declare their colour in "SRM" (Standard Reference Method). There's no obvious, simple, and direct way to get from SRM (which is a number from 0 to 40—and higher, but above the mid 30s is basically "black") to an HTML colour.

    I found a few tables online, but I wasn't terribly happy with any of them, and keeping a dictionary for lookups was big and ugly. I like the way Beer Alchemy previews its colours, and since it has HTML output, I emailed the author to see if he'd be willing to share his algorithm. Steve from Kent Place Software graciously sent me an excerpt from his Objective C code, and I translated it to PHP. This might be useful for someone, and since Steve also granted me permission to publish my version of the algorithm, here it is:

    <?php
    /**
     * Calculate HTML colour from SRM
     * Thanks to Steve from Kent Place Software (Beer Alchemy)
     *
     * @param float $srm the SRM value to turn into HTML
     * @return string HTML colour (without leading #)
     */
    public function srm2html($srm)
    {
    	if ($srm <= 0.1) { // It's water
    		$r = 197;
    		$g = 232;
    		$b = 248;
    	} elseif ($srm <= 2) {
    		$r = 250;
    		$g = 250;
    		$b = 60;
    	} elseif ($srm <= 12) {
    		$r = (250 - (6 * ($srm - 2)));
    		$g = (250 - (13.5 * ($srm - 2)));
    		$b = (60 - (0.3 * ($srm - 2)));
    	} elseif ($srm <= 22) {
    		$r = (192 - (12 * ($srm - 12)));
    		$g = (114 - (7.5 * ($srm - 12)));
    		$b = (57 - (1.8 * ($srm - 12)));
    	} else { // $srm > 22
    		$r = (70 - (5.6 * ($srm - 22)));
    		$g = (40 - (3.1 * ($srm - 22)));
    		$b = (40 - (3.2 * ($srm - 22)));
    	}
    	$r = max($r, 0);
    	$g = max($g, 0);
    	$b = max($b, 0);
    	return sprintf("%02X%02X%02X", $r, $g, $b);
    }

    Here it is, in action, in JavaScript this time:

    SRM: =
     

    3 Responses

    Feed for this Entry
    • Hi Sean,

      I've just started using BeerAlchemy on my Mac and I like it. It syncs well with my smartphone for instant portability. But, it doesn't like importing the xml files for recipes (it's 0 for 20-not a large sample size but it will take some time to build its batting average to .200)

      Is there a good utility for Mac that will convert xml recipes to BeerAlchemy's bar format?

      I'm not good with code and I'm barely rudimentary on html. So, for me, it's simply faster to type in the recipe.

    • Norm: I'm not sure. I've always just imported recipes with BeerAlchemy's normal functions (dragging into BA, double-clicking a .bar file). BA's author has been helpful to me in the past, and I bet he'd be willing to answer any questions you have.

      S

    • Genius! My site is wordpress blog and I'm no genius when it comes to PHP but off the top of my head I could probably create a template page and have an options box that calls up individual recipes so you could create a post for each recipe, select the template and then define the path to the recipe you're after.

      I'll let you know how I go!