Page: 1 | 2

Main > Diary > Development

February 20, 2012

Arduino DHT22 Library Improvement

Rob Faludi and I have been teaching a class at the International Center for Theoretical Physics in Trieste, Italy. Marco Zennaro furnished us with a number of DHT22-based Grove Temperature and Humidity Sensors for Seeed Studio. The example code on the Seeed wasn't very robust nor parameterized to work on any Arduino pin so I took a few moments to make some changes. There are now two files:

DHT22.h:

#ifndef DHT22_H
#define DHT22_H

enum DHT22_Err_t {
  DHT22_ERR_NONE = 0,
  DHT22_ERR_HUNG = 1,
  DHT22_ERR_SYNC = 2,
  DHT22_ERR_CHKSUM = 3,
};

DHT22_Err_t getDHT22(int pin, float *temperature, float *humidity);

#endif

DHT22.ino:

#include "DHT22.h"

static byte _read_dht22_dat(volatile uint8_t *in, uint8_t bitmask)
{
  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
    while(!(*in & bitmask));  // wait for 50us
    delayMicroseconds(30);
 
    if(*in & bitmask) 
      result |=(1<<(7-i));
    while((*in & bitmask));  // wait '1' finish
  }
  return result;
}

DHT22_Err_t getDHT22(int pin, float *temperature, float *humidity)
{
  byte dht22_dat[5];
  byte dht22_in;
  byte i;

  uint8_t bitmask = digitalPinToBitMask(pin);
  volatile uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *reg, *out, *in;

  // setup registers and pins
  reg = portModeRegister(port);
  out = portOutputRegister(port);
  in =  portInputRegister(port);
  *reg |= bitmask;
  *out |= bitmask;

  // start condition
  // 1. pull-down i/o pin from 18ms
  *out &= ~bitmask;
  delay(18);
  *out |= bitmask;
  delayMicroseconds(40);
 
  *reg &= ~bitmask;
  delayMicroseconds(40);
 
  dht22_in = *in & bitmask;
 
  if(dht22_in){
    Serial.println("dht22 start condition 1 not met");
    return DHT22_ERR_HUNG;
  }
  delayMicroseconds(80);
 
  dht22_in = *in & bitmask;
 
  if(!dht22_in){
    return DHT22_ERR_SYNC;
  }
  delayMicroseconds(80);
  // now ready for data reception
  for (i=0; i<5; i++)
    dht22_dat[i] = _read_dht22_dat(in, bitmask);
 
  *reg |= bitmask;
  *out |= bitmask;
 
  byte dht22_check_sum = dht22_dat[0]+dht22_dat[1]+dht22_dat[2]+dht22_dat[3];
  // check check_sum
  if(dht22_dat[4]!= dht22_check_sum)
  {
    return DHT22_ERR_CHKSUM;
  }
  
  *humidity=((float)(dht22_dat[0]*256+dht22_dat[1]))/10;
  *temperature=((float)(dht22_dat[2]*256+dht22_dat[3]))/10;
 
  return DHT22_ERR_NONE; 
}

This can be used as in in the following example:

#include "DHT22.h"

void setup() {
  Serial.begin(9600);
  delay(2000); // Recommended delay before sensor can be used
}

void loop() {
  DHT22_Err_t result;
  float temperature = 0, humidity = 0;
  
  result = getDHT22(4, &temperature, &humidity);  
  if (result != DHT22_ERR_NONE)
  {
    delay(5000);
    return;
  }
  
  Serial.print("Current humdity = ");
  Serial.print(humidity,1);
  Serial.print("%  ");
  Serial.print("temperature = ");
  Serial.print(temperature,1);
  Serial.println("C  ");
  delay(5000);
}

You may download the file ICTP_DHT22_XIG.zip. It contains a slightly enhanced example which transmits the information to the XBee Internet Gateway.

Posted by jordanh at 6:46 AM | Comments (6) | TrackBack |

Main > Diary > Development

January 14, 2012

DanceShanty

Over the past two weeks I've been involved in the construction of an Art Shanty Project called the DancyShanty.

Art Shanty Projects is a four-week exhibition that is part sculpture park, part artist residency and part social experiment, inspired by traditional ice fishing houses that dot the state's lakes in winter. It is an artist driven temporary community exploring the ways in which the relatively unregulated public space of the frozen lake can be used as a new and challenging artistic environment to expand notions of what art can be.

The DanceShanty, an innocuous white structure on a frozen lake, draws you inside with music and the sound of people having fun. As you enter you are invited to hangup your coat and dance!

My part in the DanceShanty was to design the lighting system for the project. Hans Scharler of ioBridge/ThingSpeak had shared the Cheerlights project with me where people have interconnected strands of GE Color Effects LED lights using ThingSpeak and a variety of communications components including Digi ConnectPort X2 Internet-to-ZigBee gateways and of course, good ol' Digi XBee radios.

I love lights. A hackable strand of full-color RGB Christmas lights are a dream come true. I found a strand of 25 lights for $25 at Sears. A little Processing and Arduino code (using my friend Rob Faludi's excellent book, of course!) and I had a prototype working in an evening. Using an SparkFun XBee Shield and a pair of Series 1 XBee Radios I was able to made the whole setup wireless—and able to hide away the PC from view while being able to maintain a connection to the lights. I work for Digi, so every design screams like it needs to be made wireless.

I am going to do a full tech write-up with source-code soon. The laptop I have in the DanceShanty now is old and slow and only able to run the display at about 10 frames per second. The Arduino code I wrote is able to run four synchronized strands of lights at well over 30 frames per second as you can see from the below staging video:

Before the DanceShanty comes down I am going to write a quick mobile app and connect the setup to people via iDigi in order to allow people dancing to choose the color and visualization mode of the lights. It's going to be sweet!

Posted by jordanh at 7:29 PM | Comments (1) | TrackBack |

Main > Diary > Development

November 5, 2007

Python: Using Lambda to Delay Argument Bindings

At the University of Minnesota the first Computer Science class is still taught in Scheme. A lot of students complain the learning an archaic functional language is a waste of time, I could not disagree more. I think it is a great introduction for many reasons but it is especially useful to programmers nowadays who are using modern procedural languages which have an increasing tendency to mix in paradigms from the functional domain.

I am working on an RPC interface for a project at the office and I found myself writing yet another function to dispatch an event callback into a sequence of calls. I wanted to have a Python library routine callback call one of my functions with the first argument statically assigned to be a value of my choosing. In other words: I needed to bind some of the argument variables immediately but allow the remainder of the arguments be left unbound. Here a bit of functional flair fit the solution: lambda function composition.

First we will create our stub dispatch function:

def dispatch(variant, *args):
    print "dispatch(%s, %s)" % (variant, args)
    # a real implementation may now act differently based on the value of variant

We want our Python library call back to call our function like so...

dispatch("type1", (0, 1, 2))
dispatch("type2", (0, 1, 2))
# etc

Using a simple lambda composition we can create a new function that has the variant argument bound while still allowing the *args array to be set at a later time. This may be done simply:

mk_cb = lambda v: lambda *a: dispatch(v, *a)

Then we can create a series of custom functions which may be registered as callbacks with whatever variant type we wish to set:

cb1 = mk_cb("type1")
cb2 = mk_cb("type2")

We can call one of the callback functions just to test it:


>>> cb1((0,1,2))
dispatch(type1, ((0,1,2),))

And finally we can use it with some Python library callback registration function:

some_py_obj.register_function(cb)
# cb is the dispatch() function with 'type1' as the first argument

So who says that we are, "never going to use this stuff?"

Posted by jordanh at 6:14 AM | Comments (2) | TrackBack |

Main > Diary > Development

February 7, 2007

Photoblog Archive Changed

The photoblog archive used to be this paginated lump of goo.

Now, it's a semi-slick dynamic HTML wonderland of thumbnails! Go give your eyes an eyeful.

Posted by jordanh at 12:47 AM | Comments (0) | TrackBack |

Main > Diary > Development

February 5, 2007

Enter AJAX

I AJAXified the comment system for the blog. It's about time to join the rest of 2007, I say.

Wrangling MT, my legacy templates, and all the spam prevention stuff I've got integrated proved me to completely mis-scope how long this would take. I figured I could have the whole thing done in an evening, but it turned into about three nights of work on and off the past couple of weeks. Bleh.

I pulled the basic ideas from BrettDeWoody's MT AJAX Comments, but modified the scripts and such to play nicely with the DOM structure I had already defined. A couple of AJAX spinners later and I was ready to roll. Even after the rough spots, working with prototype.js directly (outside the safety of Rails, per se) certainly does leave one with a sense of awe of the authors of http://script.aculo.us/.

Go ahead, comment away. I'll no doubt make some improvements to the system over the next little while but for now, my new primary drive will be to add some more content. It is time to pick up the camera again!

Posted by jordanh at 1:49 AM | Comments (7) | TrackBack |

Main > Diary > Development

October 30, 2006

mtcolor butt cheese

I decided to check into my referrer logs tonight just to see how much bandwidth the MySpace kidz are using hot-linking to my photoblog images (just wait until I come up with a fun image to replace them all with! Suggestions -> me) when I noticed that syntax highlighting stopped working again. This happened because I updated perl and the Syntax::Highlight::Universal module went AWOL again. Getting mtcolorer working continuously could have it's own highly paid crack support staff working 24x7. It's a terrible foundation this thing is built upon.

Long story short, I needed to rebuild the module by hand. A few modifications have to be made to the module source in order to get it to compile on a recent Linux distribution:

  1. Add -fpermissive to the CCFLAGS parameter of Makefile.PL.
  2. Use perl Makefile.PL to build a Makefile.
  3. Edit this makefile and change whatever *-gcc entries to *-g++; otherwise gcc will not generate the shared C++ symbols correctly.
  4. Edit ./colorer/common/Hashtable.h and change references to capacity and bucket on lines 22-23, 64-65 to this->capacity and this->bucket (scoping people!).
  5. make ; make install Voila!

After that it was smooth sailing; and time for bed!

{
    printf("And to all, a %s.\n", "good night");
    exit(-1);
}

Posted by jordanh at 1:11 AM | Comments (1) | TrackBack |

Main > Diary > Development

May 13, 2006

Recollating MySQL, How I Broke the latin_swedish_ci Blues...

I got mad. When I get mad sometimes I write ruby. Tonight I wrote ruby.

A couple of weeks ago the server that hosts this site melted down. I replaced the box and migrated all of the data into a freshly compiled copy of MySQL. Everything seemed to work peachy until I noticed that all of my UTF-8 characters were coming out as questions marks. It's very annoying when you want to say ???????? and you get ????????. ????!

What was worse was seeing exacly how much work it was going to take to change the collation in all of the columns in all of the tables within all of the databases on my system. Bleh.

I wrote a script in Ruby to change all of the collations en masse for a particular database. This is useful for me because I really don't use any other collation other than utf8_bin, save for the odd column set to utf8_general_ci.

If you're interested in such progmatic solution, read on...

The below 100 lines took me about an hour to write, so be careful if you're running it on a production system. Take care to know if you need any other collations other than the TARGET_COLLATION defined in the top of the class.

#!/usr/bin/ruby18

require 'mysql'

class RecollateMysqlDatabase
  HOST = "localhost"
  USERNAME = "username"
  PASSWORD = "password"
  DATABASE = "mt_ablog"

  TARGET_CHARSET = "utf8"
  TARGET_COLLATION = "utf8_bin"

  def initialize
    @dbh = nil

    begin
      @dbh = Mysql.real_connect(HOST, USERNAME, PASSWORD, DATABASE)
      puts "Connected to MySQL Server Version" +
        @dbh.get_server_info
    rescue MysqlError => e
      mysql_exception_handler(e)
    end
  end

  def mysql_exception_handler(e)
      print "Error code: ", e.errno, "\n"
      print "Error message: ", e.error, "\n"

    begin @dbh.close rescue nil end

    exit 255
  end

  def recollate_tables(preview = true)

    puts "Fetching tables..." if preview

    # get a list of tables
    tables = @dbh.list_tables
    # A place to store our operations
    table_column_hash = Hash.new
    alter_table_query_list = [ ]

    # for each table get a list of columns:
    tables.each do |table|
      puts "Have table: #{table}" if preview
      res = @dbh.query("SHOW FULL COLUMNS FROM `#{table}`")
      while row_hash = res.fetch_hash do
          if row_hash["Collation"] != "NULL" and
            row_hash["Collation"] != TARGET_COLLATION
              column_hash = { "Field" => row_hash["Field"],
                              "Type" => row_hash["Type"] }
              table_column_hash[table] = [ ] if table_column_hash[table].nil?
              table_column_hash[table].push(column_hash)
          end
      end
      table_column_hash.each_key do |table|
        puts "\nIn #{table}, these columns need re-collating:\n" if preview
        table_column_hash[table].inject(false) do |comma,column_hash|
          printf "#{((comma) ? ", " : "\t")}" + column_hash["Field"] if preview
          comma = true
          alter_table_query_list.push <<-EOQ
            ALTER TABLE `#{table}` CHANGE `#{column_hash["Field"]}`
              `#{column_hash["Field"]}` #{column_hash["Type"]}
              CHARACTER SET #{TARGET_CHARSET}
              COLLATE `#{TARGET_COLLATION}`
            EOQ
        end
        printf ".\n" if preview
      end
      printf "\n" if preview
    end

    puts "-= PREVIEW OF SQL, NO CHANGES HAVE BEEN MADE =-" if preview
    alter_table_query_list.inject(0) do |i,query|
      puts query if preview
      if not preview
        printf "Executing query ##{i}...\r"
        STDOUT.flush
        begin
          @dbh.query(query)
        rescue MysqlError => e
          mysql_exception_handler(e)
        end
      end
      i += 1
    end
    printf "\n"
    puts "-= PREVIEW OF SQL, NO CHANGES HAVE BEEN MADE =-" if preview
  end
end

rmd = RecollateMysqlDatabase.new
rmd.recollate_tables(preview = true)

printf "Okay to proceed? (YES) -> "
response = STDIN.gets.chomp
if response != "YES"
  puts 'I need the answer "YES" in all caps to proceed! Exiting...'
  exit 1
end

rmd.recollate_tables(preview = false)
puts "Done!"
exit 0

Instructions: modify the top of the class connect with the username and password for the host and database you are interested in recollating. Run the script and if you are satisfied that the ALTER TABLE queries look sane, answer YES to let the script do the work.

Good luck!

Posted by jordanh at 1:32 AM | Comments (0) | TrackBack |

Main > Diary > Development

March 10, 2006

mtcolorer-0.2 plugin source code cleanup

Here is a patch for mtcolorer-0.2 to clean up the source a bit. I was initially having trouble getting the plugin to work and I made some mostly cosmetic improvements to the source in order to facilitate debugging. Happy coding!

Here's the diff (link), using mtcolorer:

--- mtcolorer.pl.orig   2006-03-10 18:48:32.000000000 -0600
+++ mtcolorer.pl        2006-03-10 18:46:19.000000000 -0600
@@ -1,5 +1,5 @@
 # ---------------------------------------------------------------------------
-# MT-Colorer
+# MT-Colorer
 # A plugin for Movable Type
 #
 # Release 1.0.0
@@ -11,66 +11,70 @@
 # You may use it for commercial or personal use.
 # If you distribute it, please keep this notice intact.
 #
-# Copyright (c) 2006
-# ---------------------------------------------------------------------------
+# Copyright (c) 2006
+# ---------------------------------------------------------------------------
+#
+# Additional Changes:
+#
+# 10-Mar-2006 - minor fixes/clean-up work Jordan Husney <jordan@husney.com>
+#

 package MT::Plugin::Colorer;
 use Syntax::Highlight::Universal;
 use strict;
 use MT;
-use MT::Entry;
-use MT::Plugin;
+use MT::Plugin;
 use MT::Template::Context;
-use MT::WeblogPublisher;
-my $highlighter = Syntax::Highlight::Universal->new();
-my $plugin = new MT::Plugin();
-$plugin->name("MT Colorer");
-$plugin->description('Source code hightlighter based on Colorer (http://colorer.sf.net)');
-$plugin->doc_link('http://klim.doslash.org/projects/mtcolorer');
-$plugin->author_name('Vladimir Klimontovich');
+my $highlighter = Syntax::Highlight::Universal->new();
+my $plugin = new MT::Plugin();
+$plugin->name("MT Colorer");
+$plugin->description('Source code hightlighter based on Colorer (http://colorer.sf.net)');
+$plugin->doc_link('http://klim.doslash.org/projects/mtcolorer');
+$plugin->author_name('Vladimir Klimontovich');
 $plugin->author_link('http://klim.doslash.org/eng_index.shtml');
 $plugin->plugin_link('http://klim.doslash.org/projects/mtcolorer');
-$plugin->version("0.2");
+$plugin->version("0.2-jrh");

+MT->add_plugin($plugin);
 MT->add_callback("BuildPage", 1, $plugin, \&hightlight_text);

-MT->add_plugin($plugin);
-

-sub trim
-{
-   my($string)=@_;
-   for ($string)
-   {
-      s/^\s+//;
-      s/\s+$//;
-   }
-   return $string;
+sub trim
+{
+   my($string)=@_;
+   for ($string)
+   {
+      s/^\s+//;
+      s/\s+$//;
+   }
+   return $string;
 }
 sub hightlight_block
-{
-   my ($lang, $source) = @_;
-   my $htext =  $highlighter->highlight($lang, $source);
+{
+   my ($lang, $source) = @_;
+   my $htext = $highlighter->highlight($lang, $source);
    $htext = trim($htext);
    return "<pre class=\"mtc_block\">".$htext."</pre>";
-}
+}

 sub hightlight_inline
-{
-   my ($lang, $source) = @_;
-   my $htext =  $highlighter->highlight($lang, $source);
+{
+   my ($lang, $source) = @_;
+   my $htext = $highlighter->highlight($lang, $source);
    $htext = trim($htext);
    return "<span class=\"mtc_inline\">".$htext."</span>";
-}
-
-sub hightlight_text
-{
+}
+
+sub hightlight_text
+{
    my ($cb, %args) = @_;
-   use Data::Dumper;
    my $html = ${$args{'Content'}};
+
    $html =~ s/<mtc:block([^>]*?)lang="([^"]+?)"([^>]*?)>(.*?)<\/mtc:block>/hightlight_block($2,$4)/ges;
    $html =~ s/<mtc:inline([^>]*?)lang="([^"]+?)"([^>]*?)>(.*?)<\/mtc:inline>/hightlight_inline($2,$4)/ges;
-   ${$args{'Content'}} = $html;
-   return 1;
+   ${$args{'Content'}} = $html;
+
+   return 1;
 }

+1;

Posted by jordanh at 6:49 PM | Comments (0) | TrackBack |

Main > Diary > Development

mtcolorer test

This is a test of the mt-colorer plugin, test #18:

int main(int argc, char *argv[])
{
    printf("hello, %s world!\n", "big");

    return 0;
}

Success!

If you are having trouble getting the plugin working, see my comments over at http://klim.doslash.org/projects/mtcolorer/index.shtml, the mtcolorer home page.

Posted by jordanh at 4:34 PM | Comments (1) | TrackBack |

Main > Diary > Development

September 25, 2005

The Love Affair and the Hate Campaign

My love affair with Ruby continues. I wrote a small piece of software to perform numerical integration estimates. I learned that the development process in Ruby generally goes something like this:

I'm digging it.

I'm also grooving on a simple Vim plugin I went searching for. I had always wanted the ability to yank lines directly out of a shell buffer in order to be able to manipulate them within Vim. Well, I found exactly what I was looking for here.

It seems every time I wish to change something simple here on this blog of mine that I run into horrible cross-browser compatibility problems. It is silly the shear amount of infrastructure I have to put in to divide the universe into "standards-compliant" and "IE" realms. Today's problem dealt with wanting to finally solve my problem with displaying text within <pre> tags.

When I had originally published this site, I knew that pre data was getting clipped. I left it as a problem to solve on a rainy day. Well, today was rainy and I had just published and entry that I had wished to use a lot of preformatted text within.

The easy fix for Firefox is allow content in the content div to overflow. Sadly, this causes the sidebar on the right side to drop. Although I found this article on dropped div tags to be extremely useful, the JavaScript solutions presented were too much dinging around for me to bear.

I ended up allowing overflow in the standards-based stylesheet and then overriding this later in the IE-specific one. Also in the IE stylesheet pre elements are set to overflow:auto so they will get ugly little scrollbars if they overflow.

One wonders how much of this will be "fixed" in the new version of IE.

Posted by jordanh at 1:34 PM | Comments (0) | TrackBack |