• Stars
    star
    117
  • Rank 301,828 (Top 6 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created almost 4 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Open and close your garage door with a Raspberry Pi

Normally Closed

Open and close your garage door (or similar) with a Raspberry Pi.

โš ๏ธ This project is deprecated! There will be no more active development. I have personally migrated to Z-Wave (specifically, the Zooz ZEN17) to fit in the with rest of my Z-Wave infrastructure.

Sometimes I forget to close my garage door when I leave the house. Sometimes I need to let someone into my house when I am not home. This allows me to do both of those things in a low-complexity way. Or, at least, in a way with complexity that I'm comfortable with.

Pros

  • Low cost. Raspberry Pis are ubiquitous and low-cost. I had two lying around. The required HATs are cheap (or you could just solder a relay directly), cases are cheap, and wire is cheap.
  • No ecosystem. The boards connect over regular Wi-Fi or ethernet and expose a simple HTTP interface. You can expose them to the internet however you want, or don't. You can expose them to automation tooling (like Home Assistant), or don't.

Cons

  • Not turnkey. Building the hardware and setting up the software is not hard, but it is still a solution that involves more setup than something like an off-the-shelf device.
  • No polish. Will not pass the Significant-Other Barโ„ข out-of-the-box.

Quickstart

Just want to try it out? If you have Cargo installed, clone and run:

$ cargo run --no-default-features config.example.toml

And then click the link!

Example screenshot of website in browser

Press the buttons to see the changes to GPIO pins that would happen on a real Raspberry Pi.

Hardware

You will need to obtain three main components:

  • Raspberry Pi computer
  • One 24V relay per button (usually from a HAT) controlled via GPIO
  • Wall- or ceiling-mountable case

Example Build #1: Pi Zero

The Raspberry Pi Zero is the ideal board given its price, that the software CPU/RAM requirements are low, and that it will likely be mounted to the ceiling. Due to its size and HAT availability, the Pi Zero can only control at most two single-button doors or one open/close-button door.

Ensure you get the Zero W for a board that includes a Wi-Fi chip (or the Zero WH).

Raspberry Pi Zero

The BC Robotics Relay HAT provides two relays for controlling up to two single-button doors or one open/close-button door.

BC Robotics Relay HAT

The HAT attaches to the Pi via a 40-pin connector. You can use either 11mm or 12mm standoffs on the opposite side to secure it in place.

HAT secured to Pi Zero with standoffs

Looking for alternative HATs?

The Pimoroni Automation HAT mini provides only a single relay suitable for one single-button door.

Pimoroni Automation HAT mini

The HAT attaches to the Pi via a 40-pin connector. You can use 10mm standoffs on the opposite side to secure it in place.

The UniPiCase Zero (Tall) is tall enough to fit the HAT although it will require minor modification to work.

UniPiCase Zero (Tall)

The case top features two structural pieces of plastic that must be shaved down in order to accommodate the HAT.

Example shaving of structural plastic

A dedicated opening will need drilled through the case near the terminal(s) to accommodate the garage door wire.

Example wire opening in case

Attach the wire to the relays. You should use the "Common" (COM) and "Normally Open" (NO) terminals (despite the name of the project) since triggering the button should temporarily close the circuit.

Pi with wires inside the case

The case does not have mounting holes. The assembly is light enough that poster-mounting squares or other double-sided adhesive could be used. I sank two screws below and one above the case to secure it.

Case mounted to the wall adjacent to door opener

Attach the other end of the wires to the garage door motor unit in the same terminals as the wall buttons.

Close-up of wiring to common, open, and close terminals inside opener Mounted case with wires attached to garage door opener terminal Mounted case with wires running into garage door opener

Example Build #2: Pi 3/4

The full-size Raspberry Pi boards are more than capable (if not overkill). Generally they would only be preferred if you already had one or if you need more than 2 relays to control more than 2 doors (without otherwise building a custom relay board).

Raspberry Pi 3b

The Pimoroni Automation HAT provides three relays for controlling up to three single-button doors or one open/close-button door and one single-button door.

Pimoroni Automation HAT

The HAT attaches to the Pi via a 40-pin connector. You can use 10mm standoffs on the opposite side to secure it in place.

HAT secured to Pi with standoffs

The LoveRPI Active Cooling Media Center PC Case isn't made for HATs, but is trivially modified to fit them.

LoveRPI Active Cooling Media Center PC Case

If your HAT is secured to the Pi with standoffs and screws, beneath the board you will have to shave down the plastic board standoffs ~1mm to accommodate the screw heads.

Example shaving of structural plastic on bottom of case Installed Pi after shaving bottom plastic

Additionally, you will have to remove the fan, the fan mounting standoffs, and the coupling standoff to fit the HAT.

Example shaving of structural plastic on top of case Installed Pi after shaving top plastic

The garage door wire will have to be passed through the fan slits, or a dedicated hole for each relay will need to be shaped near the terminals.

Holes in the side of the case to accommodate wires

Attach the wire to the relays. You should use the "Common" (COM) and "Normally Open" (NO) terminals (despite the name of the project) since triggering the button should temporarily close the circuit.

Pi with wires attached to relay HAT Pi with wires inside the case

Since the case already had mounting holes, sink two screws into the ceiling or wall near the garage door motor unit and set up the Pi.

Bottom part of case mounted to garage ceiling Pi inside closed case mounted on garage ceiling

Attach the other end of the wires to the garage door motor unit in the same terminals as the wall buttons.

Mounted case with wires attached to garage door opener terminals Mounted case with wires attached to garage door opener

Installation

Docker

A container which runs the binary is available from Docker Hub and GitHub Container Registry.

  • jakewharton/normally-closed Docker Image Version Docker Image Size

  • ghcr.io/jakewharton/normally-closed

Mount the /config folder which contains a config.toml or mount a /config/config.toml file directly for the configuration file. The container serves the website on port 80. You can map it to your desired port using -p.

$ docker run -d \
    -v /path/to/config.toml:/config/config.toml \
    -p 8080:80 \
    jakewharton/normally-closed

Docker Compose is also supported:

services:
  normally-closed:
    image: jakewharton/normally-closed
    restart: unless-stopped
    ports:
      - 8080:80
    volumes:
      - /path/to/config.toml:/config/config.toml

Binary

If you have Rust installed with Cargo you can install the binary by running cargo install normally-closed (latest version). Otherwise a prebuilt binary is available on the latest GitHub release.

The path to your configuration file is a required argument. The website will be served on port 31415 by default.

$ normally-closed --help
normally-closed 0.1.0

USAGE:
    normally-closed [OPTIONS] <config-file>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
        --http-port <port>    HTTP port [default: 31415]

ARGS:
    <config-file>    TOML configuration file. See https://github.com/JakeWharton/NormallyClosed#configuration

Other

Want to maintain a Linux distro installation? Please do! PRs for distro installation welcome.

Configuration

A TOML file defines the available relays and which doors map to which relays.

Here is a full example:

version = 0

[relays]
board = "PIM213"

[[door]]
name = "Left"
relay = 1

[[door]]
name = "Right"
relay = 2

version

Always 0 until version 1.0.0 is released.

secondary_hosts

Additional hosts whose doors will be displayed on this host.

secondary_hosts = [
  "http://example.com:1234",
]

Doors from each host will be updated every minute.

Note: 'https' is not supported at this time.

relays

Either a named board:

[relays]
board = "PIM213"
Board Relay count
PIM213 3
PIM487 1
PIM221 1
RAS-109 / RAS-194 2

Or a list of GPIO pins corresponding to relays:

[relays]
pins = [11, 13, 15, 17]

door

Either a single toggle button:

[[door]]
name = "Garage"
relay = 1

Or multiple discrete buttons:

[[door]]
name = "Garage"
open_relay = 1
close_relay = 2
stop_relay = 3  # OPTIONAL!

In either form, all doors must have names, relays use 1-based indexing, and no door may use the same relay as another.

Usage

Visit the website in a browser. Click the buttons!

Example screenshot of website in browser Example screenshot of website in browser

Your URL will depend on the hostname of the Pi and the port you choose.

Local Development

The binary targets the Raspberry Pi through the use of a Cargo feature which is enabled by default. Disabling the default feature will allow you to run locally with GPIO pin changes printed instead.

  • Build: cargo build --no-default-features
  • Test: cargo test --no-default-features
  • Lint: cargo clippy --no-default-features
  • Format: cargo +nightly fmt
  • Run: ./target/debug/normally-closed args...

FAQ

Why not OpenGarage?

  • I already had a camera in the garage and do not need detection.
  • I did not like how it exposed itself through the internet.
  • Does not support doors with explicit open/close control buttons.
  • I had two Raspberry Pi 3b boards lying around and paternity leave time.

Why not Z-Wave / Zigbee?

  • I did not want to stand up an ecosystem for two simple toggles.
  • I had two Raspberry Pi 3b boards lying around and paternity leave time.

Why not [some other product]?

  • I probably didn't know it existed.
  • I had two Raspberry Pi 3b boards lying around and paternity leave time.

Why?

I had two Raspberry Pi 3b boards lying around and paternity leave time.

How do I access this outside of my home network?

This is your problem!

I personally use WireGuard to jump into my home network and connect directly to each Pi.

License

Copyright 2021 Jake Wharton

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

butterknife

Bind Android views and callbacks to fields and methods.
Java
25,610
star
2

timber

A logger with a small, extensible API which provides utility on top of Android's normal Log class.
Kotlin
10,406
star
3

ViewPagerIndicator

Paging indicator widgets compatible with the ViewPager from the Android Support Library and ActionBarSherlock.
Java
10,166
star
4

RxBinding

RxJava binding APIs for Android's UI widgets.
Kotlin
9,693
star
5

hugo

Annotation-triggered method call logging for your debug builds.
Java
7,892
star
6

ActionBarSherlock

[DEPRECATED] Action bar implementation which uses the native action bar on Android 4.0+ and a custom implementation on pre-4.0 through a single API and theme.
Java
7,130
star
7

DiskLruCache

Java implementation of a Disk-based LRU cache which specifically targets Android compatibility.
Java
5,766
star
8

u2020

A sample Android app which showcases advanced usage of Dagger among other open source libraries.
Java
5,682
star
9

pidcat

Colored logcat script which only shows log entries for a specific application package.
Python
4,723
star
10

NineOldAndroids

[DEPRECATED] Android library for using the Honeycomb animation API on all versions of the platform back to 1.0!
Java
4,508
star
11

ThreeTenABP

An adaptation of the JSR-310 backport for Android.
Java
3,540
star
12

scalpel

A surgical debugging tool to uncover the layers under your app.
Java
2,770
star
13

RxRelay

RxJava types that are both an Observable and a Consumer.
Java
2,475
star
14

Telecine

Record full-resolution video on your Android devices.
Java
2,472
star
15

kotterknife

View "injection" library for Android.
Kotlin
2,231
star
16

SdkSearch

An Android app and Chrome extension for searching the Android SDK documentation.
Kotlin
2,034
star
17

retrofit2-kotlin-coroutines-adapter

A Retrofit 2 adapter for Kotlin coroutine's Deferred type.
Kotlin
1,961
star
18

ProcessPhoenix

Process Phoenix facilitates restarting your application process.
Java
1,786
star
19

diffuse

Diffuse is a tool for diffing APKs, AABs, AARs, and JARs
Kotlin
1,779
star
20

mosaic

An experimental tool for building console UI in Kotlin using the Jetpack Compose compiler/runtime
Kotlin
1,500
star
21

sdk-manager-plugin

DEPRECATED Gradle plugin which downloads and manages your Android SDK.
Groovy
1,414
star
22

Android-DirectionalViewPager

[DEPRECATED] Implementation of the compatibility library ViewPager class that supports paging both vertically and horizontally.
Java
1,038
star
23

DrawerBehavior

A CoordinatorLayout behavior which mimics the functionality of DrawerLayout.
Java
894
star
24

adb-event-mirror

Mirror the touch/key/button events of one device onto one or more other devices in real-time
Kotlin
873
star
25

retrofit2-kotlinx-serialization-converter

A Retrofit 2 Converter.Factory for Kotlin serialization.
Kotlin
848
star
26

picnic

A Kotlin DSL and Java/Kotlin builder API for constructing HTML-like tables which can be rendered to text
Kotlin
838
star
27

retrofit2-rxjava2-adapter

An RxJava 2 CallAdapter.Factory implementation for Retrofit 2.
812
star
28

dependency-tree-diff

An intelligent diff tool for the output of Gradle's dependencies task
Kotlin
704
star
29

wormhole

A time-traveling bytecode rewriter which adds future APIs to android.jar
Kotlin
664
star
30

picasso2-okhttp3-downloader

A OkHttp 3 downloader implementation for Picasso 2.
Java
659
star
31

dagger-reflect

A reflection-based implementation of the Dagger dependency injection library for fast IDE builds.
Java
655
star
32

RxReplayingShare

An RxJava transformer which combines replay(1), publish(), and refCount() operators.
Java
629
star
33

flip-tables

Because pretty-printing text tables in Java should be easy.
Java
609
star
34

SwipeToDismissNOA

Backport of Roman Nurik's "Swipe-to-dismiss" sample code using NineOldAndroids to work on all API levels.
Java
552
star
35

salvage

Generic view recycler and ViewPager PagerAdapter implementation.
Java
467
star
36

okhttp-idling-resource

An Espresso IdlingResource for OkHttp.
Java
459
star
37

madge

A debugging tool to determine whether or not your bitmaps are being drawn at their native resolution.
Java
392
star
38

Reagent

Experiments for future reactive libraries.
Kotlin
364
star
39

double-espresso

[DEPRECATED] A pure Gradle port of the Espresso testing utility for Android!
Java
340
star
40

docker-gphotos-sync

A Docker image for synchronizing your original-quality Google Photos
Shell
336
star
41

gradle-android-test-plugin

[DEPRECATED] A Gradle plugin which enables good 'ol fashioned unit tests for Android builds.
Java
328
star
42

nopen

An error-prone checker which requires that classes be final, abstract or annotated with @ Open.
Java
316
star
43

mkvdts2ac3

Bash script to convert DTS audio to AC3 within a matroska file.
Shell
314
star
44

RxWindowIfChanged

An RxJava 2 operator which splits an observable into windows using a key selector.
Java
307
star
45

OverloadReturn

Bytecode rewriter that creates overloads of methods which vary only by return type.
Kotlin
300
star
46

paraphrase

An experimental Gradle plugin which generates compile-safe format string builders.
Java
281
star
47

gitout

A command-line tool and Docker image to automatically backup Git repositories from GitHub or anywhere
Rust
259
star
48

dependency-watch

Script to wait for an artifact to appear in a Maven repository or to monitor coordinates for new versions.
Kotlin
240
star
49

confundus

Kotlin compiler plugin which brings Kotlin/JS's unsafeCast to Kotlin/JVM
Kotlin
236
star
50

AutoValueAnnotations

A standalone packaging of the annotations from Google's AutoValue library.
Shell
222
star
51

adjacent-fragment-pager-sample

Demonstrates how to manage two fragments where portrait displays them in a ViewPager and landscape displays them side-by-side.
Java
214
star
52

retrofit1-okhttp3-client

A OkHttp 3 client implementation for Retrofit 1.
Java
194
star
53

retrofit2-reactor-adapter

A Project Reactor CallAdapter.Factory implementation for Retrofit 2.
Java
183
star
54

jardiff

A Python script which quickly creates diffs of the public API between two JAR files
Python
183
star
55

sdk-artifact-sync

A script which synchronizes all of the artifacts in your local Android SDK to a remote Maven artifact host.
Python
182
star
56

dodo

Synchronize your Twitter timeline to a local database for archival and search
Kotlin
182
star
57

shimo

Shimo is an adapter for Moshi which randomizes the order of keys when serializing and deserializing
Java
178
star
58

cite

A Kotlin compiler plugin for embedding information about the file being compiled
Kotlin
178
star
59

PxJava

An experiment which interprets RxJava as an entirely pull-based system written in Kotlin.
Kotlin
173
star
60

HanselAndGretel

Android library providing bread crumbs to the support library fragments.
Java
163
star
61

byteunits

Utility classes for converting between granularities of SI and IEC byte units and bit units.
Kotlin
159
star
62

agp-java-support

Tracking your ability to use new Java language features and APIs in an Android app
Java
151
star
63

crossword

A 2D canvas for rendering text, usually for console applications.
Kotlin
142
star
64

NotificationCompat2

[DEPRECATED] Please use the support library r11 or newer for these features.
Java
132
star
65

dalvik-dx

A standalone packaging of AOSP's platform/dalvik dx library.
Shell
125
star
66

jakewharton.com

Personal website and blog.
HTML
117
star
67

plex-orphaned-files

Find files in your Plex libraries which are not indexed
Kotlin
114
star
68

AndroidDesignKeynoteTheme

A simple theme for Apple Keynote which adheres to the clean look of the Android Design website.
92
star
69

py-videodownloader

[DEPRECATED] Python module and script for downloading video source files from the major online streaming sites (YouTube, Vimeo, etc.)
Python
90
star
70

jax-rs-moshi

A JAX-RS message body reader/writer and parameter converter which uses Moshi to handle JSON
Java
89
star
71

ActionBarSherlock-Plugin-Maps

[DEPRECATED] Plugin for ActionBarSherlock which provides a base activity that can be used for adding a MapView to your action bar-enabled layouts.
Java
89
star
72

dockerfile-shebang

Treat your Dockerfiles as self-contained, editable scripts
Shell
86
star
73

singular-solution

Keep your Twitter follower count at zero by blocking and then quickly unblocking any new followers
Kotlin
86
star
74

ActivityCompat2

[DEPRECATED] Please use the support library r13 or newer for these features.
Java
76
star
75

docker-mbsync

A Docker container which runs the mbsync tool automatically to synchronize your email
Shell
74
star
76

RxJava2-Java6

An automated backport of RxJava 2 to support Java 6.
Java
73
star
77

PosterBox

Rotating display of Movie and TV posters
Kotlin
72
star
78

jax-rs-kotlinx-serialization

A JAX-RS message body reader/writer and parameter converter which uses Kotlinx Serialization
Kotlin
70
star
79

gradle-like-bazel

A demo showing that you can (probably) structure Gradle projects like you would Bazel
Java
67
star
80

gms-mvn-install

[DEPRECATED] Installs Google Play Services to your local Maven repo or deploys it to a remote repo.
Shell
64
star
81

SMSBarrage

An Android application which allows you send mass repeated SMS messages to any number of contacts.
Java
63
star
82

platform-collections

Kotlin multiplatform collections which use platform-optimized storage
Kotlin
63
star
83

SMSMorse

An Android service that vibrates incoming SMS messages in Morse code.
Java
63
star
84

uniqtoo

A version of `sort | uniq -c` with output that updates in real-time as each line is parsed
Rust
62
star
85

snooker

[DEPRECATED] Please use the support library v20.0.0 or newer for these features.
Java
62
star
86

rebaseandsqua.sh

Utility and website which makes it easy to rebase and squash your branches.
56
star
87

asciinema-vsync

Batch the commands inside an Asciinema JSON file to reduce flickering
Kotlin
56
star
88

ActionBarSherlock-Gradle-Sample

[DEPRECATED] A tiny sample project that uses ActionBarSherlock via Gradle
Groovy
52
star
89

trakt-java

A Java wrapper around the Trakt RESTful API and a simple DSL for easy interaction.
Java
48
star
90

google-maven-exploder

Kotlin
48
star
91

resourcefs

A minimal FileSystem which exposes resources inside the current class loader.
Java
45
star
92

TronWallpaper

An Android live wallpaper which races lightcycles around your icons against Master Control.
Java
45
star
93

dumbo

Import a Twitter archive into a Mastodon database.
Kotlin
40
star
94

ui-spy

Monitor products on the Ubiquiti Store and receive notifications when their availability changes.
Kotlin
40
star
95

twirl-maven-plugin

A Maven plugin which compiles Twirl templates into Scala source files.
Java
40
star
96

uglify-js-middleware

Connect middleware which will automatically uglify your JS files.
JavaScript
38
star
97

SnakeWallpaper

An Android live wallpaper which plays the classic game of snake around your icons. Available on the Android Market.
Java
36
star
98

libcore-dex

A standalone packaging of AOSP's platform/libcore dex library.
Shell
32
star
99

tools-apksig

A standalone packaging of AOSP's platform/tools/apksig library.
28
star
100

WritingAgileAPKs

AnDevCon III Presentation: Writing Agile APKs
Java
26
star