From 3f54813905d2718d8ef832e435d2415a9a13ca62 Mon Sep 17 00:00:00 2001 From: akiroz Date: Fri, 12 Aug 2016 08:37:30 +0000 Subject: [PATCH 1/2] init clj project --- .gitignore | 1 + embedded/index.js | 22 ------------------ embedded/package.json | 8 ------- embedded/project.clj | 9 ++++++++ embedded/src/com/oursky/doorlock/core.clj | 27 +++++++++++++++++++++++ 5 files changed, 37 insertions(+), 30 deletions(-) delete mode 100644 embedded/index.js delete mode 100644 embedded/package.json create mode 100644 embedded/project.clj create mode 100644 embedded/src/com/oursky/doorlock/core.clj diff --git a/.gitignore b/.gitignore index f842932..69c5b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ +target/ .DS_Store ._* diff --git a/embedded/index.js b/embedded/index.js deleted file mode 100644 index a00b136..0000000 --- a/embedded/index.js +++ /dev/null @@ -1,22 +0,0 @@ -const exec = require('child_process').exec; -const execSync = require('child_process').execSync; -const setTimeout = require('timers').setTimeout; -const log = require('simple-node-logger').createSimpleLogger(); - -execSync('gpio mode 0 up'); -execSync('gpio mode 1 out'); - -function openDoor() { - execSync('gpio write 1 1'); - setTimeout(_ => execSync('gpio write 1 0'), 3000); -} - -(function listenButton() { - exec('gpio wfi 0 rising').on('exit', _ => { - log.info('Unlocked via Button'); - openDoor(); - setTimeout(_ => listenButton(), 500); - }) -})() - -log.info('=== Daemon Started ==='); diff --git a/embedded/package.json b/embedded/package.json deleted file mode 100644 index f89d76e..0000000 --- a/embedded/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "scripts": { - "start": "node index.js" - }, - "dependencies": { - "simple-node-logger": "^0.93.12" - } -} diff --git a/embedded/project.clj b/embedded/project.clj new file mode 100644 index 0000000..9846974 --- /dev/null +++ b/embedded/project.clj @@ -0,0 +1,9 @@ +(defproject com.oursky/doorlock "1.0.0-SNAPSHOT" + :min-lein-version "2.0.0" + :dependencies [[org.clojure/clojure "1.8.0"] + [org.clojure/core.async "0.2.385"] + [com.taoensso/timbre "4.7.0"] + [clj-gpio "0.2.0"] + ] + :profiles {:uberjar {:aot :all}} + :main com.oursky.doorlock.core) diff --git a/embedded/src/com/oursky/doorlock/core.clj b/embedded/src/com/oursky/doorlock/core.clj new file mode 100644 index 0000000..a76cb19 --- /dev/null +++ b/embedded/src/com/oursky/doorlock/core.clj @@ -0,0 +1,27 @@ +(ns com.oursky.doorlock.core + (:require [taoensso.timbre :as log] + [gpio.core :refer [open-port open-channel-port write-value! toggle!]] + [clojure.java.shell :refer [sh]] + [clojure.core.async :refer [ Date: Fri, 12 Aug 2016 19:00:38 +0800 Subject: [PATCH 2/2] implement doorlock daemon --- README.md | 38 ++++++++++---- embedded/doorlock.service | 3 +- embedded/project.clj | 4 +- embedded/src/com/oursky/doorlock/core.clj | 61 ++++++++++++++++------- 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 8787233..d549322 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # doorlock -Project Structure: +**Project Structure:** ``` . └── embedded Embedded System & Hardware @@ -11,30 +11,48 @@ Project Structure: Circuit diagrams are drawn with this [Circuit Simulator](http://www.falstad.com/circuit/).
Diagrams are saved as `txt` files, you can import them under `File > Import From Text`. -Relay Board: +**Relay Board:** ![](https://github.com/oursky/doorlock/raw/master/embedded/circuit.png) -Embedded System: Raspberry Pi 3 +**Embedded System:** Raspberry Pi 3 -Connections: +**Connections:** * Release Button: GPIO0/Ground * Release Signal: GPIO1/Ground ## Embedded System -**System:** ArchLinux ARM + +### Build + +**Dependencies:** + +* clojure +* leiningen + +**Build:** +``` +[~/]$ git clone ... +[~/doorlock/embedded]$ lein uberjar + +``` +The standalone JAR is now in `doorlock/embedded/target/doorlock--standalone.jar`. + +### Deploy +**Embedded OS:** ArchLinux ARM **Dependencies:** -* nodejs -* npm +* java * wiringpi-git (AUR) **Install as systemd service:** +1. copy the standalone JAR to `/home/oursky/` +2. copy `doorlock.service` to `/etc/systemd/system/` +3. enable and start the service: ``` -[oursky ~/]$ git clone ... -[oursky ~/]$ sudo cp doorlock/embedded/doorlock.service /etc/systemd/system/ [oursky ~/]$ sudo systemctl enable doorlock [oursky ~/]$ sudo systemctl start doorlock ``` -**Note: ** If your username is not `oursky`, you need to edit `doorlock.service` accordingly. + +**Note:** If your username is not `oursky`, you need to edit `doorlock.service` accordingly. ## App diff --git a/embedded/doorlock.service b/embedded/doorlock.service index c4e9e9d..be576e6 100644 --- a/embedded/doorlock.service +++ b/embedded/doorlock.service @@ -3,8 +3,7 @@ Description=Doorlock Controller Daemon [Service] User=oursky -WorkingDirectory=/home/oursky/doorlock/embedded -ExecStart=/usr/bin/npm start +ExecStart=/usr/bin/java -jar /home/oursky/doorlock-1.0.0-SNAPSHOT-standalone.jar [Install] WantedBy=multi-user.target diff --git a/embedded/project.clj b/embedded/project.clj index 9846974..d878d03 100644 --- a/embedded/project.clj +++ b/embedded/project.clj @@ -3,7 +3,7 @@ :dependencies [[org.clojure/clojure "1.8.0"] [org.clojure/core.async "0.2.385"] [com.taoensso/timbre "4.7.0"] - [clj-gpio "0.2.0"] + [http-kit "2.2.0"] ] - :profiles {:uberjar {:aot :all}} + :aot :all :main com.oursky.doorlock.core) diff --git a/embedded/src/com/oursky/doorlock/core.clj b/embedded/src/com/oursky/doorlock/core.clj index a76cb19..601a7a1 100644 --- a/embedded/src/com/oursky/doorlock/core.clj +++ b/embedded/src/com/oursky/doorlock/core.clj @@ -1,27 +1,50 @@ (ns com.oursky.doorlock.core (:require [taoensso.timbre :as log] - [gpio.core :refer [open-port open-channel-port write-value! toggle!]] [clojure.java.shell :refer [sh]] - [clojure.core.async :refer [! >!! alts! go-loop chan timeout]] + [org.httpkit.server :refer [run-server]] + ) + (:gen-class)) -; setup GPIO via wiringpi CLI interface -; the clj-gpio library does not support internal pull-up -(sh "gpio" "mode" "0" "up") -(sh "gpio" "mode" "1" "out") +; unlock triggering channel +; identify the trigger source by sending {:source } +(def unlock-chan (chan)) -(def button-chan (open-channel-port 0)) -(def unlock-port (open-port 1)) +(defn http-handler [req] + (>!! unlock-chan {:source :network}) + {:status 200}) -(go-loop - [] - (! unlock-chan {:source :button})) + (recur)) -(log/info "=== Daemon Started ===") + ; listen on unlock-chan for unlock events + ; if a new unlock event is revieved before the 3000ms timeout, the door is kept open. + (go-loop [unlock nil] + (when unlock + (sh "gpio" "write" "1" "1") + (loop [[trigger _] [unlock nil]] + (when trigger + (log/info (str "Unlock triggered by " (:source trigger))) + (recur (alts! [unlock-chan (timeout 3000)])))) + (sh "gpio" "write" "1" "0") + (log/info "Door Locked")) + (recur (