Monday, October 2, 2017

Garage door opener...or what engineers do.

Heidi got an awesome shirt for me:


So here goes:

I was really tired of my garage door openers working sometimes but not others, and I was totally inspired by my dad redoing his garage door openers with some cool arduino stuff so.

I got:
I already had some wires to connect it all, a hot glue gun, some glue, and some solder and a soldering iron.

The goal was:
  • Spin up a webserver on the ESP8266
  • host a web page with a button to trigger the relay
  • detect if the garage was open or closed and display that on the web page.
Here is the basic wiring diagram

Note that this is an AdaFruit Huzza not my beloved NodeMCU but it's what I had in my fritzing library.

Largely this was not a difficult project except that my soldering skills are not up to snuff yet.

I ran into one gotcha...that is that the 0 pin, D3 on the NodeMCU is triggered when A) the board is being programed or B) power is restored after an outage.  The problem with that is, if I used the 0 pin for the relay, it would get triggered every time the power came back on.
Fortunately the 4 and 5 pins do not have multiple uses and therefore do not trigger on boot, or flash, so I switched the relay to pin 5 and all is well.

I used the phone cord between the NodeMCU and the ultrasonic sensor since I wanted to be able to unplug it at will and I needed a fairly long run. I split the coupler, and soldered one end onto the node, and the other to the sensor, then just ran a $1 phone line between them.

I also  put in a quick plug for the relay to the garage door opener so I could pull it down whenever necessary.

Here is the code:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Ethernet.h>

MDNSResponder mdns;

// Replace with your network credentials
const char* ssid = "MYSSID";
const char* password = "MYNETWORKPASSWORD";

ESP8266WebServer server(80);

String webPage = "";
String webPageOpen ="";
String webPageClosed = "";

int switch_pin = 5; //D1 on nodeMCU
int echo_pin = 0; //D3 on nodeMCU
int ping_pin = 4; //D2 on nodeMCU
int garageStatus = 0; //closed is zero
int minDistance = 10; //inches from sensor
long duration,distance;


void setup(void){
  webPage += "<html><head><title>phatGarage</title>";
  webPage+="<style>";
  webPage+=".button {";
  webPage+="text-align:center;background-color:#000000;color:#FFFFFF;padding:10px;margin:auto;-moz-border-radius: 10px;-webkit-border-radius: 10px;width:200px;height:100px;";
  webPage+="}";
  webPage+="</style></head>";
  webPage+="</head><body><div style=\"max-width:250px\"><a href=\"toggleg\"><div class=\"button\"><h1>Garage Door</h1></div></a><hr/>";
  // if garage is open:
  webPageOpen = webPage;
  webPageOpen += "<h1 style=\"color:red;text-align:center;\">Garage is OPEN</h1><!-- close full page div--></div>";
  webPageOpen += "</body ></html>";
  // if garage is closed:
  webPageClosed += webPage;
  webPageClosed += "<h1 style=\"color:black;text-align:center;\">Garage is Closed</h1><!-- close full page div--></div>";
  webPageClosed += "</body ></html>";

  //Close off clean web page if we need it:
  webPage += "<!-- close full page div--></div></body ></html>";
  
  // preparing GPIOs
  pinMode(switch_pin, OUTPUT);
  digitalWrite(switch_pin, LOW);
  pinMode(ping_pin, OUTPUT);
  digitalWrite(ping_pin, LOW);
  
  delay(1000);
  Serial.begin(9600);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  if (mdns.begin("esp8266", WiFi.localIP())) {
    Serial.println("MDNS responder started");
  }
  
  server.on("/", [](){
    if (garageStatus == 0){
      server.send(200, "text/html", webPageClosed);
    }else {
      server.send(200, "text/html", webPageOpen);
    }
  });
  server.on("/toggleg", [](){
    if (garageStatus == 0){
      server.send(200, "text/html", webPageClosed);
    }else {
      server.send(200, "text/html", webPageOpen);
    }
    digitalWrite(switch_pin, HIGH);
    Serial.println("switch on");
    delay(1000);
    Serial.println("switch off");
    digitalWrite(switch_pin, LOW);
  });
  server.begin();
  Serial.println("HTTP server started");
}
void loop(void){
  //This does a DNS update if necessary
  Ethernet.maintain();

  //Test distance from sensor:
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(ping_pin, OUTPUT);
  digitalWrite(ping_pin, LOW);
  delayMicroseconds(10);
  digitalWrite(ping_pin, HIGH);
  delayMicroseconds(5);
  digitalWrite(ping_pin, LOW);
  // The echo pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echo_pin, INPUT);
  duration = pulseIn(echo_pin, HIGH);
  // convert the time into a distance
  distance = microsecondsToInches(duration);
  //if distance is too close, the garage door is up and being sensed by the sensor, otherwise the sensor is detecting the car or ground which is further away
  //this may need tweaking if the sensor is picking up the suburban as less than 10 inches away.
  if (distance < minDistance){
    garageStatus = 1; //the sensor sees the garage door
  }else{
    garageStatus = 0; //the sensor does not see the garage door
  }
  //Handle any requests to the webserver
  server.handleClient();
  

long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

This was a super fun project, although I'm sure Heidi did not love all the time it took this afternoon...

Tuesday, May 30, 2017

More fun ways to "spend" time

So after making an arcade console and getting the kids hooked on great old video games, I saw this set of videos from Bob at http://www.iliketomakestuff.com
Arcade Cabinet Part 1
Arcade Cabinet Part 2
Arcade Cabinet Part 3


Parts 1 and 2 were informative, but part 3... A human sensor that turns the lights on and off!!! Must have!

So I started playing with an arduino uno board, (really fun) but then I got to playing with this little creature:
  you can learn more here: https://en.wikipedia.org/wiki/NodeMCU

It took a bit of fiddling to get it to work so I wanted to capture that on the blog for later use.

First I had to get drivers here: https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

Once I had the drivers, I plugged it in and got a new terminal device: /dev/tty.SLAB_USBtoUART
So then I had to set up the Arduino IDE:
I opened preferences and added http://arduino.esp8266.com/stable/package_esp8266com_index.json to the Additional Boards manager URLs:
Clearly I did this on my mac, but it is similar in WinDOZE.

At that point I could open the boards manager:

And install the esp8266 boards by clicking the install button next to version 2.3.0:

Finally I could select the NodeMCU in the IDE user interface under tools:
and select the right port:
pushed it to the chip and ran > screen /dev/tty.SLAB_USBtoUART 115200
and lo and behold, a web server with my own custom code that actually turns my led's on and off!



How absolutely amazing!!!
Next up: get my relay working with this board, connect up the sensor, add a few buttons to turn things on and off via this web client...

Good stuff and so fun to learn something new!


Fun ways to waste time

So, for my birthday I got a Raspberry pi 3, with a case, and a power supply, and I had to immediately set it up.

I tried OSMC with Kodi
I tried straight up Raspbian
And then I found RetroPie!!!

I was completely sold. Old school games, Kodi, nice interface,
So I set the whole thing up with XBox 360 USB connectors, it was cool...but playing those old games I wanted the arcade feel: Hearing "Full point" in Karate Champ is not quite as amazing when you had to use the D-Pad and the ABXY buttons.

So I did what any one else would do, I ordered 4 joysticks and 40 buttons and 2 two player PCB boards that attach via USB, and a trackball, oh and 2 more LED joysticks (for Karate Champ!) and an OrangePi PC so I did not have to cannibalize the RPi media center.

I was excited , the OPi is:

  • Slightly faster than RPi 3 at 1.6 ghz vs 1.2
  • Has the same RAM
  • A Mic for Alexa support
  • An IR chip
  • It was only $27 with a case and power cord!


Sadly:

  • OS support is very poor 
  • The video drivers are closed source so no HW acceleration which unexpectedly makes big difference to the emulators.
So...
I built this:
The RPi found its way into this beast.  It took a ton of troubleshooting to get it to recognize both players on the separate joysticks (this post explains why) 
FYI, this is the quirk code for this unit: 

usbhid.quirks=0x0810:0xe001:0x40

It still needs a little love.  I have the second joysticks for player 1 and 2 (in the middle) to put in (they light up with LED lights!). The usb to PS2 connector for the track ball will be here shortly so it can go in. There are a couple of games that don't work quite right yet, but it is really close to functioning as expected...

Then I have to make it pretty with paint, some hot pink T-molding, and this beautiful vinyl overlay from Metro Styling (mine is that full image, but 16 inches x 5 feet): 



Then for the rest of the cabinet, I think I am going to mount it on top of a mini fridge, then fill it with Cherry Coke so that my love will enjoy it a little more.

The coolest part is seeing the kids totally into Mrs. Packman, or Galaga, or to hear them playing 4 player X-men or Teenage Mutant Ninja Turtles together (I haven't quite got them hooked on Gauntlet yet but there is still time).