I've done a lot of "Smart Home" things over the years. Unquestionably however, one reigns supreme over all else. And apparently my wife agrees; the automation I wrote to unlock the door from the garage into the house when the "car" garage door opens.
So, when MyQ decided to block out basically any company not sending them kick backs, and thus breaking my automation both myself and my wife were a tad annoyed. I had paid like $150 a few years back for an external control to make the garage door opener smarter.
Most people in my boat jumped to Ratgdo, a new garage door opener or some other solution. Only, many other solutions don't work with my archaic garage door opener and I'm not installing a new one in the middle of Canadian winter.
So, I ordered a Ratgdo (I know, I made it sounds like I wouldn't do that). It doesn't quite work with my garage. Or rather it works with my garage to the extent that it advertises that it will. Which is to say, I can open and close the door. Honestly, and this is my main beef with a lot of smart home tech... I don't really care about fancy ways to open the door. I'm perfectly happy with the button on the wall and the remote in the care. 99% of the time, I use those.
What I care about is having access to the data and events so that I can use those to control other aspects of my smart home. Like knowing if the door is currently open or close or being able to trigger an event off of it opening or closing. Those things sound INCREDIBLY mundane. And, if you smart home is just a garage door, then they probably are. My August smart lock automatically locks itself. And unlike they broke the integration, it also unlocked itself automatically anytime we got home. Never having to type in a passcode or find a key when you get home, but knowing that the house is locked the rest of the time; that is pretty awesome. And convenient.
I will be replacing the garage door opener in the spring and reusing the Ratgdo when I do. I'll be getting a model where the Ratgdo can wire in and both control and report status. At which point I won't need my current solution.
Which brings me to the current solution. Wanted to write about it because it was a pretty fun experience.
Part 1 Ratgdo and "Failure"
It started with buying the Ratgdo. It arrived earlier in the week. I wired it in. It could control the garage door just fine. It couldn't tell me when it was open. So, I had been cooking up another little add on. I had the idea before it arrived that I could use a transistor controlled by an Arduino to the trigger the pull up sensor on the Ratgdo which could make that determination using an ultrasonic sensor. The code was basically a few extra variables and if statements wrapped around the stock code for that component which came with the kit.
The first shock; when I wired it up on my desk... everything worked first try. Doubly surprising with my questionable soldering skills.
The second shock; nothing worked when I wired it up in the garage.
Part 2 Iterate
I like failure. It forced me to iterate and improve and think things through a little better. The original design was "ok". But, I had a lot of concerns and things were very complicated. Eventually, I found some of the sources of my setbacks:
- I had accidentally broken/lost one of the wires for the obstruction sensors which rendered the garage incapable of closing.
- Something, I'm still not 100% whether it was interference, bad wiring or some conflict induced by trying to run my hack solution when the board was attached to the GDO.
At this point I started making minor improvements on the design. I zip tied the sensor to the body. Added some strain relief to a number of the more questionable wires and came up with a better mounting solution.
Part 3 Abandon Hope
Not really. I just abandoned controlling the GDO with the Ratgdo. Instead, I decided to focus on the important functionality. The Ratgdo gave me a wifi connection and talked to MQTT in a way home assistant could understand. My device could still supply the logic to notify when the door opened.
And... still couldn't make it work.
Part 4 Simplify
I went back to the drawing board a few times. Sometimes the sensor would just freak out. And when I could get a solid signal it seemed impossible to get it to work when it needed to work.
During this process, I discovered a few things:
- My Arduino board had an extra 3.3v pin which the Ratgdo could use
- My car was the reason I couldn't get a good reading
- If the board isn't controlling the GDO, then I doesn't need to hand from the ceiling
Powering the Ratgdo from the Arduino meant removing an extra power brick and the ability to just strap that the back of the case I had printed for the Arduino. It also meant EVEN MORE STRAIN RELIEF! I was able to shorten some wires and secure some a bit better. All of this making installation and removal quicker which was good considering the number of failures. At this point I had probably installed and uninstalled 20+ times. It is cold out there and you apparently use a lot of leg muscles while getting up and down and hanging around on ladders.
The second one was more surprising. My best guess is that the car roof is curved JUST ENOUGH to totally mess with the ultrasonic sensors. It still doesn't make any sense to me. But then again, it isn't as though I even know what the device was reading. I just knew that, for some reason, when the car roof was in the way, my sensor thought the garage door was open and obstructing the sensors from a much closer distance.
Regardless, it finally dawned on me. I had been climbing up and down the ladder because the project started out with the Ratgdo attached to the GDO which meant I needed the sensor up high as well. Once I abandoned controlling the GDO, I should have realized MUCH sooner that it would be much easier to just mount the sensor elsewhere.
Ultimately, I decided on a cupboard hanging on the wall under the garage door. There is an outlet nearby and I can just point it up. The garage is about a foot away from the sensor when open and the ultrasonic sensor is pretty damn accurate between like 0-60cm. So, it is pretty damn reliable here. It was also much quicker to take it back in to reprogram it the one time I needed to (needed to adjust my target distances after taking it off the roof).
Final Design
I have an Elegoo Uno R3 board that came with a sensor kit. It is using the HC-SR04 ultrasonic sensor that came with the kit. It is wired up exactly the same as recommended in the guide. I could change the two pins it uses for IO from the sensor, but had no real need/reason to do so.
The code sets a distance threshold. I think I went with 45cm. If the distance read is lower than that, it means that the sensor believes that the door is open. The sensors aren't the most reliable, so I take the average 50 readings as a single reading. Then, to further filter out any potential noise, when a reading would result in a change in state, I need 10 consecutive such readings before I accept it. When I detect that the door is open I set the output pin I use to drive the Ratgdo to HIGH, otherwise, low.
That pin is connected to a transistor. Ratgdo uses a pull up to ground approach. So, the other two ends of the transistor are wired to the "Open" status pin and the ground pin on the Ratgdo. When I write the HIGH signal out it allows the connection from Open status pin to short to the ground pin telling it that the door is open. This allows me to report that the door is either "open", or "closing". I could add a second transistor to indicate closed. However, I don't personally need to differentiate between open, opening, closing and closed. I just need 2 states.
The Arduino and sensor are both in enclosures I 3D printed from designs I found on Thingiverse. I then zip tied the sensor housing to the top of the Arduino housing. The Ratgdo is zip tied to the back of the whole thing. Much of the wiring if VERY lame. The sensor, power lines and out to the transistor are all just plugged into the Arduino using the bread board still male-to-male wires or male-to-female wires in the case of those connected to the sensor. Hence the desire for LOTS of strain relief. They could come out quite easily.
I cut some wires and soldered then for the transistor. I didn't really have many options on that front, and it mean a slightly better connection. Though, still, strain relief.
Code for the sensor is here. No license, free to use. Mostly for my own reference:
/*
Use ultrasonic sensor to detect state of Garage Door and output signal via pins
*/
// defines pins numbers
const int PIN_TRIG = 9;
const int PIN_ECHO = 10;
const int PIN_OPEN_DOOR = 2;
// If sensor reads less than this value, it means that the door is close to the sensor and the garage door is open
const int MAX_DISTANCE_DOOR = 45;
// Generate a sample of a certain size so that we don't get too much noise in the data
const int DETECTIONS_PER_SAMPLE = 25;
// defines variables
long duration; // Travel duration
int distance; // Calculated distance
int lastOpen = LOW; // Open door pin state
// Sum of the current samples and the number of readings in the sample
int sampleSum = 0;
int detectionCount = 0;
// For the light status to change, we should need some number of consecutive hits indicating that it actually changed
int consecutiveHits = 0;
int requiredConsecutiveHits = 10;
void setup() {
pinMode(PIN_TRIG, OUTPUT); // Sets the trigPin as an Output
pinMode(PIN_ECHO, INPUT); // Sets the echoPin as an Input
pinMode(LED_BUILTIN, OUTPUT); // Hi-jack the board LED
pinMode(PIN_OPEN_DOOR, OUTPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}
void loop() {
readDistance();
if (detectionCount >= DETECTIONS_PER_SAMPLE) {
distance = sampleSum / detectionCount;
sampleSum = 0;
detectionCount = 0;
update(distance < MAX_DISTANCE_DOOR);
Serial.print("Current reading: ");
Serial.print(distance);
Serial.println("cm");
}
}
bool update(bool setOpen){
bool wasOpen = lastOpen == HIGH;
bool changed = true;
if ((setOpen && lastOpen) || (!setOpen && !lastOpen)){
changed = false;
consecutiveHits = 0;
}
else {
consecutiveHits++;
Serial.print("Consecutive: ");
Serial.println(consecutiveHits);
}
if (consecutiveHits < requiredConsecutiveHits){
changed = false;
}
else{
lastOpen = setOpen ? HIGH : LOW;
changed = true;
}
if (changed){
digitalWrite(PIN_OPEN_DOOR, lastOpen);
digitalWrite(LED_BUILTIN, lastOpen);
}
return changed;
}
void readDistance(){
// Clears the trigPin
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(PIN_ECHO, HIGH);
int currentDistance = (duration * 0.034 / 2);
sampleSum = sampleSum + currentDistance;
detectionCount++;
}
Comments
Post a Comment