mirror of
https://github.com/zyphlar/doorlock.git
synced 2024-04-03 21:36:03 +00:00
A happy beginning 🚪🔒
This commit is contained in:
commit
38c0bae242
13
.editorconfig
Normal file
13
.editorconfig
Normal 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
2
.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
31
.eslintrc.yml
Normal file
31
.eslintrc.yml
Normal 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
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
25
.npmrc
Normal file
25
.npmrc
Normal 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
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.vscode
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
package-lock.json
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
7
.tesselinclude
Normal file
7
.tesselinclude
Normal 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
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"git.ignoreLimitWarning": true
|
||||||
|
}
|
17
__mocks__/tessel.js
Normal file
17
__mocks__/tessel.js
Normal 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
6
config/constants.js
Normal 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
6
jest.config.js
Normal 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
5649
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
package.json
Normal file
26
package.json
Normal 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
70
readme.md
Normal 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
24
src/boot.js
Normal 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
7
src/models/access-log.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class AccessLog {
|
||||||
|
static log(member) {
|
||||||
|
console.log('LOGGING', member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AccessLog
|
11
src/models/display.js
Normal file
11
src/models/display.js
Normal 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
67
src/models/door.js
Normal 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
24
src/models/door.test.js
Normal 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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user