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