From 20aaa77701cc76f128974c86f89da4b26d123428 Mon Sep 17 00:00:00 2001 From: Chad Mercer Date: Sat, 30 May 2026 20:16:43 -0500 Subject: [PATCH] Initial import --- WIRING.txt | 216 ++++++++++++++++++++++++++++++++++++++++++++++++ config.py | 21 +++++ main.py | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+) create mode 100644 WIRING.txt create mode 100644 config.py create mode 100644 main.py diff --git a/WIRING.txt b/WIRING.txt new file mode 100644 index 0000000..bc4009f --- /dev/null +++ b/WIRING.txt @@ -0,0 +1,216 @@ +================================================================================ + GARAGE DOOR CONTROLLER - WIRING DIAGRAM + Raspberry Pi Pico 2 +================================================================================ + +HARDWARE REQUIRED +----------------- +- Raspberry Pi Pico 2 +- SunFounder 2-Channel 5V Relay Module (Amazon: B00E0NTPP4) +- 2x Door position sensors (optional, for status detection) +- Jumper wires (female-to-male recommended) +- Power supply (5V, 1A minimum) + +================================================================================ + PIN CONFIGURATION +================================================================================ + +Pico 2 Pin Layout (Top View) +============================= + | 3V3(1) (2) VBUS | + | GND (3) (4) 3V3_EN| + | GP28 (5) (6) ADC2 | + | GP27 (7) (8) ADC1 | + | GP26 (9) (10) ADC0 | + | RUN (11) (12) GP22 | + | GP21 (13) (14) GP20 | + | GP19 (15) (16) GP18 | + | GP17 (17) (18) GP16 | + | GP15 (19) (20) GP14 | + | GP13 (21) (22) GP12 | + | GND (23) (24) GP11 | + | VSYS (25) (26) GP10 | + | GND (27) (28) GP9 | + | 3V3 (29) (30) GP8 | + | 3V3 (31) (32) GP7 | + | ADC3 (33) (34) GP6 | + | GP4 (35) (36) GP5 | + | GP3 (37) (38) GP2 | + | GP1 (39) (40) GP0 | + |_____(41) (42)________| + +================================================================================ + RELAY MODULE WIRING +================================================================================ + +Relay Module Pins (Top View) +============================= + +--------+ +--------+ + | IN1 | | IN2 | + | VCC | | GND | + | GND | | COM2 | + | COM1 | | NO2 | + | NO1 | | NC2 | + | NC1 | | | + +--------+ +--------+ + +Connect Relay Module to Pico 2: +------------------------------- + Relay Module Pico 2 + ----------- ------- + VCC ----> 5V (Pin 39) + GND ----> GND (Pin 38) + IN1 ----> GP15 (Pin 20) - Door 1 + IN2 ----> GP16 (Pin 21) - Door 2 + +================================================================================ + GARAGE DOOR OPENER WIRING +================================================================================ + +OVERHEAD DOOR ODYSSEY 1000 TERMINALS +------------------------------------ +Locate the wall control terminals on your garage door opener motor unit. +These are typically labeled "WALL CONTROL" or have two screw terminals +(usually red and white wires). + +WIRING DIAGRAM FOR EACH DOOR: +----------------------------- + + +-------------------+ +-------------------+ + | Garage Door | | Garage Door | + | Opener #1 | | Opener #2 | + | | | | + | Red Wire ----+--+---------+--+--> Relay 1 COM | + | | | | | | + | White Wire --+--+---------+--+--> Relay 1 NO | + | (parallel w/ | | + | wall button) | | + +-------------------+ +-------------------+ + | + v + +-------------------+ +-------------------+ + | | | | + | Red Wire ----+--+---------+--+--> Relay 2 COM | + | | | | | | + | White Wire --+--+---------+--+--> Relay 2 NO | + | (parallel w/ | | + | wall button) | | + +-------------------+ +-------------------+ + +IMPORTANT NOTES: +- Wire in PARALLEL with existing wall buttons (keep them functional) +- Use NO (Normally Open) terminals, NOT NC +- Garage door button circuit is low voltage (~12-24V), safe to work with +- Always disconnect power before working with opener wiring + +================================================================================ + DOOR SENSOR WIRING (OPTIONAL) +================================================================================ + +If using door position sensors to detect open/closed status: + + Sensor 1 (Door 1) Pico 2 + --------------- ------- + VCC (if powered) --> 3V3 (Pin 36) + GND --> GND (Pin 38) + Signal --> GP14 (Pin 19) - Configured in config.py + + Sensor 2 (Door 2) Pico 2 + --------------- ------- + VCC (if powered) --> 3V3 (Pin 36) + GND --> GND (Pin 38) + Signal --> GP13 (Pin 18) - Configured in config.py + +Note: Config uses internal pull-up resistors, so sensors should be +configured as normally-open (closed = door open). + +================================================================================ + COMPLETE WIRING SUMMARY +================================================================================ + + +------------------+ + | Pico 2 W | + +------------------+ + | | + 5V (Pin 39) ----+--> VCC (Relay) | + | | + GND (Pin 38) ---+--> GND (Relay) | + | | + GP15 (Pin 20)-->--> IN1 (Relay) |---- Door 1 Control + | | + GP16 (Pin 21)-->--> IN2 (Relay) |---- Door 2 Control + | | + GP14 (Pin 19)-->--> Door Sensor 1 |---- (Optional) + | | + GP13 (Pin 18)-->--> Door Sensor 2 |---- (Optional) + | | + +------------------+ + +================================================================================ + CONFIGURATION +================================================================================ + +Edit config.py to customize: + + WIFI_SSID - Your WiFi network name + WIFI_PASSWORD - Your WiFi password + STATIC_IP - Fixed IP address for the Pico + SUBNET - Subnet mask + GATEWAY - Router IP address + DNS - DNS server IP + + RELAY1_PIN - GPIO pin for door 1 relay (default: 15) + RELAY2_PIN - GPIO pin for door 2 relay (default: 16) + + DOOR1_SENSOR_PIN - GPIO pin for door 1 sensor (default: 14) + DOOR2_SENSOR_PIN - GPIO pin for door 2 sensor (default: 13) + + PRESS_COOLDOWN - Seconds between button presses (default: 2) + +================================================================================ + SAFETY FEATURES +================================================================================ + +1. PRESS COOLDOWN + - Prevents rapid repeated presses + - 2-second cooldown between toggles + - Displays warning message if pressed too quickly + +2. PARALLEL WIRING + - Original wall buttons remain functional + - No loss of manual control + +3. LOW-VOLTAGE OPERATION + - Relay contacts handle the garage door opener's low-voltage circuit + - No mains voltage involved in control circuit + +================================================================================ + TESTING PROCEDURE +================================================================================ + +1. Upload config.py and main.py to Pico 2 +2. Wire relay module to Pico (5V, GND, GP15, GP16) +3. Connect relay to one garage door opener (test with door 1 first) +4. Power on Pico and check serial output for IP address +5. Navigate to http:// in browser +6. Test toggle button - door should respond +7. Verify wall button still works +8. Repeat for door 2 + +================================================================================ + FAQ +================================================================================ + +Q: The relay clicks but the door doesn't respond +A: Check wiring - ensure COM and NO terminals are used, not NC + +Q: Door status shows wrong +A: Check sensor wiring or disable sensors in code (remove sensor pins) + +Q: Can't connect to web interface +A: Verify STATIC_IP is in your network's subnet and not conflicting + +Q: Button press has no effect +A: Verify RELAY_ON/RELAY_OFF values match your relay (try swapping 0/1) + +================================================================================ \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..7ae9ce5 --- /dev/null +++ b/config.py @@ -0,0 +1,21 @@ +WIFI_SSID = "24isenough" +WIFI_PASSWORD = "UltimateDrums!" + +STATIC_IP = "192.168.1.63" +SUBNET = "255.255.255.0" +GATEWAY = "192.168.1.254" +DNS = "192.168.1.254" + +RELAY1_PIN = 15 +RELAY2_PIN = 16 + +DOOR1_SENSOR_PIN = 14 +DOOR2_SENSOR_PIN = 13 + +RELAY_ON = 0 +RELAY_OFF = 1 + +DOOR_OPEN = 1 +DOOR_CLOSED = 0 + +PRESS_COOLDOWN = 2 diff --git a/main.py b/main.py new file mode 100644 index 0000000..63e6244 --- /dev/null +++ b/main.py @@ -0,0 +1,238 @@ +import network +import socket +import time +import machine +import config +from machine import Pin + +relay1 = Pin(config.RELAY1_PIN, Pin.OUT) +relay2 = Pin(config.RELAY2_PIN, Pin.OUT) +door_sensor1 = Pin(config.DOOR1_SENSOR_PIN, Pin.IN, Pin.PULL_UP) +door_sensor2 = Pin(config.DOOR2_SENSOR_PIN, Pin.IN, Pin.PULL_UP) + +relay1.value(config.RELAY_OFF) +relay2.value(config.RELAY_OFF) + +last_press_time = {"door1": 0, "door2": 0} + +wlan = network.WLAN(network.STA_IF) +wlan.active(True) +wlan.connect(config.WIFI_SSID, config.WIFI_PASSWORD) + +max_retries = 30 +while not wlan.isconnected() and max_retries > 0: + time.sleep(1) + max_retries -= 1 + +if wlan.isconnected(): + wlan.ifconfig((config.STATIC_IP, config.SUBNET, config.GATEWAY, config.DNS)) + ip_address = config.STATIC_IP +else: + ip_address = None + + +def toggle_door(door_num): + current_time = int(time.time()) + door_key = f"door{door_num}" + + if current_time - last_press_time[door_key] < config.PRESS_COOLDOWN: + return False + + last_press_time[door_key] = current_time + + if door_num == 1: + relay1.value(config.RELAY_ON) + else: + relay2.value(config.RELAY_ON) + + time.sleep(0.5) + + if door_num == 1: + relay1.value(config.RELAY_OFF) + else: + relay2.value(config.RELAY_OFF) + + return True + + +def get_door_status(door_num): + if door_num == 1: + sensor = door_sensor1 + else: + sensor = door_sensor2 + return "open" if sensor.value() == config.DOOR_OPEN else "closed" + + +def get_html(status1, status2, msg="", client_ip=""): + return ( + """ + + + + Garage Door Control + + + +

Garage Door Control

+
+

Door 1

+
+ Door is """ + + status1.upper() + + """ +
+
+ +
+
+
+

Door 2

+
+ Door is """ + + status2.upper() + + """ +
+
+ +
+
+ """ + + ('
' + msg + "
" if msg else "") + + """ +
+

Activity Log

+ +
+
IP: """ + + (ip_address or "Not connected") + + """
+ + +""" + ) + + +def web_server(): + addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1] + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(addr) + s.listen(1) + + while True: + try: + cl, addr = s.accept() + client_ip = addr[0] + request = cl.recv(1024) + request_str = request.decode("utf-8") + + message = "" + if "POST" in request_str: + if "toggle1" in request_str: + if toggle_door(1): + message = "" + else: + message = "Please wait before pressing again" + elif "toggle2" in request_str: + if toggle_door(2): + message = "" + else: + message = "Please wait before pressing again" + + status1 = get_door_status(1) + status2 = get_door_status(2) + response = get_html(status1, status2, message, client_ip) + + cl.send("HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n") + cl.send(response) + cl.close() + except Exception as e: + pass + + +if __name__ == "__main__": + if ip_address: + print("Connected, IP:", ip_address) + web_server() + else: + print("Failed to connect to WiFi")