Skip to content

Instantly share code, notes, and snippets.

@blindman2k
Last active August 29, 2015 14:00
Show Gist options
  • Save blindman2k/11305787 to your computer and use it in GitHub Desktop.
Save blindman2k/11305787 to your computer and use it in GitHub Desktop.
Imp gateway demo - communicate with a line-oriented UART device through a web interface
const HTML = @"
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Imp Gateway Demo</title>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap-theme.min.css'>
</head>
<body>
<div class='container col-xs-12 col-sm-10 col-sm-offset-1' >
<div class='well' style='margin-top: 25px;'>
<h1 style='margin-top:0px;'>Imp Gateway Demo</h1>
<form role='form' style='margin-top: 25px;'>
<div class='form-group'>
<label for='url'>URL</label>
<input id='url' type='text' class='form-control' placeholder='http://requestb.in/1gni9ar1'>
<div class='text-right'>
<button id='configure' class='btn btn-primary btn-large' style='margin-top:15px;'>Config</button>
</div>
</div>
<div class='form-group' style='margin-top: 15px;'>
<label for='command'>COMMAND</label>
<textarea id='command' class='form-control' rows='3'></textarea>
</div>
<div class='text-right'>
<button id='post' class='btn btn-primary btn-large' style='margin-top:15px;'>Post</button>
</div>
</form>
</div>
<div class='well' style='margin-top: 25px;'>
<h1 style='margin-top:0px;'>Log</h1>
<p id='debugs'></p>
<div class='text-right'>
<button id='clear' class='btn btn-primary btn-large' style='margin-top:15px;'>Clear</button>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery-dateFormat/1.0/jquery.dateFormat.min.js'></script>
<script>
$(function() {
$('#url').val('%s');
$('#configure').click(function() {
$.ajax({
type: 'POST',
url: window.location.pathname + '/config',
data: { url : $('#url').val() }
});
return false;
})
$('#post').click(function() {
if ($('#command').val() != '') {
$.ajax({
type: 'POST',
url: window.location.pathname,
data: $('#command').val()
});
}
return false;
})
$('#clear').click(function() {
$.ajax({
type: 'GET',
url: window.location.pathname + '/clear',
success: function(data) {
$('#debugs').html('');
}
});
return false;
})
function getlogs() {
$.ajax({
type: 'GET',
url: window.location.pathname + '/logs',
timeout: 4500,
success: function(data) {
$('#debugs').html('');
data.forEach(function(log) {
var d = new Date();
d.setTime(log.ts * 1000);
var ts = jQuery.format.toBrowserTimeZone(d, 'yyyy-MM-dd HH:mm:ss');
ts = ts.replace(/ /g, '&nbsp;');
ts = ts.replace(/-/g, '&#8209;');
var text = $('<p>').text(log.text).html();
var line = '<span style=""font-family:monospace;"">' + ts + '<code>[' + log.type + ']</code> ' + text + '</span>';
$('#debugs').prepend(line + '<br/>');
})
}
});
}
setInterval(getlogs, 5000);
getlogs();
})
</script>
</body>
</html>
";
// -----------------------------------------------------------------------------
class Gateway_Agent {
_callbacks = null;
_debugs = null;
_url = null;
_persist = null;
// .........................................................................
constructor(persist = null) {
const MAXIMUM_DEBUGS = 20;
_callbacks = {};
_persist = persist;
_debugs = _persist ? _persist.read("debugs", []) : [];
_url = _persist ? _persist.read("url", "") : "";
device.on("line", device_read.bindenv(this));
http.onrequest(http_request.bindenv(this))
on("json", post_json.bindenv(this));
on("debug", post_debug.bindenv(this));
}
// .........................................................................
function device_read(line) {
local json;
try {
json = http.jsondecode(line);
} catch (e) {
if ("debug" in _callbacks) _callbacks["debug"](line);
return;
}
if ("json" in _callbacks) _callbacks["json"](json);
}
// .........................................................................
function http_request(req, res) {
try {
if (req.method == "POST") {
if (req.path == "/config") {
// This is the update of configuration data
try {
local config = http.urldecode(req.body);
if ("url" in config && config.url != "") {
_url = config.url;
if (_persist) _persist.write("url", _url);
}
} catch (e) {
res.send(400, "Invalid configuration data");
return;
}
res.send(200, "OK");
} else {
// This is the POSTing of a data block
local line = null;
try {
line = http.jsonencode(http.jsondecode(req.body));
post_debug(line, "*->")
} catch (e) {
line = req.body;
post_debug(line, "-->")
}
device.send("send", line);
res.send(200, "OK");
}
} else if (req.path == "/clear") {
_debugs = [];
if (_persist) _persist.remove("debugs");
res.send(200, "OK");
} else if (req.path == "/logs") {
res.header("Content-Type", "application/json");
res.send(200, http.jsonencode(_debugs));
} else {
// Anything else, send the HTML
res.send(200, format(HTML, _url));
}
} catch (e) {
server.error(e)
res.send(500, "Exception: " + e);
}
}
// .........................................................................
function post_json(json) {
post_debug(http.jsonencode(json), "<-*")
local url = _url;
if ("data" in json && "url" in json.data) url = json.data.url;
if (url) {
local headers = { "Content-Type": "application/json" };
local body = http.jsonencode(json);
local req = http.post(url, headers, body);
req.sendasync(function(res) {
if (res.statuscode != 200) {
server.error("Error " + res.statuscode + " posting JSON to " + url);
}
});
} else {
server.log("No URL to POST the JSON to: " + http.jsonencode(json))
}
}
// .........................................................................
function post_debug(debug, type = "<--") {
_debugs.push( { ts = time(), text = debug, type = type } );
if (_debugs.len() > MAXIMUM_DEBUGS) _debugs.remove(0);
if (_persist) _persist.write("debugs", _debugs);
}
// .........................................................................
function on(event, callback) {
if (callback == null) {
delete _callbacks[event];
} else {
_callbacks[event] <- callback;
}
}
}
// -----------------------------------------------------------------------------
class Persist {
cache = null;
// -------------------------------------------------------------------------
function read(key = null, def = null) {
if (cache == null) {
cache = server.load();
}
return (key in cache) ? cache[key] : def;
}
// -------------------------------------------------------------------------
function write(key, value) {
if (cache == null) {
cache = server.load();
}
if (key in cache) {
server.save(cache);
} else {
cache[key] <- value;
server.save(cache);
}
return value;
}
// -------------------------------------------------------------------------
function remove(key) {
if (cache == null) {
cache = server.load();
}
if (key in cache) {
delete cache[key];
server.save(cache);
}
}
}
// -----------------------------------------------------------------------------
persist <- Persist();
gateway <- Gateway_Agent(persist);
// -----------------------------------------------------------------------------
class Gateway_Device {
_uart = null;
_uart_buffer = null;
_callbacks = null;
// .........................................................................
constructor(uart) {
_uart = uart;
_uart_buffer = "";
_callbacks = {};
_uart.configure(115200, 8, PARITY_NONE, 1, 0, uart_read.bindenv(this))
agent.on("send", agent_data.bindenv(this))
on("line", send_data.bindenv(this));
}
// .........................................................................
function uart_read() {
local ch;
while ((ch = _uart.read()) != -1) {
if (ch == '\r' || ch == '\n') {
if (_uart_buffer.len() > 0 && "line" in _callbacks) {
_callbacks["line"](_uart_buffer);
}
_uart_buffer = "";
} else {
_uart_buffer += ch.tochar();
}
}
}
// .........................................................................
function agent_data(data) {
_uart.write(data + "\r\n");
}
// .........................................................................
function send_data(line) {
agent.send("line", line);
}
// .........................................................................
function on(event, callback) {
if (callback == null) {
delete _callbacks[event];
} else {
_callbacks[event] <- callback;
}
}
}
// -----------------------------------------------------------------------------
gateway <- Gateway_Device(hardware.uart57);
gateway.agent_data("Device rebooted");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment