Wednesday, August 11, 2010

PRK - 11 weeks post surgery

Well, this is probably my last post on this topic.

I went to my eye doctor today and he is very pleased with the progress. My left eye is basically perfect, but my right eye has a very slight -0.025 diopter nearsightedness, but this is starting from over -8 in both eyes. He said the right eye is still healing and this is just the tail end of the process. I am now down to only doing the FML steroid drops once a day.

My observation is that my vision - especially at a distance - is spectacular! Not having minor optical distortions or smudges or scratches from glasses is great and having back all of my peripheral vision is also fantastic. One of the best items of recent progress was that I found I didn't need reading glasses to work on the computer and I could get all my screens back to their regular fonts sizes!!

There are still some downside. I do have haloing at night which is irritating while driving but should clear up over the next few months. I do have to wear reading glasses now for reading in bed or playing games on my iPhone. Having to remember my reading glasses so I can read menus at restaurants and so on is irritating. Hopefully this will get slightly better, but I expect this is something I may be stuck with at my age. I do need to keep using artificial tears regularly, but my eyes don't seem to feel dry or uncomfortable except at the end of a long day.

When I was researching the procudure I found several useful diary blogs like this through Google. So, for those who might come upon this blog from the interwebs looking for info on PRK surgery, here are links to all the entries in sequential order:
It's been quite a journey!

Thursday, August 5, 2010

Arduino-Twilio Dialer Application

Well, it has been a while since I posted an Honest-to-God Arduino project here! What with getting my eye surgery done and one thing and another, this has taken me quite a while. Besides, there were more than a few challenges in getting it all to work along the way!

This project is a concept for an information kiosk or unit that could be placed in a public area where passers-by could request information. A user enters their mobile phone number into the keypad and they are then immediately called by the Twilio cloud-based telephony system (check out Twilio here) and presented with a simple phone menu that allows them to:
  1. Talk to an operator
  2. Leave a voice message
  3. Receive an SMS message
Here is the hardware in it’s not very pretty form:








































Here is the obligatory video showing how it works:




Hardware

The hardware consists of:
  • Arduino Duemilanove
  • Arduino Ethernetshield
  • Sparkfun serial enabled 20 x 4 LCD display (LCD-09568)
  • Sparkfun 12 button keypad (COM-08653)
Here is the circuit diagram:


The hookup of the keypad is based on this article by amando96 on Instructables. You will have to sign up for membership to see the whole article or you can just follow the above diagram. One odd thing I noticed was that the pull down resistors turned out to not be required. Originally I had them included and everything worked fine, then at a certain point in the development the keypresses started looping and I removed the resistors and everything worked fine!

This just uses the standard “keypad.h” library found on the Arduino website, but slightly modified so the pins do not interfere with the Ethernetshield. There is also an Instructable post on multiplexing the button input to use fewer digital pins, but since I didn’t need any extra digital pins I figured this was simpler.

The serial LCD is quite straightforward to hookup, but just note that I am using one of the A1 Analog pin as the Tx for the serial since I am not using any analog inputs anyway.

Software

As with the previous Twilio-Arduino project, this one requires:
  • An account with Twilio 
  • A web-server with PHP
  •  An Ethernetshield
The Arduino communicates with one PHP script running on my web-server, this then triggers Twilio to set up a call and Twilio then goes to my web-server and checks for another PHP file on what options to present to the user. It is a reasonably complex mesh of files that need to be setup, but actually the Twilio XML programming was easily the simplest part of the setup.

This diagram shows the overall flow:





The first part is the Arduino software:





/*
*  Twilio Arduino Information Service Dialer
* When used in conjunction with "dialer_twilio.php PHP script and the Twilio cloud-based
* telephony environment (www.twilio.com) this allows a user to enter a phone number into a keypad
* on an Arduino and have a call placed to their cell phone with various options for information.
*
* Uncomment the //Serial lines for troubleshooting/debug info.
*
* This code is in the public domain. Please provide credit if it is used
* in another project.
* 
* written by Chris Armour, August 4th, 2010
*
* Full description psted at http://opensource-torchris.blogspot.com/
*
*/

//=====================Libraries=============/
#include 
#include 
#include  
#include 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //MAC address for Arduino
byte ip[] = { 192,168,0,34 }; // IP address you wish to assign to Arduino
byte server[] = { 192, 168, 0, 171 }; // IP address of your PHP server
int ServerPort = 55455;
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
boolean ConnectedState = false;
char DialNum[12]={"xxxxxxxxxxx"};
int a;
NewSoftSerial mySerial =  NewSoftSerial(14,15); //osft serial running off of Analog Pin 1

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
Client client(server, ServerPort); 
TextFinder finder( client);

void setup(){
  Ethernet.begin(mac, ip);
// Serial.begin(9600);
  mySerial.begin(9600); 
  mySerial.print(254, BYTE);
  delay(100);
  mySerial.print(1, BYTE);
  delay(100);
  mySerial.print("Started - Press any key to conect to the server."); //Display initial message on LCD.
}
  
void loop(){
    
  char key = keypad.getKey();

  if (key != NO_KEY){
    if (ConnectedState == false){
       if (client.connect()){      
         if(finder.find("results:") == true){
           char c = client.read();
         // Serial.print("Value of the connect code: ");
         // Serial.println(c);
           mySerial.print(254, BYTE);
           delay(100);
           mySerial.print(1, BYTE);
           delay(100);
           mySerial.print("Connected. ");
           delay(2000);
           WelcomeMsg();    
           //If connection successful, then print Welcome Msg and flip the connected state variable.
           ConnectedState = true;
         // Serial.println(DialNum);
           }
       }
       else {
       ConnectedState == false;
       ConnectFailMsg(); //If connection fails, then print an error.
       delay(2000);
       }
    }
    if (key == '*') {
    //When it picks up the "*" then it starts gathering the digits.
    // Serial.println("Got the *");
      EnterNumMsg();       
      do {
        key = keypad.getKey();
        if (key != NO_KEY){
          delay(150);
        // Serial.println(key);
          mySerial.print(key); //Prints the keypad input to the LCD for user feedback.
          DialNum[a] = key; //Puts the key info entered into an array.
          a++;
          }

        } while (key != '#');
        
      }
      if (key == '#'){
        //When the "#" is pressed, the info is sent over to the PHP script.
         delay(250);
         mySerial.print(DialNum);
         client.println(DialNum); //Dialnum array sent to PHP.
         if(finder.find("results:") == true){//PHP script evaluates number & sends back response.
             char c = client.read();
           // Serial.print("Value of the return code: ");
           // Serial.println(c);
             if (c == 'Y'){//Y back from the script means it is a valid number & success displayed.               
               NumAcceptedMsg();
               }
             if (c == 'N'){//If it is not a valid number, then N returned & error displayed.
               NumNotAcceptedMsg();
//               client.println(DialNum);
               delay(3000);
               WelcomeMsg();//Go back to Welcome message.
               }
         delay(200);
         if(finder.find("results:") == true){
             char c = client.read();
           // Serial.print("Value of the return code: ");
           // Serial.println(c);
             if (c == 'O'){//If the call was successully placed display success then go back to Welcome.
              NumCalledMsg();
              delay(4000);
              WelcomeMsg();
         }
          if (c == 'X'){//If the call couldn't be made then error message & return to welcome.
              NumNotCalledMsg();
              delay(3000);
              WelcomeMsg();
         }
        } 
   
  // Serial.println(DialNum);
  // Serial.println(a);
    a = 0;
      }
    }
  }
}

void WelcomeMsg(){
       mySerial.print(254, BYTE);
       delay(100);
       mySerial.print(1, BYTE);
       delay(100);
       mySerial.print("Welcome to the      Information service.Press the * key to  start.");
  }
    
void EnterNumMsg(){
       mySerial.print(254, BYTE);
       delay(100);
       mySerial.print(1, BYTE);
       delay(100);
       mySerial.print("Enter your 10 digit phone number        followed by #:      ");
}  

void ConnectFailMsg(){
       mySerial.print(254, BYTE);
       delay(100);
       mySerial.print(1, BYTE);
       delay(100);
       mySerial.print("Connection Failed.  Press any key to    reconnect.");
}

void NumAcceptedMsg(){
      // Serial.println("Number accepted by server");
         mySerial.print(254, BYTE);
         delay(100);
         mySerial.print(1, BYTE);
         delay(100);
         mySerial.print("Number Accepted. ");
}

void NumNotAcceptedMsg(){
        // Serial.println("Number NOT accepted by server");
           mySerial.print(254, BYTE);
         delay(100);
         mySerial.print(1, BYTE);
         delay(100);
         mySerial.print("Number not valid.");
}

void NumCalledMsg(){
            // Serial.println("Number called successfully.");
               mySerial.print(254, BYTE);
               delay(200);
               mySerial.print(1, BYTE);
               delay(200);
               mySerial.print("Number called       successfully.");
}

void NumNotCalledMsg(){
// Serial.println("Number cannot be called.");
  mySerial.print(254, BYTE);
               delay(100);
               mySerial.print(1, BYTE);
               delay(100);
               mySerial.print("Number cannot be    called.");
}


This uses the Arduino Ethernet library to set up a client application, the Keypad library to get the keypresses, NewSoftSerial to send information to the LCD and finally the TextFinder library to parse the result codes from the server. I have put all the LCD messages into functions just to clean up the code since each message needs to have a screen clear send and some delay. I’m sure I could further clean that up to just have a function that did the screen clear, but this works.

The Arduino client in term communicates with the PHP server program (dialer_twilio.php):


request("/$ApiVersion/Accounts/$AccountSid/Calls", 
     "POST", array(
     "Caller" => "XXXXXXXXXXXXXXX",
     "Called" => $dial_num,
     "Url" => "http://xxxxx.xxxxx.xxx/twi_test.php"
    
    ));
    if($response->IsError){
     echo "Error: {$response->ErrorMessage}\n";
   socket_write($spawn, "results:X\n");
   echo "Sent over X\n";
  }  else {
     echo "Started call: {$response->ResponseXml->Call->Sid}\n";  
   socket_write($spawn, "results:O\n");
   echo "Sent over O\n";
   }
} else {
  echo ("Invalid number\n");
  socket_write($spawn, "results:N\n");
  echo "Sent over N\n";
 }

   usleep(5000);
}
}while(true);

?>




Anything marked “XXXX” above is info on the account and phone numbers to be used.

This script does a quick and dirty check if the number is valid (just making sure there are no stray “x” or “#” characters and it is the right length) then uses theTwilio REST API to  set up the call. Twilio will go to the “twi_test.php” script for info on how to handle the call.

So, when Twilio goes to twi_test.php it sees:




    header("content-type: text/xml");
    echo "\n";
?>



    Hello. Welcome to the Arduino Information Service.
    Press 1 to be connected to an operator.
    Press 2 to leave a voicemail.
    Press 3 to receive an SMS message.
    Press 4 to repeat this menu.
    Press 5 to hangup.


This sets up the top level menu of the simple IVR and then directs to go to “twi_action.php” once a button is pushed. The XML such as and are the Twilio “verbs” that defines actions on the Twilio cloud system.

So here is “twi_action.php";


$stringData = $_REQUEST['Digits'];

switch($stringData){
case 5:
    echo "";
    echo " Thank you, Good bye.";
    echo "";
    echo "";
    break;
case 4:
    echo "";
    echo "";
    echo "http://xxxxx.xxxxx.xxx/twi_test.php";
    echo "";
    echo "";
    break;
 case 3:
    echo "";
        echo "You are being sent an SMS message.";
        echo "You are receiving this message from the Twilio Arduino dialer application.";
    echo "";
    break; 
case 2:
    echo "";
    echo "Leave your message after the tone and press # when you are done.";
    echo "";
    echo "";   
    break;
case 1:
    echo "";
        echo "XXXXXXX";
        echo "Goodbye";
    echo "";       
    break;
}

?>


This parses the digit pressed from the POST command and then takes action on the digits, which is either:



  1. Connect to an operator (in this case it dials through to my Skype account).
  2. Leave a voicemail. Currently this records a sound file which you can download from the Twilio website, but it could also have the sound file sent to an email address or transcribe the voice into text and have that sent along.
  3. Receive and SMS message. This sends a canned message that could be some general information to the cell phone that made the call.
  4. Repeat the menu.
  5. Hangup.
The final small script is the one that handles the voicemail recording (voicerecorder.php):



    header("content-type: text/xml");
    echo "\n";
?>

    Thanks for the message.  Here is what you recorded.
    
    Goodbye.


This one is very simple. It just plays back the message that was just recorded. That’s all there is to it! :-)

Conclusion

This project could have some practical uses as a low cost way to place a simple information service in some public place. It does, however, have the obvious limitation that there is no validation that the number entered really does belong to the user’s cell phone and not to some little old lady in Detroit, so in it’s current form it could just be a nuisance generator. This could probably be fixed with an exchange of a PIN via SMS.

What other things could this kind of project be used for? Here are some ideas:


  • Make a super secure lock by combining this project with an RFID reader lock so that once the card is swiped the user also has to enter a PIN and a code received via SMS at a cell phone that has been pre-registered with the system. This way an intruder would have to steal not only the users RFID badge, but also their phone and their PIN number.
  • This could also be adapted to trigger phone calls or SMS messages for various conditions driven by digital or analog inputs - such as temperature readings or intruder alarms. Conversely, as discussed in my Twilio LED project, a call could be used to control switches, motors or valves remotely using a telephone.
  • If it used Power Over Ethernet it would eliminate the extra power supply requirement. Even better would be using wi-fi or GSM cellular data to eliminate the need to have it wired to a router.
  • Clever use of the PROGMEM would probably allow all the response strings to be stored on the Arduino so it might be possible to dispense with using an outside webserver altogether!
This was a pretty challenging project and I hope it provides inspiration for some further cool projects!


Friday, July 9, 2010

PRK - 5 weeks post-surgery

Wow, two blog posts in two days! Yes, there is an Arduino project in the works, but it's moving slowly!

Anyway, today was my five week checkup so it seems like a good time to give an update on my eyes. Things are continuing to go well. My doctor says I am starting to be able to read the 20-20 lines of the charts and everything is healing very nicely,

From my unscientific perspective, things have been going well especially this week. Lat week I was getting bad headaches almost everyday from eye strain, but this week things have gotten really much clearer and I haven't had a headache in days. I do now wear some store bought reading glasses when working on the computer or reading, but I can do pretty well without them. Maybe the heat wave helped somehow? Basically, the improvements are now on a week-by-week basis rather than daily, but improvements are still happening.

The best thing was being able to swim in our pool without having to worry about "where did I leave my glasses" and being able to dive and see underwater with a mask! Wow! It really does make me realize how profoundly blind I was without my glasses before.

Thursday, July 8, 2010

Home Coffee Roasting

Since this blog is basically about any interesting project or skill I can pass along, I figured people might also be interested in learning about how to roast their own coffee in the comfort of their back deck!

Over the years we have gotten used to coffee roasting and production being a huge industrial process or else done by specialist boutique-y roasters with special machines and a fancy appreciation for roasts and blending. While it is true that roasting in bulk or hitting very exact roast points does require some specialist skill and machinery, the reality is that coffee roasting really isn't too hard - probably not much more difficult than making pop corn - and the results of really fresh, fresh roasted coffee make up for any imperfection in the home roaster's skills.

A great book on the subject is "Home Coffee Roasting: Romance and Revival" by Kenneth Davids which is available from Amazon in Canada here.

Here is a quick video of me roasting a batch of coffee on my barbecue using a big iron frying pan. As usual, I am sorry for the muddy audio!



With the lid opening and closing cycles, the total process is about 10 or 12 minutes.

Note: It is important to do this outdoors! The process will generate lots of pungent blue smoke that will fill up your house in no time. Also, it works best with the really high heat from a good gas barbecue.

Tools and materials:

Here is what you will need at least the way I do it (there are lots of variations):
  •  Green coffee beans - these can be bought from Whole Foods in small batches to play with. For more variety and if you are in Canada I would recommend the Green Beanery . They have a very cool store in downtown Toronto and also great online ordering. Some Googling would find other suppliers too. Green beans will store in a cool place for over five years!
  • A big cast iron frying pan. I believe I got mine from Canadian Tire (here). Often they are sold in the camping section. Do not use a non-stick pan! The high temperatures would ruin the Teflon coating.
  • A metal colander to hold the beans after they are roasted. It must be metal! The beans will be over 500 degrees Fahrenheit when they are done.
  • A long handled metal spatula for stirring the beans.
  • Bowls and containers for the beans
  • Very stout pot holders - I use silicon oven mitts.
  • If you want to be fussy, a scale to weigh the beans out.
  • A coffee grinder to process your roasted beans.
  • That's about it!!
Process:

It's really pretty simple!
  1. Put the pan on the barbecue and get it as hot as you can! Just leave it dry with no oil or anything in it. Close the lid and let it get up to at least 500 degrees F.
  2. Measure out enough beans to cover the bottom of your pan. For me that's about 1/2 lb (250 gm).
  3. Put the beans in the skillet and make sure they are in an even layer and not bunched up. The idea is to try to roast the beans as evenly as possible.
  4. Close the lid and let the heat build up for a little while - maybe one minute.
  5. Open up the lid and stir the beans around - especially try to flip them over so the tops and bottoms get heated.
  6. Close the lid!
  7. Open it up again and stir.
  8. This cycle will continue for a while until you start to hear a bit of a crackling sound and see the beans start to smoke. This is called "First Crack".
  9. Keep opening and closing and you will see the beans pass from greenish, to yellow to light brown and then start to get darker and darker and bigger and bigger. Interestingly, the smoke doesn't really smell a thing like the "fresh roast coffee" smell we are all used to from cafes and so on - it is more pungent - like burning a piece of toast with motor oil.
  10. When the beans start to darken is when you need to use a bit of judgement - do you like lighter roasts or darker espresso or French roasts? Generally, when you hear an increase in crackling and see more smoke you are at "Second Crack". A this point you can leave them in a few seconds later before dumping them out if you want them to be a darker roast. Remember! The beans have so much internal heat built up, that they will roast a bit even after they are dumped out! You need to stop a bit before the final darkness of roast you want to achieve. This is really the hardest "art" of the whole roast.
  11. When they are ready, dump the beans out into the metal colander and stir them up to move air through them and cool them as quickly as possible. You can also give a quick spritz of water - but not too much!
  12. Once the beans have cooled down you can grind them and their peak flavor is actually about 24 hours after they are roasted and they will keep super fresh for up to two weeks. It is important to not store freshly roasted beans in a tightly sealed container - especially a glass one - since they will continue to out gas for a couple of days after roasting.
That's about it! 

Friday, June 11, 2010

PRK - 2 weeks post surgery

Well, today is two weeks and I just had a followup with my doctor, so it seems like a good time for a progress report...

In general, things are proceeding and each day is still slightly better, but then some days are better than others and the improvements are smaller. I do still get blurry vision, dry eyes this gives me a headache sometimes (like right now) - especially since my job requires a lot of computer screen time. At the end of the day it feel like I have had my contacts in for too long and it's time to take them out, but then I remember that isn't an option! On the other hand, I can drive again and when my vision is completely clear it is spectacular.

My eye doctor says everything is healing perfectly and looks great, but that it will likely take the more like 3 to 6 months for everything to fully clear up. The residual blurriness and so on is apparently because of minute swelling of the cornea as part of the recovery process. Naturally, I would have liked everything to be perfect by the end of two weeks, but my doctor makes the perfectly valid point that I did have 25% of my cornea blasted away by a laser and that takes some time to heal. A friend of mine who had PRK recommends keeping well hydrated, which does seem to help and is just good advice in general!

Friday, June 4, 2010

PRK - 1 week post surgery

So, it has now officially been a week post-surgery and things continue to progress albeit not in a completely linear fashion.

Today I realized I could once again read small magazine text without reading glasses and I was able to bump down the font sizes on my computer for the first time. Still, it is hard to work at the computer screen for extended periods and moving to focus from close to far objects is tough. I also still have halo'ing. My vision also seems to be clearer when I yawn, which I expect is because of the effect of tearing up slightly when I yawn. I also have to do lots of artificial tears.

Still, on the positive side, things are getting better each day and I am really liking have peripheral vision again like I did when I wore contacts many years ago! Not having to reach for my glasses in the morning or middle of the night is pretty cool. I am still getting used to my non-glassed face in the mirror when I shave. My wife says it is definitely a transition for her since she has only ever known me with glasses!

I also wanted to thank the two people who more than anyone (well, besides my surgeon, eye doctor & wife) have contributed to my recovery - Tom and Ray Magliozzi from Car Talk on NPR. I downloaded I don't know how many episodes of the show onto my iPhone and I've listened to them all back-to-back - especially earlier on when I pretty much couldn't do anything! If you aren't familiar with them, check them out at cartalk.com. I'm just waiting for my car to make a weird noise so I can call it in and have them laugh at me!

Wednesday, June 2, 2010

PRK - Post Surgery Day 5

Quick update today...

My doctor (and most of my reading on the surgery) said the recovery would not be linear and I guess today was the non-linear day. Things that were quite clear yesterday are very blurry again today - for instance I totally can't read the house addresses across the street. Even a moderate amount of computer work is very fatiguing and I have had to take some Tylenol for a headache.

Well, I will keep the faith that this will sort out over the next few days as everyone has promised. Tomorrow I am starting back to work, but I will definitely have to take frequent rests from the computer screen now and then.

I also picked up a pair of reading glasses today and for the 1st time got to utter the immortal phrase "Honey, have you seen my reading glasses?" Fortunately they weren't balanced on my forehead or something at the time!