1

I have a simple html file in which there's javascript code referring to google charts.

The code I use is this (I'll show the important part):

function drawChart(){
    var data = google.visualization
                     .arrayToDataTable([ ['Label', 'Value'],['Temp', 22.75],]);

    // etc...
}

I use a bash command (sed) to replace that 22.75 value with a new one from the last line of a .txt file. However, this throws some errors which I haven't been able to neither correct nor ever identify.

So is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?

UPDATE:

Sorry for the lack of info in this question, I really appreciate all the people that took the time on reading my question. I'll try to fill with more information in the next minutes.

I am able to extract the last line of the .txt file, extract the value on the right part of the '-' symbol and store it in a variable. Then that value is taken to update the html file with a sed command. The error comes when the value is updated but with no value. I guess that happends due to a failed record of temperature in the txt file, then the extracted value is a null. Finally is the html fiel with javascrit code happens to be like this:

(...)['Temp', ],]);

Then the updater can't update the value since due to the way that sed command is written I guess there's no way that it can detect a no-number-value in there. So the html remains without a value all the time.

TXT File structure:

(...)
20:25:03-23.312
20:26:02-23.312
20:27:03-23.375
20:28:03-23.375
20:29:02-23.375
20:30:02-23.312

Bash script:

# (...code...)
lastRecord=`cat /home/pi/scripts/temp_control/logs/"$today".log | awk 'END{print}'`

function rightNow {
  lastTemp=`echo $lastRecord | cut -d'-' -f2`

  timeOfTemp=`echo $lastRecord | cut -d'-' -f1` # Not used yet

  #Command used to update
  sed -i "s/['Temp', [0-9]\{1,2\}.[0-9]\{1,3\}]/$lastTemp]/" /var/www/rightnow.html
}

rightNow
Michael Foukarakis
  • 35,789
  • 5
  • 74
  • 113
ederollora
  • 994
  • 2
  • 10
  • 28
  • Almost certainly. How is the text file structured? – Scott Sauyet Sep 14 '13 at 23:15
  • Please add the last part (say the last 2..3 lines) of the file to your question. Also, is there also java involved? If not, delete that tag. Also, what environment runs the html-file? I'm guessing a browser, so please state what browser you use (since I'm guessing the txt file is a local file ?) ? – GitaarLAB Sep 14 '13 at 23:21
  • @OneOfOne The errors are not erros themselves. The bash script that updates the html file, updates it with no value. Then the script (due to the way that sed command was written) is not capable of updating the value again. So when the updater script updates it as "['Temp', ],]);" the sed command can't replace the gap again with a new temperature value. – ederollora Sep 15 '13 at 18:39
  • @ScottSauyet It's made this way: (new line)20:27:03-23.375 (new line)20:28:03-23.375 (new line)20:29:02-23.375 (new line)20:30:02-23.312 – ederollora Sep 15 '13 at 18:40

3 Answers3

4

You cud get your file just like any other ajax request.

Using javascript

var request = new XMLHttpRequest();
request.open('GET', 'public_path_to_file.txt', false);
request.send();

var textFileContent = request.responseText

Using jQuery

var textFileContent;
$.get('public_path_to_file.txt', function(data) {
  textFileContent = data;
});

Whats left is to get the right part from textFileContent. Dependent of the structure of the file we can do this in different ways. Without an example file you are on your own but here is some examples.

If you need the last line

var lines = textFileContent.split("\n");
var lastLine = lines[lines.length - 1];

If you need to use regex

var regex = //* some regex to get your content*//gm;
var result = regex.exec(textFileContent);
// result should now the content who matches your regex
aross
  • 4,804
  • 1
  • 23
  • 30
1

First I'll assume that you ultimately want to read a local file with your browser and your current workflow is something like a local 'bash-script' that

  1. first updates/modifies an inline piece of javascript (inside a locally stored html file) with the last occurring value retrieved from a local txt-file (using sed)
  2. opens the (just modified html-) file (via commandline) inside a common browser.

Then I assume the sed-route once worked but now doesn't work anymore (probably because the html file has changed?) and now you'd like the inline javascript (in the html file) to fetch that value from the textfile itself and subsequently use it (thus without the need for the 'bash-script'/sed solution.

Thus, the answer (based on above assumptions) to your final question: 'is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?', depends on your final requirement:
are you ok with a file-input where you select the text-file every time you view the html-file?

If your answer is YES, then, (depending on the browser you use) you can read a local file (and work your magic on it's contents).
In modern browsers, using the File API (which was added to the DOM in HTML5) it's now possible for web content to ask the user to select local files, then read the contents of those files.

For example, using FireFox's 'FileReader' you could do:

html:

<input type="file" id="fileinput" multiple />

javascript:

function readAllFiles(evt){
    var files = evt.target.files, i = 0, r, f;
    if(files){
        for(; f = files[i++]; ){
            r = new FileReader();
            r.onload = (function(f){
                return function(e){
                    alert(e.target.result);
                };
            })(f);
            r.readAsText(f);
        }
    } else {
        alert("Error loading files");
    }
}
document.getElementById('fileinput')
        .addEventListener('change', readAllFiles, false);

Note that for accessing local files in Chrome you must start Chrome with this switch: chrome --disable-web-security

However,
if the answer is NO (so you want to specify the file, and more importantly it's path, inside the 'code', so you don't have to select the text-file every time your local app runs) then you (usually) can't (because you can't get/set the path, thank the great maker)...
Unless you choose a specific older/unpatched browser (specifically for this task) where you know of a (hack) way to do this anyway (like the IE xml vulnerability or the XMLHTTP vulnerability or etc... you get the picture..).

Some alternative solutions (that don't require you to select the correct textfile over and over again)

  1. Setup a fullblown web (LAMP) server (to use the XMLHttpRequest way as used in aross answer, but this might feel like shooting at a mosquito with a cannon..)
  2. Explore different script languages (but effectively still do the same as your now broken sed-solution)
  3. Combine 1 and 2, choosing from php (the latest version has a small webserver included, you might start/stop it when needed (even in the bash-script workflow) OR using node.js (which is 'javascript' and where you can program/control a small task-specific server in just a couple of lines).

Hope this helps!


Update:
Based on your updated question, comments and request for recommendation, I'd like to suggest to use PHP to dynamically fetch the value from your log txt file and have it generate your html code with inline javascript on the fly (every time you visit the page).

The browser will never see the php code, only what php inserted to your page (in this example the last found value or 0).

You'd rename the rightnow.html file to rightnow.php and modify it (something like) this:

<!DOCTYPE html>
<html><head>
  <!-- your header code -->

<script type="text/javascript">
//parts of your javascript

<?php                                // start php script
$logFile= '/pathToYour/logFile.log'; // <-Modify
if( $fp= @fopen($logFile, "r") ){    // if logfile succesfully opened,
    fseek($fp, -30, SEEK_END);       // set pointer 30 chars from EOF
    $val= array_pop(explode("-", rtrim(fread($fp, 30))));  //get last value
    fclose($fp);                     // close file
} 
?>                                   // end php script

function drawChart(){
  var data=google.visualization
                 .arrayToDataTable([ ['Label', 'Value'],
                                     ['Temp', <?php echo $val? $val : "0"; ?>],
                                   ]);     // ^php above inserts value or 0

  // etc...
}

//parts of your javascript
</script>

</head><body>

  <!-- your body code -->

</body></html>

Note that fopen in combination with setting the filepointer via fseek and sequentially fread-ing from the pointer to EOF does not load the complete logfile (60min * 24hour=1440 lines of 16 bytes=22.5kB at the end of the day) into memory (good for this purpose), but only the last 30 chars (as in this example).

The variable to your logfile and path must still be modified to your situation (I don't know the format of your $today variable).

Depending on your further needs you might want to perform some extra checks/logic on the array of values that explode returns (instead of popping the last value). Or what about modifying the html a little so you could also include the last temperature's time reading, etc. (But this tested piece of code should get you started and explains the procedure of going the php way).


Update:
Since you have chosen to place the last known value of your logfile as in textfile placed inside your public www-root (with a bash script I assume, every minute of the day?), you can now indeed go the 'ajax' way, as answered by aross!

However I want to hint that the code/solutions in all current answers here could be mixed (since you now also have ajax working): instead of ajax-ing (loading) a txt file, you could have php fetch and send this value to the browser on-the-fly/on-demand!

So, instead of requesting http://url_to_my_rpi/file_to_download.txt, you could request http://url_to_my_rpi/read_last_temperature.PHP which should fetch the last known value out of the log-file (set proper security/access) and send it to the browser (set proper headers), just like your text-file did. You wouldn't have to change anything in the html/javascript except the url you request.

The advantage would be (depending on how your current bash-scripts works) that your PI now only does this 'work' (of getting the last value of your logfile) when you are viewing your monitor-page. And that you are not writing that file in your www-root every minute of every day (as I suspect).

Community
  • 1
  • 1
GitaarLAB
  • 13,494
  • 9
  • 51
  • 74
  • Hi @GitaarLAB ! Thanks for your time. I updated my info, sorry for the lack of info. I'll sum you up the info I added. A Basch script (that you can find in my question) updates a javascript line inside the html file. The error happens when no value is updated, making the javascript code fail and moreover, the updater script can0t update the value again. So I was thinking in some kind of dynamic code that can fetch a file in my Raspberry Pi, and read the last line of the file containing the info. – ederollora Sep 15 '13 at 18:57
  • 1
    I see var/www in the location of the html-file, does that mean you already have a webserver running on the pi? If so, then my next question would be if you also have php support. If so, then I highly recommend to go the php way. – GitaarLAB Sep 15 '13 at 23:32
  • Yes I am runnign apache. (My main trouble is how to request the file, os at least request the value, and update it on the javascript code). To be true I am starting to program in several languages so my knowledge is quite basic, but I was trying with jquery too. Which is your recommendation? – ederollora Sep 15 '13 at 23:40
  • UPDATE: I am able to successfully retrieve the file and display it on the console. however is there any way that the value stored in jquery's variable, be able to use in the javascript code? – ederollora Sep 15 '13 at 23:46
  • 1
    If you have the value in jquery, then you have the value in javascript, since jquery is a massive library *in/on top of javascript*. However, now that I know what you want to accomplish with your PI and you already have a webserver running (possibly php to), I'd suggest to look into PHP. Your browser would then navigate to http:/ /urlToPI/rightnow.php. You then take your existing html file with inline javascript and modify it like this: `.arrayToDataTable([ ['Label', 'Value'],['Temp', ],]);` – GitaarLAB Sep 16 '13 at 03:21
  • GitaarLAB!! Done it!! Will answer my question with the proper code used, finally I achieved it with jQuery!! Thanks for all your info, I've learned a lot with you!! – ederollora Sep 16 '13 at 11:09
  • You're welcome. I'm curious to your answer and how you got jquery to access your '/home/pi/scripts/temp_control/logs/' path (security wise). – GitaarLAB Sep 16 '13 at 11:17
  • no no finally I decided to export the temperature with just the last temperature in a file (so that it was easy to download and parse) in the /var/www/ folder ;) – ederollora Sep 16 '13 at 11:33
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/37454/discussion-between-ederollora-and-gitaarlab) – ederollora Sep 16 '13 at 12:30
0

The solution achieved, finally, was like this:

I did it with a jQuery statement and reusing the javascript code of Google Charts.

First I added javascript and jQuery tags in the html file:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>

Then I merged jquery code and javascript code that I had in one script:

<script type='text/javascript'>

  // Needed this var so that I could use it in other places of the code 
  var t;

  jQuery.get('http://url_to_my_rpi/file_to_download.txt',function(data){
  console.log(data)

  t=data;

  },'text');    

  google.load('visualization', '1', {packages:['gauge']});
  google.setOnLoadCallback(drawChart);
  function drawChart() {

    t=eval(t);

    var data = google.visualization.arrayToDataTable([
      ['Label', 'Value'],
      ['Temp', t],]);

   // (... more javascript with Google Charts options, display parameters..)

</script>

Finally, and even if it's not listed as the main question, be sure to enable *mod_headers* on your apache and add Header set to apache2.conf file (In my case: /etc/apache2/apache2.conf)

1) Enable the module:

a2enmod headers

2) Add the line on your configuration file

Header set Access-Control-Allow-Origin "*"

3) Restart apache 2

4) In case the 3 steps above didn't work, follow the instrcutions by entering in this website or reinstall apache2.

ederollora
  • 994
  • 2
  • 10
  • 28
  • I think it's darn cool of you to actually follow up and post your solution including the configuration steps needed! For future readers I'd like to point out that you have solved the difficult part (accessing the logfile outside of your hosting-root) by simply placing a short file containing the value you need inside your www root (as you have commented on my answer). – GitaarLAB Sep 17 '13 at 23:28
  • However (realizing you are new to javascript), I 'must' object against the use of `eval` (or *evil* as javascripters commonly call it) to convert a text-string (representing a number) to a number. Not because it is unsafe (you hardcoded the file link to a file you control) but eval also has a massive overhead (of cloning your variable scope etc.) whilst a simple `Number(stringVariable)` or `parseFloat(stringVariable, 10)` (10 for a decimal base/radix) is the correct way. – GitaarLAB Sep 17 '13 at 23:29
  • Or even simpler, using `+` operator: `+stringVariable`. Advice: never visit/read/copy anything ever again from the source where you got your code: `t=eval(t);`. Lastly I setup an [example on jsfiddle](http://jsfiddle.net/XkxSb/) for you, demonstrating a more reliable (event-driven, think of loading-time vs decencies) and flexible (one/more temperature gauge objects that can be `refresh()`ed (even at an interval, etc) without reloading the page, reaping the benefits of ajax) method. Just to get you started! Hope that helps! – GitaarLAB Sep 18 '13 at 07:05
  • I would like, in short text, explain how much I personally appreciate all the hard work by GitaarLAB. I am a newbie in general Java programming (Javascript in general) and I really think it's perfect all the work he has done. I am giving some "make up" to the code you've written in jsFiddle. I'll post my final solution soon. Finally just to tell you, I've finally written a " window.setInterval("reFresh()",60000); " to make the refresh automatic. Thanks a lot!!! – ederollora Sep 19 '13 at 22:24
  • Thank you for your kind words! I [upgraded the previous jsfiddle to version 2](http://jsfiddle.net/XkxSb/2/), because I didn't like to load the visualization package for every new temperature control, so that's fixed. I also added what I had in mind to use as auto-refresh together with a button that kills that auto-refresh. – GitaarLAB Sep 20 '13 at 07:30