Start project with blootstrap (pre publishing)
This commit is contained in:
commit
3f9e2853b0
|
@ -0,0 +1 @@
|
|||
node_modules
|
|
@ -0,0 +1,45 @@
|
|||
'use strict'
|
||||
|
||||
const ble = require('./lib/blootstrap')
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const gpio = require('gpio')
|
||||
const gpio4 = gpio.export(4, {
|
||||
direction: 'out',
|
||||
interval: 100,
|
||||
ready : () => {
|
||||
}
|
||||
})
|
||||
const PORT = process.env.PORT || 6699
|
||||
const APPNAME = 'my_project'
|
||||
|
||||
function blink (req, res, next) {
|
||||
console.log('Blinking!')
|
||||
gpio4.set(1)
|
||||
setTimeout(() => {
|
||||
gpio4.set(0)
|
||||
res.send('<h1>You blinked!</h1>')
|
||||
next()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function index (req, res, next) {
|
||||
res.send(
|
||||
`<h1>Welcome to my app!</h1>
|
||||
<form action="/blink" method="post">
|
||||
<input type="submit" value="Blink!" />
|
||||
</form>`)
|
||||
next()
|
||||
}
|
||||
|
||||
ble.on('data', (str) => {
|
||||
console.log(str)
|
||||
blink()
|
||||
})
|
||||
|
||||
app.get('/', index)
|
||||
app.all('/blink', blink)
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`${APPNAME} listening on port ${PORT}!`)
|
||||
})
|
|
@ -0,0 +1,32 @@
|
|||
'use strict'
|
||||
|
||||
const ipc = require('node-ipc')
|
||||
|
||||
function capitalize (s) {
|
||||
return s[0].toUpperCase() + s.slice(1)
|
||||
}
|
||||
|
||||
class Blootstrap {
|
||||
constructor () {
|
||||
this._onData = () => {}
|
||||
ipc.connectTo('blootstrap_ble', () => {
|
||||
ipc.of.blootstrap_ble.on('connect', () => {
|
||||
ipc.log(`Connected to the blootstrap_ble service`)
|
||||
|
||||
})
|
||||
ipc.of.blootstrap_ble.on('data', data => {
|
||||
const str = data.toString()
|
||||
ipc.log(str)
|
||||
this._onData(str)
|
||||
})
|
||||
ipc.of.blootstrap_ble.on('disconnect', () => {
|
||||
ipc.log(`Disconnected from the blootstrap_ble service`)
|
||||
})
|
||||
})
|
||||
}
|
||||
on (eventName, callback) {
|
||||
this[`_on${capitalize(eventName)}`] = callback
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Blootstrap()
|
|
@ -0,0 +1,90 @@
|
|||
'use strict'
|
||||
|
||||
const networkPattern = /network[\s\S]*?=[\s\S]*?{([\s\S]*?)}/gi
|
||||
const quoteRe = new RegExp('"', 'g')
|
||||
|
||||
const filePath = '/etc/wpa_supplicant/wpa_supplicant.conf'
|
||||
const reconfigure = '/sbin/wpa_cli reconfigure'
|
||||
const refresh = '/sbin/ifdown wlan0 && /sbin/ifup --force wlan0'
|
||||
const iwlist = '/sbin/iwlist wlan0 scanning | grep "ESSID:"'
|
||||
const iwgetid = '/sbin/iwgetid'
|
||||
|
||||
const exec = require('child_process').exec
|
||||
const fs = require('fs')
|
||||
|
||||
class wifi {
|
||||
constructor () {
|
||||
this._callback = () => {}
|
||||
this._entry = null
|
||||
}
|
||||
list (callback) {
|
||||
exec(iwlist, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return callback(err)
|
||||
}
|
||||
const lines = stdout.split('\n')
|
||||
const output = []
|
||||
let line
|
||||
for (let l of lines) {
|
||||
line = l.replace('ESSID:', '').trim()
|
||||
if (line != '""') {
|
||||
line = line.replace(quoteRe, '')
|
||||
output.push(line)
|
||||
}
|
||||
}
|
||||
return callback(null, output)
|
||||
})
|
||||
}
|
||||
_readConfigCb (err, data) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return this._callback(err)
|
||||
}
|
||||
if (data.search(networkPattern) === -1) {
|
||||
data += `\n${this._entry}`
|
||||
} else {
|
||||
data = data.replace(networkPattern, entry)
|
||||
}
|
||||
fs.writeFile(filePath, data, 'utf8', this._writeConfigCb)
|
||||
}
|
||||
_writeConfigCb (err) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return this._callback(err)
|
||||
}
|
||||
exec(reconfigure, this._reconfigureCb)
|
||||
}
|
||||
_reconfigureCb (err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return this._callback(err)
|
||||
}
|
||||
console.log('Wifi reconfigured')
|
||||
exec(refresh, this._refreshCb)
|
||||
}
|
||||
_refreshCb (err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return this._callback(err)
|
||||
}
|
||||
console.log('Wifi refreshed')
|
||||
this._callback(null, { ssid : ssid, pwd : pwd.length })
|
||||
this._callback = () => {}
|
||||
}
|
||||
setNetwork (ssid, pwd, callback) {
|
||||
this._entry = `network={\n\tssid="${ssid}"\n\tpsk="${pwd}"\n}\n`
|
||||
this._callback = callback
|
||||
fs.readFile(filePath, 'utf8', this._readConfigCb)
|
||||
}
|
||||
getNetwork (callback) {
|
||||
exec(iwgetid, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
callback(null, stdout)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new wifi()
|
|
@ -0,0 +1,47 @@
|
|||
#blootstrap nginx conf
|
||||
|
||||
#uncomment and modify following files for ssl
|
||||
#server {
|
||||
|
||||
#listen 80;
|
||||
#server_name my_project;
|
||||
#return 301 https://$server_name$request_uri;
|
||||
|
||||
#}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
#listen 443 ssl;
|
||||
|
||||
#ssl on;
|
||||
#ssl_certificate {{SSL_CERT_PATH}};
|
||||
#ssl_certificate_key {{SSL_KEY_PATH}};
|
||||
|
||||
#ssl_session_timeout 5m;
|
||||
#ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
|
||||
#ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
|
||||
#ssl_prefer_server_ciphers on;
|
||||
|
||||
#server_name my_project;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:6699/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
gzip on;
|
||||
gzip_comp_level 9;
|
||||
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json;
|
||||
}
|
||||
#uncomment for static file servers
|
||||
#location /static/ {
|
||||
#uncomment to turn on caching
|
||||
#expires modified 1y;
|
||||
#access_log off;
|
||||
#add_header Cache-Control "public";
|
||||
#gzip on;
|
||||
#gzip_comp_level 9;
|
||||
#gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json;
|
||||
#alias /var/node/blootstrap/static/;
|
||||
#}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "intval3",
|
||||
"version": "0.0.1",
|
||||
"description": "Intervalometer for the Bolex",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sixteenmillimeter/intval3.git"
|
||||
},
|
||||
"jshintConfig": {
|
||||
"esversion": 6,
|
||||
"strict": "global",
|
||||
"node": true,
|
||||
"asi": true
|
||||
},
|
||||
"author": "sixteenmillimeter",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/sixteenmillimeter/intval3/issues"
|
||||
},
|
||||
"homepage": "https://github.com/sixteenmillimeter/intval3#readme",
|
||||
"dependencies": {
|
||||
"bleno": "^0.4.2",
|
||||
"gpio": "^0.2.7",
|
||||
"node-ipc": "^9.1.0",
|
||||
"restify": "^5.2.0",
|
||||
"uuid": "^3.1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"apps" : [
|
||||
{
|
||||
"name" : "ble",
|
||||
"script" : "./services/bluetooth/index.js",
|
||||
"watch" : false,
|
||||
"env" : {
|
||||
"BLENO_DEVICE_NAME" : "intval3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Running blootstrap install script"
|
||||
apt-get update
|
||||
apt-get install git ufw nginx -y
|
||||
|
||||
echo "Installing node.js dependencies.."
|
||||
apt-get install nodejs npm -y
|
||||
npm install -g n
|
||||
n latest
|
||||
npm install -g npm@latest
|
||||
npm install -g pm2
|
||||
|
||||
echo "Installing bluetooth dependencies..."
|
||||
apt-get install bluetooth bluez libbluetooth-dev libudev-dev -y
|
||||
|
||||
echo "Finished installing blootstrap dependencies"
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Running blootstrap install script"
|
||||
apt-get update
|
||||
apt-get install git ufw nginx -y
|
||||
|
||||
echo "Installing node.js dependencies.."
|
||||
apt-get install nodejs npm -y
|
||||
npm install -g n
|
||||
n latest
|
||||
npm install -g npm@latest
|
||||
npm install -g pm2
|
||||
|
||||
echo "Installing bluetooth dependencies..."
|
||||
apt-get install bluetooth bluez libbluetooth-dev libudev-dev -y
|
||||
|
||||
echo "Configuring ufw (firewall)..."
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
ufw allow ssh
|
||||
ufw allow http
|
||||
ufw allow https
|
||||
ufw enable
|
||||
|
||||
echo "Installing blootstrap project..."
|
||||
mkdir /var/node
|
||||
cd /var/node
|
||||
wget https://github.com/mattmcw/blootstrap/archive/master.zip
|
||||
unzip master.zip -d blootstrap/
|
||||
rm master.zip
|
||||
|
||||
cd blootstrap
|
||||
npm install
|
||||
pm2 start process.json
|
||||
|
||||
echo "Finished installing blootstrap"
|
|
@ -0,0 +1,116 @@
|
|||
'use strict'
|
||||
|
||||
const ipc = require('node-ipc')
|
||||
const bleno = require('bleno')
|
||||
const util = require('util')
|
||||
const wifi = require('../../lib/wifi')
|
||||
|
||||
const BLENO_DEVICE_NAME = process.env.BLENO_DEVICE_NAME || 'my_project'
|
||||
const DEVICE_ID = process.env.DEVICE_ID || 'my_project_id'
|
||||
const SERVICE_ID = process.env.SERVICE_ID || 'blootstrap'
|
||||
const CHAR_ID = process.env.CHAR_ID || 'blootstrapwifi'
|
||||
|
||||
const chars = []
|
||||
|
||||
ipc.config.id = 'blootstrap_ble'
|
||||
ipc.config.retry = 1500
|
||||
ipc.config.rawBuffer = true
|
||||
ipc.config.encoding = 'hex'
|
||||
|
||||
function createChar(name, uuid, prop, write, read) {
|
||||
function characteristic () {
|
||||
bleno.Characteristic.call(this, {
|
||||
uuid : uuid,
|
||||
properties: prop
|
||||
})
|
||||
}
|
||||
util.inherits(characteristic, bleno.Characteristic)
|
||||
if (prop.indexOf('read')) {
|
||||
//data, offset, withoutResponse, callback
|
||||
characteristic.prototype.onReadRequest = read
|
||||
}
|
||||
if (prop.indexOf('write')) {
|
||||
characteristic.prototype.onWriteRequest = write
|
||||
}
|
||||
char.push(new characteristic())
|
||||
}
|
||||
|
||||
function onWifiWrite (data, offset, withoutResponse, callback) {
|
||||
let result
|
||||
let utf8
|
||||
let obj
|
||||
let ssid
|
||||
let pwd
|
||||
if (offset) {
|
||||
console.warn(`Offset scenario`)
|
||||
result = bleno.Characteristic.RESULT_ATTR_NOT_LONG
|
||||
return callback(result)
|
||||
}
|
||||
utf8 = data.toString('utf8')
|
||||
obj = JSON.parse(utf8)
|
||||
ssid = obj.ssid
|
||||
pwd = obj.pwd
|
||||
console.log(`Connecting to AP: ${ssid}...`)
|
||||
return wifi.setNetwork(ssid, pwd, (err, data) => {
|
||||
if (err) {
|
||||
console.error('Error configuring wifi', err)
|
||||
result = bleno.Characteristic.RESULT_UNLIKELY_ERROR
|
||||
return callback(result)
|
||||
}
|
||||
console.log(`Connected to ${ssid}`)
|
||||
result = bleno.Characteristic.RESULT_SUCCESS
|
||||
return callback(result)
|
||||
})
|
||||
}
|
||||
|
||||
function onWifiRead (offset, callback) {
|
||||
const result = bleno.Characteristic.RESULT_SUCCESS
|
||||
|
||||
callback(result, data.slice(offset, data.length))
|
||||
}
|
||||
|
||||
console.log('Starting bluetooth service')
|
||||
|
||||
bleno.on('stateChange', state => {
|
||||
console.log('on -> stateChange: ' + state)
|
||||
if (state === 'poweredOn') {
|
||||
console.log('Started advertising blootstrap services')
|
||||
bleno.startAdvertising(BLENO_DEVICE_NAME, [DEVICE_ID])
|
||||
} else {
|
||||
bleno.stopAdvertising()
|
||||
}
|
||||
})
|
||||
|
||||
bleno.on('advertisingStart', err => {
|
||||
console.log('on -> advertisingStart: ' + (err ? 'error ' + err : 'success'))
|
||||
if (!err) {
|
||||
bleno.setServices([
|
||||
new bleno.PrimaryService({
|
||||
uuid : SERVICE_ID, //hardcoded across panels
|
||||
characteristics : chars
|
||||
})
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
bleno.on('accept', clientAddress => {
|
||||
console.log(`${clientAddress} accepted`)
|
||||
})
|
||||
|
||||
bleno.on('disconnect', clientAddress => {
|
||||
console.log(`${clientAddress} disconnected`)
|
||||
})
|
||||
|
||||
ipc.serve(() => {
|
||||
ipc.server.on('connect', socket => {
|
||||
ipc.log('Client connected to socket')
|
||||
})
|
||||
ipc.server.on('disconnect', () => {
|
||||
ipc.log('Client disconnected from socket')
|
||||
})
|
||||
ipc.server.on('data', (data, socket) => {
|
||||
ipc.server.emit(socket, JSON.stringify({}))
|
||||
})
|
||||
})
|
||||
|
||||
ipc.server.start()
|
Loading…
Reference in New Issue