-
Here is the web server example:
var fs = new(require("FlashStoreWrite"))(0x7c000); //fs.item('/images/logo.png').delete(); fs.item('/favicon.ico').wget('http://www.espruino.com/favicon.ico'); fs.item('/images/logo.png').wget('http://www.espruino.com/images/logo.png'); function Doc() { this.str=''; } Doc.prototype.write=function(s) { this.str+=s; this.str+='\n'; }; Doc.prototype.toString=function(){return this.str;}; var document=new Doc(); // http://www.accessify.com/tools-and-wizards/developer-tools/html-javascript-convertor/ document.write("<html lang=\"en\">"); document.write(" <head>"); document.write(" <meta charset=\"utf-8\">"); document.write(" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"); document.write(" <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"); document.write(" <link rel=\"stylesheet\" href=\"http:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.5\/css\/bootstrap.min.css\">"); document.write(" <\/head>"); document.write(" <body>"); document.write(" <div class=\"well well-lgt\"> "); document.write(" <div class=\"panel-heading\">"); document.write(" <h3>Web Flash Server<\/h3>"); document.write(" <\/div>"); document.write(" <button class=\"btn btn-warning\" id=\"send\" onclick=\"action(this);\">Send to Espruino<\/button>"); document.write(" <ul id=\"list\" class=\"list-group\">"); document.write(" <li class=\"list-group-item\"><\/li>"); document.write(" <li class=\"list-group-item\"><img src=\"\/images\/logo.png\"><\/li>"); document.write(" <\/ul>"); document.write(" <\/div>"); document.write(" <script src=\"\/js\/app.js\"><\/script>"); document.write(" <\/body>"); document.write("<\/html>"); console.log( document.toString() ); fs.item('/',document.toString(),'text/html'); document.str=''; document.write("var count=1;"); document.write("function action(btn) {"); document.write(" btn.innerHTML = 'Send ' + count;"); document.write(" send_json(count);"); document.write(" count = count + 1;"); document.write("}"); document.write("function add(text) {"); document.write(" var ul = document.getElementById(\"list\");"); document.write(" var li = document.createElement(\"li\");"); document.write(" li.className = \"list-group-item\";"); document.write(" li.appendChild(document.createTextNode(text));"); document.write(" ul.appendChild(li);"); document.write("}"); document.write("function send_json(count) {"); document.write(" count = count + 1;"); document.write(" var xhttp = new XMLHttpRequest();"); document.write(" xhttp.onreadystatechange = function () {"); document.write(" if (xhttp.readyState == 4 && xhttp.status == 200) {"); document.write(" add(xhttp.responseText);"); document.write(" }"); document.write(" };"); document.write(" xhttp.open(\"GET\", \"\/json?count=\" + count, true);"); document.write(" xhttp.send();"); document.write("};"); fs.item('/js/app.js',document.toString(),'application/javascript'); print( process.memory()); delete document; print( process.memory()); var fs = new(require("FlashStore"))(0x7c000); require("http").createServer(function (request, response) { var u = url.parse(request.url, true); var q = fs.find(u.pathname); if (q) { console.log({match:u.pathname}); q.pipe(response); } else { if ( u.pathname === '/json' ) { // response.writeHead(200); response.end(Date.now().toString()); return; } console.log({ q : u.query, p : u.pathname }); response.writeHead(404); response.end("404: Not found"); } }).listen(80); print(process.memory());
The webserver - using the FlashStore object to retrieve, it assumes you have a saved
wifi.save()
that is already connected:var fs = new(require("FlashStore"))(0x7c000); require("http").createServer(function (request, response) { var u = url.parse(request.url, true); var q = fs.find(u.pathname); if (q) { console.log({match:u.pathname}); q.pipe(response); } else { if ( u.pathname === '/json' ) { // response.writeHead(200); response.end(Date.now().toString()); return; } console.log({ q : u.query, p : u.pathname }); response.writeHead(404); response.end("404: Not found"); } }).listen(80); print(process.memory());
The ico and image assets are saved, then the index.html root document and /js/app.js
The webserver code searches the store, and if the content is matched it s served from the flash, using the .pipe method.
When the button is clicked, a /json method is called, and this returning the current time back to the browser...
-
-
-
Complex types can be stored, they are automatically converted to JSON strings and back again:
var fs = new(require("FlashStoreWrite"))(0x7c000); var config={start:4, end:9, data:'fishing'}; fs.item('config',config);
var rfs=new(require("FlashStore"))(0x7c000); var my_config=rfs.item('config').valueOf(); console.log(my_config);
Flash map 4MB:512/512, manuf 0xe0 chip 0x4016 >echo(0); { "start": 4, "end": 9, "data": "fishing" }
-
I'm still refining this, however recent activity on gitter has prompted me to publish this now!
https://github.com/wilberforce/EspruinoDocs/tree/master/modules
There are 3 modules used.
The FlashStoreWrite module is used to populate flash with assets that you want access to in your real application. It is a key based storage system, that takes a key, and stores a js object against it. This can then be recovered using the FlashStore module.
The basic usage is:
var fs = new(require("FlashStoreWrite"))(0x7c000); fs.item('example','store me!');
The FlashItem object is used for recovering the stored object, which has methods toString() and valueOf();
var str=fs.item('example').toString();
The flashItem also knows about the types of object so treats the differently.
This allows us to store things like web assets such as css and js files, images and have them served by a the http server object (using pipe so that not much memory) is consumed.
We can also store modules in flash, and load them on demand.
-
Thanks Gordon.
Here is the code modified to save the results to an array, updating every 1/2 sec and displaying every sec:
var pin = D5; // update for your hardware! var ow = new OneWire(pin); ds = require("https://raw.githubusercontent.com/espruino/EspruinoDocs/master/devices/DS18B20.js"); var s = ow.search(); console.log({ search : s }); var sensors = s.map(function (device) { return ds.connect(ow, device); }); var temps = []; setInterval(function () { sensors.forEach(function (sensor, index) { sensor.getTemp(function (temp) { temps[index] = temp; }); }); }, 500); setInterval(function () { console.log(temps); }, 1000);
{ "search": [ "28cc2e230500006b", "283260dc04000001" ] } =undefined [ ] [ 24.5, 24.4375 ] [ 24.5625, 24.4375 ] [ 24.5, 24.4375 ] [ 24.5, 24.4375 ]
-
or not ;-(
After re-powering the board, the sensors reverted to the 85C state:
"search": [ "28cc2e230500006b", "283260dc04000001" ] } initial: 85 initial: 85 =undefined 0: undefined 1: undefined { "cb_temp": 26.3125 }
I guess if you executed other code before the first actual call to getTemp() this would work out ok....
By setting the mode to 9 bit so the conversion is shorter:
var sensors = s.map(function (device) { var t=ds.connect(ow, device); t.setRes(9); t.getTemp(); t.setRes(12); return t; });
{ "search": [ "28cc2e230500006b", "283260dc04000001" ] } initial: 25.4375 initial: 24.0625 =undefined 0: undefined 1: undefined { "cb_temp": 25.875 } { "cb_temp": 24.9375 }
-
Should getTemp return the last value, even with a callback, rather than undefined?
here is how to avoid the intial bogus value:
var sensors = s.map(function (device) { var t=ds.connect(ow, device); t.getTemp(); return t; }); sensors.forEach(function (sensor, index) { console.log('initial' + ": " + sensor.getTemp()); });
This could be done automagically in the constructor here:
this.type=parseInt(this.sCode[0]+this.sCode[1]); this.getTemp(); // trigger a conversion }
-
The callback needs some sort of identifier, as you can't assume the order of the readings in the callbacks. I have two sensors connected:
var pin=D5; // update for your hardware! var ow = new OneWire(pin); ds = require("https://raw.githubusercontent.com/espruino/EspruinoDocs/master/devices/DS18B20.js"); function cb(t) { print({cb_temp:t}); } var s=ow.search(); console.log( { search:s } ); var sensors = s.map(function (device) { return ds.connect(ow, device); }); setInterval(function() { sensors.forEach(function (sensor, index) { console.log(index + ": " + sensor.getTemp(cb)); }); },2000);
{ "search": [ "28cc2e230500006b", "283260dc04000001" ] } =undefined 0: undefined 1: undefined { "cb_temp": 25.8125 } { "cb_temp": 24.9375 } 0: undefined 1: undefined { "cb_temp": 25.8125 } { "cb_temp": 24.9375 } 0: undefined 1: undefined
There are a couple of options:
if (callback) callback(temp);
if (callback) callback(this);
function cb(t) {
print({cb_temp:t.getTemp()});
}if (callback) callback(temp,this.sCode);
or probably most flexible:
if (callback) callback(temp,this);
And then you have the object if you need it... -
works for me with DS18B20 devices - had to add for the esp8266:
A1=NodeMCU.D1;or my case change to D5: ( wired to different pin)
var t = require("https://raw.githubusercontent.com/espruino/EspruinoDocs/master/devices/DS18B20.js").connect(new OneWire(D5)); t.getTemp(console.log);
WARNING: the esp8266 port is in beta! Flash map 4MB:512/512, manuf 0xe0 chip 0x4016 >echo(0); =undefined 25.75 >
I'll test the callback soon, and have some questions on how this will work multiple sensors.
Can we start a conversion on all sensors, and then have a callback with all temps?
I'm not sure if the current callback identifies the device, I'll set up some test cases.
-
IMO the command-line option would be the way to go
Agreed
and also the Telnet docs I linked in my first post
http://www.espruino.com/Reference#Telnet
I guess it's making the association that the Telnet server implementation is what the web IDE is using, perhaps that could be spelt out. -
@Gordon
There are a few things going on in this thread!I'm still a bit confused here - does the existing DS18B20 library not work with ESP8266? My understanding was just that the current one was fine, but it just returned the previous reading (which means the first one returns 85 or something like that).
a. Yes - the code works on the ESP8266
b. Add support ds18s20 as well as ds18s20
@hygyI modifed this code originally, cause the original is does not work with ds18s20 just with 18b20.
c. Callback
@gordon The code above waits 1 second for the callback - seems pretty extreme? I doubt many people would be happy with that.
The time it takes for a conversion depends on the resolution and if parasitic mode mode is in use.
http://forum.espruino.com/comments/12612450/
The modified code #21 http://forum.espruino.com/comments/12729356/ takes the resolution into account so, the callback is no longer 1 sec, but depends on the resolutiond. One of the issues with the original code is that the initial reading is bogus. The device returns all 111111's, and this turns out to be a value of 85c. For the next call, the real value is in place as the conversion is done. There is no way of knowing if this is a 'real' 85c or the bogus first value
One solution would be to return
undefined
until the first conversion is done.
Another, the constructor could be modified to starts a conversion, so that by the time the first call is made to getTemp, however this could not be guaranteed.e. The original code has
function getTemp(verify)
- Gets the temperature reading.
the proposed code hasfunction(callback,verify)
So existing code that use getTemp with verify used would fails as the first param is now a callback.
I have not idea how widespread this usage is, however I believe the getTemp should work for older code without having to change params.f. versioning
The git hash is a good idea, although the .js and .min.js would have different hash, even though they are a 'pair'. If the .js source had a hash comment, at least local projects and SD card modules would have the version details in them.
The idea of the x.y notation like used in node is that if a function signature changes (like e above), the major number x would be incremented to indicate. However without package.json this would not be of much benefit ;-( -
Is there a way of making this backward compatible with the existing library?
So instead of:
DS18B20.prototype.getTemp = function(callback,verify) { if ((verify && !this.isPresent()) || !this.sCode) {
Will this work with older code:
console.log(sensor.getTemp());
So if the callback is missing, it will wait and return?
Which leads to this question.. There is no versioning in modules, so if the library code was updated there is no easy way to tell if an update has been made.
Would a simple 1.2 type version number in the module header suffice?
-
I did try to use back ticks, but it went bung, so I removed them!
I thought I would add now on the iPad, however the character isn't on the keyboard!
For the Linux build is there any other way of loading code via the ide, if there isn't - that's why I was expecting it to be on by default. Can it be called a security hole if it's not on a default port?
As you say documenting makes all the difference!
I updated the gcc compiler on the 32 bit system - it made no difference
-
WARNING: jsnative.c sanity check failed (int-float-int passing)
root@esp8266-VirtualBox:/home/esp8266/Espruino/Espruino# uname -a
Linux esp8266-VirtualBox 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 i686 i686 i686 GNU/Linux`
root@esp8266-VirtualBox:/home/esp8266/Espruino/Espruino# gcc -v
Using built-in specs.
COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.8/lto-wrapper Target: i686-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 --with-arch-directory=i386 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-targets=all --enable-multiarch --disable-werror --with-arch-32=i686 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu Thread model: posix gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
Ok on this system:
root@nodejs ~/Espruino# uname -a Linux nodejs 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u3 x86_64 GNU/Linux
root@nodejs ~/Espruino# gcc -v
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-5' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.7.2 (Debian 4.7.2-5)
So I'm wondering if it a gcc version thing?
-
Thanks to @MaBe, it turns out the Makefile had the telnet off by default, need to do a pull request and update!
BOARD=LINUX
LINUX=1
USE_FILESYSTEM=1
USE_HASHLIB=1
USE_GRAPHICS=1
USE_CRYPTO=1
USE_TLS=1
#USE_TELNET=1 # enable telnet to have it listen on port 2323 as JS console
#USE_LCD_SDL=1USE_TELNET=1 # enable telnet to have it listen on port 2323 as JS console
-
-
-
This works:
var http = require("http"); http.createServer(function (req, res) { res.writeHead(200); res.end("Hello World"); }).listen(8080);
I have checked telnet is not running - well it doesn't answer on :
telnet 192.168.69.12 Connecting To 192.168.69.12...Could not open connection to the host, on port 23: Connect failed
-
I've built using these instructions in a linux VM:
http://forum.espruino.com/comments/5764/
git clone https://github.com/espruino/Espruino.git cd Espruino make
The exe spins up:
root@nodejs ~/Espruino# ./espruino Interactive mode. Size of JsVar is now 32 bytes Size of JsVarRef is now 4 bytes Added SIGINT hook Added SIGHUP hook Added SIGTERM hook 1v85.1272 Copyright 2016 G.Williams Espruino is Open Source. Our work is supported only by sales of official boards and donations: http://espruino.com/Donate
How do I connect with the Web ide?
I tried adding the IP of the VM under communications > Connect over Ip Address, however the instance is not found.
Do you need to set up a virtual com port, or can connect via IP to a Linux instance.
I'm hoping the VM version will be a lot more snappy for development - especially uploading when developing modules!
-
-
Here is an example using a Node MCU board. The firmware used is:
1v85 Copyright 2016 G.Williams
I have 2 DS18s20 connected to pin D1 (with the pullup resistor), and led connected via a 330Ohm resistor connected to pin D2.
The led is flashed ever 5 seconds, and the temperatures of each of the sensors echoed.
The [Flash] button on the board is watched, and this also toggles the state of the LED._____ _ | __|___ ___ ___ _ _|_|___ ___ | __|_ -| . | _| | | | | . | |_____|___| _|_| |___|_|_|_|___| |_| http://espruino.com 1v85 Copyright 2016 G.Williams Espruino is Open Source. Our work is supported only by sales of official boards and donations: http://espruino.com/Donate WARNING: the esp8266 port is in beta! Flash map 4MB:512/512, manuf 0xe0 chip 0x4016 >echo(0); =undefined 0: 85 1: 85 0: 26.75 1: 26.25 0: 26.8125 1: 26.3125 0: 26.8125 1: 26.3125 button 0: 26.875 1: 26.375 0: 26.9375 1: 26.4375 >
var led = Pin(NodeMCU.D2); var toggle=1; var ow = new OneWire(NodeMCU.D1); var sensors = ow.search().map(function (device) { return require("DS18B20").connect(ow, device); }); function updateLed(){ digitalWrite(led, toggle); toggle=!toggle; } setInterval(function() { updateLed(); sensors.forEach(function (sensor, index) { console.log(index + ": " + sensor.getTemp()); }); },5000); function button_down() { updateLed(); print('button'); } setWatch(button_down,NodeMCU.D3, {repeat:true, edge:"falling"});
I hope someone finds this useful!
-
Thanks.
Here are mine:
{ "Reset" : "reset();", "Memory" : "process.memory();", "ClearInterval" : "clearInterval();", "ClearCmdHistory" : "global['\\xFF'].history=[]", "Esp8266.printLog" : "require('ESP8266').printLog()", "Esp8266.reboot" : "require(\"ESP8266\").reboot()", "Esp8266.SocketInfo" : "require('ESP8266').dumpSocketInfo();require('ESP8266').printLog();", "Esp8266.IdeDebug" : "require('ESP8266').setLog(2);", "Esp8266.JoinWifi" : "function join(ssid,password){wifi.connect(ssid,{password:password},function(err,ipInfo){ipInfo=wifi.getIP();print(\"Wifi IP: \"+JSON.stringify(ipInfo));wifi.save();});}" }
For the wifi one, run the snippet to define the function, then join your network.
join('your-ssid','your-password');
The clear command history is used when you are running low on space, and want to free up some memory.
-
@allObjects
At this stage I've decided to keep it very simple.
The likes of the ESP12 with 4Mb means that we have oodles of space.
This is the structure used to store items:
The magic is in the
_root
object, this is stored in JSON.stringify format in the first page of the flash, and is restored in the FileStorage constructor.The page size is 4K - currently each object takes up at least on page. This seems wasteful, however the trade off is speed.
An existing object can get appended too - as long as it fits in the space allocated to it.
I did not think it was worth the extra trouble of storing intra page and managing indexes.
Given that you can store a complex js structure, you could pack everything you wanted in a structure and store that.
The
fs.item('my_key').delete();
method removes an item. At this stage it is removed from the list of objects. The page is wasted, as the only management at this stage is theitems._root.next_page
.A future enhancement could be to have an array of free pages, and this could be checked and used for a new write.
In my case, I wanted to store web pages, and modules. Both of these are easy to re-populate, so rather than garbage collect and move pages around (with limited available memory), it is more straightforward to call
fs.erase()
and re-populate everything again.I wanted the
FileStore
module to be as small as possible, so that the end application has as much memory without bloating the module with methods. This is why theFileStoreWrite
inherits it's methods fromFileStore
and adds the writing methods.