Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelkadolph committed Mar 26, 2013
0 parents commit c77a360
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 0 deletions.
56 changes: 56 additions & 0 deletions README.md
@@ -0,0 +1,56 @@
# doors

## Description

## What you need

* [PhidgetSBC3](http://www.phidgets.com/products.php?product_id=1073_0)
* Relays (i.e. [Dual SSR Relay Board](http://www.phidgets.com/products.php?category=9&product_id=3053_0) or [8 Channel SSR Module Board](http://www.sainsmart.com/8-channel-5v-solid-state-relay-module-board-omron-ssr-4-pic-arm-avr-dsp-arduino.html))
* Door Controller (i.e [KT-300](http://www.kantech.com/Products/controllers_kt300.aspx))

## Preperation

### Hardware

This will be mostly up to you because it will vary widly depending on what door controller you use.
What you need to do is connect the PhidgetSBC3 to the relays and the relays to the door controller in such a way that when closing the relay, the door will be unlocked.
I recommend the [Kantech KT-300](http://www.kantech.com/Products/controllers_kt300.aspx) and [Kantech EntraPass](http://www.kantech.com/Products/software_entrapass.aspx) because that is what we use at Shopify and we've got it working because we configured the inputs to be secondary Request to exit (REX) for each door.

### Software

1. Plug your PhidgetSBC3 into power and network
2. Go to [phidgetsbc.local](http://phidgetsbc.local/) and set a password
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.53.39_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.53.39_AM.png" alt="Go to phidgetsbc.local and set a password" width="828" height="363" class="size-full wp-image-768" /></a>
3. Enable the SSH server
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.54.05_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.54.05_AM.png" alt="Enable the SSH server" width="828" height="656" class="size-full wp-image-769" /></a>
4. Enable the full Debian Package Repository
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.58.28_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.58.28_AM.png" alt="Enable the full Debian Package Repository " width="828" height="748" class="size-full wp-image-772" /></a>
5. Add your ssh key to the phidgetsbc *(optional)*
* `ssh root@phidgetsbc.local "mkdir -p .ssh && echo '$(cat ~/.ssh/id_rsa.pub)' >> .ssh/authorized_keys"`
6. SSH in
* `ssh root@phidgetsbc.local`
7. Add my apt key
* `apt-key adv --keyserver keys.gnupg.net --recv-keys B4F808A2`
8. Add my apt repo
* `echo "deb http://apt.samuelkadolph.com/ wheezy main" > /etc/apt/sources.list.d/samuelkadolph.list`
9. Update apt
* `apt-get update`
10. Install the required packages
* `apt-get install golang-tip build-essential git-core libphidget21-dev ca-certificates -y`

## Installation

1. Go to [phidgetsbc.local](http://phidgetsbc.local/) and log in
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.35.27_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.35.27_AM.png" alt="Go to phidgetsbc.local and log in" width="828" height="299" /></a>
2. Create a project
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.38.37_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.38.37_AM.png" alt="Create a project" width="828" height="517" /></a>
3. Install the application
<pre><code>GOPATH=$HOME/go go get github.com/samuelkadolph/doors</code></pre>
4. Copy the binary to the project
<pre><code>cp $HOME/go/bin/doors /usr/userapps/doors/doors</code></pre>
5. Create the config file
<pre><code>TODO</code></pre>
6. Set the executable and enable boot startup for the project
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.39.50_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.39.50_AM.png" alt="Set the executable and enable boot startup for the project" width="828" height="787" /></a>
7. Start the application
<a href="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.40.49_AM.png"><img src="https://i0.wp.com/samuel.kadolph.com/wp-content/uploads/2013/03/Screen_Shot_2013-03-25_at_1.40.49_AM.png" alt="Start the application" width="828" height="506" /></a>
59 changes: 59 additions & 0 deletions door.go
@@ -0,0 +1,59 @@
package main

import (
"encoding/json"
"github.com/samuelkadolph/go/phidgets"
"time"
)

type Door struct {
Lock *int
Mag *int
Name string
}

func (d *Door) MagDisengage(ifk *phidgets.InterfaceKit) error {
return ifk.Outputs[*d.Mag].SetState(false)
}

func (d *Door) MagEngage(ifk *phidgets.InterfaceKit) error {
return ifk.Outputs[*d.Mag].SetState(true)
}

func (d *Door) Open(ifk *phidgets.InterfaceKit) error {
if err := ifk.Outputs[*d.Lock].SetState(true); err != nil {
return err
}

time.Sleep(20 * time.Millisecond)

return ifk.Outputs[*d.Lock].SetState(false)
}

func (d *Door) MarshalJSON() ([]byte, error) {
o := make(map[string]string)

if d.Lock != nil {
o["Lock"] = "supported"
} else {
o["Lock"] = "unsupported"
}

if d.Mag != nil {
s, err := ifk.Outputs[*d.Mag].State()
if err != nil {
o["Mag"] = "error"
}
if s {
o["Mag"] = "engaged"
} else {
o["Mag"] = "disengaged"
}
} else {
o["Mag"] = "unsupported"
}

o["Name"] = d.Name

return json.Marshal(o)
}
198 changes: 198 additions & 0 deletions main.go
@@ -0,0 +1,198 @@
package main

import (
"encoding/json"
"fmt"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/samuelkadolph/go/phidgets"
"io/ioutil"
"log"
"net/http"
"os"
"time"
)

type Config struct {
Doors []*Door
Secret string
}

type hash map[string]interface{}

var config Config
var ifk *phidgets.InterfaceKit

func DoorMagDisengage(w http.ResponseWriter, r *http.Request) {
var d *Door

if !checkSecret(w, r) {
return
}
if !checkDoor(w, r, &d) {
return
}
if !checkDoorMag(w, r, d) {
return
}

if err := d.MagDisengage(ifk); err != nil {
response(w, 200, hash{}, hash{"success": false, "error": err.Error()})
} else {
response(w, 200, hash{}, hash{"success": true})
}
}

func DoorMagEngage(w http.ResponseWriter, r *http.Request) {
var d *Door

if !checkSecret(w, r) {
return
}
if !checkDoor(w, r, &d) {
return
}
if !checkDoorMag(w, r, d) {
return
}

if err := d.MagEngage(ifk); err != nil {
response(w, 200, hash{}, hash{"success": false, "error": err.Error()})
} else {
response(w, 200, hash{}, hash{"success": true})
}
}

func DoorOpen(w http.ResponseWriter, r *http.Request) {
var d *Door

if !checkSecret(w, r) {
return
}
if !checkDoor(w, r, &d) {
return
}

if err := d.Open(ifk); err != nil {
response(w, 200, hash{}, hash{"success": false, "error": err.Error()})
} else {
response(w, 200, hash{}, hash{"success": true})
}
}

func ShowDoor(w http.ResponseWriter, r *http.Request) {
var d *Door

if !checkSecret(w, r) {
return
}
if !checkDoor(w, r, &d) {
return
}

response(w, 200, hash{}, d)
}

func Root(w http.ResponseWriter, r *http.Request) {
response(w, 200, hash{}, hash{"hi": true})
}

func NotFound(w http.ResponseWriter, r *http.Request) {
response(w, 404, hash{}, hash{"error": "not found"})
}

func checkDoor(w http.ResponseWriter, r *http.Request, o **Door) bool {
v := mux.Vars(r)
d := findDoor(v["door"])

if d == nil {
response(w, 404, hash{}, hash{"error": "door not found"})
return false
}
if d.Lock == nil {
response(w, 422, hash{}, hash{"error": "door does not support opening"})
return false
}

*o = d
return true
}

func checkDoorMag(w http.ResponseWriter, r *http.Request, d *Door) bool {
if d.Mag == nil {
response(w, 422, hash{}, hash{"error": "door does not support mag"})
return false
}

return true
}

func checkSecret(w http.ResponseWriter, r *http.Request) bool {
r.ParseForm()

if config.Secret != r.Form.Get("secret") {
response(w, 403, hash{}, hash{"error": "bad secret"})
return false
}

return true
}

func findDoor(name string) *Door {
for _, d := range config.Doors {
if d.Name == name {
return d
}
}
return nil
}

func response(w http.ResponseWriter, s int, h hash, b interface{}) {
o, _ := json.Marshal(b)
h["Content-Length"] = len(o)
h["Content-Type"] = "application/json"
for k, v := range h {
w.Header().Set(k, fmt.Sprintf("%v", v))
}
w.WriteHeader(s)
w.Write([]byte(o))
}

func init() {
var err error
var file []byte

if file, err = ioutil.ReadFile("./config.json"); err != nil {
log.Fatalf("Error while opening config.json - %s", err)
}

if err = json.Unmarshal(file, &config); err != nil {
log.Fatalf("Error while unmarshaling config - %s", err)
}

if ifk, err = phidgets.NewInterfaceKit(); err != nil {
log.Fatalf("%s", err)
}

if err = ifk.Open(phidgets.Any); err != nil {
log.Fatalf("%s", err)
}

if err = ifk.WaitForAttachment(2 * time.Second); err != nil {
log.Fatalf("%s", err)
}
}

func main() {
r := mux.NewRouter()
r.NewRoute().Methods("POST").Path("/doors/{door}/mag/disengage").Handler(http.HandlerFunc(DoorMagDisengage))
r.NewRoute().Methods("POST").Path("/doors/{door}/mag/engage").Handler(http.HandlerFunc(DoorMagEngage))
r.NewRoute().Methods("POST").Path("/doors/{door}/open").Handler(http.HandlerFunc(DoorOpen))
r.NewRoute().Methods("GET").Path("/doors/{door}").Handler(http.HandlerFunc(ShowDoor))
r.NewRoute().Methods("GET").Path("/").Handler(http.HandlerFunc(Root))
r.NewRoute().Handler(http.HandlerFunc(NotFound))

h := handlers.CombinedLoggingHandler(os.Stdout, r)

log.Fatalf("Error while starting server %s", http.ListenAndServe(":4567", h))
}

0 comments on commit c77a360

Please sign in to comment.