Feasibility - Three pushbuttons to control a single servo?

We always leave our bathroom fan on for too long, and in the winter months it sucks in cold air from outside in all the rooms of the apartment.

I had an idea to create a mechanical wall switch flipper which would allow us to select three runtime intervals for the fan. Obviously I could do this electronically, but I love the clickety-clack of old-school mechanical devices, hence my desire to flip the switch mechanically. I already have all the mechanical stuff figured out.

My Mission:

  1. Have three different momentary-contact pushbuttons to control how much time to allow the fan to run.
  2. Green button: Servo flips the switch on and shuts it off after 10 minutes
  3. Yellow button: Servo flips the switch on and flips it back off after 20 minutes
  4. Red button: For those "Code Red" trips to the bathroom after dinner at the local Mexican restaurant. Servo flips the switch on and flips it back off after 30 minutes.

Just seems like a fun project, and practical so we're not leaving the fan on for hours.

Is it feasible to use these three pushbuttons to actuate the servo for three different time intervals? I was thinking of a simplistic algorithm of 3 "if" statements followed by a simple pause depending on which button was pressed, but I have a feeling that this is the least elegant way to do it.

Any thoughts would be appreciated. It's pretty obvious I'm a rank beginner, and I'm doing my best to describe what I want to accomplish. Thanks!

Who cares? This would work fine.

You might get more satisfaction out of complicating it, for elegance or some other measurement.

And doing would leave you off better able to tackle the next project, with elegance, where a simple approach might just not be so good an idea.

It does mean you'd have trouble enhancing this device, but if it works, is deployed and becomes part of the background, again, who cares?

I have some really dodgy projects that would benefit from a visit or two, but they work, have for years and I'd prolly just start over if upgrades are considered.

a7

Yes, it is.

The sketch needs three timers to control the servo via the pushbuttons.

1 Like

Depends what you meant by "a simple pause". The most obvious way to get that pause is to use the delay() function. But what if someone presses a button while the pause/delay() is still running? Let's say 29 minutes after someone presses red, someone else, maybe the same person, presses red again. The press will be ignored (because that's what happens when you use the delay() function) and the fan will switch off one minute later.

Better to use millis() function instead of delay()!

1 Like

And other good points to settle during the design phase.

Perhaps one button and a stack of LEDs, 10 minutes each out to an hour (dunno what kind of lame Mexican restaurants are in your neighborhood!), press the button N times for N * 10 minutes run time.

a7

1 Like

Please share what you can on the mechanical concept you are working with.

Pictures if you already have hardware, prose and pencil drawings if not.

TIA. This could be fun to make and go way overboard on the software.

a7

1 Like

Hello steambc

Try, check and modify this small example to you needs.

#include <Servo.h>
Servo myservo;  // create servo object to control a servo
enum Event {Green, Yellow, Red};
constexpr byte ButtonPins[] {A0, A1, A2};   // |PortPin|------|PushButton|------ |GND|
constexpr unsigned long VentiTimes[] {1000, 2000, 3000};
void setup()
{
  myservo.attach(7);  // attaches the servo on pin 7 to the servo object
  myservo.write(0);
  delay(1000);
  myservo.write(180);
  delay(1000);
  myservo.write(0);
  delay(1000);
  for (auto ButtonPin : ButtonPins) pinMode(ButtonPin, INPUT_PULLUP);
}
void loop()
{
  if (!digitalRead(ButtonPins[Green])) myservo.write(180), delay(VentiTimes[Green]);
  if (!digitalRead(ButtonPins[Yellow])) myservo.write(180), delay(VentiTimes[Yellow]);
  if (!digitalRead(ButtonPins[Red])) myservo.write(180), delay(VentiTimes[Red]);
  myservo.write(0);
}

1 Like

Wow, thank you for the code. I will certainly try it and experiment, and will make it my business to understand enums and constexpr.

Is your code utilizing the the internal pullup resistor, or must I use external ones? From my meager knowledge it looks like you're using the internal pullup for all three switches.

Thanks for all the great tips guys. I'll be putting them to work.

The sketch uses the internal pullup resistor.

It works perfectly! I can't thank you enough!

I wonder if there is a way to incorporate the user changing their mind? Let's say they enter the bathroom and push red, and then realize it was a false alarm and they want to change it to green or yellow. I'm no asking you to do all my work for me, but I'm wondering if there's a method to accommodate a change of mind.

Again, thank you for your help!

Yes, it´s possible.

The sketch has to be redesigned to use a millis()-based timer instead using the delay() function.

EDIT:
Do it Q&D and install a fourth button to reset the Arduino.

Or you can use this

If I used that, I wouldn't have the spirit of an inventor, would I? Reread my initial post.

How is your research going?

Thanks. I was actually thinking of a reset button and eliminating the initial servo actuation and instead put in a little out-of-sight test button for a quick flip on and off to verify operation.

At least for the sake of interfacing advice, it would be appropriate to post details.

That's my intent.

I don't understand, since you haven't posted them. Cogent replies really depend on seeing some kind of concrete plan.

ATM there is a lot missing, for example we don't even know which Arduino you have.

Yes, it had been mentioned several times already. Use millis(), not delay().

When using delay(), you write code similar to this:

  1. Switch fan on
  2. Wait 30 minutes (meaning delay(1800000))
  3. Switch fan off.

The problem is that delay() does nothing while the time passes. Not even checking for button presses.

With millis() you would do it slightly differently:

  1. Switch fan on
  2. Make a note of the time now, in a variable

The above happens in pretty much an instant.

Your code also needs to do this:

  1. Calculate how much time has passed since the fan was switched on and the time now
  2. If that time has exceeded 30 mins, switch the fan off

millis() gives you the "time now". Not the time of day in hours and minutes, but in milliseconds since the Arduino was powered up or reset.