mirror of https://github.com/jeelabs/esp-link.git
commit
483800fd8d
@ -1,46 +0,0 @@ |
||||
<div id="main"> |
||||
<div class="header"> |
||||
<h1>Microcontroller Console</h1> |
||||
</div> |
||||
|
||||
<div class="content"> |
||||
<p>The Microcontroller console shows the last 1024 characters |
||||
received from UART0, to which a microcontroller is typically attached. |
||||
The UART is configured for 8 bits, no parity, 1 stop bit (8N1).</p> |
||||
<p> |
||||
<a id="reset-button" class="pure-button button-primary" href="#">Reset µC</a> |
||||
Baud: |
||||
<span id="baud-btns"></span> |
||||
</p> |
||||
<pre class="console" id="console"></pre> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script type="text/javascript">console_url = "/console/text"</script> |
||||
<script src="console.js"></script> |
||||
<script type="text/javascript"> |
||||
var rates = [57600, 115200, 230400, 460800]; |
||||
|
||||
onLoad(function() { |
||||
fetchText(100, true); |
||||
|
||||
$("#reset-button").addEventListener("click", function(e) { |
||||
e.preventDefault(); |
||||
var co = $("#console"); |
||||
co.innerHTML = ""; |
||||
ajaxSpin('POST', "/console/reset", |
||||
function(resp) { showNotification("uC reset"); co.textEnd = 0; }, |
||||
function(s, st) { showWarning("Error resetting uC"); } |
||||
); |
||||
}); |
||||
|
||||
rates.forEach(function(r) { baudButton(r); }); |
||||
|
||||
ajaxJson('GET', "/console/baud", |
||||
function(data) { showRate(data.rate); }, |
||||
function(s, st) { showNotification(st); } |
||||
); |
||||
}); |
||||
</script> |
||||
</body></html> |
@ -1,72 +0,0 @@ |
||||
function fetchText(delay, repeat) { |
||||
var el = $("#console"); |
||||
if (el.textEnd == undefined) { |
||||
el.textEnd = 0; |
||||
el.innerHTML = ""; |
||||
} |
||||
window.setTimeout(function() { |
||||
ajaxJson('GET', console_url + "?start=" + el.textEnd, |
||||
function(resp) { |
||||
var dly = updateText(resp); |
||||
if (repeat) fetchText(dly, repeat); |
||||
}, |
||||
function() { retryLoad(repeat); }); |
||||
}, delay); |
||||
} |
||||
|
||||
function updateText(resp) { |
||||
var el = $("#console"); |
||||
|
||||
var delay = 3000; |
||||
if (resp != null && resp.len > 0) { |
||||
console.log("updateText got", resp.len, "chars at", resp.start); |
||||
if (resp.start > el.textEnd) { |
||||
el.innerHTML = el.innerHTML.concat("\r\n<missing lines\r\n"); |
||||
} |
||||
el.innerHTML = el.innerHTML.concat(resp.text); |
||||
el.textEnd = resp.start + resp.len; |
||||
delay = 500; |
||||
} |
||||
return delay; |
||||
} |
||||
|
||||
function retryLoad(repeat) { |
||||
fetchText(1000, repeat); |
||||
} |
||||
|
||||
//===== Console page
|
||||
|
||||
function showRate(rate) { |
||||
rates.forEach(function(r) { |
||||
var el = $("#"+r+"-button"); |
||||
el.className = el.className.replace(" button-selected", ""); |
||||
}); |
||||
|
||||
var el = $("#"+rate+"-button"); |
||||
if (el != null) el.className += " button-selected"; |
||||
} |
||||
|
||||
function baudButton(baud) { |
||||
$("#baud-btns").appendChild(m( |
||||
' <a id="'+baud+'-button" href="#" class="pure-button">'+baud+'</a>')); |
||||
|
||||
$("#"+baud+"-button").addEventListener("click", function(e) { |
||||
e.preventDefault(); |
||||
ajaxSpin('POST', "/console/baud?rate="+baud, |
||||
function(resp) { showNotification("" + baud + " baud set"); showRate(baud); }, |
||||
function(s, st) { showWarning("Error setting baud rate: " + st); } |
||||
); |
||||
}); |
||||
} |
||||
|
||||
//===== Log page
|
||||
|
||||
function showDbgMode(mode) { |
||||
var btns = $('.dbg-btn'); |
||||
for (var i=0; i < btns.length; i++) { |
||||
if (btns[i].id === "dbg-"+mode) |
||||
addClass(btns[i], "button-selected"); |
||||
else |
||||
removeClass(btns[i], "button-selected"); |
||||
} |
||||
} |
Before Width: | Height: | Size: 874 B |
@ -1,10 +0,0 @@ |
||||
<!doctype html> |
||||
<html><head> |
||||
<title>esp-link</title> |
||||
<link rel="stylesheet" href="/pure.css"> |
||||
<link rel="stylesheet" href="/style.css"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<script src="/ui.js"></script> |
||||
</head> |
||||
<body> |
||||
<div id="layout"> |
@ -1,87 +0,0 @@ |
||||
<div id="main"> |
||||
<div class="header"> |
||||
<div><img src="favicon.ico" height="64"><span class="jl">JEELABS</span></div> |
||||
<h1 style="margin-top:0"><span class="esp">esp</span>-link</h1> |
||||
<h2 id="version"></h2> |
||||
</div> |
||||
|
||||
<div class="content"> |
||||
<div class="pure-g"> |
||||
<div class="pure-u-1"><div class="card"> |
||||
<p>The JeeLabs esp-link firmware bridges the ESP8266 serial port to Wifi and can |
||||
program microcontrollers over the serial port, in particular Arduinos, AVRs, and |
||||
NXP's LPC800 and other ARM processors.</p> |
||||
<p style="margin-bottom:0;">Program an Arduino/AVR using avrdude using a command |
||||
line similar to:</p> |
||||
<div class="tt">/home/arduino-1.0.5/hardware/tools/avrdude \<br> |
||||
-DV -patmega328p -Pnet:esp-link.local:23 -carduino -b115200 -U \<br> |
||||
-C /home/arduino-1.0.5/hardware/tools/avrdude.conf flash:w:my_sketch.hex:i |
||||
</div> |
||||
<p>where <tt>-Pnet:esp-link.local:23</tt> tells avrdude to connect to port 23 of esp-link. |
||||
You can substitute the IP address of your esp-link for esp-link.local if necessary.</p> |
||||
<p>Please refer to |
||||
<a href="https://github.com/jeelabs/esp-link/blob/master/README.md">the online README</a> |
||||
for up-to-date help and to the forthcoming |
||||
<a href="http://jeelabs.org">JeeLabs blog</a> for an intro to the codebase.</p> |
||||
</div></div> |
||||
</div> |
||||
<div class="pure-g"> |
||||
<div class="pure-u-1 pure-u-md-1-2"> |
||||
<div class="card"> |
||||
<h1>Wifi summary</h1> |
||||
<div id="wifi-spinner" class="spinner spinner-small"></div> |
||||
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody> |
||||
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr> |
||||
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr> |
||||
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr> |
||||
<tr><td>Wifi status</td><td id="wifi-status"></td></tr> |
||||
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr> |
||||
<tr><td>Configured hostname</td><td id="wifi-hostname"></td></tr> |
||||
</tbody> </table> |
||||
</div> |
||||
<div class="card"> |
||||
<h1>TCP client</h1> |
||||
<form action="#" id="tcpform" class="pure-form"> |
||||
<legend>TCP client support in esp-link</legend> |
||||
<div class="form-horizontal"> |
||||
<input type="checkbox" name="tcp_enable"/> |
||||
<label>Enable serial port TCP client</label> |
||||
</div> |
||||
<br> |
||||
<legend>Grovestreams data push</legend> |
||||
<div class="form-horizontal"> |
||||
<input type="checkbox" name="rssi_enable"/> |
||||
<label>Send RSSI</label> |
||||
</div> |
||||
<div class="pure-form-stacked"> |
||||
<label>API key/passwd</label> |
||||
<input type="password" name="api_key"/> |
||||
</div> |
||||
<button id="tcp-button" type="submit" |
||||
class="pure-button button-primary">Change!</button> |
||||
</form> |
||||
</div> |
||||
</div> |
||||
<div class="pure-u-1 pure-u-md-1-2"><div class="card"> |
||||
<h1>Pin assignment</h1> |
||||
<legend>Select one of the following signal/pin assignments to match your hardware</legend> |
||||
<fieldset class='radios' id='pin-mux'> |
||||
<div class="spinner spinner-small"></div> |
||||
</fieldset> |
||||
</div></div> |
||||
</div> |
||||
<div class="pure-g"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script type="text/javascript"> |
||||
onLoad(function() { |
||||
fetchPins(); |
||||
getWifiInfo(); |
||||
fetchTcpClient(); |
||||
bnd($("#tcpform"), "submit", changeTcpClient); |
||||
}); |
||||
</script> |
||||
</body></html> |
Before Width: | Height: | Size: 4.0 KiB |
@ -1,48 +0,0 @@ |
||||
<div id="main"> |
||||
<div class="header"> |
||||
<h1>Debug Log</h1> |
||||
</div> |
||||
|
||||
<div class="content"> |
||||
<p>The debug log shows the most recent characters printed by the esp-link software itself to |
||||
its own debug log.</p> |
||||
<div class="pure-g"> |
||||
<p class="pure-u-1-4"> |
||||
<a id="refresh-button" class="pure-button button-primary" href="#">Refresh</a> |
||||
</p> |
||||
<p class="pure-u-3-4" style="vertical-align: baseline"> |
||||
UART debug log: |
||||
<a id="dbg-auto" class="dbg-btn pure-button" href="#">auto</a> |
||||
<a id="dbg-off" class="dbg-btn pure-button" href="#">off</a> |
||||
<a id="dbg-on" class="dbg-btn pure-button" href="#">on</a> |
||||
</p> |
||||
</div> |
||||
<pre id="console" class="console" style="margin-top: 0px;"></pre> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script type="text/javascript">console_url = "/log/text"</script> |
||||
<script src="console.js"></script> |
||||
<script type="text/javascript"> |
||||
onLoad(function() { |
||||
fetchText(100, false); |
||||
|
||||
$("#refresh-button").addEventListener("click", function(e) { |
||||
e.preventDefault(); |
||||
fetchText(100, false); |
||||
}); |
||||
|
||||
["auto", "off", "on"].forEach(function(mode) { |
||||
bnd($('#dbg-'+mode), "click", function(el) { |
||||
ajaxJsonSpin('POST', "/log/dbg?mode="+mode, |
||||
function(data) { showNotification("UART mode " + data.mode); showDbgMode(data.mode); }, |
||||
function(s, st) { showWarning("Error setting UART mode: " + st); } |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
ajaxJson('GET', "/log/dbg", function(data) { showDbgMode(data.mode); }, function() {}); |
||||
}); |
||||
</script> |
||||
</body></html> |
File diff suppressed because it is too large
Load Diff
@ -1,380 +0,0 @@ |
||||
/* All fonts */ |
||||
html, button, input, select, textarea, .pure-g [class *= "pure-u"] { |
||||
font-family: sans-serif; |
||||
} |
||||
|
||||
body { |
||||
color: #777; |
||||
} |
||||
a:visited, a:link { |
||||
color: #009; |
||||
} |
||||
a:hover { |
||||
color: #00c; |
||||
} |
||||
|
||||
.card { |
||||
background-color: #eee; |
||||
padding: 1em; |
||||
margin: 0.5em; |
||||
-moz-border-radius: 0.5em; |
||||
-webkit-border-radius: 0.5em; |
||||
border-radius: 0.5em; |
||||
border: 0px solid #000000; |
||||
} |
||||
|
||||
/* wifi AP selection form */ |
||||
#aps label div { |
||||
display: inline-block; |
||||
margin: 0em 0.2em; |
||||
} |
||||
fieldset.radios { |
||||
border: none; |
||||
padding-left: 0px; |
||||
} |
||||
fieldset fields { |
||||
clear: both; |
||||
} |
||||
#pin-mux input { |
||||
display: block; |
||||
margin-top: 0.4em; |
||||
float: left; |
||||
} |
||||
#pin-mux label { |
||||
display: block; |
||||
margin: 0em 0.2em 0em 1em; |
||||
width: 90%; |
||||
} |
||||
|
||||
.pure-table td, .pure-table th { |
||||
padding: 0.5em 0.5em; |
||||
} |
||||
|
||||
/* make images size-up */ |
||||
.xx-pure-img-responsive { |
||||
max-width: 100%; |
||||
height: auto; |
||||
} |
||||
|
||||
/* Add transition to containers so they can push in and out */ |
||||
#layout, #menu, .menu-link { |
||||
-webkit-transition: all 0.2s ease-out; |
||||
-moz-transition: all 0.2s ease-out; |
||||
-ms-transition: all 0.2s ease-out; |
||||
-o-transition: all 0.2s ease-out; |
||||
transition: all 0.2s ease-out; |
||||
} |
||||
|
||||
/* This is the parent `<div>` that contains the menu and the content area */ |
||||
#layout { |
||||
position: relative; |
||||
padding-left: 0; |
||||
} |
||||
#layout.active #menu { |
||||
left: 150px; |
||||
width: 150px; |
||||
} |
||||
|
||||
#layout.active .menu-link { |
||||
left: 150px; |
||||
} |
||||
|
||||
div.tt { |
||||
font-family: monospace; |
||||
font-size: 120%; |
||||
color: #390; |
||||
background-color: #ddd; |
||||
padding: 2px; |
||||
margin: 2px 0; |
||||
line-height: 100%; |
||||
} |
||||
|
||||
/* The content `<div>` */ |
||||
.content { |
||||
margin: 0 auto; |
||||
padding: 0 2em; |
||||
max-width: 800px; |
||||
margin-bottom: 50px; |
||||
line-height: 1.6em; |
||||
} |
||||
|
||||
.header { |
||||
margin: 0; |
||||
color: #333; |
||||
text-align: center; |
||||
padding: 2.5em 2em 0; |
||||
border-bottom: 1px solid #eee; |
||||
background-color: #fc0; |
||||
} |
||||
.header h1 { |
||||
margin: 0.2em 0; |
||||
font-size: 3em; |
||||
font-weight: 300; |
||||
} |
||||
.header h1 .esp { |
||||
font-size: 1.25em; |
||||
} |
||||
.jl { |
||||
font: normal 800 1.5em sans-serif; |
||||
position: relative; |
||||
bottom: 19px; |
||||
color: #9d1414; |
||||
margin-left: 3px; |
||||
} |
||||
|
||||
.content-subhead { |
||||
margin: 50px 0 20px 0; |
||||
font-weight: 300; |
||||
color: #888; |
||||
} |
||||
|
||||
form button { |
||||
margin-top: 0.5em; |
||||
} |
||||
.button-primary { |
||||
background-color: #99f; |
||||
} |
||||
.button-selected { |
||||
background-color: #fc6; |
||||
} |
||||
|
||||
/* Text console */ |
||||
pre.console { |
||||
background-color: #663300; |
||||
-moz-border-radius: 5px; |
||||
-webkit-border-radius: 5px; |
||||
border-radius: 5px; |
||||
border: 0px solid #000000; |
||||
color: #66ff66; |
||||
padding: 5px; |
||||
} |
||||
|
||||
pre.console a { |
||||
color: #66ff66; |
||||
} |
||||
|
||||
/* log page */ |
||||
.dbg-btn, #refresh-button { |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
.lock-icon { |
||||
background-image: url("/wifi/icons.png"); |
||||
background-color: transparent; |
||||
width: 32px; |
||||
height: 32px; |
||||
display: inline-block; |
||||
} |
||||
|
||||
#menu { |
||||
margin-left: -150px; |
||||
width: 150px; |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
bottom: 0; |
||||
z-index: 1000; |
||||
background: #191818; |
||||
overflow-y: auto; |
||||
-webkit-overflow-scrolling: touch; |
||||
} |
||||
|
||||
#menu a { |
||||
color: #999; |
||||
border: none; |
||||
padding: 0.6em 0 0.6em 0.6em; |
||||
} |
||||
|
||||
#menu .pure-menu, #menu .pure-menu ul { |
||||
border: none; |
||||
background: transparent; |
||||
} |
||||
|
||||
#menu .pure-menu ul, #menu .pure-menu .menu-item-divided { |
||||
border-top: 1px solid #333; |
||||
} |
||||
|
||||
#menu .pure-menu li a:hover, #menu .pure-menu li a:focus { |
||||
background: #333; |
||||
} |
||||
|
||||
#menu .pure-menu-selected, #menu .pure-menu-heading { |
||||
background: #9d1414; |
||||
} |
||||
|
||||
#menu .pure-menu-selected a { |
||||
color: #fff; |
||||
} |
||||
|
||||
#menu .pure-menu-heading { |
||||
font-size: 110%; |
||||
color: #fff; |
||||
margin: 0; |
||||
text-transform: none; |
||||
} |
||||
|
||||
#menu .pure-menu-heading img { |
||||
vertical-align: middle; |
||||
top: -1px; |
||||
position: relative; |
||||
} |
||||
|
||||
#menu .pure-menu-item { |
||||
height:2em; |
||||
} |
||||
|
||||
/* -- Dynamic Button For Responsive Menu -------------------------------------*/ |
||||
|
||||
.menu-link { |
||||
position: fixed; |
||||
display: block; |
||||
top: 0; |
||||
left: 0; |
||||
background: #000; |
||||
background: rgba(0,0,0,0.7); |
||||
font-size: 10px; |
||||
z-index: 10; |
||||
width: 2em; |
||||
height: auto; |
||||
padding: 2.1em 1.6em; |
||||
} |
||||
|
||||
.menu-link:hover, .menu-link:focus { |
||||
background: #000; |
||||
} |
||||
|
||||
.menu-link span { |
||||
position: relative; |
||||
display: block; |
||||
} |
||||
|
||||
.menu-link span, .menu-link span:before, .menu-link span:after { |
||||
background-color: #fff; |
||||
width: 100%; |
||||
height: 0.2em; |
||||
} |
||||
|
||||
.menu-link span:before, .menu-link span:after { |
||||
position: absolute; |
||||
margin-top: -0.6em; |
||||
content: " "; |
||||
} |
||||
|
||||
.menu-link span:after { |
||||
margin-top: 0.6em; |
||||
} |
||||
|
||||
/* -- Responsive Styles (Media Queries) ------------------------------------- */ |
||||
|
||||
@media (min-width: 56em) { |
||||
.header, .content { |
||||
padding-left: 2em; |
||||
padding-right: 2em; |
||||
} |
||||
|
||||
#layout { |
||||
padding-left: 150px; |
||||
left: 0; |
||||
} |
||||
#menu { |
||||
left: 150px; |
||||
} |
||||
|
||||
.menu-link { |
||||
position: fixed; |
||||
left: 150px; |
||||
display: none; |
||||
} |
||||
|
||||
#layout.active .menu-link { |
||||
left: 150px; |
||||
} |
||||
} |
||||
|
||||
@media (max-width: 56em) { |
||||
#layout.active { |
||||
position: relative; |
||||
left: 150px; |
||||
} |
||||
} |
||||
|
||||
/*===== spinners and notification messages */ |
||||
|
||||
#messages { |
||||
position: absolute; |
||||
left: 25%; |
||||
width: 50%; |
||||
top: 10; |
||||
z-index: 200; |
||||
font-size: 110%; |
||||
text-align: center; |
||||
} |
||||
#warning { |
||||
background-color: #933; |
||||
color: #fcc; |
||||
padding: 0.1em 0.4em; |
||||
} |
||||
#notification { |
||||
background-color: #693; |
||||
color: #cfc; |
||||
padding: 0.1em 0.4em; |
||||
} |
||||
|
||||
#spinner { |
||||
position: absolute; |
||||
right: 10%; |
||||
top: 20; |
||||
z-index: 1000; |
||||
} |
||||
.spinner { |
||||
height: 50px; |
||||
width: 50px; |
||||
-webkit-animation: rotation 1s infinite linear; |
||||
-moz-animation: rotation 1s infinite linear; |
||||
-o-animation: rotation 1s infinite linear; |
||||
animation: rotation 1s infinite linear; |
||||
border-left: 10px solid rgba(204, 51, 0, 0.15); |
||||
border-right: 10px solid rgba(204, 51, 0, 0.15); |
||||
border-bottom: 10px solid rgba(204, 51, 0, 0.15); |
||||
border-top: 10px solid rgba(204, 51, 0, 0.8); |
||||
border-radius: 100%; |
||||
} |
||||
.spinner-small { |
||||
display: inline-block; |
||||
height: 1em; |
||||
width: 1em; |
||||
border-width: 4px; |
||||
} |
||||
|
||||
@-webkit-keyframes rotation { |
||||
from { |
||||
-webkit-transform: rotate(0deg); |
||||
} |
||||
to { |
||||
-webkit-transform: rotate(359deg); |
||||
} |
||||
} |
||||
@-moz-keyframes rotation { |
||||
from { |
||||
-moz-transform: rotate(0deg); |
||||
} |
||||
to { |
||||
-moz-transform: rotate(359deg); |
||||
} |
||||
} |
||||
@-o-keyframes rotation { |
||||
from { |
||||
-o-transform: rotate(0deg); |
||||
} |
||||
to { |
||||
-o-transform: rotate(359deg); |
||||
} |
||||
} |
||||
@keyframes rotation { |
||||
from { |
||||
transform: rotate(0deg); |
||||
} |
||||
to { |
||||
transform: rotate(359deg); |
||||
} |
||||
} |
@ -1,397 +0,0 @@ |
||||
//===== Collection of small utilities
|
||||
|
||||
/* |
||||
* Bind/Unbind events |
||||
* |
||||
* Usage: |
||||
* var el = document.getElementyById('#container'); |
||||
* bnd(el, 'click', function() { |
||||
* console.log('clicked'); |
||||
* }); |
||||
*/ |
||||
|
||||
var bnd = function( |
||||
d, // a DOM element
|
||||
e, // an event name such as "click"
|
||||
f // a handler function
|
||||
){ |
||||
d.addEventListener(e, f, false); |
||||
} |
||||
|
||||
/* |
||||
* Create DOM element |
||||
* |
||||
* Usage: |
||||
* var el = m('<h1>Hello</h1>'); |
||||
* document.body.appendChild(el); |
||||
* |
||||
* Copyright (C) 2011 Jed Schmidt <http://jed.is> - WTFPL
|
||||
* More: https://gist.github.com/966233
|
||||
*/ |
||||
|
||||
var m = function( |
||||
a, // an HTML string
|
||||
b, // placeholder
|
||||
c // placeholder
|
||||
){ |
||||
b = document; // get the document,
|
||||
c = b.createElement("p"); // create a container element,
|
||||
c.innerHTML = a; // write the HTML to it, and
|
||||
a = b.createDocumentFragment(); // create a fragment.
|
||||
|
||||
while ( // while
|
||||
b = c.firstChild // the container element has a first child
|
||||
) a.appendChild(b); // append the child to the fragment,
|
||||
|
||||
return a // and then return the fragment.
|
||||
} |
||||
|
||||
/* |
||||
* DOM selector |
||||
* |
||||
* Usage: |
||||
* $('div'); |
||||
* $('#name'); |
||||
* $('.name'); |
||||
* |
||||
* Copyright (C) 2011 Jed Schmidt <http://jed.is> - WTFPL
|
||||
* More: https://gist.github.com/991057
|
||||
*/ |
||||
|
||||
var $ = function( |
||||
a, // take a simple selector like "name", "#name", or ".name", and
|
||||
b // an optional context, and
|
||||
){ |
||||
a = a.match(/^(\W)?(.*)/); // split the selector into name and symbol.
|
||||
return( // return an element or list, from within the scope of
|
||||
b // the passed context
|
||||
|| document // or document,
|
||||
)[ |
||||
"getElement" + ( // obtained by the appropriate method calculated by
|
||||
a[1] |
||||
? a[1] == "#" |
||||
? "ById" // the node by ID,
|
||||
: "sByClassName" // the nodes by class name, or
|
||||
: "sByTagName" // the nodes by tag name,
|
||||
) |
||||
]( |
||||
a[2] // called with the name.
|
||||
) |
||||
} |
||||
|
||||
/* |
||||
* Get cross browser xhr object |
||||
* |
||||
* Copyright (C) 2011 Jed Schmidt <http://jed.is>
|
||||
* More: https://gist.github.com/993585
|
||||
*/ |
||||
|
||||
var j = function( |
||||
a // cursor placeholder
|
||||
){ |
||||
for( // for all a
|
||||
a=0; // from 0
|
||||
a<4; // to 4,
|
||||
a++ // incrementing
|
||||
) try { // try
|
||||
return a // returning
|
||||
? new ActiveXObject( // a new ActiveXObject
|
||||
[ // reflecting
|
||||
, // (elided)
|
||||
"Msxml2", // the various
|
||||
"Msxml3", // working
|
||||
"Microsoft" // options
|
||||
][a] + // for Microsoft implementations, and
|
||||
".XMLHTTP" // the appropriate suffix,
|
||||
) // but make sure to
|
||||
: new XMLHttpRequest // try the w3c standard first, and
|
||||
} |
||||
|
||||
catch(e){} // ignore when it fails.
|
||||
} |
||||
|
||||
// createElement short-hand
|
||||
|
||||
e = function(a) { return document.createElement(a); } |
||||
|
||||
// chain onload handlers
|
||||
|
||||
function onLoad(f) { |
||||
var old = window.onload; |
||||
if (typeof old != 'function') { |
||||
window.onload = f; |
||||
} else { |
||||
window.onload = function() { |
||||
old(); |
||||
f(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//===== helpers to add/remove/toggle HTML element classes
|
||||
|
||||
function addClass(el, cl) { |
||||
el.className += ' ' + cl; |
||||
} |
||||
function removeClass(el, cl) { |
||||
var cls = el.className.split(/\s+/), |
||||
l = cls.length; |
||||
for (var i=0; i<l; i++) { |
||||
if (cls[i] === cl) cls.splice(i, 1); |
||||
} |
||||
el.className = cls.join(' '); |
||||
return cls.length != l |
||||
} |
||||
function toggleClass(el, cl) { |
||||
if (!removeClass(el, cl)) addClass(el, cl); |
||||
} |
||||
|
||||
//===== AJAX
|
||||
|
||||
function ajaxReq(method, url, ok_cb, err_cb) { |
||||
var xhr = j(); |
||||
xhr.open(method, url, true); |
||||
var timeout = setTimeout(function() { |
||||
xhr.abort(); |
||||
console.log("XHR abort:", method, url); |
||||
xhr.status = 599; |
||||
xhr.responseText = "request time-out"; |
||||
}, 9000); |
||||
xhr.onreadystatechange = function() { |
||||
if (xhr.readyState != 4) { return; } |
||||
clearTimeout(timeout); |
||||
if (xhr.status >= 200 && xhr.status < 300) { |
||||
console.log("XHR done:", method, url, "->", xhr.status); |
||||
ok_cb(xhr.responseText); |
||||
} else { |
||||
console.log("XHR ERR :", method, url, "->", xhr.status, xhr.responseText, xhr); |
||||
err_cb(xhr.status, xhr.responseText); |
||||
} |
||||
} |
||||
console.log("XHR send:", method, url); |
||||
try { |
||||
xhr.send(); |
||||
} catch(err) { |
||||
console.log("XHR EXC :", method, url, "->", err); |
||||
err_cb(599, err); |
||||
} |
||||
} |
||||
|
||||
function dispatchJson(resp, ok_cb, err_cb) { |
||||
var j; |
||||
try { j = JSON.parse(resp); } |
||||
catch(err) { |
||||
console.log("JSON parse error: " + err + ". In: " + resp); |
||||
err_cb(500, "JSON parse error: " + err); |
||||
return; |
||||
} |
||||
ok_cb(j); |
||||
} |
||||
|
||||
function ajaxJson(method, url, ok_cb, err_cb) { |
||||
ajaxReq(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb); |
||||
} |
||||
|
||||
function ajaxSpin(method, url, ok_cb, err_cb) { |
||||
$("#spinner").removeAttribute('hidden'); |
||||
ajaxReq(method, url, function(resp) { |
||||
$("#spinner").setAttribute('hidden', ''); |
||||
ok_cb(resp); |
||||
}, function(status, statusText) { |
||||
$("#spinner").setAttribute('hidden', ''); |
||||
//showWarning("Error: " + statusText);
|
||||
err_cb(status, statusText); |
||||
}); |
||||
} |
||||
|
||||
function ajaxJsonSpin(method, url, ok_cb, err_cb) { |
||||
ajaxSpin(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb); |
||||
} |
||||
|
||||
//===== main menu, header spinner and notification boxes
|
||||
|
||||
onLoad(function() { |
||||
var l = $("#layout"); |
||||
var o = l.childNodes[0]; |
||||
// spinner
|
||||
l.insertBefore(m('<div id="spinner" class="spinner" hidden></div>'), o); |
||||
// notification boxes
|
||||
l.insertBefore(m( |
||||
'<div id="messages"><div id="warning" hidden></div><div id="notification" hidden></div></div>'), o); |
||||
// menu hamburger button
|
||||
l.insertBefore(m('<a href="#menu" id="menuLink" class="menu-link"><span></span></a>'), o); |
||||
// menu left-pane
|
||||
var mm = m( |
||||
'<div id="menu">\ |
||||
<div class="pure-menu">\ |
||||
<a class="pure-menu-heading" href="https://github.com/jeelabs/esp-link">\ |
||||
<img src="/favicon.ico" height="32"> esp-link</a>\ |
||||
<ul id="menu-list" class="pure-menu-list"></ul>\ |
||||
</div>\ |
||||
</div>\ |
||||
'); |
||||
l.insertBefore(mm, o); |
||||
|
||||
// make hamburger button pull out menu
|
||||
var ml = $('#menuLink'), mm = $('#menu'); |
||||
bnd(ml, 'click', function (e) { |
||||
console.log("hamburger time"); |
||||
var active = 'active'; |
||||
e.preventDefault(); |
||||
toggleClass(l, active); |
||||
toggleClass(mm, active); |
||||
toggleClass(ml, active); |
||||
}); |
||||
|
||||
// populate menu via ajax call
|
||||
var getMenu = function() { |
||||
ajaxJson("GET", "/menu", function(data) { |
||||
var html = "", path = window.location.pathname; |
||||
for (var i=0; i<data.menu.length; i+=2) { |
||||
var href = data.menu[i+1]; |
||||
html = html.concat(" <li class=\"pure-menu-item" + |
||||
(path === href ? " pure-menu-selected" : "") + "\">" + |
||||
"<a href=\"" + href + "\" class=\"pure-menu-link\">" + |
||||
data.menu[i] + "</a></li>"); |
||||
} |
||||
$("#menu-list").innerHTML = html; |
||||
|
||||
v = $("#version"); |
||||
if (v != null) { v.innerHTML = data.version; } |
||||
}, function() { setTimeout(getMenu, 1000); }); |
||||
}; |
||||
getMenu(); |
||||
}); |
||||
|
||||
//===== Wifi info
|
||||
|
||||
function showWifiInfo(data) { |
||||
Object.keys(data).forEach(function(v) { |
||||
el = $("#wifi-" + v); |
||||
if (el != null) { |
||||
if (el.nodeName === "INPUT") el.value = data[v]; |
||||
else el.innerHTML = data[v]; |
||||
} |
||||
}); |
||||
var dhcp = $('#dhcp-r'+data.dhcp); |
||||
if (dhcp) dhcp.click(); |
||||
$("#wifi-spinner").setAttribute("hidden", ""); |
||||
$("#wifi-table").removeAttribute("hidden"); |
||||
currAp = data.ssid; |
||||
} |
||||
|
||||
function getWifiInfo() { |
||||
ajaxJson('GET', "/wifi/info", showWifiInfo, |
||||
function(s, st) { window.setTimeout(getWifiInfo, 1000); }); |
||||
} |
||||
|
||||
//===== Notifications
|
||||
|
||||
function showWarning(text) { |
||||
var el = $("#warning"); |
||||
el.innerHTML = text; |
||||
el.removeAttribute('hidden'); |
||||
} |
||||
function hideWarning() { |
||||
el = $("#warning").setAttribute('hidden', ''); |
||||
} |
||||
var notifTimeout = null; |
||||
function showNotification(text) { |
||||
var el = $("#notification"); |
||||
el.innerHTML = text; |
||||
el.removeAttribute('hidden'); |
||||
if (notifTimeout != null) clearTimeout(notifTimeout); |
||||
notifTimout = setTimeout(function() { |
||||
el.setAttribute('hidden', ''); |
||||
notifTimout = null; |
||||
}, 4000); |
||||
} |
||||
|
||||
//===== GPIO Pin mux card
|
||||
|
||||
var currPin; |
||||
// pin={reset:12, isp:13, LED_conn:0, LED_ser:2}
|
||||
function createInputForPin(pin) { |
||||
var input = document.createElement("input"); |
||||
input.type = "radio"; |
||||
input.name = "pins"; |
||||
input.data = pin.name; |
||||
input.className = "pin-input"; |
||||
input.value= pin.value; |
||||
input.id = "opt-" + pin.value; |
||||
if (currPin == pin.name) input.checked = "1"; |
||||
|
||||
var descr = m('<label for="opt-'+pin.value+'"><b>'+pin.name+":</b>"+pin.descr+"</label>"); |
||||
var div = document.createElement("div"); |
||||
div.appendChild(input); |
||||
div.appendChild(descr); |
||||
return div; |
||||
} |
||||
|
||||
function displayPins(resp) { |
||||
var po = $("#pin-mux"); |
||||
po.innerHTML = ""; |
||||
currPin = resp.curr; |
||||
resp.map.forEach(function(v) { |
||||
po.appendChild(createInputForPin(v)); |
||||
}); |
||||
var i, inputs = $(".pin-input"); |
||||
for (i=0; i<inputs.length; i++) { |
||||
inputs[i].onclick = function() { setPins(this.value, this.data) }; |
||||
}; |
||||
} |
||||
|
||||
function fetchPins() { |
||||
ajaxJson("GET", "/pins", displayPins, function() { |
||||
window.setTimeout(fetchPins, 1000); |
||||
}); |
||||
} |
||||
|
||||
function setPins(v, name) { |
||||
ajaxSpin("POST", "/pins?map="+v, function() { |
||||
showNotification("Pin assignment changed to " + name); |
||||
}, function() { |
||||
showNotification("Pin assignment change failed"); |
||||
window.setTimeout(fetchPins, 100); |
||||
}); |
||||
} |
||||
|
||||
//===== TCP client card
|
||||
|
||||
function tcpEn(){return document.querySelector('input[name="tcp_enable"]')} |
||||
function rssiEn(){return document.querySelector('input[name="rssi_enable"]')} |
||||
function apiKey(){return document.querySelector('input[name="api_key"]')} |
||||
|
||||
function changeTcpClient(e) { |
||||
e.preventDefault(); |
||||
var url = "tcpclient"; |
||||
url += "?tcp_enable=" + tcpEn().checked; |
||||
url += "&rssi_enable=" + rssiEn().checked; |
||||
url += "&api_key=" + encodeURIComponent(apiKey().value); |
||||
|
||||
hideWarning(); |
||||
var cb = $("#tcp-button"); |
||||
addClass(cb, 'pure-button-disabled'); |
||||
ajaxSpin("POST", url, function(resp) { |
||||
removeClass(cb, 'pure-button-disabled'); |
||||
getWifiInfo(); |
||||
}, function(s, st) { |
||||
showWarning("Error: "+st); |
||||
removeClass(cb, 'pure-button-disabled'); |
||||
getWifiInfo(); |
||||
}); |
||||
} |
||||
|
||||
function displayTcpClient(resp) { |
||||
tcpEn().checked = resp.tcp_enable > 0; |
||||
rssiEn().checked = resp.rssi_enable > 0; |
||||
apiKey().value = resp.api_key; |
||||
} |
||||
|
||||
function fetchTcpClient() { |
||||
ajaxJson("GET", "/tcpclient", displayTcpClient, function() { |
||||
window.setTimeout(fetchTcpClient, 1000); |
||||
}); |
||||
} |
||||
|
||||
|
Before Width: | Height: | Size: 914 B |
@ -1,84 +0,0 @@ |
||||
<div id="main"> |
||||
<div class="header"> |
||||
<h1>Wifi Configuration</h1> |
||||
</div> |
||||
|
||||
<div class="content"> |
||||
<div class="pure-g"> |
||||
<div class="pure-u-1 pure-u-md-1-2"><div class="card"> |
||||
<h1>Wifi State</h1> |
||||
<div id="wifi-spinner" class="spinner spinner-small"></div> |
||||
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody> |
||||
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr> |
||||
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr> |
||||
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr> |
||||
<tr><td>Wifi status</td><td id="wifi-status"></td></tr> |
||||
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr> |
||||
<tr><td>Wifi rssi</td><td id="wifi-rssi"></td></tr> |
||||
<tr><td>Wifi phy</td><td id="wifi-phy"></td></tr> |
||||
<tr><td>Wifi MAC</td><td id="wifi-mac"></td></tr> |
||||
<tr><td colspan="2" id="wifi-warn"></td></tr> |
||||
</tbody> </table> |
||||
</div></div> |
||||
<div class="pure-u-1 pure-u-md-1-2"><div class="card"> |
||||
<h1>Wifi Association</h1> |
||||
<p id="reconnect" style="color: #600" hidden></p> |
||||
<form action="#" id="wifiform" class="pure-form pure-form-stacked"> |
||||
<legend>To connect to a WiFi network, please select one of the detected networks, |
||||
enter the password, and hit the connect button...</legend> |
||||
<label>Network SSID</label> |
||||
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div> |
||||
<label>WiFi password, if applicable:</label> |
||||
<input id="wifi-passwd" type="password" name="passwd" placeholder="password"> |
||||
<button id="connect-button" type="submit" class="pure-button button-primary">Connect!</button> |
||||
</form> |
||||
</div></div> |
||||
</div> |
||||
<div class="pure-g"> |
||||
<div class="pure-u-1 pure-u-md-1-2"><div class="card"> |
||||
<h1>Special Settings</h1> |
||||
<form action="#" id="specform" class="pure-form"> |
||||
<legend>Special settings, use with care!</legend> |
||||
<div class="form-horizontal"> |
||||
<label for="dhcp-ron" style="margin-right:1em"> |
||||
<input type="radio" name="dhcp" value="on" id="dhcp-ron"/> |
||||
DHCP</label> |
||||
<label for="dhcp-roff"> |
||||
<input type="radio" name="dhcp" value="off" id="dhcp-roff"/> |
||||
Static IP</label> |
||||
</div> |
||||
<div id="dhcp-on" class="pure-form-stacked"> |
||||
<label>Hostname when requesting DHCP lease</label> |
||||
<input id="wifi-hostname" type="text" name="hostname"/> |
||||
</div> |
||||
<div id="dhcp-off" class="pure-form-stacked"> |
||||
<label>Static IP address</label> |
||||
<input id="wifi-staticip" type="text" name="staticip"/> |
||||
<label>Netmask (for static IP)</label> |
||||
<input id="wifi-netmask" type="text" name="netmask"/> |
||||
<label>Gateway (for static IP)</label> |
||||
<input id="wifi-gateway" type="text" name="gateway"/> |
||||
</div> |
||||
<button id="special-button" type="submit" |
||||
class="pure-button button-primary">Change!</button> |
||||
</form> |
||||
</div></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script type="text/javascript"> |
||||
</script> |
||||
<script src="wifi.js"></script> |
||||
<script type="text/javascript"> |
||||
onLoad(function() { |
||||
getWifiInfo(); |
||||
bnd($("#wifiform"), "submit", changeWifiAp); |
||||
bnd($("#specform"), "submit", changeSpecial); |
||||
bnd($("#dhcp-ron"), "click", doDhcp); |
||||
bnd($("#dhcp-roff"), "click", doStatic); |
||||
scanTimeout = window.setTimeout(scanAPs, 500); |
||||
}); |
||||
</script> |
||||
</body></html> |
@ -1,200 +0,0 @@ |
||||
var currAp = ""; |
||||
var blockScan = 0; |
||||
|
||||
function createInputForAp(ap) { |
||||
if (ap.essid=="" && ap.rssi==0) return; |
||||
|
||||
var input = e("input"); |
||||
input.type = "radio"; |
||||
input.name = "essid"; |
||||
input.value=ap.essid; |
||||
input.id = "opt-" + ap.essid; |
||||
if (currAp == ap.essid) input.checked = "1"; |
||||
|
||||
var bars = e("div"); |
||||
var rssiVal = -Math.floor(ap.rssi/51)*32; |
||||
bars.className = "lock-icon"; |
||||
bars.style.backgroundPosition = "0px "+rssiVal+"px"; |
||||
|
||||
var rssi = e("div"); |
||||
rssi.innerHTML = "" + ap.rssi +"dB"; |
||||
|
||||
var encrypt = e("div"); |
||||
var encVal = "-64"; //assume wpa/wpa2
|
||||
if (ap.enc == "0") encVal = "0"; //open
|
||||
if (ap.enc == "1") encVal = "-32"; //wep
|
||||
encrypt.className = "lock-icon"; |
||||
encrypt.style.backgroundPosition = "-32px "+encVal+"px"; |
||||
|
||||
var label = e("div"); |
||||
label.innerHTML = ap.essid; |
||||
|
||||
var div = m('<label for=\"opt-' + ap.essid + '"></label>').childNodes[0]; |
||||
div.appendChild(input); |
||||
div.appendChild(encrypt); |
||||
div.appendChild(bars); |
||||
div.appendChild(rssi); |
||||
div.appendChild(label); |
||||
return div; |
||||
} |
||||
|
||||
function getSelectedEssid() { |
||||
var e = document.forms.wifiform.elements; |
||||
for (var i=0; i<e.length; i++) { |
||||
if (e[i].type == "radio" && e[i].checked) return e[i].value; |
||||
} |
||||
return currAp; |
||||
} |
||||
|
||||
var scanTimeout = null; |
||||
var scanReqCnt = 0; |
||||
|
||||
function scanResult() { |
||||
if (scanReqCnt > 60) { |
||||
return scanAPs(); |
||||
} |
||||
scanReqCnt += 1; |
||||
ajaxJson('GET', "scan", function(data) { |
||||
currAp = getSelectedEssid(); |
||||
if (data.result.inProgress == "0" && data.result.APs.length > 1) { |
||||
$("#aps").innerHTML = ""; |
||||
var n = 0; |
||||
for (var i=0; i<data.result.APs.length; i++) { |
||||
if (data.result.APs[i].essid == "" && data.result.APs[i].rssi == 0) continue; |
||||
$("#aps").appendChild(createInputForAp(data.result.APs[i])); |
||||
n = n+1; |
||||
} |
||||
showNotification("Scan found " + n + " networks"); |
||||
var cb = $("#connect-button"); |
||||
cb.className = cb.className.replace(" pure-button-disabled", ""); |
||||
if (scanTimeout != null) clearTimeout(scanTimeout); |
||||
scanTimeout = window.setTimeout(scanAPs, 20000); |
||||
} else { |
||||
window.setTimeout(scanResult, 1000); |
||||
} |
||||
}, function(s, st) { |
||||
window.setTimeout(scanResult, 5000); |
||||
}); |
||||
} |
||||
|
||||
function scanAPs() { |
||||
console.log("scanning now"); |
||||
if (blockScan) { |
||||
scanTimeout = window.setTimeout(scanAPs, 1000); |
||||
return; |
||||
} |
||||
scanTimeout = null; |
||||
scanReqCnt = 0; |
||||
ajaxReq('POST', "scan", function(data) { |
||||
//showNotification("Wifi scan started");
|
||||
window.setTimeout(scanResult, 1000); |
||||
}, function(s, st) { |
||||
//showNotification("Wifi scan may have started?");
|
||||
window.setTimeout(scanResult, 1000); |
||||
}); |
||||
} |
||||
|
||||
function getStatus() { |
||||
ajaxJsonSpin("GET", "connstatus", function(data) { |
||||
if (data.status == "idle" || data.status == "connecting") { |
||||
$("#aps").innerHTML = "Connecting..."; |
||||
showNotification("Connecting..."); |
||||
window.setTimeout(getStatus, 1000); |
||||
} else if (data.status == "got IP address") { |
||||
var txt = "Connected! Got IP "+data.ip; |
||||
showNotification(txt); |
||||
showWifiInfo(data); |
||||
blockScan = 0; |
||||
|
||||
if (data.modechange == "yes") { |
||||
var txt2 = "esp-link will switch to STA-only mode in a few seconds"; |
||||
window.setTimeout(function() { showNotification(txt2); }, 4000); |
||||
} |
||||
|
||||
$("#reconnect").removeAttribute("hidden"); |
||||
$("#reconnect").innerHTML = |
||||
"If you are in the same network, go to <a href=\"http://"+data.ip+ |
||||
"/\">"+data.ip+"</a>, else connect to network "+data.ssid+" first."; |
||||
} else { |
||||
blockScan = 0; |
||||
showWarning("Connection failed: " + data.status + ", " + data.reason); |
||||
$("#aps").innerHTML = |
||||
"Check password and selected AP. <a href=\"wifi.tpl\">Go Back</a>"; |
||||
} |
||||
}, function(s, st) { |
||||
//showWarning("Can't get status: " + st);
|
||||
window.setTimeout(getStatus, 2000); |
||||
}); |
||||
} |
||||
|
||||
function changeWifiMode(m) { |
||||
blockScan = 1; |
||||
hideWarning(); |
||||
ajaxSpin("POST", "setmode?mode=" + m, function(resp) { |
||||
showNotification("Mode changed"); |
||||
window.setTimeout(getWifiInfo, 100); |
||||
blockScan = 0; |
||||
}, function(s, st) { |
||||
showWarning("Error changing mode: " + st); |
||||
window.setTimeout(getWifiInfo, 100); |
||||
blockScan = 0; |
||||
}); |
||||
} |
||||
|
||||
function changeWifiAp(e) { |
||||
e.preventDefault(); |
||||
var passwd = $("#wifi-passwd").value; |
||||
var essid = getSelectedEssid(); |
||||
showNotification("Connecting to " + essid); |
||||
var url = "connect?essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd); |
||||
|
||||
hideWarning(); |
||||
$("#reconnect").setAttribute("hidden", ""); |
||||
$("#wifi-passwd").value = ""; |
||||
var cb = $("#connect-button"); |
||||
var cn = cb.className; |
||||
cb.className += ' pure-button-disabled'; |
||||
blockScan = 1; |
||||
ajaxSpin("POST", url, function(resp) { |
||||
$("#spinner").removeAttribute('hidden'); // hack
|
||||
showNotification("Waiting for network change..."); |
||||
window.scrollTo(0, 0); |
||||
window.setTimeout(getStatus, 2000); |
||||
}, function(s, st) { |
||||
showWarning("Error switching network: "+st); |
||||
cb.className = cn; |
||||
window.setTimeout(scanAPs, 1000); |
||||
}); |
||||
} |
||||
|
||||
function changeSpecial(e) { |
||||
e.preventDefault(); |
||||
var url = "special"; |
||||
url += "?dhcp=" + document.querySelector('input[name="dhcp"]:checked').value; |
||||
url += "&hostname=" + encodeURIComponent($("#wifi-hostname").value); |
||||
url += "&staticip=" + encodeURIComponent($("#wifi-staticip").value); |
||||
url += "&netmask=" + encodeURIComponent($("#wifi-netmask").value); |
||||
url += "&gateway=" + encodeURIComponent($("#wifi-gateway").value); |
||||
|
||||
hideWarning(); |
||||
var cb = $("#special-button"); |
||||
addClass(cb, 'pure-button-disabled'); |
||||
ajaxSpin("POST", url, function(resp) { |
||||
removeClass(cb, 'pure-button-disabled'); |
||||
getWifiInfo(); |
||||
}, function(s, st) { |
||||
showWarning("Error: "+st); |
||||
removeClass(cb, 'pure-button-disabled'); |
||||
getWifiInfo(); |
||||
}); |
||||
} |
||||
|
||||
function doDhcp() { |
||||
$('#dhcp-on').removeAttribute('hidden'); |
||||
$('#dhcp-off').setAttribute('hidden', ''); |
||||
} |
||||
|
||||
function doStatic() { |
||||
$('#dhcp-off').removeAttribute('hidden'); |
||||
$('#dhcp-on').setAttribute('hidden', ''); |
||||
} |
@ -0,0 +1,274 @@ |
||||
#include "Time.h" |
||||
|
||||
static tmElements_t tm; // a cache of time elements
|
||||
static time_t cacheTime; // the time the cache was updated
|
||||
static time_t syncInterval = 300; // time sync will be attempted after this many seconds
|
||||
|
||||
static os_timer_t micros_overflow_timer; |
||||
static uint32_t micros_at_last_overflow_tick = 0; |
||||
static uint32_t micros_overflow_count = 0; |
||||
|
||||
static time_t sysTime = 0; |
||||
static time_t prevMillis = 0; |
||||
static time_t nextSyncTime = 0; |
||||
static timeStatus_t Status = timeNotSet; |
||||
|
||||
getExternalTime getTimePtr; |
||||
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
totalMinutes(int16_t hours, int8_t minutes) |
||||
{ |
||||
return (hours * 60) + minutes; |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
micros_overflow_tick(void* arg) { |
||||
uint32_t m = system_get_time(); |
||||
if (m < micros_at_last_overflow_tick) |
||||
++micros_overflow_count; |
||||
micros_at_last_overflow_tick = m; |
||||
} |
||||
|
||||
unsigned long ICACHE_FLASH_ATTR
|
||||
millis() { |
||||
uint32_t m = system_get_time(); |
||||
uint32_t c = micros_overflow_count + ((m < micros_at_last_overflow_tick) ? 1 : 0); |
||||
return c * 4294967 + m / 1000; |
||||
} |
||||
|
||||
unsigned long ICACHE_FLASH_ATTR
|
||||
micros() { |
||||
return system_get_time(); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
time_init() { |
||||
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*)µs_overflow_tick, 0); |
||||
os_timer_arm(µs_overflow_timer, 60000, 1); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
breakTime(time_t time, tmElements_t *tm){ |
||||
|
||||
uint8_t year; |
||||
uint8_t month, monthLength; |
||||
unsigned long days; |
||||
|
||||
tm->Second = time % 60; |
||||
time /= 60; // now it is minutes
|
||||
tm->Minute = time % 60; |
||||
time /= 60; // now it is hours
|
||||
tm->Hour = time % 24; |
||||
time /= 24; // now it is days
|
||||
tm->Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
year = 0; |
||||
days = 0; |
||||
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { |
||||
year++; |
||||
} |
||||
tm->Year = year; // year is offset from 1970
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365; |
||||
time -= days; // now it is days in this year, starting at 0
|
||||
|
||||
days = 0; |
||||
month = 0; |
||||
monthLength = 0; |
||||
for (month = 0; month<12; month++) { |
||||
if (month == 1) { // february
|
||||
if (LEAP_YEAR(year)) { |
||||
monthLength = 29; |
||||
} |
||||
else { |
||||
monthLength = 28; |
||||
} |
||||
} |
||||
else { |
||||
monthLength = monthDays[month]; |
||||
} |
||||
|
||||
if (time >= monthLength) { |
||||
time -= monthLength; |
||||
} |
||||
else { |
||||
break; |
||||
} |
||||
} |
||||
tm->Month = month + 1; // jan is month 1
|
||||
tm->Day = time + 1; // day of month
|
||||
} |
||||
|
||||
/*
|
||||
* Convert the "timeInput" time_t count into "struct tm" time components. |
||||
* This is a more compact version of the C library localtime function. |
||||
* Note that year is offset from 1970 !!! |
||||
*/ |
||||
void ICACHE_FLASH_ATTR
|
||||
timet_to_tm(time_t timeInput, struct tmElements *tmel){ |
||||
|
||||
uint8_t year; |
||||
uint8_t month, monthLength; |
||||
uint32_t time; |
||||
unsigned long days; |
||||
|
||||
time = (uint32_t)timeInput; |
||||
tmel->Second = time % 60; |
||||
time /= 60; // Now it is minutes.
|
||||
tmel->Minute = time % 60; |
||||
time /= 60; // Now it is hours.
|
||||
tmel->Hour = time % 24; |
||||
time /= 24; // Now it is days.
|
||||
tmel->Wday = ((time + 4) % 7) + 1; // Sunday is day 1.
|
||||
|
||||
year = 0; |
||||
days = 0; |
||||
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { |
||||
year++; |
||||
} |
||||
tmel->Year = year; // The year is offset from 1970.
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365; |
||||
time -= days; // Now it is days in this year, starting at 0.
|
||||
|
||||
days = 0; |
||||
month = 0; |
||||
monthLength = 0; |
||||
for (month = 0; month<12; month++) { |
||||
if (month == 1) { // February.
|
||||
if (LEAP_YEAR(year)) { |
||||
monthLength = 29; |
||||
} |
||||
else { |
||||
monthLength = 28; |
||||
} |
||||
} |
||||
else { |
||||
monthLength = monthDays[month]; |
||||
} |
||||
|
||||
if (time >= monthLength) { |
||||
time -= monthLength; |
||||
} |
||||
else { |
||||
break; |
||||
} |
||||
} |
||||
tmel->Month = month + 1; // Jan is month 1.
|
||||
tmel->Day = time + 1; // Day of month.
|
||||
} |
||||
|
||||
/*
|
||||
* Reconstitute "struct tm" elements into a time_t count value. |
||||
* Note that the year argument is offset from 1970. |
||||
*/ |
||||
time_t ICACHE_FLASH_ATTR
|
||||
tm_to_timet(struct tmElements *tmel){ |
||||
|
||||
int i; |
||||
uint32_t seconds; |
||||
|
||||
// Seconds from 1970 till 1st Jan 00:00:00 of the given year.
|
||||
seconds = tmel->Year*(SECS_PER_DAY * 365); |
||||
for (i = 0; i < tmel->Year; i++) { |
||||
if (LEAP_YEAR(i)) { |
||||
seconds += SECS_PER_DAY; // Add extra days for leap years.
|
||||
} |
||||
} |
||||
|
||||
// Add the number of elapsed days for the given year. Months start from 1.
|
||||
for (i = 1; i < tmel->Month; i++) { |
||||
if ((i == 2) && LEAP_YEAR(tmel->Year)) { |
||||
seconds += SECS_PER_DAY * 29; |
||||
} |
||||
else { |
||||
seconds += SECS_PER_DAY * monthDays[i - 1]; // "monthDay" array starts from 0.
|
||||
} |
||||
} |
||||
seconds += (tmel->Day - 1) * SECS_PER_DAY; // Days...
|
||||
seconds += tmel->Hour * SECS_PER_HOUR; // Hours...
|
||||
seconds += tmel->Minute * SECS_PER_MIN; // Minutes...
|
||||
seconds += tmel->Second; // ...and finally, Seconds.
|
||||
return (time_t)seconds; |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
refreshCache(time_t t){ |
||||
if (t != cacheTime) |
||||
{ |
||||
breakTime(t, &tm); |
||||
cacheTime = t; |
||||
} |
||||
} |
||||
|
||||
int ICACHE_FLASH_ATTR
|
||||
hour() { // the hour now
|
||||
time_t t = now(); |
||||
refreshCache(t); |
||||
return tm.Hour; |
||||
} |
||||
|
||||
int ICACHE_FLASH_ATTR
|
||||
minute() { // the minute now
|
||||
time_t t = now(); |
||||
refreshCache(t); |
||||
return tm.Minute; |
||||
} |
||||
|
||||
int ICACHE_FLASH_ATTR
|
||||
second() { // the second now
|
||||
time_t t = now(); |
||||
refreshCache(t); |
||||
return tm.Second; |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
setTime(time_t t){ |
||||
#ifdef TIME_DRIFT_INFO |
||||
if (sysUnsyncedTime == 0) |
||||
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
||||
#endif |
||||
|
||||
sysTime = t; |
||||
nextSyncTime = t + syncInterval; |
||||
Status = timeSet; |
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
} |
||||
|
||||
time_t ICACHE_FLASH_ATTR
|
||||
now(){ |
||||
while (millis() - prevMillis >= 1000){ |
||||
sysTime++; |
||||
prevMillis += 1000; |
||||
#ifdef TIME_DRIFT_INFO |
||||
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
|
||||
#endif |
||||
} |
||||
if (nextSyncTime <= sysTime){ |
||||
if (getTimePtr != 0){ |
||||
time_t t = getTimePtr(); |
||||
if (t != 0) |
||||
setTime(t); |
||||
else |
||||
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; |
||||
} |
||||
} |
||||
return sysTime; |
||||
} |
||||
|
||||
timeStatus_t ICACHE_FLASH_ATTR
|
||||
timeStatus(){ // indicates if time has been set and recently synchronized
|
||||
return Status; |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
setSyncProvider(getExternalTime getTimeFunction){ |
||||
getTimePtr = getTimeFunction; |
||||
nextSyncTime = sysTime; |
||||
now(); // this will sync the clock
|
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
setSyncInterval(time_t interval){ // set the number of seconds between re-sync
|
||||
syncInterval = interval; |
||||
} |
@ -0,0 +1,130 @@ |
||||
#ifndef _TIME_H_ |
||||
#define _TIME_H_ |
||||
|
||||
#include <esp8266.h> |
||||
|
||||
/*
|
||||
* Constants. |
||||
*/ |
||||
#define SECS_PER_MIN (60UL) |
||||
#define SECS_PER_HOUR (3600UL) |
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) |
||||
#define DAYS_PER_WEEK (7UL) |
||||
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) |
||||
#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) |
||||
#define SECS_YR_2000 (946684800UL) // The time_t value at the very start of Y2K.
|
||||
|
||||
/*
|
||||
* Days per month. |
||||
* Note that the standard time.h starts months from "1", but this |
||||
* version starts from "0". |
||||
*/ |
||||
static const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
||||
|
||||
/*
|
||||
* Standard "struct tm" equivalent. |
||||
* =NOTE= Differences:- |
||||
* - Year offset is from 1970 (standard tm is from 1900). |
||||
* - Wday Sunday is day "1" (standard tm has it as day "0"). |
||||
* - The "Day" field is what standard tm refers to as "yday". |
||||
* - There is no "date" or Day-of-Month field. |
||||
* - There is no "isdst" field. |
||||
*/ |
||||
struct tmElements { |
||||
uint8_t Second; |
||||
uint8_t Minute; |
||||
uint8_t Hour; |
||||
uint8_t Wday; // Day of week, with Sunday as day 1.
|
||||
uint8_t Day; // This is "yday" - Day of Year.
|
||||
uint8_t Month; |
||||
uint8_t Year; // Offset from 1970.
|
||||
}; |
||||
|
||||
typedef enum { |
||||
timeNotSet, timeNeedsSync, timeSet |
||||
} timeStatus_t; |
||||
|
||||
typedef enum { |
||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday |
||||
} timeDayOfWeek_t; |
||||
|
||||
typedef enum { |
||||
tmSecond, tmMinute, tmHour, tmWday, tmDay, tmMonth, tmYear, tmNbrFields |
||||
} tmByteFields; |
||||
|
||||
typedef struct { |
||||
uint8_t Second; |
||||
uint8_t Minute; |
||||
uint8_t Hour; |
||||
uint8_t Wday; // day of week, sunday is day 1
|
||||
uint8_t Day; |
||||
uint8_t Month; |
||||
uint8_t Year; // offset from 1970;
|
||||
} tmElements_t, TimeElements, *tmElementsPtr_t; |
||||
|
||||
// This leap year calulator expects year argument as years offset from 1970.
|
||||
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) |
||||
|
||||
/*
|
||||
* Convenience macros to convert to and from tm years. |
||||
*/ |
||||
#define tmYearToCalendar(Y) ((Y) + 1970) // Full, four-digit year.
|
||||
#define CalendarYrToTm(Y) ((Y) - 1970) |
||||
#define tmYearToY2k(Y) ((Y) - 30) // Offset from 2000.
|
||||
#define y2kYearToTm(Y) ((Y) + 30) |
||||
|
||||
typedef time_t(*getExternalTime)(); |
||||
|
||||
/*
|
||||
* Useful Macros for getting elapsed time values. |
||||
*/ |
||||
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) |
||||
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) |
||||
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) |
||||
#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday.
|
||||
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // The number of days since Jan 1 1970.
|
||||
#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // The number of seconds since last midnight.
|
||||
|
||||
|
||||
/*
|
||||
* The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971. |
||||
* Always set the correct time before setting alarms. |
||||
*/ |
||||
#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // Time at the start of the given day.
|
||||
#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // Time at the end of the given day.
|
||||
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // Week starts on day 1.
|
||||
#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // Time at the start of the week for the given time.
|
||||
#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // Time at the end of the week for the given time.
|
||||
|
||||
|
||||
/*
|
||||
* Useful Macros for converting elapsed time to a time_t value. |
||||
*/ |
||||
#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) |
||||
#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) |
||||
#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // Fixed on Jul 22 2011.
|
||||
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) |
||||
|
||||
/*
|
||||
* Time and date function defines. |
||||
* Low-level functions to convert to and from system time. |
||||
*/ |
||||
int16_t totalMinutes(int16_t hours, int8_t minutes); |
||||
void breakTime(time_t time, tmElements_t* tm); |
||||
void timet_to_tm(time_t time, struct tmElements *tmel); // Convert a time_t value into "struct tm" elements.
|
||||
time_t tm_to_timet(struct tmElements *tmel); // Reconstitute "struct tm" elements into a time_t value.
|
||||
time_t now(); |
||||
void setTime(time_t t); |
||||
int hour(); |
||||
int minute(); |
||||
int second(); |
||||
void time_init(); |
||||
unsigned long micros(); |
||||
unsigned long millis(); |
||||
|
||||
/* time sync functions */ |
||||
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
|
||||
void setSyncProvider(getExternalTime getTimeFunction); // identify the external time provider
|
||||
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
|
||||
|
||||
#endif // _TIME_H_
|
@ -0,0 +1,37 @@ |
||||
#include "user_funcs.h" |
||||
|
||||
bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute) { |
||||
uint16_t NumMinsToday = totalMinutes(hour(), minute()); |
||||
bool state = false; |
||||
|
||||
if (totalMinutes(offHour, offMinute) > totalMinutes(onHour, onMinute)) { |
||||
state = (NumMinsToday >= totalMinutes(onHour, onMinute)) ? true : false; |
||||
|
||||
if (NumMinsToday >= totalMinutes(offHour, offMinute)) |
||||
state = false; |
||||
} |
||||
else { |
||||
state = (NumMinsToday >= totalMinutes(offHour, offMinute)) ? false : true; |
||||
|
||||
if (NumMinsToday >= totalMinutes(onHour, onMinute)) |
||||
state = true; |
||||
} |
||||
return state; |
||||
} |
||||
|
||||
const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { |
||||
static char b[9]; |
||||
b[0] = '\0'; |
||||
|
||||
int z; |
||||
for (z = 128; z > 0; z >>= 1) { |
||||
strcat(b, ((num & z) == z) ? "1" : "0"); |
||||
} |
||||
return b; |
||||
} |
||||
|
||||
const uint8_t ICACHE_FLASH_ATTR binToByte(char* bin_str) { |
||||
char * tmp; |
||||
long x = strtol(bin_str, &tmp, 2); |
||||
return (x <= 255) ? (uint8_t)x : -1; |
||||
} |
@ -0,0 +1,10 @@ |
||||
#ifndef _USER_FUNCS_H_ |
||||
#define _USER_FUNCS_H_ |
||||
#include <esp8266.h> |
||||
#include <Time.h> |
||||
|
||||
bool pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute); |
||||
const char* byteToBin(uint8_t num); |
||||
const uint8_t binToByte(char* bin_str); |
||||
|
||||
#endif // _USER_FUNCS_H_
|
@ -0,0 +1,158 @@ |
||||
/******************************************************************************
|
||||
* Copyright 2013-2014 Espressif Systems (Wuxi) |
||||
* |
||||
* FileName: user_json.c |
||||
* |
||||
* Description: JSON format set up and parse. |
||||
* Check your hardware transmation while use this data format. |
||||
* |
||||
* Modification history: |
||||
* 2014/5/09, v1.0 create this file. |
||||
*******************************************************************************/ |
||||
#include "user_json.h" |
||||
|
||||
LOCAL char* json_buf; |
||||
LOCAL int pos; |
||||
LOCAL int size; |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : find_json_path |
||||
* Description : find the JSON format tree's path |
||||
* Parameters : json -- A pointer to a JSON set up |
||||
* path -- A pointer to the JSON format tree's path |
||||
* Returns : A pointer to the JSON format tree |
||||
*******************************************************************************/ |
||||
struct jsontree_value*ICACHE_FLASH_ATTR |
||||
find_json_path(struct jsontree_context* json, const char* path) { |
||||
struct jsontree_value* v; |
||||
const char* start; |
||||
const char* end; |
||||
int len; |
||||
|
||||
v = json->values[0]; |
||||
start = path; |
||||
|
||||
do { |
||||
end = (const char *)os_strstr(start, "/"); |
||||
|
||||
if (end == start) { |
||||
break; |
||||
} |
||||
|
||||
if (end != NULL) { |
||||
len = end - start; |
||||
end++; |
||||
} |
||||
else { |
||||
len = os_strlen(start); |
||||
} |
||||
|
||||
if (v->type != JSON_TYPE_OBJECT) { |
||||
v = NULL; |
||||
} |
||||
else { |
||||
struct jsontree_object* o; |
||||
int i; |
||||
|
||||
o = (struct jsontree_object *)v; |
||||
v = NULL; |
||||
|
||||
for (i = 0; i < o->count; i++) { |
||||
if (os_strncmp(start, o->pairs[i].name, len) == 0) { |
||||
v = o->pairs[i].value; |
||||
json->index[json->depth] = i; |
||||
json->depth++; |
||||
json->values[json->depth] = v; |
||||
json->index[json->depth] = 0; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
start = end; |
||||
} |
||||
while (end != NULL && *end != '\0' && v != NULL); |
||||
|
||||
json->callback_state = 0; |
||||
return v; |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : json_putchar |
||||
* Description : write the value to the JSON format tree |
||||
* Parameters : c -- the value which write the JSON format tree |
||||
* Returns : result |
||||
*******************************************************************************/ |
||||
int ICACHE_FLASH_ATTR |
||||
json_putchar(int c) { |
||||
if (json_buf != NULL && pos <= size) { |
||||
json_buf[pos++] = c; |
||||
return c; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : json_ws_send |
||||
* Description : set up the JSON format tree for string |
||||
* Parameters : tree -- A pointer to the JSON format tree |
||||
* path -- A pointer to the JSON format tree's path |
||||
* pbuf -- A pointer for the data sent |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
json_ws_send(struct jsontree_value* tree, const char* path, char* pbuf) { |
||||
struct jsontree_context json; |
||||
/* maxsize = 128 bytes */ |
||||
json_buf = (char *)os_malloc(JSON_SIZE); |
||||
|
||||
/* reset state and set max-size */ |
||||
/* NOTE: packet will be truncated at 512 bytes */ |
||||
pos = 0; |
||||
size = JSON_SIZE; |
||||
|
||||
json.values[0] = (struct jsontree_value *)tree; |
||||
jsontree_reset(&json); |
||||
find_json_path(&json, path); |
||||
json.path = json.depth; |
||||
json.putchar = json_putchar; |
||||
|
||||
while (jsontree_print_next(&json) && json.path <= json.depth); |
||||
|
||||
json_buf[pos] = 0; |
||||
os_memcpy(pbuf, json_buf, pos); |
||||
os_free(json_buf); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : json_parse |
||||
* Description : parse the data as a JSON format |
||||
* Parameters : js_ctx -- A pointer to a JSON set up |
||||
* ptrJSONMessage -- A pointer to the data |
||||
* Returns : none |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
json_parse(struct jsontree_context* json, char* ptrJSONMessage) { |
||||
/* Set value */ |
||||
struct jsontree_value* v; |
||||
struct jsontree_callback* c; |
||||
struct jsontree_callback* c_bak = NULL; |
||||
|
||||
while ((v = jsontree_find_next(json, JSON_TYPE_CALLBACK)) != NULL) { |
||||
c = (struct jsontree_callback *)v; |
||||
|
||||
if (c == c_bak) { |
||||
continue; |
||||
} |
||||
|
||||
c_bak = c; |
||||
|
||||
if (c->set != NULL) { |
||||
struct jsonparse_state js; |
||||
|
||||
jsonparse_setup(&js, ptrJSONMessage, os_strlen(ptrJSONMessage)); |
||||
c->set(json, &js); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
#ifndef __USER_JSON_H__ |
||||
#define __USER_JSON_H__ |
||||
|
||||
#include <esp8266.h> |
||||
#include "json/jsonparse.h" |
||||
#include "json/jsontree.h" |
||||
|
||||
#define JSON_SIZE 1024 |
||||
void json_parse(struct jsontree_context* json, char* ptrJSONMessage); |
||||
void json_ws_send(struct jsontree_value* tree, const char* path, char* pbuf); |
||||
int json_putchar(int c); |
||||
struct jsontree_value* find_json_path(struct jsontree_context* json, const char* path); |
||||
|
||||
#endif |
Loading…
Reference in new issue