Skip to content

Commit

Permalink
Merge pull request #3 from resin-io-projects/wifi-connect
Browse files Browse the repository at this point in the history
include wifi-connect
  • Loading branch information
curcuz authored Nov 18, 2016
2 parents 0f9220a + 220a5bb commit de28829
Show file tree
Hide file tree
Showing 23 changed files with 604 additions and 36 deletions.
31 changes: 27 additions & 4 deletions Dockerfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ RUN apt-get update && apt-get install -y \
gstreamer1.0-plugins-bad \
haproxy \
mopidy-spotify \
mopidy-soundcloud && rm -rf /var/lib/apt/lists/*
mopidy-soundcloud \
dnsmasq \
hostapd \
iproute2 \
iw \
libdbus-1-dev \
libexpat-dev \
rfkill && rm -rf /var/lib/apt/lists/*

# Enable haproxy
RUN echo 'ENABLED=1' >> /etc/default/haproxy
Expand All @@ -53,6 +60,8 @@ RUN printf "%s\n" "${PWD##}" > SOURCEFOLDER
# Deploy haproxy config
COPY "$SOURCEFOLDER/Dockerbin/haproxy.cfg" /etc/haproxy/haproxy.cfg

RUN mkdir -p /usr/src/app/

# Move to app dir
WORKDIR /usr/src/app

Expand All @@ -65,13 +74,27 @@ COPY "$SOURCEFOLDER/Dockerbin/asound.conf" /etc/asound.conf
# Move package.json to filesystem
COPY "$SOURCEFOLDER/app/package.json" ./

# NPM i app
RUN JOBS=MAX npm i --production
# Install npm modules for the application
RUN JOBS=MAX npm install --unsafe-perm --production \
&& npm cache clean

# Move bower.json to filesystem
COPY "$SOURCEFOLDER/app/bower.json $SOURCEFOLDER/app/.bowerrc" /usr/src/app/

# Install
RUN ./node_modules/.bin/bower --allow-root install \
&& ./node_modules/.bin/bower --allow-root cache clean

# Move app to filesystem
COPY "$SOURCEFOLDER/app" ./

## uncomment if you want systemd
# Compile coffee
RUN ./node_modules/.bin/coffee -c ./src

# Disable haproxy service - we will manually start it later
RUN systemctl disable haproxy

## Uncomment if you want systemd
ENV INITSYSTEM on

# Start app
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ please refer to [this link](https://github.com/resin-io-playground/boombeastic/b
## Getting started

- Sign up on [resin.io](https://dashboard.resin.io/signup)
- go throught the [getting started guide](http://docs.resin.io/raspberrypi/nodejs/getting-started/) and create a new application called `boombeasticmini`
- go throught the [getting started guide](http://docs.resin.io/raspberrypi/nodejs/getting-started/) and create a new RPI zero application called `boombeasticmini`
- clone this repository to your local workspace
- set these variables in the `Fleet Configuration` application side tab

Expand All @@ -46,6 +46,7 @@ MOPIDY_SPOTIFY_PASSWORD | `none` | your Spotify password
MOPIDY_SOUNDCLOUD_ENABLED | `false` | if set `true` loads the [SoundCloud extension](https://github.com/mopidy/mopidy-soundcloud)
MOPIDY_SOUNDCLOUD_AUTH_TOKEN | `none` | your SoundCloud [token](https://www.mopidy.com/authenticate/)
MOPIDY_YOUTUBE_ENABLED | `false` | if set `true` loads the [YouTube extension](https://github.com/mopidy/mopidy-youtube)
PORTAL_SSID | `ResinAP` | the name of the Access Point that [wifi-connect](https://github.com/resin-io/resin-wifi-connect) spawns if no known WiFi networks are found in order to expose WiFi configuration

## Videos

Expand Down
8 changes: 8 additions & 0 deletions app/.bowerrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"directory": "src/public/bower_components",
"storage": {
"packages": ".bower-cache",
"registry": ".bower-registry"
},
"tmp": ".bower-tmp"
}
20 changes: 20 additions & 0 deletions app/bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "resin-wifi-connect",
"version": "0.0.0",
"homepage": "https://github.com/pcarranzav/resin-wifi-connect",
"authors": [
"Pablo Carranza Vélez <[email protected]>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"src/public/bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.3.5"
}
}
41 changes: 20 additions & 21 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
(function() {
'use strict';

{
const fs = require('fs');
const ini = require('ini');
const exec = require('child_process').exec;
Expand All @@ -12,36 +10,36 @@
let mopidy = ini.parse(fs.readFileSync('/etc/mopidy/mopidy.conf', 'utf-8'));
console.log(chalk.cyan('configuring Mopidy from env vars...'));
let updating = false;

// http config
mopidy.http.port = (process.env.MOPIDY_HTTP_PORT == null) ? "8080" : process.env.MOPIDY_HTTP_PORT;

mopidy.http.port = (process.env.MOPIDY_HTTP_PORT === null) ? "8080" : process.env.MOPIDY_HTTP_PORT;
// mpd config
mopidy.mpd.port = (process.env.MOPIDY_MPD_PORT == null) ? "6680" : process.env.MOPIDY_MPD_PORT;

mopidy.mpd.port = (process.env.MOPIDY_MPD_PORT === null) ? "6680" : process.env.MOPIDY_MPD_PORT;
// audio config
mopidy.audio.mixer_volume = (process.env.MOPIDY_AUDIO_MIXER_VOLUME == null) ? "50" : process.env.MOPIDY_AUDIO_MIXER_VOLUME;

mopidy.audio.mixer_volume = (process.env.MOPIDY_AUDIO_MIXER_VOLUME === null) ? "50" : process.env.MOPIDY_AUDIO_MIXER_VOLUME;
// Google Play Music config
mopidy.gmusic.enabled = (process.env.MOPIDY_GMUSIC_ENABLED == null) ? "false" : process.env.MOPIDY_GMUSIC_ENABLED;
mopidy.gmusic.username = (process.env.MOPIDY_GMUSIC_USERNAME == null) ? "none" : process.env.MOPIDY_GMUSIC_USERNAME;
mopidy.gmusic.password = (process.env.MOPIDY_GMUSIC_PASSWORD == null) ? "none" : process.env.MOPIDY_GMUSIC_PASSWORD;
mopidy.gmusic.all_access = (process.env.MOPIDY_GMUSIC_ALL_ACCESS == null) ? "false" : process.env.MOPIDY_GMUSIC_ALL_ACCESS;
mopidy.gmusic.enabled = (process.env.MOPIDY_GMUSIC_ENABLED === null) ? "false" : process.env.MOPIDY_GMUSIC_ENABLED;
mopidy.gmusic.username = (process.env.MOPIDY_GMUSIC_USERNAME === null) ? "none" : process.env.MOPIDY_GMUSIC_USERNAME;
mopidy.gmusic.password = (process.env.MOPIDY_GMUSIC_PASSWORD === null) ? "none" : process.env.MOPIDY_GMUSIC_PASSWORD;
mopidy.gmusic.all_access = (process.env.MOPIDY_GMUSIC_ALL_ACCESS === null) ? "false" : process.env.MOPIDY_GMUSIC_ALL_ACCESS;
// Spotify config
mopidy.spotify.enabled = (process.env.MOPIDY_SPOTIFY_ENABLED == null) ? "false" : process.env.MOPIDY_SPOTIFY_ENABLED;
mopidy.spotify.username = (process.env.MOPIDY_SPOTIFY_USERNAME == null) ? "none" : process.env.MOPIDY_SPOTIFY_USERNAME;
mopidy.spotify.password = (process.env.MOPIDY_SPOTIFY_PASSWORD == null) ? "none" : process.env.MOPIDY_SPOTIFY_PASSWORD;
mopidy.spotify.enabled = (process.env.MOPIDY_SPOTIFY_ENABLED === null) ? "false" : process.env.MOPIDY_SPOTIFY_ENABLED;
mopidy.spotify.username = (process.env.MOPIDY_SPOTIFY_USERNAME === null) ? "none" : process.env.MOPIDY_SPOTIFY_USERNAME;
mopidy.spotify.password = (process.env.MOPIDY_SPOTIFY_PASSWORD === null) ? "none" : process.env.MOPIDY_SPOTIFY_PASSWORD;
// Soundcloud config
mopidy.soundcloud.enabled = (process.env.MOPIDY_SOUNDCLOUD_ENABLED == null) ? "false" : process.env.MOPIDY_SOUNDCLOUD_ENABLED;
mopidy.soundcloud.auth_token = (process.env.MOPIDY_SOUNDCLOUD_AUTH_TOKEN == null) ? "none" : process.env.MOPIDY_SOUNDCLOUD_AUTH_TOKEN;
mopidy.soundcloud.enabled = (process.env.MOPIDY_SOUNDCLOUD_ENABLED === null) ? "false" : process.env.MOPIDY_SOUNDCLOUD_ENABLED;
mopidy.soundcloud.auth_token = (process.env.MOPIDY_SOUNDCLOUD_AUTH_TOKEN === null) ? "none" : process.env.MOPIDY_SOUNDCLOUD_AUTH_TOKEN;
// Soundcloud config
mopidy.youtube.enabled = (process.env.MOPIDY_YOUTUBE_ENABLED == null) ? "false" : process.env.MOPIDY_YOUTUBE_ENABLED;
mopidy.youtube.enabled = (process.env.MOPIDY_YOUTUBE_ENABLED === null) ? "false" : process.env.MOPIDY_YOUTUBE_ENABLED;

fs.writeFileSync('/etc/mopidy/mopidy.conf', ini.stringify(mopidy));
console.log(chalk.cyan('starting Mopidy - HTTP port:' + mopidy.http.port + ' (proxy on port 80); MPD port:' + mopidy.mpd.port));
display.init(function() {
display.init(() => {
'use strict';
display.image(display.presets.splash);
});
exec('systemctl start mopidy', (error, stdout, stderr) => {
'use strict';
if (error) {
console.log(chalk.red(`exec error: ${error}`));
return;
Expand All @@ -51,6 +49,7 @@
});

setInterval(function keepalive() {
'use strict';
request(process.env.RESIN_SUPERVISOR_ADDRESS + '/v1/device?apikey=' + process.env.RESIN_SUPERVISOR_API_KEY, function(error, response, body) {
if (!error && response.statusCode == 200) {
body = JSON.parse(body);
Expand All @@ -76,4 +75,4 @@
});
}, 500);

})();
}
26 changes: 20 additions & 6 deletions app/libs/display.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/bin/env node

(function() {
'use strict';
{
const rpio = require('rpio');
const matrix = require('8x8matrix');
const randomIntArray = require('random-int-array');

let display = function() {
'use strict';
if (!(this instanceof display)) return new display();

this.presets = {
Expand Down Expand Up @@ -109,6 +109,17 @@
0, 0, 1, 1, 0, 0, 0, 0,
],

"wifi": [
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 1, 1, 0, 0, 0,
],

"blank": [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
Expand All @@ -125,17 +136,20 @@

};

display.prototype.init = function(callback) {
display.prototype.init = (callback) => {
'use strict';
let self = this;
matrix.init(rpio);
callback();
};
display.prototype.image = function(img) {
display.prototype.image = (img) => {
'use strict';
let self = this;
matrix.writeArray(img.reverse());
img.reverse();
};
display.prototype.random = function() {
display.prototype.random = () => {
'use strict';
let self = this;
self.randomImage = randomIntArray({
count: 64,
Expand All @@ -146,4 +160,4 @@

module.exports = display();

})();
}
12 changes: 11 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
"url": "https://github.com/resin-io-playground/boombeastic/issues"
},
"homepage": "https://github.com/resin-io-playground/boombeastic#readme",
"jshintConfig": {
"esnext": true,
"strict": true
},
"dependencies": {
"8x8matrix": "0.0.1",
"chalk": "^1.1.3",
Expand All @@ -48,6 +52,12 @@
"random-bool": "^1.0.2",
"random-int-array": "^1.0.0",
"request": "^2.72.0",
"rpio": "^0.9.12"
"rpio": "^0.9.12",
"bluebird": "^3.4.1",
"body-parser": "^1.15.2",
"bower": "^1.7.9",
"coffee-script": "~1.9.3",
"dbus": "^0.2.19",
"express": "^4.14.0"
}
}
69 changes: 69 additions & 0 deletions app/src/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
Promise = require 'bluebird'
fs = Promise.promisifyAll(require('fs'))
express = require 'express'
bodyParser = require 'body-parser'

config = require './config'

utils = require './utils'
connman = require './connman'
hotspot = require './hotspot'
wifiScan = require './wifi-scan'

app = express()

app.use(bodyParser.json())
app.use(bodyParser.urlencoded(extended: true))
app.use(express.static(__dirname + '/public'))

ssids = []

app.get '/ssids', (req, res) ->
res.json(ssids)

app.post '/connect', (req, res) ->
if not (req.body.ssid? and req.body.passphrase?)
return res.sendStatus(400)

console.log('Selected ' + req.body.ssid)

res.send('OK')

data = """
[service_home_ethernet]
Type = ethernet
Nameservers = 8.8.8.8,8.8.4.4
[service_home_wifi]
Type = wifi
Name = #{req.body.ssid}
Passphrase = #{req.body.passphrase}
Nameservers = 8.8.8.8,8.8.4.4
"""

Promise.all [
utils.durableWriteFile(config.connmanConfig, data)
hotspot.stop()
]
# XXX: make it so this delay isn't needed
.delay(1000)
.then ->
connman.waitForConnection(15000)
.then ->
utils.durableWriteFile(config.persistentConfig, data)
.then ->
process.exit()
.catch (e) ->
hotspot.start()

app.use (req, res) ->
res.redirect('/')

wifiScan.scanAsync()
.then (results) ->
ssids = results

hotspot.start()

app.listen(80)
8 changes: 8 additions & 0 deletions app/src/config.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports =
ssid: process.env.PORTAL_SSID or 'ResinAP'
passphrase: process.env.PORTAL_PASSPHRASE
iface: process.env.PORTAL_INTERFACE or 'wlan0'
gateway: process.env.PORTAL_GATEWAY or '192.168.42.1'
dhcpRange: process.env.PORTAL_DHCP_RANGE or '192.168.42.2,192.168.42.254'
connmanConfig: process.env.PORTAL_CONNMAN_CONFIG or '/host/var/lib/connman/network.config'
persistentConfig: process.env.PORTAL_PERSISTENT_CONFIG or '/data/network.config'
37 changes: 37 additions & 0 deletions app/src/connman.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Promise = require 'bluebird'
DBus = require './dbus-promise'

dbus = new DBus()

bus = dbus.getBus('system')

SERVICE = 'net.connman'
WIFI_OBJECT = '/net/connman/technology/wifi'
TECHNOLOGY_INTERFACE = 'net.connman.Technology'

exports.waitForConnection = (timeout) ->
console.log('Waiting for connman to connect..')

bus.getInterfaceAsync(SERVICE, WIFI_OBJECT, TECHNOLOGY_INTERFACE)
.then (wifi) ->
new Promise (resolve, reject, onCancel) ->
handler = (name, value) ->
if name is 'Connected' and value is true
wifi.removeListener('PropertyChanged', handler)
resolve()

# Listen for 'Connected' signals
wifi.on('PropertyChanged', handler)

# # But try to read in case we registered the event handler
# # after is was already connected
wifi.GetPropertiesAsync()
.then ({ Connected }) ->
if Connected
wifi.removeListener('PropertyChanged', handler)
resolve()

setTimeout ->
wifi.removeListener('PropertyChanged', handler)
reject()
, timeout
Loading

0 comments on commit de28829

Please sign in to comment.