Chart.js persitant time graph example

Place code snippets and demo code here
BeanieBots
Posts: 345
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 183 times
Been thanked: 112 times

Chart.js persitant time graph example

Post by BeanieBots »

I know that Annex comes bundled with some very useful graphing files but they are a little limited, so I thought I'd have a go with the more up-to-date Chart.js version. The full suite is a whopping 400k but they have a facility to create your own chart.min.js file with just the bits you need.
The example here uses the jsdeliver service which obviously requires your device to have internet access.
Special thanks to cicciocb without whom I would never have been able to get the web page and Annex to talk to each other.
Hope this little snippet is of use to someone.

Code: [Local Link Removed for Guests]

'****************************************************************************************
'*                                                                                      *
'*  Example of Chart.js persistant time graph with variable data sets                   *
'*  V1.0.0  16/06/2023 © BeanieBots.                                                    *
'*  Thanks to cicciocb for the help with html & jarva bits.                             *
'*  For more information on the use of Chart.js, please see https://www.chartjs.org/    *
'*  Tested on ESP8266 FW 1.44.2  &  ESP32 FW BLE CAN 1.48.22                            *
'*                                                                                      *
'****************************************************************************************

RAMspare = 60000      'The amount of RAM left spare after creating the datasets.
                      'Determines how long data will be stored before deleting.
                      'The ESP8266 can be as low 32000 but the ESP32 requires at
                      'least 60000 to be reliable.
                  
NumSets = 3           'The number of EXTRA datasets to be plotted.
Dim Value(NumSets)    'Create an array to hold the new values.
Dim DataSet$(NumSets) 'Create a string array to hold each dataset.
Angle = 0             'Starting value for  dummy data
TimeStamp$ = ""       'Declare empty timestamp.
'-----------------------------------------------------------------------------------------
OnHtmlReload ReLoadPage'Re-Load page for new connections.
'-----------------------------------------------------------------------------------------
Gosub LoadPage         'Load initial page
Timer0 3000, NextData  'Do not set < 2000
wait
'-----------------------------------------------------------------------------------------
NextData:
  Gosub GetTimeStamp 'Each piece of data requires a timestamp in string format
  Gosub GetValue     'Generate some example data.
  Gosub UpdateChart  'Send data to page and update
 
  while ramfree < RAMspare  'When low on RAM start removing old data from the left.
  
    For Set = 0 to NumSets 'Remove data from the left
      DataSet$(Set) = right$(DataSet$(Set),(len(DataSet$(Set))-instr(DataSet$(Set),"}")-1))
    Next Set
    'An alternative (especially if datasets have different frame rates) would be to set
    'a maximun string length (possibly for each set individualy) and then trim accordingly.
  wend
 
Return
'-----------------------------------------------------------------------------------------
GetTimeStamp: '-1 hour (60*60*1000) for GB time.
  TimeStamp = (dateUNIX(date$)+timeunix(time$))*1000-(60*60*1000)
  Timestamp$ = str$(TimeStamp,"%0.0f")
Return
'-----------------------------------------------------------------------------------------
UpdateChart:
  For Set = 0 to NumSets 'Add the new data to the existing string for each dataset.
    DataSet$(Set) = DataSet$(Set) + "{x:"+TimeStamp$+",y:"+str$(Value(Set))+"},"
    jscall "mychart.data.datasets[" + str$(Set )+ "].data = [" + DataSet$(Set) + "];" 
    Pause 100 'wait for data to load
  Next Set  
  jscall "mychart.update();" 'now update the chart.
Return
'-----------------------------------------------------------------------------------------
GetValue: 'Create some dummy data for each dataset.
  angle = angle+2*pi/47
  if angle > 2*pi then 'limit angle to between 0 & 2.pi radians.
    angle = angle-(2*pi) 
  endif
  For N = 0 to NumSets
    Value(N) = sin(angle+(N*(2*pi/12))) 'each set is 30 degrees ahead of the previous one
  Next N
Return
'-----------------------------------------------------------------------------------------
LoadPage:
cls
jsexternal "https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"
pause 500 'wait a little bit for the library to load
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"
'Required for 'time' scale plots.
pause 100 'wait a little bit for the library to load
cls
A$=""
A$ = |<h> Time Graph </h>|
A$ = A$ + |<div>|
A$ = A$ + |  <canvas id="myChart"></canvas>|
A$ = A$ + |<style> body {background-color: #cce;}</style>|
A$ = A$ + |</div>|
html a$
'Generate the chart
A$ = ||
A$ = A$ + |ctx = document.getElementById('myChart');|
A$ = A$ + ||
A$ = A$ + |   mychart = new Chart(ctx, {|
A$ = A$ + |    type: 'line',|
A$ = A$ + |    data: {|
'Add the first dataset
A$ = A$ + |      datasets: [{|
A$ = A$ + |        label: 'Data0',|
A$ = A$ + |        data: [],|
'Add subsequent datasets (if any)
For Set = 1 to NumSets
  Title$ = "Data" + Str$(Set)
  A$ = A$ + |    },{|
  A$ = A$ + |      label: '|+Title$+|',|
  A$ = A$ + |      data: [],|
Next Set
'Close off the datasets, set scales and add any options.
A$ = A$ + |      },]|
A$ = A$ + |    },|
A$ = A$ + |    options: {|
A$ = A$ + |      scales: {|
A$ = A$ + |        x: {|
A$ = A$ + |          type: 'time',|
A$ = A$ + |          time: {unit: 'minute'},|
A$ = A$ + |        }|
A$ = A$ + |      }|
A$ = A$ + |    }|
A$ = A$ + |  });|
jscript A$
A$ = ""
Pause 100
Return
'-----------------------------------------------------------------------------------------
ReLoadPage:
  Gosub LoadPage
  If TimeStamp$ <> "" then 'Don't update an empty graph.
    Gosub UpdateChart
  endif   
Return
'-----------------------------------------------------------------------------------------
End   
Test runs have shown that an ESP8266 can log and maintain 3 data sets sampling at once a minute for over an hour.
An ESP32 can maintain 10 data sets samples every 3 seconds for about 8 minutes.
If anyone ever tries it on one of the large S3 devices, I'd be curious to know how much it can handle.
User avatar
cicciocb
Site Admin
Posts: 2056
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 439 times
Been thanked: 1354 times
Contact:

Re: Chart.js persitant time graph example

Post by cicciocb »

Thanks for your demo example, an interesting application.
One remark : you can simply obtain the GB time putting this string in the config page
GMT0BST,M3.5.0/1,M10.5.0
image.png
About the size of the memory, using an ESP32 with PSRAM you'll have 4MB of additional RAM available :D
WIth the ESP32-S3 there are 8MB!

In any case, as you add more and more elements, your program is transferring a lot of data at each cycle so the limit is probably the memory used for the transfer of the block with JSCALL.

You could probably transfer on the more recent point and let the javascript (so the memory of the browser) add the point.

This is a slightly modified example

Code: [Local Link Removed for Guests]

'****************************************************************************************
'*                                                                                      *
'*  Example of Chart.js persistant time graph with variable data sets                   *
'*  V1.0.0  16/06/2023 © BeanieBots.                                                    *
'*  Thanks to cicciocb for the help with html & jarva bits.                             *
'*  For more information on the use of Chart.js, please see https://www.chartjs.org/    *
'*  Tested on ESP8266 FW 1.44.2  &  ESP32 FW BLE CAN 1.48.22                            *
'*                                                                                      *
'****************************************************************************************

RAMspare = 60000      'The amount of RAM left spare after creating the datasets.
                      'Determines how long data will be stored before deleting.
                      'The ESP8266 can be as low 32000 but the ESP32 requires at
                      'least 60000 to be reliable.
                  
NumSets = 9           'The number of EXTRA datasets to be plotted.
Dim Value(NumSets)    'Create an array to hold the new values.
Dim DataSet$(NumSets) 'Create a string array to hold each dataset.
Angle = 0             'Starting value for  dummy data
TimeStamp$ = ""       'Declare empty timestamp.
'-----------------------------------------------------------------------------------------
OnHtmlReload ReLoadPage'Re-Load page for new connections.
'-----------------------------------------------------------------------------------------
Gosub LoadPage         'Load initial page
Timer0 1000, NextData  'Do not set < 2000
wait
'-----------------------------------------------------------------------------------------
NextData:
  Gosub GetTimeStamp 'Each piece of data requires a timestamp in string format
  Gosub GetValue     'Generate some example data.
  Gosub UpdateChart  'Send data to page and update
 
  while ramfree < RAMspare  'When low on RAM start removing old data from the left.
  
    For Set = 0 to NumSets 'Remove data from the left
      DataSet$(Set) = right$(DataSet$(Set),(len(DataSet$(Set))-instr(DataSet$(Set),"}")-1))
    Next Set
    'An alternative (especially if datasets have different frame rates) would be to set
    'a maximun string length (possibly for each set individualy) and then trim accordingly.
  wend
 
Return
'-----------------------------------------------------------------------------------------
GetTimeStamp: '-1 hour (60*60*1000) for GB time.
  Timestamp = (dateUNIX(date$)+timeunix(time$))*1000-(60*60*1000) 
  Timestamp$ = str$(TimeStamp,"%0.0f")
  wlog Timestamp$
Return
'-----------------------------------------------------------------------------------------
UpdateChart:
  For Set = 0 to NumSets 'Add the new data to the existing string for each dataset.
    DataSet$(Set) = ""
    DataSet$(Set) = DataSet$(Set) + "{x:"+TimeStamp$+",y:"+str$(Value(Set))+"},"
    'jscall "mychart.data.datasets[" + str$(Set )+ "].data = [" + DataSet$(Set) + "];" 
    jscall "mychart.data.datasets[" + str$(Set )+ "].data.push(" + DataSet$(Set) + ");" 'send only last value
    'Pause 100 'wait for data to load
  Next Set  
  jscall "mychart.update();" 'now update the chart.
Return
'-----------------------------------------------------------------------------------------
GetValue: 'Create some dummy data for each dataset.
  angle = angle+2*pi/47
  if angle > 2*pi then 'limit angle to between 0 & 2.pi radians.
    angle = angle-(2*pi) 
  endif
  For N = 0 to NumSets
    Value(N) = sin(angle+(N*(2*pi/12))) 'each set is 30 degrees ahead of the previous one
  Next N
Return
'-----------------------------------------------------------------------------------------
LoadPage:
cls
jsexternal "https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"
pause 500 'wait a little bit for the library to load
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"
'Required for 'time' scale plots.
pause 100 'wait a little bit for the library to load
cls
A$=""
A$ = |<h> Time Graph </h>|
A$ = A$ + |<div>|
A$ = A$ + |  <canvas id="myChart"></canvas>|
A$ = A$ + |<style> body {background-color: #fff;}</style>|
A$ = A$ + |</div>|
html a$
'Generate the chart
A$ = ||
A$ = A$ + |ctx = document.getElementById('myChart');|
A$ = A$ + ||
A$ = A$ + |   mychart = new Chart(ctx, {|
A$ = A$ + |    type: 'line',|
A$ = A$ + |    data: {|
'Add the first dataset
A$ = A$ + |      datasets: [{|
A$ = A$ + |        label: 'Data0',|
A$ = A$ + |        data: [],|
'Add subsequent datasets (if any)
For Set = 1 to NumSets
  Title$ = "Data" + Str$(Set)
  A$ = A$ + |    },{|
  A$ = A$ + |      label: '|+Title$+|',|
  A$ = A$ + |      data: [],|
Next Set
'Close off the datasets, set scales and add any options.
A$ = A$ + |      },]|
A$ = A$ + |    },|
A$ = A$ + |    options: {|
A$ = A$ + |      scales: {|
A$ = A$ + |        x: {|
A$ = A$ + |          type: 'time',|
A$ = A$ + |          time: {unit: 'minute'},|
A$ = A$ + |        }|
A$ = A$ + |      }|
A$ = A$ + |    }|
A$ = A$ + |  });|
jscript A$
A$ = ""
Pause 100
Return
'-----------------------------------------------------------------------------------------
ReLoadPage:
  Gosub LoadPage
  If TimeStamp$ <> "" then 'Don't update an empty graph.
    Gosub UpdateChart
  endif   
Return
'-----------------------------------------------------------------------------------------
End   

You do not have the required permissions to view the files attached to this post.
User avatar
cicciocb
Site Admin
Posts: 2056
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 439 times
Been thanked: 1354 times
Contact:

Re: Chart.js persitant time graph example

Post by cicciocb »

This is also another example using another extension for the scrolling charts

This is the kind of graphs that can be generated (scrolling from the right to the left like an oscilloscope)
image.png

Code: [Local Link Removed for Guests]

'****************************************************************************************
'*                                                                                      *
'*  Example of Chart.js persistant time graph with variable data sets                   *
'*  V1.0.0  16/06/2023 © BeanieBots.                                                    *
'*  Thanks to cicciocb for the help with html & jarva bits.                             *
'*  For more information on the use of Chart.js, please see https://www.chartjs.org/    *
'*  Tested on ESP8266 FW 1.44.2  &  ESP32 FW BLE CAN 1.48.22                            *
'*                                                                                      *
'****************************************************************************************

RAMspare = 60000      'The amount of RAM left spare after creating the datasets.
                      'Determines how long data will be stored before deleting.
                      'The ESP8266 can be as low 32000 but the ESP32 requires at
                      'least 60000 to be reliable.
                  
NumSets = 4           'The number of EXTRA datasets to be plotted.
Dim Value(NumSets)    'Create an array to hold the new values.
Dim DataSet$(NumSets) 'Create a string array to hold each dataset.
Angle = 0             'Starting value for  dummy data
TimeStamp$ = ""       'Declare empty timestamp.
'-----------------------------------------------------------------------------------------
OnHtmlReload ReLoadPage'Re-Load page for new connections.
'-----------------------------------------------------------------------------------------
Gosub LoadPage         'Load initial page
Timer0 200, NextData  'Do not set < 2000
wait
'-----------------------------------------------------------------------------------------
NextData:
  Gosub GetTimeStamp 'Each piece of data requires a timestamp in string format
  Gosub GetValue     'Generate some example data.
  Gosub UpdateChart  'Send data to page and update
 
  while ramfree < RAMspare  'When low on RAM start removing old data from the left.
  
    For Set = 0 to NumSets 'Remove data from the left
      DataSet$(Set) = right$(DataSet$(Set),(len(DataSet$(Set))-instr(DataSet$(Set),"}")-1))
    Next Set
    'An alternative (especially if datasets have different frame rates) would be to set
    'a maximun string length (possibly for each set individualy) and then trim accordingly.
  wend
 
Return
'-----------------------------------------------------------------------------------------
GetTimeStamp: '-1 hour (60*60*1000) for GB time.
  Timestamp = (dateUNIX(date$)+timeunix(time$))*1000
  Timestamp$ = str$(TimeStamp,"%0.0f")
  'wlog time$
Return
'-----------------------------------------------------------------------------------------
UpdateChart:
  For Set = 0 to NumSets 'Add the new data to the existing string for each dataset.
    'the next line is using the local time
    'jscall "mychart.data.datasets[" + str$(Set )+ "].data.push(" + "{x:"+TimeStamp$+",y:"+str$(Value(Set))+"});"
    'the next line is using the time in the browser
    jscall "mychart.data.datasets[" + str$(Set )+ "].data.push(" + "{x:"+"Date.now()"+",y:"+str$(Value(Set))+"});"
    'Pause 100 'wait for data to load
  Next Set  
  'not required as the chart is autoupdated
'  jscall "mychart.update();" 'now update the chart.
Return
'-----------------------------------------------------------------------------------------
GetValue: 'Create some dummy data for each dataset.
  angle = angle+2*pi/47
  if angle > 2*pi then 'limit angle to between 0 & 2.pi radians.
    angle = angle-(2*pi) 
  endif
  For N = 0 to NumSets
    Value(N) = sin(angle+(N*(2*pi/12))) 'each set is 30 degrees ahead of the previous one
  Next N
Return
'-----------------------------------------------------------------------------------------
LoadPage:
cls
jsexternal "https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"
pause 500 'wait a little bit for the library to load
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"
'Required for 'time' scale plots.
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0"
'required for the scrolling chart

cls
A$=""
A$ = |<h> Time Graph </h>|
A$ = A$ + |<div>|
A$ = A$ + |  <canvas id="myChart"></canvas>|
A$ = A$ + |<style> body {background-color: #fff;}</style>|
A$ = A$ + |</div>|
html a$
'Generate the chart
A$ = ||
A$ = A$ + |ctx = document.getElementById('myChart');|
A$ = A$ + ||
A$ = A$ + |   mychart = new Chart(ctx, {|
A$ = A$ + |    type: 'line',|
A$ = A$ + |    data: {|
'Add the first dataset
A$ = A$ + |      datasets: [{|
A$ = A$ + |        label: 'Data0',|
A$ = A$ + |        data: [],|
A$ = A$ + |        fill: false,|
'Add subsequent datasets (if any)
For Set = 1 to NumSets
  Title$ = "Data" + Str$(Set)
  A$ = A$ + |    },{|
  A$ = A$ + |      label: '|+Title$+|',|
  A$ = A$ + |      data: [],|
Next Set
'Close off the datasets, set scales and add any options.
A$ = A$ + |      },]|
A$ = A$ + |    },|
A$ = A$ + |    options: {|
A$ = A$ + |      animation: {|
A$ = A$ + |        duration: 0 |
A$ = A$ + |      },|
A$ = A$ + |      scales: {|
A$ = A$ + |        x: {|
A$ = A$ + |          type: 'realtime',|
A$ = A$ + |          realtime: {|
'Parameters for the real time plot
A$ = A$ + |            duration: 20000,|
A$ = A$ + |            refresh: 100,|
A$ = A$ + |            delay: 1000,|
A$ = A$ + |            pause: false,|
A$ = A$ + |            ttl: undefined|
A$ = A$ + |          }|


'A$ = A$ + |          time: {unit: 'minute'},|
A$ = A$ + |        },|

A$ = A$ + |        y: {|
A$ = A$ + |        beginAtZero: true|
A$ = A$ + |        }|


A$ = A$ + |      }|
A$ = A$ + |    }|
A$ = A$ + |  });|
jscript A$
A$ = ""
Pause 100
Return
'-----------------------------------------------------------------------------------------
ReLoadPage:
  Gosub LoadPage
  If TimeStamp$ <> "" then 'Don't update an empty graph.
    Gosub UpdateChart
  endif   
Return
'-----------------------------------------------------------------------------------------
End   

You do not have the required permissions to view the files attached to this post.
BeanieBots
Posts: 345
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 183 times
Been thanked: 112 times

Re: Chart.js persitant time graph example

Post by BeanieBots »

Thanks for those alternative examples however, they both somewhat defeat my main objective which is to have persistant data. (Hence the topic title.)
My main criteria is to have a web page which can be periodically viewed to examine any trends in data yet carry on updating if left on view.
This would be applicable to fairly slow changing data such as room/outside temperatures where samples are taken every minute or so but also keep the history of the last few hour/days when the page is closed and then re-opened.
For much faster 'change-as-you-view' types of data, your examples would be a much better choice. Though I would probably use a different chart such as one which you have also done a demo of here. Namely smoothiecharts.

At the moment, I am considering a hybrid method of periodically saving to flash (kept to a minimum to save on wear) with the remainder maintained in RAM. This would be a good way of doing something like comparing on the same chart today with yesterday whilst also showing the latest data.
I'd be interested in your thoughts on how to make my example more RAM efficient. Maybe there is a way of reducing the very inefficient way of sending the data (particularly the time stamps) as numbers instead of text and have jarva do the conversion. (another language I have very little knowledge of :oops: ) Comments appreciated.
efalken
Posts: 38
Joined: Tue Mar 02, 2021 3:47 pm
Has thanked: 17 times
Been thanked: 27 times

Re: Chart.js persitant time graph example

Post by efalken »

Hello, I trink one should not overload such a small device. My way ist to send MQTT data to a Server running a management Software like OpenHab, a database, inluxDB for example, and presenting with grafana. This way you keep years of data of multiple devices, no matter what my tiny ESP is facing..
User avatar
cicciocb
Site Admin
Posts: 2056
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 439 times
Been thanked: 1354 times
Contact:

Re: Chart.js persitant time graph example

Post by cicciocb »

As I said before you should use devices with more RAM, such as any ESP32 with PSRAM.
You could, eventually, store the data into a numerical array and send only the values, doing the conversion in the javascript side as you suggest.
However , your approach is limited by the quantity data to be transferred transfer at each cycle, probably you should send the data splitted in "batches" to limit the quantity of memory used each time.
What is interesting is to understand how many items you would like to hold in memory; this will not be a real issue for modules with 4 or 8MB of PSRAM.

Anyway, I think that this is not the right approach as all the data are resident in the chip and lost in case of power off.

I suggest to use a free service like ThingSpeak for example and store the data online.
An example is available here https://thingspeak.com/channels/357142

The advantage of this approach is that you can have WEB access to your data without compromising your local network as your module simply send data to the remote server.

For a more advanced approach, if you are a lucky owner of a web hosting service, you could store the data on your space (in this case you should use php in addition to javascript) and develop your own pages
BeanieBots
Posts: 345
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 183 times
Been thanked: 112 times

Re: Chart.js persitant time graph example

Post by BeanieBots »

Thanks to both for the tips.
I'm simply trying to get as much out of the device as possible. (unused RAM is wasted RAM).
I do have a web hosting device. My ESP ;)
Seriously though, the obvious solution is to post to a service and use their dashboard but that means putting up with their dashboard limitations or paying premium rates to customise it.
I do have a NAS which alegedly can host a web service. I will need to investigate that further.
RonS
Posts: 115
Joined: Thu Mar 02, 2023 10:15 pm
Location: germany
Has thanked: 64 times
Been thanked: 23 times

Re: Chart.js persitant time graph example

Post by RonS »

Thanks for sharing your thoughts -
I've modified the code a bit for monitoring an incubator - the result is not yet ideal it lacks the current output in numbers
( can be seen via WLOG however ) as well as a warning message in case of deviation of the temperature as well as a daily count
( an egg need 21 days with different temperatures )
- I'm posting this here as an example of useful applications :) -An hdc1080 was used as a sensor for temperature and humidity

Code: [Local Link Removed for Guests]

'****************************************************************************************
'*                                                                                      *
'*  Example of Chart.js persistant time graph with variable data sets                   *
'*  V1.0.0  16/06/2023 © BeanieBots.                                                    *
'*  Thanks to cicciocb for the help with html & jarva bits.                             *
'*  For more information on the use of Chart.js, please see https://www.chartjs.org/    *
'*  Tested on ESP8266 FW 1.44.2  &  ESP32 FW BLE CAN 1.48.22                            *
'*  mofified by Ron S as INKUBATOR- Monitor 07/23                                                                                    *
'****************************************************************************************

RAMspare = 60000      'The amount of RAM left spare after creating the datasets.
                      'Determines how long data will be stored before deleting.
                      'The ESP8266 can be as low 32000 but the ESP32 requires at
                      'least 60000 to be reliable.
i2c.setup 21, 22

if hdc1080.Setup(&h40) = 1 then wlog "HDC1080 not found" : end
                  
NumSets = 1           'The number of EXTRA datasets to be plotted.
Dim Value(NumSets)    'Create an array to hold the new values.
Dim DataSet$(NumSets) 'Create a string array to hold each dataset.
Angle = 0             'Starting value for  dummy data
TimeStamp$ = ""       'Declare empty timestamp.
'-----------------------------------------------------------------------------------------
OnHtmlReload ReLoadPage'Re-Load page for new connections.
'-----------------------------------------------------------------------------------------
Gosub LoadPage         'Load initial page
Timer0 1000, NextData  'Do not set < 2000
wait
'-----------------------------------------------------------------------------------------
NextData:

  Gosub GetTimeStamp 'Each piece of data requires a timestamp in string format
  Gosub GetValue     'Generate some example data.
  Gosub UpdateChart  'Send data to page and update
 
  while ramfree < RAMspare  'When low on RAM start removing old data from the left.
  
    For Set = 0 to NumSets 'Remove data from the left
      DataSet$(Set) = right$(DataSet$(Set),(len(DataSet$(Set))-instr(DataSet$(Set),"}")-1))
    Next Set
    'An alternative (especially if datasets have different frame rates) would be to set
    'a maximun string length (possibly for each set individualy) and then trim accordingly.
  wend
 
Return
'-----------------------------------------------------------------------------------------
GetTimeStamp: '-1 hour (60*60*1000) for GB time.
  Timestamp = (dateUNIX(date$)+timeunix(time$))*1000
  Timestamp$ = str$(TimeStamp,"%0.0f")
  wlog time$,
Return
'-----------------------------------------------------------------------------------------
UpdateChart:
  For Set = 0 to NumSets 'Add the new data to the existing string for each dataset.
    'the next line is using the local time
    'jscall "mychart.data.datasets[" + str$(Set )+ "].data.push(" + "{x:"+TimeStamp$+",y:"+str$(Value(Set))+"});"
    'the next line is using the time in the browser
    jscall "mychart.data.datasets[" + str$(Set )+ "].data.push(" + "{x:"+"Date.now()"+",y:"+str$(Value(Set))+"});"
    'Pause 100 'wait for data to load
  Next Set  

  'not required as the chart is autoupdated
'  jscall "mychart.update();" 'now update the chart.
Return
'-----------------------------------------------------------------------------------------
GetValue: 'Create some dummy data for each dataset.
  
    Value(0) = hdc1080.temp 'each set is 30 degrees ahead of the previous one
    Value(1) = hdc1080.hum
    wlog "Temperature "; hdc1080.temp, "Humidity "; hdc1080.hum
hum$=str$(hdc1080.hum)

  pause 1000
Return
'-----------------------------------------------------------------------------------------
LoadPage:
cls
jsexternal "https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"
pause 500 'wait a little bit for the library to load
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"
'Required for 'time' scale plots.
jsexternal "https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0"
'required for the scrolling chart

cls
A$=""
A$ = A$ +  |<h> INKUBATOR-MONITOR </h>|

A$ = A$ + |<div>|
A$ = A$ + |  <canvas id="myChart" ></canvas>|
A$ = A$ + |<style> body {background-color: #fff;}</style>|
A$ = A$ + |</div>|
html a$

'Generate the chart
A$ = ||
A$ = A$ + |ctx = document.getElementById('myChart');|
A$ = A$ + ||
A$ = A$ + |   mychart = new Chart(ctx, {|
A$ = A$ + |    type: 'line',|
A$ = A$ + |    data: {|
'Add the first dataset
A$ = A$ + |      datasets: [{|
A$ = A$ + |        label: 'BrutTemperatur',|

A$ = A$ + |        data: [],|
A$ = A$ + |        fill: false,|
'Add subsequent datasets (if any)
Title$ = "LuftFeuchtigkeit"
  A$ = A$ + |    },{|
  A$ = A$ + |      label: '|+Title$+|',|
  A$ = A$ + |      data: [],|
  

'Close off the datasets, set scales and add any options.
A$ = A$ + |      },]|
A$ = A$ + |    },|
A$ = A$ + |    options: {|
A$ = A$ + |      animation: {|
A$ = A$ + |        duration: 0 |
A$ = A$ + |      },|
A$ = A$ + |      scales: {|
A$ = A$ + |       x: {|
A$ = A$ + |          type: 'realtime',|
A$ = A$ + |          realtime: {|
'Parameters for the real time plot
A$ = A$ + |            duration: 20000,|
A$ = A$ + |            refresh: 100,|
A$ = A$ + |            delay: 1000,|
A$ = A$ + |            pause: false,|
A$ = A$ + |            ttl: undefined|
A$ = A$ + |          }|


rem A$ = A$ + |          time: {unit: 'minute'},|
A$ = A$ + |        },|

A$ = A$ + |        y: {|
A$ = A$ + |        beginAtZero: true|
A$ = A$ + |        }|


A$ = A$ + |      }|
A$ = A$ + |    }|
A$ = A$ + |  });|
jscript A$
A$ = ""
Pause 100
Return
'-----------------------------------------------------------------------------------------
ReLoadPage:
  Gosub LoadPage
  If TimeStamp$ <> "" then 'Don't update an empty graph.
    Gosub UpdateChart
  endif   
Return
'-----------------------------------------------------------------------------------------
End   
DSCI0466.JPG
Opera Momentaufnahme_2023-07-31_090538_192.168.2.110.png
You do not have the required permissions to view the files attached to this post.
Modules : 3xESP32-Cam MB (Chip"DM ESP32 S" ),AI-Thinker Audio Kit (ES8388), ESP32 Dev Kit with Display
User avatar
cicciocb
Site Admin
Posts: 2056
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 439 times
Been thanked: 1354 times
Contact:

Re: Chart.js persitant time graph example

Post by cicciocb »

[Local Link Removed for Guests] wrote: [Local Link Removed for Guests]Mon Jul 31, 2023 7:36 am Thanks for sharing your thoughts -
I've modified the code a bit for monitoring an incubator - the result is not yet ideal it lacks the current output in numbers
( can be seen via WLOG however ) as well as a warning message in case of deviation of the temperature as well as a daily count
( an egg need 21 days with different temperatures )
- I'm posting this here as an example of useful applications :) -An hdc1080 was used as a sensor for temperature and humidity
Nice :D
BeanieBots
Posts: 345
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 183 times
Been thanked: 112 times

Re: Chart.js persitant time graph example

Post by BeanieBots »

Glad you found it of use. Not all data needs to be posted to a hosting site to be available for ever, but many like yours need periodic checking just to keep an eye on what's going on.
Post Reply