A happy beginning 🚪🔒

This commit is contained in:
Dana Woodman 2018-03-03 13:28:55 -08:00
commit 38c0bae242
21 changed files with 6001 additions and 0 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_size = 4
trim_trailing_whitespace = false

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
dist
node_modules

31
.eslintrc.yml Normal file
View File

@ -0,0 +1,31 @@
---
parser: babel-eslint
parserOptions:
ecmaVersion: 6
sourceType: module
ecmaFeatures:
jsx: true
impliedStrict: true
experimentalObjectRestSpread: true
globals:
Promise: true
env:
browser: true
jest: true
node: true
commonjs: true
extends:
- eslint:recommended
- plugin:react/recommended
rules:
no-empty: warn
no-console: off
semi:
- error
- never
sort-vars: error
sort-imports:
- error
- ignoreCase: true
sort-keys: error
react/jsx-sort-prop: true

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
.DS_Store

25
.npmrc Normal file
View File

@ -0,0 +1,25 @@
# This file is a special npm configuration file.
#
# From npm docs:
#
# The --global-style argument will cause
# npm to install the package into your
# local node_modules folder with the same
# layout it uses with the global node_modules
# folder. Only your direct dependencies
# will show in node_modules and everything
# they depend on will be flattened in their
# node_modules folders. This obviously will
# eliminate some deduping.
#
# t2-cli gives third party modules control over what
# files and dependencies get deployed to a Tessel 2
# by supporting .tesselignore and .tesselinclude files.
# Ever since npm 3, dependency flattening has taken that
# control away, since the rules in those files are
# resolved relative to the third party module itself.
# Forcing Tessel 2 project dependencies to install as
# described above restores that control, ideally
# producing smaller project bundles.
global-style = true

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v6.10.3

4
.prettierignore Normal file
View File

@ -0,0 +1,4 @@
.vscode
dist
node_modules
package-lock.json

5
.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "es5"
}

7
.tesselinclude Normal file
View File

@ -0,0 +1,7 @@
# This file should list any files or directories you want included with the
# T2 bundling and deployment process. This is handy for including
# non-JavaScript assets, like HTML, CSS, and images, for use within your project.
# .tesselinclude works the same as .npminclude
# You DO NOT need to list node_modules or package.json
# For more information, visit: https://tessel.io/docs/cli#usage
index.html

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

17
__mocks__/tessel.js Normal file
View File

@ -0,0 +1,17 @@
function LED() {
return {
off: jest.fn(),
on: jest.fn(),
}
}
const tessel = {
led: {
0: LED(), // red
1: LED(), // amber
2: LED(), // green
3: LED(), // blue
},
}
module.exports = tessel

6
config/constants.js Normal file
View File

@ -0,0 +1,6 @@
const ENV = process.env.NODE_ENV || 'development'
const DOOR_OPEN_DELAY = ENV === 'test' ? 1 : 6000 // in milliseconds
module.exports = {
DOOR_OPEN_DELAY,
}

6
jest.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
moduleFileExtensions: ['ts', 'tsx', 'js'],
testEnvironment: 'node',
testMatch: ['**/*.test.(ts|tsx|js)'],
testPathIgnorePatterns: ['/node_modules/', '/config/'],
}

5649
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "doorlock",
"version": "0.1.0",
"main": "src/boot.js",
"scripts": {
"start": "t2 run src/boot.js",
"test": "jest",
"watch-test": "jest --watch"
},
"dependencies": {
"axios": "0.17.1",
"chalk": "2.3.1",
"consolidate": "0.15.0",
"eslint": "4.17.0",
"express": "4.16.2",
"node-hid": "0.7.2",
"pug": "2.0.0-rc.4",
"serialport": "6.0.5",
"tessel": "0.3.25"
},
"devDependencies": {
"babel-eslint": "8.2.2",
"eslint-plugin-react": "7.7.0",
"jest": "22.4.2"
}
}

70
readme.md Normal file
View File

@ -0,0 +1,70 @@
# Chimera Doorlock
Powered by a [Tessel][tessel]
## Development
Follow the [start guide][start] on [Tessel.io][tessel].
Install `t2-cli` globally:
```bash
npm install -g t2-cli
```
Now install the correct version of node using nvm:
```bash
nvm install
nvm use
npm install
```
Now you can deploy to your connected Tessel device:
```bash
npm start
```
### Testing
We use [Jest][jest] to do testing of the core code in the library. Make sure to write tests for new code or update tests on existing code as needed. Test files are next to their source file named with a `.test.js` extension.
Run tests once: `npm test`
Run tests watching for changes: `npm run watch-test`
### RFID Cards
Read cards from Cobot:
<https://www.cobot.me/api-docs/check-ins#list-check-in-tokens>
### Useful Commands
```bash
# Connect to WiFi
t2 wifi -n network-name -p "some password"
# List devices
t2 list
# Update Tessel
t2 update
# Deploy code
t2 push index.js
# Clear code
t2 erase
# Create access point and server
t2 ap -n doorlock
```
### USB Storage
* Make sure to format USB to be FAT32!
[start]: http://tessel.github.io/t2-start
[tessel]: http://tessel.io

24
src/boot.js Normal file
View File

@ -0,0 +1,24 @@
const Door = require('./models/door')
Door.open()
// const server = require('./server')
// doorlock.updateCards()
// server()
// const HID = require('node-hid')
// choose driverType
// default is 'libusb' for Mac OSX & Windows
// default is 'hidraw', for Linux
// let type = null
// if (process.argv[2]) {
// type = process.argv[2]
// }
// disabled until prebuild gets multi-target, see issue node-hid#242
// console.log('driverType:', (type) ? type : 'default');
// HID.setDriverType( type );
// console.log('devices:', HID.devices())

7
src/models/access-log.js Normal file
View File

@ -0,0 +1,7 @@
class AccessLog {
static log(member) {
console.log('LOGGING', member)
}
}
module.exports = AccessLog

11
src/models/display.js Normal file
View File

@ -0,0 +1,11 @@
class Display {
static successMessage(msg) {
console.log('SUCCESS', msg)
}
static failureMessage(msg) {
console.log('FAILURE', msg)
}
}
module.exports = Display

67
src/models/door.js Normal file
View File

@ -0,0 +1,67 @@
const tessel = require('tessel')
const constants = require('../../config/constants')
// const fs = require('fs')
// const path = require('path')
// const USB_MOUNT_PATH = '/mnt/sda1'
// const CARDS_PATH = path.join(USB_MOUNT_PATH, 'cards.json')
class Door {
static open() {
// TODO: trigger door opening...
tessel.led[2].on()
return new Promise(resolve => {
setTimeout(() => {
// TODO: trigger door closing
Door.close()
resolve()
}, constants.DOOR_OPEN_DELAY)
})
}
static close() {
console.log('CLOSE DOOR')
tessel.led[2].off()
}
}
module.exports = Door
// const doorlock = {}
// doorlock.updateCards = () => {
// console.log('fetch cards from API and update file')
// const cards = [{ card: '1234', name: 'John' }, { card: '5566', name: 'Jane' }]
// doorlock.writeCards(cards)
// }
// doorlock.readCards = cb => {
// fs.readFile(CARDS_PATH, function(err, data) {
// if (err) throw err
// console.log('data:', data.toString())
// cb(JSON.parse(data))
// })
// }
// doorlock.writeCards = cards => {
// const text = JSON.stringify(cards)
// fs.writeFile(CARDS_PATH, text, err => {
// if (err) throw err
// console.log('wrote:', cards)
// })
// }
// doorlock.open = () => {
// console.log('open!')
// tessel.led[2].on()
// setTimeout(() => tessel.led[2].off(), 3000)
// }
// doorlock.close = () => {
// console.log('close!')
// tessel.led[3].on()
// setTimeout(() => tessel.led[3].off(), 3000)
// }
// module.exports = doorlock

24
src/models/door.test.js Normal file
View File

@ -0,0 +1,24 @@
const Door = require('./door')
const tessel = require('tessel')
jest.mock('tessel')
describe('models/door', () => {
describe('.open', () => {
test('opens door', () => {
jest.spyOn(Door, 'close')
// Door.close = jest.fn()
return Door.open().then(() => {
expect(tessel.led[2].on).toBeCalled()
expect(Door.close).toBeCalled()
})
})
})
describe('.close', () => {
test('closes door', () => {
Door.close()
expect(tessel.led[2].off).toBeCalled()
})
})
})