I guess it's time to share

Nice project.

As an exercise to regain memory, maybe you could try removing all the "OO" layering ?
I'm not sure how efficient the compiler does that, but if you don't define buttons and relays etc. as objects,
but simply as functions, it should spare memory space.

Or am I just an ignorant of modern C++ compilers ? (which I am :wink: )

In your button function/object, you don't need to check twice for "if(digitalRead(_pin1) == LOW)" and you don't need to repeat debounce calls (should be const BTW), but that won't spare much. Probably moving all stuff into buttons.ino will bring a sensible memory gain.

My 2 cents, I don't program much either.