Dundee Stool Chart

Image

An alternative to the ‪‎Bristol Stool Chart‬?

An alternative to the ‎Bristol Stool Chart‬?

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/10/07/304/
RSS
Follow by Email
SHARE

Celebratory Cascade

Image

Celebratory Cascade

Picture taken by me at the official opening of the University of Dundee Discovery Centre for Translational and Interdisciplinary Research.

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/10/07/celebratory-cascade/
RSS
Follow by Email
SHARE

QtWebKit and Favicons

I’m currently working on developing a stripped down tabbed browser for a project and therefore wanted to get the favicon for the page that is being displayed in each tab. However, there seems to be a bug with Qt4/WebKit when it comes to using the QWebSettings.iconForUrl() method in that it doesn’t seem to (consistently at least) return anything… so I wrote my own solution as follows:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebKit import *
from PyQt5.QtNetwork import *
 
from html.parser import HTMLParser
 
class QtFavicon(QObject):
    NAIVE = 0
    PAGE  = 1
    ICON  = 2
 
    class _Threaded(QObject):
        finished=pyqtSignal()
 
        def __init__(self, url, parent=None, **kwargs):
            QObject.__init__(self, parent, **kwargs)
 
            self._nam=None
            self._url=QUrl(url)
            self.data=QByteArray()
 
        def request(self, url, reason=0):
            self._reason=reason
            request=QNetworkRequest(url)
            request.setRawHeader("User-Agent", "PyQt4.QtNetwork.QNetworkAccessManager")
            request.setRawHeader("Connection", "close")
 
            if not self._nam: self._nam=QNetworkAccessManager()
            self._reply=self._nam.get(request)
            self._reply.finished.connect(self._finished)
 
        @pyqtSlot()
        def start(self): self.request(self._url.resolved(QUrl("favicon.ico")))
 
        @pyqtSlot()
        def _finished(self):
            try:
                if self._reply.error()==QNetworkReply.NoError:
                    if self._reason in (QtFavicon.NAIVE, QtFavicon.ICON) and \
                            self._reply.bytesAvailable()>0:
                        self.data=self._reply.readAll()
 
                    elif self._reason in (QtFavicon.PAGE,) and self._reply.bytesAvailable()>0:
                        page=self._reply.readAll()
                        p=QtFavicon._Parser()
                        p.feed(page.data())
                        self.request(QUrl(p.faviconHref), QtFavicon.ICON)
                        return
 
                elif self._reply.error()==QNetworkReply.ContentNotFoundError:
                    if self._reason in (QtFavicon.NAIVE,):
                        return self.request(self._url, QtFavicon.PAGE)
            except: pass
            self.finished.emit()
 
    class _Parser(HTMLParser):
        def __init__(self, *args, **kwargs):
            HTMLParser.__init__(self, *args, **kwargs)
 
            self.faviconHref=None
 
        def handle_starttag(self, tag, attrs):
            attrs=dict(attrs)
            if tag.lower()!="link" or \
                    'rel' not in attrs or \
                    attrs['rel'] not in ("icon", "shortcut icon"): return
            self.faviconHref=attrs['href']
 
    @staticmethod
    def iconForUrl(url, timeout=10000):
        thread=QThread()
        threaded=QtFavicon._Threaded(url, finished=thread.quit)
        thread.started.connect(threaded.start)
        threaded.moveToThread(thread)
 
        _timeout=QTime.currentTime().addMSecs(timeout)
        thread.start()
        while not thread.isFinished():
            qApp.processEvents()
            if QTime.currentTime()<_timeout: continue
            thread.terminate()
            thread.wait(timeout)
            break
             
        p=QPixmap()
        data=threaded.data
        if data.length()>0: p.loadFromData(threaded.data)
        return QIcon(p)
 
if __name__=="__main__":
    from sys import argv, exit
 
    class Widget(QWidget):
        def __init__(self, parent=None, **kwargs):
            QWidget.__init__(self, parent, **kwargs)
 
            l=QVBoxLayout(self)
            self._href=QLineEdit(self)
            l.addWidget(self._href)
            l.addWidget(QPushButton("Get Favicon", self, clicked=self.iconForUrl))
 
        @pyqtSlot()
        def iconForUrl(self):
            href=self._href.text()
            self.setWindowTitle(href)
            self.setWindowIcon(QtFavicon.iconForUrl(href))
 
    a=QApplication(argv)
    w=Widget()
    w.show()
    w.raise_()
    exit(a.exec_())

I hope somebody else finds this useful.

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/10/07/qtwebkit-and-favicons/
RSS
Follow by Email
SHARE

Mapping a Network Drive with Python

Recently I found it necessary for an application I’m creating to automatically map a network drive when the program starts if the operating system (Windows 7) has not all ready done so. This may seem like a relatively simple think to want to do, particularly when you consider how simple it is for the user to do it manually from an Explorer window, however a little Googling reveals that is actually quite a task and almost impossible from Python without the use of a 3rd party library, e.g. pywin32. As I would like my application to be lightweight, portable and easily built with py2exe I am therefore trying to keep the dependency count low so I thought I would instead go about implementing my own method with a single simple DLL written in C++ (my second favourite language) which would take advantage of the Windows API directly.

So, step one was to fire up Visual C++ 2008 Express and start a new DLL solution imaginatively called ‘MapDrive’. This is done by selecting ‘File > New > Project…’ and selecting ‘Win32 Console Application’ from the ‘Templates’ section of the resulting dialog. Pressing the ‘Ok’ button in this dialog results in a new one titled ‘Win32 Application Wizard’, the second page of which allows you to set the ‘Application Type’ to ‘DLL’. I also checked the ‘Precompiled header’ option under the ‘Additional options’ section. Clicking the ‘Finish’ button in this dialog will result in a project containing a number of header and source files with example DLL function implementations in them. For this project we need the following six files:

  • MapDrive.h
  • stdafx.h
  • targetver.h
  • dllmain.cpp
  • MapDrive.cpp
  • stdafx.cpp

targetver.h is auto-generated and needs no modification or explanation. The same can be said for dllmain.cpp except that an extra include line is required for our MappDrive.h implementation as follows:

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "MapDrive.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

stdafx.cpp is a simple one-liner to include its header file:

#include "stdafx.h"

stdafx.h itself includes most of the Windows headers and libraries required for the project as follows:

#pragma once
#include "targetver.h"

#define WIN32_LEAN_AND_MEAN

#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "mpr.lib")

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <Winnetwk.h>

Finally, we get to the implementation of our functionality. MapDrive.h defines the only function we actually wish to expose and the MAPDRIVE_API macro which will expose our function to the outside world in the C language style (i.e. without C++ name mangling):

#ifdef MAPDRIVE_EXPORTS
#define MAPDRIVE_API extern "C" __declspec(dllexport)
#else
#define MAPDRIVE_API __declspec(dllimport)
#endif

MAPDRIVE_API int mapDrive(LPWSTR, LPWSTR, LPWSTR, LPWSTR, LPWSTR);

MapDrive.cpp contains the implementation of our mapDrive() function as well as a convenience function that nicely formats error messages from the Windows API for us as follows:

#include "stdafx.h"
#include "MapDrive.h"
#include <strsafe.h>

#define ASCII 20127

void formatError(DWORD error, LPWSTR errorStr){
	LPVOID msg, display;

	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
		error,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR) &msg,
		0,
		NULL
	);
	
	int sizeNeeded=lstrlen((LPCTSTR)msg);
	display=(LPVOID)LocalAlloc(LMEM_ZEROINIT, sizeNeeded*sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)display, LocalSize(display)/sizeof(TCHAR), TEXT("%s"), msg); 
	StringCbPrintf(errorStr, 80, L"%s", display);
 
	LocalFree(msg);
    LocalFree(display);
}

MAPDRIVE_API int mapDrive(LPWSTR name, LPWSTR path, LPWSTR username, LPWSTR password, LPWSTR message){
	NETRESOURCE nr;
	memset(&nr, 0, sizeof(NETRESOURCE));
	nr.dwType=RESOURCETYPE_ANY;
	nr.lpLocalName=name;
	nr.lpRemoteName=path;
	nr.lpProvider=NULL;

	DWORD flags=CONNECT_UPDATE_PROFILE;

	DWORD retVal=WNetAddConnection2(&nr, password, username, flags);
	if(retVal==NO_ERROR) return 0;

	formatError(retVal, message);
	return retVal;
}

The mapDrive() function simply constructs a NETRESOURCE struct and populates it with desired drive letter and the UNC path to be mapped and passes it to the WNetAddConntection2() Windows API function along with the user credentials to be used and a flag which tells the operating system to automatically remap this drive if possible when booting in the future. If this function returns 0 (success) then it returns, otherwise the formatError() function is called to get an error string for the returned error code (which is written to the pointer passed as an argument).

Thats all the C++ required and compiling this solution in Release mode results in a nice little DLL only 8KB in size. All we need do now is create a Python interface to the DLL. I actually implemented this is in two ways, the first being my usual approach using just ctypes and the second using Qt (via PyQt, because I’m a big fan and the application I’m writing depends on it), mostly as an experiment. The code is as follows:

import ctypes
from ctypes.wintypes import LPWSTR
from PyQt4.QtCore import QLibrary

class MapDrive(object):
	_handle=ctypes.cdll.LoadLibrary("MapDrive.dll")

	@classmethod
	def mapDrive(cls, name, path, username, password):
		m=LPWSTR(" "*80)
		ok=cls._handle.mapDrive(
		    LPWSTR(name),
		    LPWSTR(path),
		    LPWSTR(username),
		    LPWSTR(password),
		    m
		)
		return ok, m.value

class MapDrive2(object):
	_handle=QLibrary("MapDrive.dll")
	assert _handle.load()
	assert _handle.isLoaded()
	_mapDrive=ctypes.CFUNCTYPE(
		ctypes.c_int,
		LPWSTR,
		LPWSTR,
		LPWSTR,
		LPWSTR,
		LPWSTR
	)(int(_handle.resolve("mapDrive")))

	@classmethod
	def mapDrive(cls, name, path, username, password):
		m=LPWSTR(" "*80)
		ok=cls._mapDrive(
		    LPWSTR(name),
		    LPWSTR(path),
		    LPWSTR(username),
		    LPWSTR(password),
		    m
		)
		return ok, m.value

if __name__=="__main__":
	print "MapDrive 1:", MapDrive.mapDrive(
		"Y:", 
		"\\\\path\\to\\be\\mapped",
		"username",
		"password"
	)

	print "MapDrive 2:", MapDrive2.mapDrive(
		"Y:", 
		"\\\\path\\to\\be\\mapped",
		"username",
		"password"
	)

To be honest, the pure ctypes method is cleaner, neater and shorter and is the one I will be using as, unlike the QLibrary method, it automatically detects the C++ function signature which somehow seems more safe and secure. I only include the QLibrary example as I have used this from C++ in the past and it certainly simplifies the process in that language and I was simply wondering if it were possible to use this method from Python too (which it is, as proved).

I hope this post and the example it contains is useful to someone, somewhere and if you have any questions or comments I will happily respond. I will also try and either upload a zip of the all the C++ and Python code or place it in my Google code repository at some point.

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/08/10/mapping-a-network-drive-with-python/
RSS
Follow by Email
SHARE

Python & C#: Making Them Talk Nicely

Over the years I have had to write a number of interfaces and wrappers between different programming languages (C/C++ and Python, Ada and C, Java and Python to name a few). Some of these are easy to achieve, other less so. A new challenge came along today with a need to access a C# class from Python. After a number of false starts I came up with the following solution which is to package the C# code as a COM object, register it with the OS (Windows) and access this from Python. There are surprisingly few full, correct and complete examples of this out there so I though I would provide one.

The first thing to do is to create a C# COM object. I used Visual Studio 2013 and created a new Visual C# Class Library solution. It is necessary to go in to the “Build” tab of the projects properties dialog and check the “Register for COM interop” option. The following is all the necessary code:

using System;
using System.Runtime.InteropServices;

namespace TestCOM
{
    [ComVisible(true)]
    [Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
    public interface ComClass1Interface {
        void helloWorld();
    }

    [ComVisible(true)]
    [Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
            ClassInterface(ClassInterfaceType.None)]
    public class ComClass1 : ComClass1Interface {
        public void helloWorld() { Console.WriteLine("Hello World"); }
    }
}

Building this solution will generate a type library file (TLB) and as well as a DLL which will be registered with the OS (you may need to run Visual Studio “As Administrator” for this to happen).

Now that we have successfully created and registered our COM object we can get on with accessing it from Python. To do this we use the comtypes package (easy_install comtypes) as follows:

from comtypes.client import GetModule, CreateObject
GetModule("TestCOM.tlb")

from comtypes.gen.TestCOM import ComClass1

o=CreateObject(ComClass1)
o.helloWorld()

NB You will need to change the path passed to GetModule() if the TLB file is not in the same directory as the Python script.

When you run this script, assuming everything has gone to plan, you will see something akin to the following in the console:

> python comtest.py
# Generating comtypes.gen._4146E699_C65F_479C_961A_BA3D8EFFC700_0_1_0
# Generating comtypes.gen._BED7F4EA_1A96_11D2_8F08_00A0C9A6186D_0_2_4
# Generating comtypes.gen.TestCOM
Hello World

The “# Generating…” lines will only occur when the content of the TLB/DLL files are changed and comtypes has to update the auto-generated Python module. The “Hello World” line is our C# code printing to the console, success!

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/06/25/python-c-making-them-talk-nicely/
RSS
Follow by Email
SHARE

Waiting for a Signal

Occasionally it becomes necessary to block and wait for a signal to be emitted. This may seem a little oxymoronic when using an event driven framework like Qt where the whole point is not to block, but, I promise you, sometimes it is necessary. The issue is that although you may want to block the execution of some function or method until a signal is emitted, you don’t want to block the event loop because the GUI will become unresponsive, not good. Therefore, we need sprinkle a little fairy dust over the problem and block one loop whilst executing another. However, we don’t want to wait indefinitely, we need to have a fallback that will release the block after some suitable period if the signal isn’t emitted in a timely fashion (if at all). I’ve tried, with varying levels of success, a few different methods of achieving this and the following is the latest, which is a well honed melange:

import sip
sip.setapi('QString',2)
sip.setapi('QVariant',2)

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

def waitForSignal(sender, senderSignal, timeoutMs, expectedSignalParams=None):
    timer=QTimer(singleShot=True)
    loop=QEventLoop()

    senderSignalArgsWrong=[]

    @pyqtSlot()
    def senderSignalSlot(*args):
        senderSignalArgsWrong.append((expectedSignalParams is not None) and 
                (expectedSignalParams!=args))
        loop.quit()

    senderSignal.connect(senderSignalSlot)
    timer.timeout.connect(loop.quit)

    QTimer.singleShot(0, sender)
    timer.start(timeoutMs)

    ex=[]
    def exceptHook(type_, value, traceback):
        ex.append(value)
        oeh(type_, value, traceback)

    oeh=sys.excepthook
    sys.excepthook=exceptHook

    loop.exec_()
    if ex: raise ex[0]

    ret=timer.isActive()
    timer.stop()
    senderSignal.disconnect(senderSignalSlot)
    timer.timeout.disconnect(loop.quit)

    sys.excepthook=oeh

    return ret and senderSignalArgsWrong and (not senderSignalArgsWrong[0])

if __name__=="__main__":
    from sys import argv, exit

    class Widget(QWidget):
        def __init__(self, parent=None, **kwargs):
            QWidget.__init__(self, parent, **kwargs)

            l=QVBoxLayout(self)
            l.addWidget(QPushButton("Start", self, clicked=self.start))
            self._stopButton=QPushButton("Stop", self)
            l.addWidget(self._stopButton)

        @pyqtSlot()
        def start(self):
            print "Start"
            ret=waitForSignal(self.work, self._stopButton.clicked, 5000)
            print "Finished:", ret

        @pyqtSlot()
        def work(self): print "Work"

    a=QApplication(argv)
    w=Widget()
    w.show()
    w.raise_()
    exit(a.exec_())

The basic principle is to block the execution of the main event loop and create a second loop to handle events in the mean time. A timer is used to release the block in the event of a failure. A timer is also used to execute the worker function to make sure it is executed in the correct event loop and the desired signal is caught. A certain amount of inspiration for this particular implemenation was gathered from the test suite for the Enki text editor.

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/06/03/waiting-for-a-signal/
RSS
Follow by Email
SHARE

(Py)Qt4 Font on MacOSX Mavericks

In preparing my project for its next release I have found the default font on MacOSX 10.9 Mavericks has changed to be retina optimised which seems to upset (Py)Qt4. The symptom is that text tends to be vertically misaligned on widgets such as QPushButton and QComboBox. This can be easily rectified however as follows:

import platform
if platform.system()=='Darwin':
    _release,_versioninfo,_machine=platform.mac_ver()
    if float(_release[:4])>=10.9: QFont.insertSubstitution(".Lucida Grande UI", "Lucida Grande")

If you prefer to your thing with Qt in C++, then the following is for you:

#ifdef Q_OS_MACX
  if (QSysInfo::MacintoshVersion>QSysInfo::MV_10_8)
    QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
#endif
Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/02/21/pyqt4-font-on-macosx-mavericks/
RSS
Follow by Email
SHARE

Raspberry Pi and GertDuino

Santa was very generous with his gift giving as far as I was concerned this year. Not only did I receive an Ethernet Shield for my Arduino and a pair of Nordic Semiconductor nRF24L01 boards, I was also delighted to tear the wrapping paper off of a GertDuino. For those who have not encountered one of these wonderful things yet, a GertDuino is an Arduino compatible add-on board for the Raspberry Pi which allows the developer to develop for and communicate with not one, but two Atmel Microcontrollers: an ATmega328p and an ATmega48pa. Now, I’m not going to reiterate all of the information detailed in the excellent 20+ page manual that is available for the GertDuino, if you want to know more about it and its features, read the aforementioned. What I am going to do is briefly describe the setup process and my experience of it.

I started with a vanilla Raspberry Pi Model B with a 16GB SD Card on to which I installed Raspbian via NOOBS 1.2.1. If that doesn’t mean anything to you then… this post probably isn’t for you. The next step is to fire up a terminal and install the Arduino package which contains the cross compiler and the IDE:

$ sudo apt-get install arduino

Then you need a program called avrdude to actually program the ATmega’s:

$ cd /tmp
$ wget http://project-downloads.drogon.net/gertboard/avrdude_5.10-4_armhf.deb
$ sudo dpkg -i avrdude_5.10-4_armhf.deb
$ sudo chmod 4755 /usr/bin/avrdude

The next step is to power off your Raspberry Pi and plug in the GertDuino, and this is where we deviate from the script a little. When I re-powered my Pi I got as far as, what I call the “rainbow test card”, and then nothing: the Pi wouldn’t boot. A little googling brought me to this page which explains that some GertDuino’s have been shipped with the factory test program still residing in the ATmega48 which pulls down the SCL pin and puts the Pi into safe boot. This only happens with NOOBS 1.2, if you’re using NOOBS 1.3 you apparently won’t experience this issue. To fix the issue you set the jumpers on the GertDuino so as to program the ATmega48 (see section 4.2 of the user guide). This will hold the ATmega48 in reset and stops it pulling down the SCL pin. You can now boot the Pi and erase the test program from the ATmega48 using the following command:

$ /usr/bin/avrdude -c gpio -p m48pa -e

This command unfortunately failed for me. Instead of erasing the ATmega48, avrdude complains that it doesn’t know what an “m48pa” is. Some further investigation reveals that this is due simply to a missing definition in the avrdude.conf file. I’ll save you the gory details of how to patch it and let you download it: avrdude.conf. Just place it in the /etc/ folder on your Pi and rerun the above command. Now you can power down the Pi, swap the jumpers over to program the ATmega328 and run the examples.

Thats as far as the GertDuino documentation takes you (which is a very long way!). However, if you want to use the Arduino IDE to write your sketches and program your processors then you’ll need to install one more thing. Gordon Henderson, as well as porting avrdude to the Pi, has created a script that configures the Pi and the Arduino IDE for us. All you have to do is the following:

$ cd /tmp
$ wget http://project-downloads.drogon.net/gertboard/setup.sh
$ chmod +x setup.sh
$ ./setup.sh

Now you can start the Arduino IDE:

$ arduino

You’ll need to tell the Arduino IDE to use your GertDuino and to use a programmer (the Pi’s GPIO in this case). So, from the menu:

Tools > Board > Gertboard with ATmega328

and then:

Tools > Programmer > Raspberry Pi GPIO

I then wrote the most minimalistic sketch version of the blink example documented in the GertDuino’s user guide as follows:

#define NUM_LEDS 6
// LED:              0   1   2   3   4   5
// PIN:              PB5 PB1 PB2 PD3 PD5 PD6
unsigned int LEDS[]={13, 9,  10, 3,  5,  6}, LED=0;
int DIR=-1;

void setup(){
  unsigned int i;
  for(i=0; i&lt;NUM_LEDS; i++) pinMode(LEDS[i], OUTPUT);
}

void loop(){
  digitalWrite(LEDS[LED], HIGH);
  delay(100);
  digitalWrite(LEDS[LED], LOW);

  if(LED==NUM_LEDS-1 || LED==0) DIR*=-1;
  LED+=DIR;
}

To send this to your ATmega328, you can’t use the upload button on the IDE’s toolbar, you have to use the following menu option:

File > Upload using programmer

Or use the Ctrl+Shift+U keyboard shortcut. All being well you should see a KITT like chase pattern on your GertDuino’s LED’s as can be seen in the following video:

YouTube Preview Image

My apologies for the dodgy, shaky, out of focus camera work!

That’s it, that’s as far as I’ve got so far. It took me just a couple of hours to get here and that includes waiting for downloads and googling for my couple of issues. I hope this little post helps someone else get up and running with their Pi/GertDuino combo.

Edit 06/01/14

Since writing this post I have been playing with getting serial communication between the Pi and the ATmega328 up and running. After some false starts and helpfull suggestions from the Raspberry Pi forums, I found I needed to make a change to boards.txt and adjust the CPU frequency Arduino uses to calculate baud rates. See the forum topic here for details.

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2014/01/02/raspberry-pi-and-gertduino/
RSS
Follow by Email
SHARE

Ginger Beer Mark 1 – Bottling

So, the ginger beer fermentation gradually slowed and stopped over the last couple of days therefore, last night, after 9 nine days, it was time to rack the beer to bottles for second ferment and conditioning. As this is a test batch and I wanted to be able to observe the process more easily I’ve used 2L plastic lemonade bottles rather than glass. These are perfect because they are appropriate as pressure vessels (as they are intended to contain a carbonated drink) but aren’t thick enough to distort the view of the contents. Also there volume can be adjusted simply by deforming (squeezing ;o) them. This deformation is useful as it provides a simple way to gauge the progress of the second ferment, the technique of which is as follows:

  1. Empty the original content from the bottles and sterilise (I use that old reliable: Milton Sterilising Fluid)
  2. Add 1tsp of sugar per litre of volume of the bottle, i.e. for a 2L bottle, add 2tsp sugar.
  3. Siphon the beer from the fermenter into the bottles, leaving a gap of 30-40mm and being careful not to disturb/pickup the yeast bed in the fermenter.
  4. Squeeze each bottle to raise the level of the liquid as close to the top of the neck as possible and screw the cap on tight.
  5. Keep the bottles and there contents at the fermentation temperature until they have re-inflated and are incompressible. This is the second fermentation step which will carbonate the beer.
  6. Store in a cool place (i.e. at a temperature below that acceptable for fermentation) for 6-8 weeks to allow the beer to condition and the flavour to develop.

Below is an image of my two bottles ~8 hours after racking. As can be seen, they have re-inflated, but I have left them in my warm place a little longer as the bottles were not as hard/incompressible as I would like. Please excuse the blur, it was 6am and I was in a hurry!

Inflated Bottles!

Inflated Bottles!

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2013/08/28/ginger-beer-mark-1-bottling/
RSS
Follow by Email
SHARE

Ginger Beer Mark 1

After a break of more than year I have finally gotten around to starting a new batch of home brewed beer. I am a particular fan of alcoholic ginger beers and there are a number of good brands out there, my only criticism of which would be that they are not hot or spicy enough for my taste. With that in mind, I thought I would experiment a little with a short batch to see if I could produce something more pleasing. So, I purchased a 4.5L bucket meant for the fermenting of wine and then researched/devised the following recipe:

Ingredients:

  • 225g Fresh Ginger, sliced
  • 375ml White Sugar
  • 310ml Soft Brown Sugar
  • 80ml Lemon Juice
  • Zest of ¼ Lemon
  • ½ Cinnamon Stick
  • 1 Clove
  • ½tbsp Vanilla Extract
  • 1 Sachet of Champagne Yeast

Initial Method:

  1. Put the ginger, cinnamon and clove in a saucepan with 1L of water, bring to the boil and then turn down to simmer for 1 hour.
  2. Place the white and brown sugars and the lemon zest into a 4.5L fermenter or demijohn. Line a fine sieve with cheese cloth and strain the saucepans contents into the fermenter. Stir this ‘wort’ to dissolve the sugars and then take the cheese cloth from the sieve and wring out as much liquid from the ginger solids as possible into the fermenter.
  3. Add the lemon juice and vanilla extract to the wort and then dilute to a volume of 4.5L with cold water. Allow the wort to cool to a temperature tolerable to the yeast (in this case 27°C). Due to warm weather conditions I actually helped this cooling along by adding a few ice cubes.
  4. Pitch the yeast into the wort, close the fermenter and set the airlock.

The brew was started on Sunday 18th August 2013. Some pictures of the preparation and setup are shown below:

UPDATE (20/08/2013): After approximately 36 hours of fermenting a drop in ambient temperature has caused the temperature of the wort to drop to 20ºC and therefore necessitated the use of heater base to stay within the yeasts operating window (20-27°C).

UPDATE (20/08/2013): After about 12 hours the temperature of the wort has reached the high end of the acceptable range and therefore the heater base has been switched off (this heater base is designed to maintain the temperature of a much larger 21L batch).

Share:
Facebook
Twitter
Google+
http://www.gulon.co.uk/2013/08/20/ginger-beer-mark-1/
RSS
Follow by Email
SHARE