Last active
December 11, 2015 01:53
-
-
Save lampeh/7f49e596d2c10c1eaa5a to your computer and use it in GitHub Desktop.
cp-xmas2015
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user www-data; | |
worker_processes auto; | |
pid /run/nginx.pid; | |
events { | |
multi_accept on; | |
} | |
http { | |
sendfile on; | |
tcp_nopush on; | |
server_tokens off; | |
include /etc/nginx/mime.types; | |
default_type application/octet-stream; | |
# access_log /dev/null; | |
access_log /var/log/nginx/access.log; | |
error_log /var/log/nginx/error.log; | |
gzip on; | |
gzip_min_length 100; | |
gzip_vary on; | |
gzip_proxied any; | |
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; | |
upstream uv4l { | |
server 127.0.0.1:8080; | |
keepalive 1; | |
} | |
upstream node { | |
server 127.0.0.1:3000; | |
keepalive 1; | |
} | |
proxy_http_version 1.1; | |
proxy_set_header Connection ""; | |
server { | |
listen 80 default_server; | |
listen [::]:80 default_server; | |
server_name xmas.commerce-plus.com; | |
root /var/www/html; | |
index index.html; | |
location / { | |
try_files $uri $uri/ =404; | |
expires +1h; | |
} | |
location ~ \.(js|css|svg|png|ico)$ { | |
expires +1h; | |
} | |
location = /stream/video.mjpeg { | |
proxy_pass http://uv4l; | |
proxy_buffering off; | |
} | |
location /app/ { | |
proxy_pass http://node; | |
include /etc/nginx/cors.conf; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "cp-xmas2015", | |
"version": "1.0.0", | |
"homepage": "http://xmas.commerce-plus.com/", | |
"license": "UNLICENSED", | |
"private": true, | |
"config" : { | |
"port": "3000", | |
"switch_host": "192.168.252.64", | |
"switch_user": "user:kl4cK", | |
"led_device": "/dev/ttyUSB0" | |
}, | |
"dependencies": { | |
"express": "^4.13.3", | |
"body-parser": "^1.14.1", | |
"serialport": "^2.0.5" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://xmas.commerce-plus.com/ | |
// Switch: Koukaam NETIO 230A, http://www.koukaam.se/koukaam/downloads/MAN_DE_NETIO-230A_2.20.pdf | |
// LED: LED stripe, Atmega 168, https://www.arduino.cc/en/Tutorial/ReadASCIIString | |
var express = require("express"); | |
var bodyParser = require("body-parser"); | |
var serialport = require("serialport"); | |
var http = require("http"); | |
// default config | |
const appPort = process.env.npm_package_config_port || 3000; | |
const switchHost = process.env.npm_package_config_switch_host || "192.168.10.100"; | |
const switchUser = process.env.npm_package_config_switch_user || "user:user"; | |
const ledDevice = process.env.npm_package_config_led_device || "/dev/ttyAMA0"; | |
// TODO: unsorted foo | |
const switchTimeout = 2 * 1000; | |
const loginDelay = 0.5 * 1000; | |
var lastSwitchVal = ""; | |
// switch refresh rate | |
const switchInterval = 1 * 1000; | |
// color refresh rate | |
const ledInterval = 0.5 * 1000; | |
// serial connection to Atmega | |
var ledPort = new serialport.SerialPort(ledDevice, { | |
baudrate: 9600, | |
parser: serialport.parsers.readline("\n") | |
}); | |
// initial state | |
var ledColor = { "red": 0x00, "green": 0xFF, "blue": 0x00 } | |
// auto-reset switch if timeout > 0 | |
var switchState = { | |
"sw1": { "val": 0, "timeout": 0 }, | |
"sw2": { "val": 0, "timeout": 30 * 1000 }, | |
"sw3": { "val": 1, "timeout": 0 }, | |
"sw4": { "val": 0, "timeout": 10 * 1000 } | |
}; | |
var app = express(); | |
app.set("etag", false); | |
app.use(bodyParser.json()); | |
app.route("/app/color") | |
.get(function(req, res) { | |
res.send(ledColor); | |
}) | |
.post(function(req, res) { | |
console.log("POST color:", req.body); | |
for (var attr in ledColor) { | |
if (typeof req.body[attr] !== "undefined") { | |
var val = Math.max(0, Math.min(255, parseInt(req.body[attr]))); | |
ledColor[attr] = isNaN(val) ? 0 : val; | |
} | |
} | |
console.log("ledColor =", ledColor); | |
res.send(ledColor); | |
}); | |
app.route("/app/switch") | |
.post(function(req, res, next) { | |
console.log("POST switch:", req.body); | |
for (var attr in switchState) { | |
if (typeof req.body[attr] !== "undefined") { | |
// reset switch after timeout | |
if (switchState[attr].timeout && req.body[attr] && !switchState[attr].val) { | |
clearTimeout(switchState[attr].timer); | |
switchState[attr].timer = setTimeout(function(attr) { | |
switchState[attr].val = 0; | |
}, switchState[attr].timeout, attr); | |
} | |
switchState[attr].val = (req.body[attr] ? 1 : 0); | |
} | |
} | |
console.log("switchState =", switchState); | |
next(); | |
}) | |
// TODO: match only GET/POST without code duplication | |
.all(function(req, res) { | |
// reformat object | |
var body = {}; | |
for (var attr in switchState) { | |
body[attr] = switchState[attr].val; | |
} | |
res.send(body); | |
}); | |
function switchControl(command, cb) { | |
var options = { | |
host: switchHost, | |
path: "/tgi/control.tgi?" + command | |
}; | |
var req = http.request(options, function(res) { | |
console.log("switch response code:", res.statusCode); | |
console.log("switch response headers:", res.headers); | |
var str = ""; | |
res.on("data", function(chunk) { str += chunk; }); | |
res.on("end", function() { cb(str); }); | |
}); | |
req.on("error", function(e) { | |
console.error("HTTP client error:", e); | |
cb(null); | |
}); | |
req.setTimeout(switchTimeout, req.abort); | |
req.end(); | |
} | |
function switchLogin() { | |
console.log("switchLogin()"); | |
switchControl("login=p:" + switchUser, function(str) { | |
console.log("login response:", str); | |
setTimeout(updateSwitches, loginDelay); | |
}); | |
} | |
// continously check switchState for updates | |
function updateSwitches() { | |
// var val = "" + switchState.sw1.val + switchState.sw2.val + switchState.sw3.val + switchState.sw4.val; | |
// TODO: performance in main loop? | |
// TODO: ensure consistent swX order | |
var val = ""; | |
for (var attr in switchState) { | |
val += switchState[attr].val; | |
} | |
if (val === lastSwitchVal) { | |
setTimeout(updateSwitches, switchInterval); | |
return; | |
} | |
console.log("updateSwitches(): " + val); | |
switchControl("port=" + val, function(str) { | |
console.log("switch response:", str); | |
if (str === "<html>250 OK</html>\r\n") { | |
lastSwitchVal = val; | |
} else if (str === "<html>555 FORBIDDEN</html>\r\n") { | |
setTimeout(switchLogin, loginDelay); | |
return; | |
} | |
setTimeout(updateSwitches, switchInterval); | |
}); | |
} | |
// continously set color through serial port | |
function updateColor() { | |
// TODO: driver is active-high. update Atmega code to use non-inverted values | |
var val = "" + (255-ledColor.red) + "," + (255-ledColor.green) + "," + (255-ledColor.blue); | |
// console.log("updateColor: " + val); | |
if (ledPort.isOpen()) { | |
ledPort.write(val + "\n", function(error, result) { | |
// console.log("ledPort.write() result:", result); | |
if (!error) { | |
ledPort.drain(function(error) { | |
if (error) { | |
console.error("ledPort.drain() error:", error); | |
} | |
setTimeout(updateColor, ledInterval); | |
}); | |
} else { | |
console.error("ledPort.write() error:", error); | |
setTimeout(updateColor, ledInterval); | |
} | |
}); | |
} else { | |
setTimeout(updateColor, ledInterval); | |
} | |
} | |
function startLED() { | |
ledPort.on("open", function() { | |
console.log("ledPort opened"); | |
ledPort.on("data", function(data) { | |
// console.log("ledPort rx:", data); | |
}); | |
updateColor(); | |
}); | |
} | |
function startSwitch() { | |
updateSwitches(); | |
} | |
function startServer() { | |
// TODO: fork? | |
app.listen(appPort, function() { | |
console.log("listening at http://%s:%s", this.address().address, this.address().port); | |
}); | |
} | |
startLED(); | |
startSwitch(); | |
startServer(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
driver = raspicam | |
auto-video_nr = yes | |
verbosity = 6 | |
syslog-host = localhost | |
frame-buffers = 4 | |
drop-bad-frames = yes | |
encoding = mjpeg | |
width = 640 | |
height = 480 | |
framerate = 10 | |
quality = 10 | |
stills-denoise = yes | |
video-denoise = yes | |
nopreview = yes | |
fullscreen = no | |
### image settings options: | |
# sharpness = 0 | |
# contrast = 0 | |
# brightness = 50 | |
# saturation = 0 | |
# iso = 400 | |
# vstab = yes | |
# ev = 0 | |
# exposure = auto | |
# awb = auto | |
# imgfx = none | |
# metering = average | |
# rotation = 0 | |
hflip = no | |
vflip = no | |
# shutter-speed = 0 | |
# drc = off | |
# red-gain = 100 | |
# blue-gain = 100 | |
# text-annotation = HelloWorld! | |
# text-annotation-background = yes | |
statistics = yes | |
# output-buffers = 3 | |
server-option = --port=8080 | |
server-option = --max-streams=30 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment