How to use getJSON ?

My webpage is slow, so I decided to use Bridge.put() and use those values in the webpage.
I have read this : http://forum.arduino.cc/index.php?topic=309596.0
But I can’t get that value into a webpage.

I’m using “zepto.min.js”, and that is working.
To fill a webpage from the Leonardo part, I use command “test” in a refresh:

$('#content').load('/arduino/test');

Now I want to show the JSON value in my webpage.

// Why is this not working ?
$('#content').getJSON('/data/get/temperature');

// I have to use something like this, but how to get the temperature in my webpage ?
// Do I have to create a function "json" ?
$.getJSON("/data/get/temperature",
      function(json){
        document.getElementById('tempValue').innerHTML=json.value;
      });

The Bridge.put() is working, I can see the JSON with http:///data/get

very cool thank you.

@Koepel,
the bridge does not return JSON. It only returns values.

Read the documentation. In this case, the bridge library.

This tutorial should help clarify things.

If you have tried the example on the link you point to, please upload, or post, your Arduino code. Please you markup, if you post the code. (see attached image)

Jesse

arduino_markup.png

jessemonroy650: the bridge does not return JSON. It only returns values.

Are you sure about that? When used locally within a sketch or on the Linux side, get() does indeed return just the string value. But when you access Bridge values using the web interface as mentioned by the OP, the response sure looks like JSON to me. For example, when I access http://yun3.local/data/get, I receive:

{"value":{"T2":"234","T3":"345","T1":"123","H2":"222","Sketch":"BarcodeMaster - Dec 28 2015 17:31:17","H1":"111","T4":"456"},"response":"get"}

If I try a specific element like T2: http://yun3.local/data/get/T2, I get:

{"value":"234","key":"T2","response":"get"}

The example you reference is for the REST API, not for accessing Bridge values from the web interface. Also, the Bridge library documentation does not go into the level of detail explaining web access of Bridge values, nor is there a standard example of it.

My experience shows that /data/get web requests return JSON objects, but I don't do web programming, so I can't offer any advice on how to parse/process/handle that response in a web page.

@ShapeShifter, if you do a straight REST call to the bridge, you only get values. My response was because - I wanted to make sure that was established, as the OP is not clear on what actions transpired. These are my real question:

  • Did you copy the code verbatim?
  • If so, which one?
  • Did you modify the code?
  • How are you validating that your Arduino code works?
  • If you just use your webbrowser, what does the response look like?

FWIW: You might remember I did this tutorial a few months ago.

An IoT Tutorial for Phonegap, and the Arduino Yun using the Bridge REST API

What may not be apparent - is that I am NOT using JSON. There is no need to use JSON, but the OP might have a different goal.

It is what it is. Jesse

I'm working on it (struggling with it).

When I click a button on the webpage, it takes more than a second until that reaches the sketch. After I started using a YUV webcam on my Yun it gets a lot worse. That is why I want to use Bridge.put(), so the website does not have to wait for the sketch.

I also want to start internet radio from the webpage, perhaps I can try the Bridge Mailbox to pass the URL to the sketch. The sketch starts wget and madplay on OpenWRT for internet radio.

Another option is to create a file on the sd card for the webpage from the sketch via the Bridge. I don't have that working yet.

So far I managed to reduce the system load for the YUV webcam (lower priority, lower resolution, lower quality, lower framerate):

yunProcess.runShellCommandAsynchronously(F( "nice -n 1 mjpg_streamer -i \"input_uvc.so -d /dev/video0 -r 320x240 --yuv -q 50 -f 4\" -o \"output_http.so -p 8080 -w /mnt/sd/arduino/www/webcam\""));
delay(200);

Update: I have the Bridge.put with JSON working. This way the Python load (the bridge script) does not have a big cpu load. I can also write a file from the sketch. The mailbox is not working yet. I will try to use multiple JSON values.

jessemonroy650:
as the OP is not clear on what actions transpired.

We must have read the post differently: the OP’s last line made it pretty clear to me that he is not using REST:

Koepel:
The Bridge.put() is working, I can see the JSON with http:///data/get


Koepel:
When I click a button on the webpage, it takes more than a second until that reaches the sketch.
After I started using a YUV webcam on my Yun it gets a lot worse.
That is why I want to use Bridge.put(), so the website does not have to wait for the sketch.

Yes, using the REST API as in the Bridge Example is not the fastest solution, as it is synchronous with the sketch, and requires interaction with the sketch’s code.

Using Bridge.put() in the sketch, and then reading it with a /data/get request should be faster as it is asynchronous with the sketch: the request only accesses the Linux side and does not have to synchronize with or wait for the sketch. Of course,there are some limitations: you can only transfer string values, you can only see the latest value, you can’t tell if a value was overwritten or lost, and you can’t delete a value. Still, it can be a very useful mechanism.

I also want to start internet radio from the webpage, perhaps I can try the Bridge Mailbox to pass the URL to the sketch.

My experience is that the mailbox mechanism is similar to the REST API as far as timing goes. I’ve used it for sending the occasional asynchronous command to the sketch, but I wouldn’t consider it a fast real time operation. It’s not painfully slow, but it is not instantaneous.

The sketch starts wget and madplay on OpenWRT for internet radio.

Any mechanism that requires a request to go through the sketch, just to be passed back down to the Linux side, is not going to be snappy. If you want to be able to make a network request to the system, and have it control operations on the Linux side, you will get the best response if you keep it on the Linux side and not involve the sketch. There are many ways to do this - not being an expert in Linux based web programming and CGI scripts, I’ve used the Bottle framework with Python and had good results and a reasonably responsive system. And I am NOT a web programmer, but using Bottle I’ve been able to get some reasonably interactive applications going. It sounds like you have more web experience than I (at least you’re using JavaScript which I’ve so far avoided) so you could do much more advanced things with it than I.

Another option is to create a file on the sd card for the webpage from the sketch via the Bridge. I don’t have that working yet.

This is another operation that is faster if you can keep it on the Linux side. Any time you get the sketch involved, things will be slower.

What is your endgame here? So far, from what you’ve described, I don’t see any need to have the sketch involved - it can all be handled on the Linux side, and doing so will make the system much more responsive. My personal experiences have given the best results when I try to move as much processing as possible down to the Linx side, and just use the sketch as a smart I/O controller - let it handle the interaction with the shield pins, and try to do everything else in Linux.

The endgame is a webcam-security-sensors-radio-and-more to be placed in a tube radio which is beyond repair. Don't worry, I will keep the original parts that are inside, and I won't change the wooden case.

Starting a online radio (wget, madplay) from a webpage in OpenWRT seems to require a cgi script, which is something I don't know how to use.

The Bottle framework would be another thing that I don't understand.

Setting the volume lower and higher should be fast. I do that as well via the sketch route, and it can get very slow. At the moment I'm looking for a way to execute this from a webpage: amixer -c 0 set PCM new_volume But I have no clue at all.

I know c, most of c++, bash, simple html and a some javascript. I have no experience with Perl or Python or cgi or PHP or lua.

At the basic level, a CGI script is nothing but an executable file in a special directory, which when run generates the desired output. While the Yun doesn’t have bash, it does have ash, which can do a lot of the same things.

I just tried a very simple CGI script using ash, and it works.

/www/cgi-bin/test

#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<h1>Sample CGI Output</h1>"
echo "
"
echo "This is a test..."
echo "
"

The key here is that it is in the /www/cgi-bin folder, which is the default folder where the Yun’s web server looks for CGI scripts. That can be changed, but until you get familiar with configuring the web server, it’s easiest to just work from there. Once entered, make the file executable:

chmod +x /www/cgi-bin/test

Then, just access the URL from a web browser:

http://yun4.local/cgi-bin/test

The output of the script starts with the HTTP headers: the only one I’ve included is to set the content type to HTML so the web browser renders it properly. Of course, you can set whatever content type you want, including “application/json” if you want to return JSON data. After the header(s) comes a blank line, and then the body of the response.

Something like that should be able to let you significantly speed up some of the operations. I know it’s uncharted territory (it was for me recently) but spending a little time learning Python and a framework like Bottle or Flask can greatly simplify the effort of creating a web application. For me, it’s been worth the effort.

Thanks ShapeShifter ! That is what I needed. I can start internet-radio with a button without the route via the sketch. Now I have to put everything together.

@ShapeShifter, How did we get from getJSON() to here? FWIW: you may have noticed a pattern with new users.

A confused question (or improper-assumption) on the part of the OP, often leads to something completely different and not related to the original question.

Best of Luck on this one. Jesse

jessemonroy650: How did we get from getJSON() to here?

It's a classic case of being stuck on a particular issue (like you said, an assumed path) without considering the goal (why I asked about the endgame): Describe the goal, not the step.

In this case, the real issue isn't how to update the web page based on a JSON response, it was how to get better performance of the overall system. The REST API method was too slow, so the Bridge get method was tried and ran into a roadblock. Once the actual goal was known, it's clear that neither method is ideal. I think the ultimate solution is to develop a web application using a framework that does a lot of the work for you, but using ash as a CGI script may be a reasonable workaround given the OP's coding comfort level.

Actually, I don't think this was too bad, it sometimes takes several pages for the real issue to come out and reach this point. I almost didn't respond to this thread because it appeared to be strictly a JavaScript question, and that is not one of my interests or qualifications. I only stuck around because I thought I might learn something about JavaScript from someone like you.

Come on, my questions are clear, and your answers did help a lot !
jessemonroy650, you probably have not used a YUV webcam in OpenWRT :wink: The YUV has to be translated into a jpg-stream, which requires a lot of the cpu. My Logitech webcams don’t have this problem, but the YUV webcam is not just a webcam, it is a boroscope.
I did read the links and your tutorial, but I did not understand how to use that in my sketch and webpage.

First of all, the real issue is how to get JSON in a webpage. Because displaying sensor values on a webpage was slow (my first sentence was: “My webpage is slow”). Maybe OpenWRT can read a DS18B20, but I want to do that with the ATmega32U4. And I want to add more sensors, maybe even VirtualWire/RadioHead.

Then I wrote: “I also want to start internet radio…”, which was also using the Bridge to the sketch and back via the Bridge to OpenWRT.

At this moment I have a big mess of sketches and webpages and I’m still testing and putting things together.
Sometimes the JSON values at http:///data/get are not ready, but the getJSON from “zepto.min.js” is still returning some value.

How I use getJSON:

In the sketch, the values are updated (for example every two seconds). They must be strings. So either itoa(), sprintf() (int only) or dtostrf() might be needed.

Bridge.put( "temperature", "-1.23");
Bridge.put( "humidity", "60");

The system load for the Bridge.put() is minimal.

In the webpage, using “zepto.min.js” for reading the values and JavaScript reads the temperature and humidity from the JSON object. They are updated every few seconds.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript">
function refresh() 
{
  $.getJSON("/data/get/temperature", function(json) { document.getElementById('mytemp').innerHTML=json.value; });
  $.getJSON("/data/get/humidity", function(json) { document.getElementById('myhum').innerHTML=json.value; });
}
</script>

</head>
<body onload="setInterval(refresh, 2000);">

Temperature: <span id='mytemp'>---.--</span> degrees Celsius.

Humidity: <span id='myhum'>--</span> percent.
</body>
</html>

The system load for reading JSON is some extra for OpenWRT and some for the browser. Overall it is only a little extra for both.

How I use cgi:
I have added an extra span with id ‘status’.
And extra function calls the script and updates the status. A simple button calls the function.

// extra function
function cgi()
{
  $('#status').load('/cgi-bin/test.cgi');
}

...

<button onclick="cgi()">Start internet radio</button>

The cgi script is actually a sh/ash/bash script. But I name the file test.cgi. It is to start something, but the script also writes to the status field.

#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "GLT Blues Radio started"
wget -O - http://wgltradio.ilstu.edu:8000/wgltblues.mp3 | madplay -o /dev/dsp -

Thanks for the follow up, and the detailed description of what you're doing. It looks like you're well on your way.

And I appreciate the simple example of how you are updating the temperature/humidity on your page, I think I can use that idea on my current project. One question: you make separate calls to get the two values. Could that be re-written to a single getJSON call to /data/get which gets all values at once in a single JSON object, and then make two calls to update the HTML? I assume the major overhead of the process is the web request, and not the processing of the received data, and making just one request would be more efficient. Did you try this? If so, was there a problem? What would be the syntax to get the JSON data: json.value.tempetature? (OK, so it's more thane one question... :-[ )

Pardon me for taking this off-topic, but how would you handle the situation where the JSON data isn't just being displayed, but is a status value that selects which image is to be displayed - is there a simple way to pass the image name in the JSON data, and have the image object dynamically change the displayed picture? I assume the JavaScript would access the image object by name, but assign to a different attribute than innerHTML?

And just like that, the roles are reversed and the student becomes the master. ;). (After all, I did say I stuck around on this thread mostly to try and learn some JavaScript!)

ShapeShifter: - is there a simple way to pass the image name in the JSON data, and have the image object dynamically change the displayed picture? I assume the JavaScript would access the image object by name, but assign to a different attribute than innerHTML?

I did a little googling while waiting for a long compile to finish, and I think I can answer my own question:

document.getElementById('myImg').src = json.value;

where the json.value is the name of the new image file. (The assumption being that the bridge variable is the proper name of the image file.)

I haven't been able to test this yet, I won't have a chance until much later tonight...

I started this topic two days ago, and learned a lot. Thanks !

About the single call for multiple JSON objects, I don't know about that. I would need an example to try it. However, that is mostly JavaScript in the browser, so I don't care, as long as my Yun has little cpu load.

The "json.value" can be put into a variable, and a extension and path can be added to it. JavaScript is flexible enough to do everything with it. Setting the "document...src" to the "json.value" will work. I think you need some kind of action to update the image. A refresh or button click or mouseclick on the image itself or something like that.

For the image, the name of the image must be known in the sketch. Perhaps it is easier if the sketch only sets a status value (in a JSON object), and JavaScript selects the image with that status.

HTML5 can do even more. Perhaps it is possible to store the temperatures and show them as a graph in a HTML5 canvas.

I also have HttpClient working, so I can retrieve something from the internet and use that in the sketch.

Koepel: I started this topic two days ago, and learned a lot. Thanks !

And thank you! I'm also learning here.

About the single call for multiple JSON objects, I don't know about that. I would need an example to try it.

I gave a try to getting both temperature and humidty values in one fetch, then update the two HTML elements with the returned value. It works. The HTML file is the same as what you posted in reply #12 but I changed the refresh() function to:

function refresh()
{
  $.getJSON("/data/get", function(json)
                         {
                            document.getElementById('mytemp').innerHTML=json.value.temperature;
                            document.getElementById('myhum').innerHTML=json.value.humidity;
                         });
}

The idea is that using /data/get, and leaving off the key name, makes the Yun return a JSON object with all of the Bridge values at once. So there is a single network transaction (probably the costly part of the update) and then the two different HTML elements are updated with the individual values from the JSON object.

I guess the trade-off here is if you have a LOT of Bridge values that have been set, but are only interested in one or two, it may be more efficient to get them individually. But if you are fetching all (or most) of the Bridge values, then it's probably more efficient to grab them all at once.

Setting the "document...src" to the "json.value" will work. I think you need some kind of action to update the image. A refresh or button click or mouseclick on the image itself or something like that.

Of course. I was thinking of putting it in a refresh function, but didn't go into that level of detail since you had already covered it in your example. But I did say I was a rank beginner when it comes to JavaScript (I have over 30 years of professional embedded programming experience, but no real web programming, just some very basic static HTML) so you are right to assume I know nothing and you should include such important details.

For the image, the name of the image must be known in the sketch. Perhaps it is easier if the sketch only sets a status value (in a JSON object), and JavaScript selects the image with that status.

I would agree that sending just the status makes sense in most situations. In my case, however, the existing page is dynamically generated from a template file using some Python code and the Bottle framework, so the Python code already knows how to translate the system status to an image file name that gets inserted into the static page. So in this case, it makes sense to keep that logic in the Python application, and not duplicate it in the JavaScript. When the page is loaded, the current status is used to put the initial image name in the HTML file, then a refresh function will periodically request a new image file name based on the status at that time.

I will give that a try next. The question is whether setting the .src property of the image will always trigger a new image fetch, even if it's the same as the current image name. If so, then the refresh function will need to have a little intelligence to compare the new image name to the current name and only update .src if it is different.

Thanks for your help, you're encouraging this old dog to learn some new tricks!

Image update works!

The image element in my HTML file:

<img id="myimg" height="300" src="/static/{{img}}" width="200" />

The {{img}} construct is a template tag from the Bottle framework: when Bottle renders the page, I pass it a string named “img” and Bottle’s template engine substitutes the file name I provide into the HTML before it serves up the page. It’s like a server side dynamic page.

I added an onload tag, just like yours, to trigger an automatic refresh, and included this refresh function:

function refresh()
{
  $.getJSON("/status/img", function(json) { document.getElementById('myimg').src="/static/".concat(json.img); });
}

So, requesting /status/img returns a JSON object with the image name representing the current status. For example:

{"img": "On.jpg"}

The image source is updated, but it only triggers the browser to fetch the new image if the name has actually changed. Fortunately, assigning the same value as is already there does not trigger the image file to be loaded again. Nice.

The last part of the puzzle is getting the Bottle framework to send back the image file name in response to requesting /status/img. This is the easiest part. I already have a get_image() function that determines the proper filename based on the current status, so the only thing I need to do is set up a route for requesting /status/img and get it to call that function and return a JSON object with the appropriate data:

@route('/status/img')
def do_status_img():
    return {'img':get_image()}

Dynamic pages: here I come!

The multiple values, using the full description "json.value.temperature" is very nice. Thanks.

Meanwhile, I found the wrong explanation in the FileIO reference. https://www.arduino.cc/en/Reference/YunFileIOConstructor They say that FileIO can be used for the sd card. That is not true, it can be used for the complete OpenWRT file system.

I use that because I want to keep all my user data on the sd card. I have added a check for the "index.html" and copy the cgi file to /www/cgi if it didn't exist.

  // Test if files exist.
  // The webpage is on the sd card (or a usb flash drive).
  // The *.cgi files will be copied to /www/cgi-bin of the wifi module.
  // 
  if( !FileSystem.exists("/mnt/sd/arduino/www/index.html"))
  {
    SerialUSB.println(F( "ERROR, webpage not found on sd card"));
  }
  
  if( !FileSystem.exists("/www/cgi-bin/mcmichael.cgi"))
  {
    Process yunProcess;
    yunProcess.runShellCommand(F( "cp /mnt/sd/arduino/www/cgi-bin/mcmichael.cgi /www/cgi-bin/mcmichael.cgi"));

    while(yunProcess.available() > 0)
    {
      char c = yunProcess.read();
      SerialUSB.print( c);
    }

    SerialUSB.println(F( "mcmichael.cgi copied from sd card to wifi module"));
  }

And the FILE_WRITE is wrong explaned at https://www.arduino.cc/en/Reference/YunFileIOOpen This is what I use to make a log file:

  // -------------------------------
  // Write to a log file
  // -------------------------------
  // 
  // FILE_WRITE does not append, it overwrites the previous file contents.
  // FILE_APPEND does append and also creates a new file if it didn't exist yet. The folder must exist.
  File dataFile = FileSystem.open("/mnt/sd/arduino/log.txt", FILE_APPEND);
  if( dataFile)
  {
    SerialUSB.println(F( "File is written"));
    dataFile.println(F( "Sketch compilation at: " __DATE__ ", " __TIME__));
    dataFile.close();  
  }
  else
  {
    SerialUSB.println(F( "Log error. Does the folder exist ?"));
  }

Koepel:
They say that FileIO can be used for the sd card. That is not true, it can be used for the complete OpenWRT file system.

Yes, I’ve noticed that some of the documentation is rather narrowly focused. Besides FileIO having a broader application than documented, much of the documentation and examples focuses strictly on WiFi communications, when in reality just about anything that works over the WiFi will work equally well over the Ethernet connection, with no changes to the code. About the only thing that is specific to the WiFi interface that doesn’t apply equally to the Ethernet interface is the actual WiFi configuration.