Rain8net Ruby Library v1.0.0

I previously wrote about a product called Rain8net. I’m happy to announce the initial release of my Rain8net ruby library. The library is now available from rubyforge.org.

Or, just install it like this:

gem install rain8net

Now you won’t have to worry about sending the specific codes I detailed in my last post. Controlling your sprinklers is as easy as:

r8 = Rain8net.new
r8.turn_on_zone(1)
r8.turn_off_zone(1)

See the online documentation at the project homepage for more information.

Irrigation 2.0 with Rain8Net

The problem: Automatic sprinklers are great for convenience but waste a ton of water. You see businesses and neighbors running sprinklers during a rainstorm all the time–right? Rain conscious individuals can turn their sprinklers off when not needed, but you lose convenience and sometimes it is a pain to get back on track.

The solution: Rain8Net from WGL Designs, a PC with a serial port, and a little bit of Ruby programming.

Disclaimer: this post is a bit premature. I just got my Rain8Net last weekend and spent some time trying to program it. I plan to script the whole system so that it reads weather reports from the Internet to determine irrigation needs. That part isn’t ready yet. This is just an introduction to what I’ve discovered so far.

That being said, here is a sample of how to communicate with the Rain8Net via Ruby. (First, be sure to download and install the ruby-serialport library.)

require 'serialport.so'
tty = 0
rain8 = SerialPort.new(tty, 4800, 8, 1, SerialPort::NONE)
# Turn on Zone 1
rain8.write(["400131"].pack("H*"))
sleep(60)
# Turn off Zone 1
rain8.write(["400141"].pack("H*"))

WLG Designs has great documentation explaining what the various codes do. I am providing the code above as an example of how to implement the provided codes. (It took me many tries to get this far. Hopefully it will save someone else a bit of work.)

I plan to develop a Ruby library for use with the Rain8Net which will make it much easier to use. Watch for it…

Build a Development Infrastructure…or buy a Mac

Disclaimer: Let me start out by saying I am not anti-Mac. That being said, I am very pro-Linux. I am not a Dell lover either. I just picked them for comparison.

As a web developer, I have found it extremely beneficial to have access to my own servers for development purposes. I have my own infrastructure for version control. I maintain my own DNS servers and can quickly provide access to a temporary site for clients.  While developing TheBigFork, I developed several long-running data cleanup scripts. These would not have been possible without an always-on server to do the work.

Great. So, what does that have to do with buying a mac? Nothing, really. I recently have become aware that more and more web developers (especially Ruby developers) are developing on a Mac. Frankly, I don’t get it. I’ve tried it, and it doesn’t come close to developing on Linux. But, that’s really a discussion for another day. This article is about price.

I compared the price of a MacBook Pro 17″ 2.5 gHz notebook with a collection of Dell machines. The MacBook is listed at $2799. For that much money, you could buy:

Seven Dell Vostro 200 desktops with a 20″ widescreen display and a 250 gig hard drive. These come with Windows XP, but you can easily reformat it and install Ubuntu or Fedora. Doing so opens up a whole world of freely available open-source software. (And, don’t argue that Linux isn’t ready for the desktop. If you can switch from Windows to Mac, you can easily make the switch to Linux.)

With 7 computers, you can hire a receptionist, bookkeeper and project manager and still have a few extra machines for some junior developers. Granted, these aren’t the most powerful machines out there and they probably aren’t worthy of acting as a server–unless you’re desperate.

Here’s another scenario. Buy a Dell PowerEdge 840 server plus a Dell Precision T4300 workstation (which alone rivals the macbook’s specs). The only problem is, you’ll have almost $1400 extra. I guess you’ll have to buy a Dell Latitude D830 laptop for working on-the-go, and a second 21″ monitor for your workstation. Wait–you still have extra money. So, grab a Vostro 200 from the previous scenario. Now you have four machines: a server, a high-powered 64-bit workstation, a nice notebook and an extra desktop for your assistant.

If you really need a laptop with more horsepower than the MacBook, just get the Precision M6300 mobile workstation instead of the workstation and notebook above. You’ll still have enough for a server and the spare desktop.

Finally, if computers aren’t your thing, put a down-payment on a nice new car!

Bottom line: Macs are very nice. To me, they are simply not worth the extra cash–especially when you have work to get done.

In case you’re wondering, the best Ruby IDE that I’ve found is Aptana Radrails which runs poorly on Mac and excellent on Linux. Textmate is the Ruby IDE of choice on Mac. I found it lacking in features and difficult to use.

Pinewood Derby 2008

Sometimes a picture is worth…

RFC_READ_TABLE with Ruby and SAP::Rfc

Warning: another code sample is included in this post.

I spent a few hours this morning trying to use Piers Harding’s SAP/Rfc library for Ruby to read a table from SAP. I found several examples using other languages (Perl, VBscript, PHP, etc.), but the only Ruby example I could find reads the entire table. Figuring out how to load the “options” took some trial and error.

The idea of this example is to read the “LQUA” table in SAP which stores information about where to find a particular material in the warehouse. The whole thing is wrapped up in its own model so it can be easily called elsewhere in my Rails app:

class SapMaterial < SAP4Rails::Base
  function_module :RFC_READ_TABLE
  class << self

    def find_stock(options={})
      material = options[:material]
      return nil if material.blank?
      rfc = self.RFC_READ_TABLE
      rfc.query_table.value = "LQUA"
      rfc.delimiter.value = "|"
      rfc.options.value = ["MATNR EQ '#{material}'"]
      rfc.call()
      rfc
    end

  end
end

This is called with something like this:

stock_locations = SapMaterial.find_stock(:material=>'VOC300V')

Which yields a handy data set containing all the locations and available quantity for the DigiTech Vocalist 300 in the warehouse. This will be used as part of my new scan gun application which directs the shipping department to the various storage bins for picking large orders.

Ruby: Howto convert numbers to letters

Let’s say you have a series of numbers (1,2,3,4,5…500+) and you need to convert them to letters like A,B,C,D…AA…ZZ (think Excel column headers.)

I searched and searched to find a built-in way of doing this with Ruby, but I couldn’t find it. So, I tried to write my own:

def number_to_letter(n=1)
  n.to_i.to_s(27).tr("0-9a-q", "A-Z")
end

That works great except that 1=B instead of A, so all of AA,AB,AC…AZ doesn’t work. I tried all sorts of different ideas based on the one above. Then, I stumbled on: succ.

For an Integer, it makes a lot sense: 1.succ = 2, and so on (returns the next integer). But, it also does exactly what I need for strings: “A”.succ = “B” and “Z”.succ = “AA”. So, rather than converting numbers to letters, I ended up with a block like this:

column = "A"
(1..500).to_a.each do |i|
   puts "#{i} : #{column}"
   column = column.succ
end

Teague dancing…NO!

A few years ago, we used to listen to They Might Be Giant’s album called, “NO!” all the time. I captured Teague dancing to it one day. Be sure to watch all the way through.

Asher and the mint candy

mint candyLast night I was stacking the plates in the cupboard after unloading the dishwasher. Suddenly, one of the smaller plates shattered in the middle of the stack.

Upon closer investigation, I found that the plate was one that had endured one of Asher’s experiments a few years ago.

One morning I awoke to the smell of something burning. I rushed to the kitchen to find Asher with a small plate holding a pile of black ash. Groggy and confused I asked him what it was.

“I don’t want to say,” he replied and ran into the next room.

I could tell he was upset, so I backed off from scolding him. I asked why he was so upset. The poor little guy explained that he was trying to cook a mint in the microwave. He was very upset that it didn’t turn out the way he had envisioned it.

“How long did you cook it?”

“I pushed the ‘4′ button because I’m 4.”

So, in case you’re wondering how long it takes to turn a mint into a pile of ash (and probably catch fire), four minutes will work nicely.

After two years, the charred mark on the plate had almost completely worn off before the plate spontaneously burst into a hundred pieces. The stress must’ve been too much for it. I can’t blame it, though. Asher is glad to see it go. Ever since that fateful day, we made sure to give the same plate to Asher whenever we got out the small plates…just as a reminder that he shouldn’t play with the microwave.

Welcome Back, VW

These days, everyone is miles-per-gallon-conscious. Sam recently purchased a CNG-powered Honda Civic and has been very happy with it.

I’ve been researching the possibilities of a new vehicle to replace my tiring ‘95 Jetta (my fifth beloved oil burner). Sadly, the fuel economy of the latest VWs have been less-than-impressive. I’m not sure why the TDI Jetta was discontinued after the 2006 model. I had given up on VW.

This has steered my focus towards the Prius and Sam’s Civic. I’ve never really been a fan of the toy-like handling of Hondas and the Prius is just too pricey. (Anything over $20k is too high.) I’m also interested in a vehicle with more cargo room for trips to the (un-named) hardware stores, IKEA, etc. Dad’s Corvette has more trunk space than Sam’s new Civic. To make matters worse, this winter has heightened my awareness of the virtues of 4-wheel drive (something I’ve never had).

As far as fuel efficiency, I’ve set my targets on 40+ mpg. I’d also like to be able to fuel up in remote areas which aren’t equipped with CNG fueling stations.

Gather all of those requirements, and it is nearly impossible to find a vehicle on the market that fits my needs…until now…

VW Sportwagen frontIt hasn’t hit the market yet, but the new Jetta Sportwagen TDI certainly looks promising. The turbo-charged fuel injected diesel engine touts about 55 mpg on the freeway (most of my driving). The sporty tiptronic transmission and 4-motion traction system takes care of winter driving concerns (climbing out of a snow-packed ravine at Bear Lake). It has more cargo room than our Honda Odyssey and Sam’s old Pathfinder. It even has a nice rack.

Fueling up the sportwagen won’t be an issue, either. Diesel is readily available just about everywhere. (Previous TDI models have also been known to perform well on bio-diesel fuel should the need arise.)

I’m interested to see if it can tow a (very) small trailer with a snowmobile on it without too much extra effort. No, I don’t have one, but I think I need one.

I would also need to retrofit a reverse-facing seat in the way-back. Otherwise, what’s the point of having a stationwagon–right? Plus, then I could convince Laura that she needs one so she can dump her gas-guzzling Tahoe.

Some claim the tail end of the car is less visually appealing than the rest of the car. I’ll have to agree on that one. Maybe a really tall wing on back would spice it up.

The VW site does not have any information on pricing or availability, but rumors put it under $20k and the TDI version should hit the market towards the end of 2008 (as a 2009 model).

I need one.

Subversion with Active Directory Authentication via Apache

Laura–skip this one.

I recently started using Subversion at work. It has been popular enough, that several other employees have found a need for it. So, I decided I’d better figure out Active Directory authentication so I don’t end up maintaining a separate set of passwords for everyone.  It took quite a bit of trial-and-error. Here’s my Apache config for the subversion site:

<VirtualHost *:80>
ServerName svn.domain.com
DocumentRoot /var/svn/www
<Location /repos/>
DAV svn
SVNParentPath /var/svn/repos
SVNListParentPath on
AuthzSVNAccessFile /var/svn/svnaccess
AuthType Basic
AuthName “SVN Server”
AuthBasicProvider ldap
AuthzLDAPAuthoritative Off
AuthLDAPBindDN “DOMAIN\administrator”
AuthLDAPBindPassword password_for_administrator
AuthLDAPURL ldap://domain_controller:389/dc=ad,dc=domain,dc=com?sAMAccountName?sub?(objectClass=*)
Require valid-user
</Location>
</VirtualHost>

No, it is not a good idea to use your domain administrator in the config above. Do it for testing. Then, replace it with an account with read-only access in your domain.

Many of the examples on the web were geared towards non-Active Directory implementations. Those that were specific for AD still didn’t work until I removed the “cn=Users” from the first part of the ldapurl. Our users are not all part of the “Users” group. Removing this from the string means that all AD accounts can login. So, then I turned to the AuthzSVNAccessFile to fine-tune the access to the various repositories. Here is an example of that file:

[groups]
it=username1,username2
engineers=username3,username4

[:/]
*=r

[/]
*=r

[intranet:/]
@it = rw

[helpdesk:/]
@it = rw

[product_development:/]
@it = r
@engineers=rw

Have fun.