How do I integrate global int/string variables into my ESP8266 website? - html

I use my NODEMCU ESP8266 to control my LED strip behind my couch. I have a web-server that posts the HTML with server.send() in every loop. Now I want the website to show the current state of the led stripe, but I can't just integrate the variables into the HTML code of the website because the server is obviously going to treat it like HTML instead of actually reading the variables.
//a variable I use for the LEDs
int colorCode;
// thats in the handler function
String s = MAIN_page; //Read HTML contents
server.send(200, "text/html", s); //Send web page
// thats the website
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE HTML>
<html lang="de">
...website...
</html>
)=====";
I just need a small hint as to how I can integrate variables like int colorCode into the HTML before it gets sent to the server with server.send().

Similar has been done by, e.g., the OpenEVSE hardware project, which builds its JSON responses in Arduino strings (String JSON):
json += "{";
json += "\"rssi\":"+String(WiFi.RSSI(i));
json += ",\"hidden\":"+String(WiFi.isHidden(i)?"true":"false");
json += "}";
You could do the same as long as send() receives the right type of string. It would involve dropping the PROGMEM, probably the const, and likely using a high-level string class for convenience. Note that there are several reasons OpenEVSE chooses to keep the HTML static:
AJAX lets their app be more responsive than one that must be reloaded every page, and
an ESP8266's limited memory goes much further when it does not need to build a whole webpage.
Practically speaking: program memory can store large strings, but they will not be dynamic. If the string is not known at compile time, then it will have to be assembled at run time, and RAM will be used to keep track of it. Building the webpage in a string makes sense as long as the page is small and the variables few.

Related

What's the lightest way to add the smallest amount of dynamics to a static HTML site?

I have a personal website that's all static html.
It works perfectly for my needs, except for one tiny thing.
I want to dynamically change a single word on a single page: the name of the current map for a game server I'm running.
I can easily run a cron job to dump the name of the map into a file in the site's html directory, call it mapname.txt. This file contains a single line of text, the name of the map.
How would I update, say, game.html to include this map name?
I would very strongly prefer to not pull in some massive framework, or something like php or javascript to accomplish this.
I want the lightest weight solution possible. Using sed is an option, although definitely a hacky one. What's the tiniest step up from static html?
If you say "dynamically", do you mean:
If the information changes ...
A) the user should see it after they have re-loaded the page?
B) the page should update without the need to reload?
For A, you can use PHP (or any other language your server supports) to read the data from the file and print it into the web page. This will happen on server side.
For B, you can use JS that queries the file and updates the HTML. This will happen on client side.
To change text there are a few way though only two appropriate methods.
First is using textContent:
document.getElementById('example').textContent = 'some example text';
Secondly is the older nodeValue however it's a bit more tricky since you have to specify the exact textNode (e.g. .firstChild):
document.getElementById('example').firstChild.nodevalue = 'some example text';
You're 100% on the mark about not using frameworks or libraries, almost everything exists without the suck.
I'm not going to test this though this is a very stripped down version of my ajax function from my web platform. Some people might scream about the Fetch API however the syntax is an absolute mess. I recommend figuring out how to standardize this function so you can use it for everything instead of making copies of the code for every instance. Mine supports both GET and POST requests.
function ajax(method, url, param_id_container_pos, id_container)
{
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.timeout = 8000;
xhr.open(method,url,true);
xhr.send(null);
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
if (xhr.getResponseHeader('content-type'))
{
var type = xhr.getResponseHeader('content-type').split('/')[1];
if (type.indexOf(';') >- 1) {type = type.split(';')[0];}
}
else {var type = 'xml';}//Best guess for now.
console.log(type,xhr);
console.log(xhr.responseText);
//console.log(type,xhr.responseXML);
//document.getElementById('example').textContent = xhr.responseText;
}
}
}
You're also going to have to ensure that the url is set to an absolute path. I use path variable in my platform (see my profile for the link, wildly clean and organized code).
There are plenty of ways to make this function reusable and I highly recommend doing that. For now use the last non-curley-bracket line to update your line of text.

Espressif ESP32 web server HTML example

I'm working on an embedded ESP32 design using one of the web server examples included in the esp-idf examples. I'm able to get the device into soft AP mode and display a simple web page. Now that I have that working, I'm trying to build a page with a graphic.
I'm using the Linux hex tool "xxd -i " to convert the HTML file into a hex dump array for the C include file. It works fine if the document is just HTML, but I'm stuck on trying to do this with an image.
I went as far as using xxd on both the HTML file and the image file and using "netconn_write" to write out both files. I also tried combining them into a single hex dump file. At this point I'm not sure how to proceed, any help is greatly appreciated.
You can use this utility to embed any number of binary files in your executable. Don't forget to set a correct mime type. Also, if the file is big, you have to rate limit the sending, which might become a non-trivial task.
Therefore I suggest to use a filesystem and an embedded web server to do the job. Take a look at https://github.com/cesanta/mongoose-os/tree/master/fw/examples/mjs_hello (disclaimer: I am one of the developers). It'll take you few minutes to get a firmware with working HTTP server, ready for you prototypes.
You can use de directive EMBED_FILES directly in CMakeLists.txt. For example, to add the file favicon.jpg image, in my CMakeLists.txt, in the same directory of main.c:
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
EMBED_FILES "favicon.jpg")
And somewhere in the main.c:
/* The favicon */
static esp_err_t favicon_handler(httpd_req_t *req)
{
extern const char favicon_start[] asm("_binary_favicon_jpg_start");
extern const char favicon_end[] asm("_binary_favicon_jpg_end");
size_t favicon_len = favicon_end - favicon_start;
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_send(req, favicon_start, favicon_len);
return ESP_OK;
}
static const httpd_uri_t favicon_uri = {
.uri = "/favicon.ico",
.method = HTTP_GET,
.handler = favicon_handler,
.user_ctx = NULL
};
You can add as many files you need in this way, text, html, json, etc... (respecting device memory, of course).

Simple function to read file from an URL to a string buffer ( C++ / MQL{4|5} using WinInet.dll )

I am looking for a simple function which is able to read a text or binary file from the internet into a string variable.
It´s unbelievable that I could not find anything in the web, just low level descriptions of all the WinInet functions and useless samples, that do not work at all, at the MQL-forums.
What I need is a function like:
string buffer = ReadTextFileFromWeb( "www.myurl.net/textfile.txt" );
No more, no less. I am not very familiar with internet programming stuff at all, but I am sure there is anybody out there who is able to present the reason just like that.
The code will be used in MQL4/MQL5. I know that there is already a WebRequest() function which works, but it is restricted to expert advisors and cannot be used in Custom Indicator type of code.
I need this solution to load data into a custom indicator.
Go get this on github https://github.com/sergeylukin/mql4-http
//For MT4 Add HTTP Access
#include <mql4-http.mqh>
string URLr = "www.myurl.net/textfile.txt";
Print("URLr return is: ", URLr);
For MT5 you are on your own.
The above dose not have the issues that WebRequest() has. Or I have not seen it have any issues. I use it all the time in a lot of EA and never had a chart lockup or have a issue.

Extracting the outputs/results from an executed .pexe file

My goal is to convert a C++ program in to a .pexe file in order to execute it later on a remote computer. The .pexe file will contain some mathematical formulas or functions to be calculated on a remote computer, so I’ll be basically using the computational power of the remote computer. For all this I’ll be using the nacl_sdk with the Pepper library and I will be grateful if someone could clarify some things for me:
Is it possible to save the outputs of the executed .pexe file on the remote computer in to a file, if it’s possible then how? Which file formats are supported?
Is it possible to send the outputs of the executed .pexe file on the remote computer automatically to the host computer, if it’s possible then how?
Do I have to install anything for that to work on the remote computer?
Any suggestion will be appreciated.
From what I've tried it seems like you can't capture the stuff that your pexe writes to stdout - it just goes to the stdout of the browser (it took me hours to realize that it does go somewhere - I followed a bad tutorial that had me believe the pexes stdout was going to be posted to the javascript side and was wondering why it "did nothing").
I currently work on porting my stuff to .pexe also, and it turned out to be quite simple, but that has to do with the way I write my programs:
I write my (C++) programs such that all code-parts read inputs only from an std::istream object and write their outputs to some std::ostream object. Then I just pass std::cin and std::cout to the top-level call and can use the program interactively in the shell. But then I can easily swap out the top-level call to use an std::ifstream and std::ofstream to use the program for batch-processing (without pipes from cat and redirecting to files, which can be troublesome under some circumstances).
Since I write my programs like that, I can just implement the message handler like
class foo : public pp::Instance {
... ctor, dtor,...
virtual void HandleMessage(const pp::Var& msg) override {
std::stringstream i, o;
i << msg.AsString();
toplevelCall(i,o);
PostMessage(o.str());
}
};
so the data I get from the browser is put into a stringstream, which the rest of the code can use for inputs. It gets another stringstream where the rest of the code can write its outputs to. And then I just send that output back to the browser. (Downside is you have to wait for the program to finish before you get to see the result - you could derive a class from ostream and have the << operator post to the browser directly... nacl should come with a class that does that - I don't know if it actually does...)
On the html/js side, you can then have a textarea and a pre (which I like to call stdin and stdout ;-) ) and a button which posts the content of the textarea to the pexe - And have an eventhandler that writes the messages from the pexe to the pre like this
<embed id='pnacl' type='application/x-pnacl' src='manifest.nmf' width='0' height='0'/>
<textarea id="stdin">Type your input here...</textarea>
<pre id='stdout' width='80' height='25'></pre>
<script>
var pnacl = document.getElementById('pnacl');
var stdout = document.getElementById('stdout');
var stdin = document.getElementById('stdin');
pnacl.addEventListener('message', function(ev){stdout.textContent += ev.data;});
</script>
<button onclick="pnacl.postMessage(stdin.value);">Submit</button>
Congratulations! Your program now runs in the browser!
I am not through with porting my compilers, but it seems like this would even work for stuff that uses flex & bison (you only have to copy FlexLexer.h to the include directory of the pnacl sdk and ignore the warnings about the "register" storage location specifier :-)
Are you using the .pexe in a browser? That's the usual case.
I recommend using nacl_io to emulate POSIX in the browser (also look at file_io. This will allow you to save files locally, retrieve them, in any format you fancy.
To send the output use the browser's usual capabilities such as XMLHttpRequest. You need PNaCl to talk to JavaScript for this, you may want to look at some of the examples.
A regular web server will do, it really depends on what you're doing.

calling a webservice without using a wsdl file

I need to make a call to a webservice and at the moment i am doing it this way:
private var myWebService:WebService = new WebService();
myWebService.loadWSDL('path to wsdl file');
myWebService.addEventListener(ResultEvent.RESULT , function(event:ResultEvent):void {
trace(event);
});
myWebService.addEventListener(FaultEvent.FAULT , function(event:FaultEvent):void {
trace(event);
});
myWebService.soapcallName();
Now i would like to do the same thing but without loading the WSDL file and doing the soapcalls directly to the right url. Is this possible?
Yes, I had to do this when our WS calls had to hit a proxy in a DMZ, but the WSDL for the ACTUAL service was behind a firewall and unreachable. But it is a tricky process.
First you will need to create the soap post requests manually. You can read all about the structure on wikipedia http://en.wikipedia.org/wiki/SOAP . This means you will need to generate all calls manually since you can't say SomeService.SomeMethod without the wsdl loaded. Now the next problem you will face is actually sending it out. Because you need to add custom http headers on a POST, you will need to build the full request document (strings and line breaks etc) and send it over a socket (HTTPService will not support custom headers on a POST). If you need more help getting this going, I can add further examples on here.
Example:
You need to basically create a method to generate SOAP Envelopes. Here's a quick i.e. from the link I gave you...
private function getStockPrice(symbol:String):String{
// you can do this with xml also and call toString() on it later
var envelope:String = "<?xml version=\"1.0\"?>";
envelope += "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">";
envelope += "<soap:Header></soap:Header>";
envelope += "<soap:Body><m:GetStockPrice xmlns:m=\"http://www.example.org/stock\">";
envelope += "<m:StockName>" + symbol + "</m:StockName>";
envelope += "</m:GetStockPrice></soap:Body></soap:Envelope>";
return envelope;
}
Then you call getStockPrice("IBM") which will return the ready to go SOAP envelope that you will use as the POST body of your call. Note that in the example, you will have to know the information that would have been in the WSDL ahead of time like method names, param names etc. Use the Socket() class to send the post body to the server since you will need to add a custom SOAPAction header. If you need help with that part, here is a class to begin hacking on that already does that... use it instead of HTTPService. RestHTTPService.