{"id":71709,"date":"2023-03-06T09:00:32","date_gmt":"2023-03-06T09:00:32","guid":{"rendered":"https:\/\/www.cryptocabaret.com\/?p=71709"},"modified":"2023-03-06T09:00:32","modified_gmt":"2023-03-06T09:00:32","slug":"build-a-raspberry-pi-monitoring-dashboard-in-under-30-minutes","status":"publish","type":"post","link":"https:\/\/www.cryptocabaret.com\/?p=71709","title":{"rendered":"Build a Raspberry Pi monitoring dashboard in under 30 minutes"},"content":{"rendered":"<p><span class=\"field field--name-title field--type-string field--label-hidden\">Build a Raspberry Pi monitoring dashboard in under 30 minutes<\/span><br \/>\n<span class=\"field field--name-uid field--type-entity-reference field--label-hidden\"><a title=\"View user profile.\" href=\"https:\/\/opensource.com\/users\/keyur-paralkar\" class=\"username\">Keyur Paralkar<\/a><\/span><br \/>\n<span class=\"field field--name-created field--type-created field--label-hidden\">Mon, 03\/06\/2023 &#8211; 03:00<\/span><\/p>\n<div class=\"clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item\">\n<p>If you\u2019ve ever wondered about the performance of your Raspberry Pi, then you might need a dashboard for your Pi. In this article, I demonstrate how to quickly building an on-demand monitoring dashboard for your Raspberry Pi so you can see your CPU performance, memory and disk usage in real time, and add more views and actions later as you need them.<\/p>\n<p>If you\u2019re already using Appsmith, you can also import the <a href=\"https:\/\/github.com\/appsmithorg\/foundry\/tree\/main\/resources\/blogs\/Raspberry%20Pi%20Dashboard\">sample app<\/a> directly and get started.<\/p>\n<h2>Appsmith<\/h2>\n<p>Appsmith is an open source, <a href=\"https:\/\/www.redhat.com\/architect\/low-code-platform?intcmp=7013a000002qLH8AAM\" target=\"_blank\" rel=\"noopener\">low-code<\/a> app builder that helps developers build internal apps like dashboards and admin panels easily and quickly. It\u2019s a great choice for your dashboard, and reduces the time and complexity of traditional coding approaches.<\/p>\n<p>For the dashboard in this example, I display usage stats for:<\/p>\n<ul>\n<li>CPU\n<ul>\n<li>Percentage utilization<\/li>\n<li>Frequency or clock speed<\/li>\n<li>Count<\/li>\n<li>Temperature<\/li>\n<\/ul>\n<\/li>\n<li>Memory\n<ul>\n<li>Percentage utilization<\/li>\n<li>Percentage available memory<\/li>\n<li>Total memory<\/li>\n<li>Free memory<\/li>\n<\/ul>\n<\/li>\n<li>Disk\n<ul>\n<li>Percentage disk utilization<\/li>\n<li>Absolute disk space used<\/li>\n<li>Available disk space<\/li>\n<li>Total disk space<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Creating an endpoint<\/h2>\n<p>You need a way to get this data from your Raspberry Pi (RPi) and into Appsmith. The <a href=\"https:\/\/psutil.readthedocs.io\/en\/latest\/\">psutils<\/a> Python library is useful for monitoring and profiling, and the <a href=\"https:\/\/flask-restful.readthedocs.io\/en\/latest\/\">Flask-RESTful<\/a> Flask extension creates a <a href=\"https:\/\/www.redhat.com\/en\/topics\/api\/what-is-a-rest-api?intcmp=7013a000002qLH8AAM\" target=\"_blank\" rel=\"noopener\">REST API<\/a>.<\/p>\n<p>Appsmith calls the REST API every few seconds to refresh data automatically, and gets a JSON object in response with all desired stats as shown:<\/p>\n<pre>\n<code>{ \"cpu_count\": 4,\n\"cpu_freq\": [\n600.0,\n600.0,\n1200.0 ],\n\"cpu_mem_avail\": 463953920,\n\"cpu_mem_free\": 115789824,\n\"cpu_mem_total\": 971063296,\n\"cpu_mem_used\": 436252672,\n\"cpu_percent\": 1.8,\n\"disk_usage_free\": 24678121472,\n\"disk_usage_percent\": 17.7,\n\"disk_usage_total\": 31307206656,\n\"disk_usage_used\": 5292728320,\n\"sensor_temperatures\": 52.616 }<\/code><\/pre>\n<h2>1. Set up the REST API<\/h2>\n<p>If your Raspberry Pi doesn\u2019t have Python on it yet, open a terminal on your Pi and run this install command:<\/p>\n<pre>\n<code>$ sudo apt install python3<\/code><\/pre>\n<p>Now set up a <a href=\"https:\/\/opensource.com\/article\/20\/10\/venv-python\">Python virtual environment<\/a> for your development:<\/p>\n<pre>\n<code>$ python -m venv PiData<\/code><\/pre>\n<p>Next, activate the environment. You must do this after rebooting your Pi.<\/p>\n<pre>\n<code>$ source PiData\/bin\/activate\n$ cd PiData<\/code><\/pre>\n<p>To install Flask and Flask-RESTful and dependencies you\u2019ll need later, create a file in your Python virtual environment called <code>requirements.txt<\/code> and add these lines to it:<\/p>\n<pre>\n<code>flask\nflask-restful\ngunicorn<\/code><\/pre>\n<p>Save the file, and then use <code>pip<\/code> to install them all at once. You must do this after rebooting your Pi.<\/p>\n<pre>\n<code>(PyData)$ python -m pip install -r requirements.txt<\/code><\/pre>\n<p>Next, create a file named <code>pi_stats.py<\/code> to house the logic for retrieving the RPi\u2019s system stats with <code>psutils<\/code>. Paste this code into your <code>pi_stat.py<\/code> file:<\/p>\n<pre>\n<code>from flask import Flask\nfrom flask_restful import Resource, Api\nimport psutil\napp = Flask(__name__)\n\napi = Api(app)\nclass PiData(Resource):\n    def get(self):\n        return \"RPI Stat dashboard\"\n\napi.add_resource(PiData, '\/get-stats')\n\nif __name__ == '__main__':\n    app.run(debug=True)<\/code><\/pre>\n<p>Here\u2019s what the code is doing:<\/p>\n<ul>\n<li>Use app = Flask(<strong>name<\/strong>) to define the app that nests the API object.<\/li>\n<li>Use Flask-RESTful\u2019s <a href=\"https:\/\/flask-restful.readthedocs.io\/en\/latest\/api.html#id1\">API method<\/a> to define the API object.<\/li>\n<li>Define PiData as a concrete <a href=\"https:\/\/flask-restful.readthedocs.io\/en\/latest\/api.html#flask_restful.Resource\">Resource class<\/a> in Flask-RESTful to expose methods for each supported HTTP method.<\/li>\n<li>Attach the resource, <code>PiData<\/code>, to the API object, <code>api<\/code>, with <code>api.add_resource(PiData, '\/get-stats')<\/code>.<\/li>\n<li>Whenever you hit the URL <code>\/get-stats<\/code>, <code>PiData<\/code> is returned as the response.<\/li>\n<\/ul>\n<h2>2. Read stats with psutils<\/h2>\n<p>To get the stats from your Pi, you can use these built-in functions from <code>psutils<\/code>:<\/p>\n<ul>\n<li><code>cpu_percentage<\/code>, <code>cpu_count<\/code>, <code>cpu_freq<\/code>, and <code>sensors_temperatures<\/code> functions for the percentage utilization, count, clock speed, and temperature respectively, of the CPU <code>sensors_temperatures<\/code> reports the temperature of all the devices connected to the RPi. To get just the CPU\u2019s temperature, use the key <code>cpu-thermal<\/code>.<\/li>\n<li><code>virtual_memory<\/code> for total, available, used, and free memory stats in bytes.<\/li>\n<li><code>disk_usage<\/code> to return the total, used, and free stats in bytes.<\/li>\n<\/ul>\n<p>Combining all of the functions in a Python dictionary looks like this:<\/p>\n<pre>\n<code>system_info_data = {\n'cpu_percent': psutil.cpu_percent(1),\n'cpu_count': psutil.cpu_count(),\n'cpu_freq': psutil.cpu_freq(),\n'cpu_mem_total': memory.total,\n'cpu_mem_avail': memory.available,\n'cpu_mem_used': memory.used,\n'cpu_mem_free': memory.free,\n'disk_usage_total': disk.total,\n'disk_usage_used': disk.used,\n'disk_usage_free': disk.free,\n'disk_usage_percent': disk.percent,\n'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'\n][0].current, }<\/code><\/pre>\n<p>The next section uses this dictionary.<\/p>\n<h2>3. Fetch data from the Flask-RESTful API<\/h2>\n<p>To see data from your Pi in the API response, update <code>pi_stats.py<\/code> to include the dictionary <code>system_info_data<\/code> in the class <code>PiData<\/code>:<\/p>\n<pre>\n<code>from flask import Flask\nfrom flask_restful import Resource, Api\nimport psutil\napp = Flask(__name__)\napi = Api(app)\n\nclass PiData(Resource):\n    def get(self):\n        memory = psutil.virtual_memory()\n        disk = psutil.disk_usage('\/')\n        system_info_data = {\n            'cpu_percent': psutil.cpu_percent(1),\n            'cpu_count': psutil.cpu_count(),\n            'cpu_freq': psutil.cpu_freq(),\n            'cpu_mem_total': memory.total,\n            'cpu_mem_avail': memory.available,\n            'cpu_mem_used': memory.used,\n            'cpu_mem_free': memory.free,\n            'disk_usage_total': disk.total,\n            'disk_usage_used': disk.used,\n            'disk_usage_free': disk.free,\n            'disk_usage_percent': disk.percent,\n            'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current, }\n\n    return system_info_data\n\napi.add_resource(PiData, '\/get-stats')\n\nif __name__ == '__main__':\n    app.run(debug=True)<\/code><\/pre>\n<p>Your script\u2019s ready. Run the <code>PiData.py<\/code> script:<\/p>\n<pre>\n<code>$ python PyData.py\n * Serving Flask app \"PiData\" (lazy loading)\n * Environment: production\n WARNING: This is a development server. Do not run this in a production environment.\n \n * Debug mode: on\n * Running on http:\/\/127.0.0.1:5000 (Press CTRL+C to quit)\n * Restarting with stat\n * Debugger is active!<\/code><\/pre>\n<p>You have a working API!<\/p>\n<h2>4. Make the API available to the internet<\/h2>\n<p>You can interact with your API on your local network. To reach it over the internet, however, you must open a port in your firewall and forward incoming traffic to the port made available by Flask. However, as the output of your test advised, running a Flask app from Flask is meant for development, not for production. To make your API available to the internet safely, you can use the <code>gunicorn<\/code> production server, which you installed during the project setup stage.<\/p>\n<p>Now you can start your Flask API. You must do this any time you\u2019ve rebooted your Pi.<\/p>\n<pre>\n<code>$ gunicorn -w 4 'PyData:app'\nServing on http:\/\/0.0.0.0:8000<\/code><\/pre>\n<p>To reach your Pi from the outside world, open a port in your network firewall and direct incoming traffic to the IP address of your PI, at port 8000.<\/p>\n<p>First, get the internal IP address of your Pi:<\/p>\n<pre>\n<code>$ ip addr show | grep inet<\/code><\/pre>\n<p>Internal IP addresses start with 10 or 192 or 172.<\/p>\n<p>Next, you must configure your firewall. There\u2019s usually a firewall embedded in the router you get from your internet service provider (ISP). Generally, you access your home router through a web browser. Your router\u2019s address is sometimes printed on the bottom of the router, and it begins with either 192.168 or 10. Every device is different, though, so there\u2019s no way for me to tell you exactly what you need to click on to adjust your settings. For a full description of how to configure your firewall, read Seth Kenlon\u2019s article <a href=\"https:\/\/opensource.com\/article\/20\/9\/firewall\">Open ports and route traffic through your firewall<\/a>.<\/p>\n<p>Alternately, you can use <a href=\"https:\/\/theboroer.github.io\/localtunnel-www\/\">localtunnel<\/a> to use a dynamic port-forwarding service.<\/p>\n<p>Once you\u2019ve got traffic going to your Pi, you can query your API:<\/p>\n<pre>\n<code>$ curl https:\/\/example.com\/get-stats\n{\n   \"cpu_count\": 4,\n   \"cpu_freq\": [\n      600.0,\n      600.0,\n      1200.0 ],\n   \"cpu_mem_avail\": 386273280,\n   ...<\/code><\/pre>\n<p>If you have gotten this far, the toughest part is over.<\/p>\n<h2>5. Repetition<\/h2>\n<p>If you reboot your Pi, you must follow these steps:<\/p>\n<ol type=\"1\">\n<li>Reactivate your Python environment with <code>source<\/code><\/li>\n<li>Refresh the application dependencies with <code>pip<\/code><\/li>\n<li>Start the Flask application with <code>gunicorn<\/code><\/li>\n<\/ol>\n<p>Your firewall settings are persistent, but if you\u2019re using localtunnel, then you must also start a new tunnel after a reboot.<\/p>\n<p>You can automate these tasks if you like, but that\u2019s a whole other tutorial. The final section of this tutorial is to build a UI on Appsmith using the drag-and-drop widgets, and a bit of Javascript, to bind your RPi data to the UI. Believe me, it\u2019s easy going from here on out!<\/p>\n<h2>Build the dashboard on Appsmith.<\/h2>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/03\/dashboard.png\" width=\"1920\" height=\"1080\" alt=\"A hardware monitoring dashboard\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>To get to a dashboard like this, you need to connect the exposed API endpoint to Appsmith, build the UI using Appsmith\u2019s widgets library, and bind the API\u2019s response to your widgets. If you\u2019re already using Appsmith, you can just import the <a href=\"https:\/\/github.com\/appsmithorg\/foundry\/tree\/main\/resources\/blogs\/Raspberry%20Pi%20Dashboard\">sample app<\/a> directly and get started.<\/p>\n<p>If you haven\u2019t done so already, <a href=\"https:\/\/appsmith.com\/sign-up\">sign up<\/a> for a free Appsmith account. Alternately, you can <a href=\"https:\/\/docs.appsmith.com\/getting-started\/setup\">self-host Appsmith<\/a>.<\/p>\n<h2>Connect the API as an Appsmith datasource<\/h2>\n<p>Sign in to your Appsmith account.<\/p>\n<ol type=\"1\">\n<li>Find and click the <strong>+<\/strong> button next to <strong>QUERIES\/JS<\/strong> in the left nav.<\/li>\n<li>Click <strong>Create a blank API.<\/strong><\/li>\n<li>At the top of the page, name your project <strong>PiData<\/strong>.<\/li>\n<li>Get your API\u2019s URL. If you\u2019re using localtunnel, then that\u2019s a <code>localtunnel.me<\/code> address, and as always append <code>\/get-stats<\/code> to the end for the stat data. Paste it into the first blank field on the page, and click the <strong>RUN<\/strong> button.<\/li>\n<\/ol>\n<p>Confirm that you see a successful response in the <strong>Response<\/strong> pane.<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/success.webp\" width=\"1920\" height=\"1080\" alt=\"The Appsmith interface\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<h2>Build the UI<\/h2>\n<p>The interface for AppSmith is pretty intuitive, but I recommend going through <a href=\"https:\/\/docs.appsmith.com\/getting-started\/start-building\">building your first application on Appsmith<\/a> tutorial if you feel lost.<\/p>\n<p>For the title, drag and drop a Text, Image, and Divider widget onto the canvas. Arrange them like this:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/TITLE.webp\" width=\"1400\" height=\"234\" alt=\"Set your project title\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>The Text widget contains the actual title of your page. Type in something cooler than \u201cRaspberry Pi Stats\u201d.<\/p>\n<p>The Image widget houses a distinct logo for the dashboard. You can use whatever you want.<\/p>\n<p>Use a Switch widget for a toggled live data mode. Configure it in the <strong>Property<\/strong> pane to get data from the API you\u2019ve built.<\/p>\n<p>For the body, create a place for CPU Stats with a Container widget using the following widgets from the Widgets library on the left side:<\/p>\n<ul>\n<li>Progress Bar<\/li>\n<li>Stat Box<\/li>\n<li>Chart<\/li>\n<\/ul>\n<p>Do the same for the Memory and Disk stats sections. You don\u2019t need a Chart for disk stats, but don\u2019t let that stop you from using one if you can find uses for it.<\/p>\n<p>Your final arrangement of widgets should look something like this:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/property.webp\" width=\"1920\" height=\"1080\" alt=\"Property settings in Appsmith\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>The final step is to bind the data from the API to the UI widgets you have.<\/p>\n<h2>Bind data to the widgets<\/h2>\n<p>Head back to the canvas and find your widgets in sections for the three categories. Set the CPU Stats first.<\/p>\n<p>To bind data to the Progress Bar widget:<\/p>\n<ol type=\"1\">\n<li>Click the Progress Bar widget to see the Property pane on the right.<\/li>\n<li>Look for the Progress property.<\/li>\n<li>Click the <strong>JS<\/strong> button to activate Javascript.<\/li>\n<li>Paste <code>{{PiData.data.cpu_percent ?? 0}}<\/code> in the field for <strong>Progress<\/strong>. That code references the stream of data from of your API named <code>PiData<\/code>. Appsmith caches the response data within the <code>.data<\/code> operator of <code>PiData<\/code>. The key <code>cpu_percent<\/code> contains the data Appsmith uses to display the percentage of, in this case, CPU utilization.<\/li>\n<li>Add a Text widget below the Progress Bar widget as a label.<\/li>\n<\/ol>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/config.webp\" width=\"1920\" height=\"1080\" alt=\"Binding data in the config screen\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>There are three Stat Box widgets in the CPU section. Binding data to each one is the exact same as for the Progress Bar widget, except that you bind a different data attribute from the <code>.data<\/code> operator. Follow the same procedure, with these exceptions:<\/p>\n<ul>\n<li><code>{{${PiData.data.cpu_freq[0]} ?? 0 }}<\/code> to show clock speed.<\/li>\n<li><code>{{${PiData.data.cpu_count} ?? 0 }}<\/code> for CPU count.<\/li>\n<li><code>{{${(PiData.data.sensor_temperatures).toPrecision(3)} ?? 0 }}<\/code> for CPU temperature data.<\/li>\n<\/ul>\n<p>Assuming all goes to plan, you end up with a pretty dashboard like this one:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/final.webp\" width=\"1920\" height=\"1080\" alt=\"A dashboard for your Raspberry Pi\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<h2>CPU utilization trend<\/h2>\n<p>You can use a Chart widget to display the CPU utilization as a trend line, and have it automatically update over time.<\/p>\n<p>First, click the widget, find the Chart Type property on the right, and change it to LINE CHART. To see a trend line, store <code>cpu_percent<\/code> in an array of data points. Your API currently returns this as a single data point in time, so use Appsmith\u2019s <code>storeValue<\/code> function (an Appsmith-native implementation of a browser\u2019s <code>setItem<\/code> method) to get an array.<\/p>\n<p>Click the <strong>+<\/strong> button next to <strong>QUERIES\/JS<\/strong> and name it <strong>utils<\/strong>.<\/p>\n<p>Paste this Javascript code into the <strong>Code<\/strong> field:<\/p>\n<pre>\n<code>export default {\n  getLiveData: () =&gt; {\n  \/\/When switch is on:\n    if (Switch1.isSwitchedOn) {\n      setInterval(() =&gt; {\n        let utilData = appsmith.store.cpu_util_data;\n\n        PiData.run()\n          storeValue(\"cpu_util_data\", [...utilData, {\n            x: PiData.data.cpu_percent,\n            y: PiData.data.cpu_percent\n          }]);           \n        }, 1500, 'timerId')\n      } else {\n    clearInterval('timerId');\n  }\n},\ninitialOnPageLoad: () =&gt; {\n  storeValue(\"cpu_util_data\", []);\n  }\n}<\/code><\/pre>\n<p>To initialize the <code>Store<\/code>, you\u2019ve created a JavaScript function in the object called <code>initialOnPageLoad<\/code>, and you\u2019ve housed the <code>storeValue<\/code> function in it.<\/p>\n<p>You store the values from <code>cpu_util_data<\/code> into the <code>storeValue<\/code> function using <code>storeValue(\"cpu_util_data\", []);<\/code>. This function runs on page load.<\/p>\n<p>So far, the code stores one data point from <code>cpu_util_data<\/code> in the <code>Store<\/code> each time the page is refreshed. To store an array, you use the <code>x<\/code> and <code>y<\/code> subscripted variables, both storing values from the <code>cpu_percent<\/code> data attribute.<\/p>\n<p>You also want this data stored automatically by a set interval between stored values. When the function <a href=\"https:\/\/docs.appsmith.com\/reference\/appsmith-framework\/widget-actions\/intervals-time-events#setinterval\">setInterval<\/a> is executed:<\/p>\n<ol type=\"1\">\n<li>The value stored in <code>cpu_util_data<\/code> is fetched.<\/li>\n<li>The API <code>PiData<\/code> is called.<\/li>\n<li><code>cpu_util_data<\/code> is updated as <code>x<\/code> and <code>y<\/code> variables with the latest <code>cpu_percent<\/code> data returned.<\/li>\n<li>The value of <code>cpu_util_data<\/code> is stored in the key <code>utilData<\/code>.<\/li>\n<li>Steps 1 through 4 are repeated if and only if the function is set to auto-execute. You set it to auto-execute with the Switch widget, which explains why there is a <code>getLiveData<\/code> parent function.<\/li>\n<\/ol>\n<p>Navigate to the <strong>Settings<\/strong> tab to find all the parent functions in the object and set <code>initialOnPageLoad<\/code> to <strong>Yes<\/strong> in the <strong>RUN ON PAGE LOAD<\/strong> option.<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-02\/load-on-page.webp\" width=\"1920\" height=\"1080\" alt=\"Set the function to execute on page load\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>Now refresh the page for confirmation<\/p>\n<p>Return to the canvas. Click the Chart widget and locate the Chart Data property. Paste the binding <code>{{ appsmith.store.disk_util_data }}<\/code> into it. This gets your chart if you run the object <code>utils<\/code> yourself a few times. To run this automatically:<\/p>\n<ol type=\"1\">\n<li>Find and click the <strong>Live Data Switch<\/strong> widget in your dashboard\u2019s title.<\/li>\n<li>Look for the <code>onChange<\/code> event.<\/li>\n<li>Bind it to <code>{{ utils.getLiveData() }}<\/code>. The Javascript object is <code>utils<\/code>, and <code>getLiveData<\/code> is the function that activates when you toggle the Switch on, which fetches live data from your Raspberry Pi. But there\u2019s other live data, too, so the same switch works for them. Read on to see how.<\/li>\n<\/ol>\n<h2>Bind all the data<\/h2>\n<p>Binding data to the widgets in the Memory and Disk sections is similar to how you did it for the CPU Stats section.<\/p>\n<p>For Memory, bindings change to:<\/p>\n<ul>\n<li><code>{{( PiData.data.cpu_mem_avail\/1000000000).toPrecision(2) * 100 ?? 0 }}<\/code> for the Progress Bar.<\/li>\n<li><code>{{ ${(PiData.data.cpu_mem_used\/1000000000).toPrecision(2)} ?? 0 }} GB<\/code>, <code>{{ ${(PiData.data.cpu_mem_free\/1000000000).toPrecision(2)} ?? 0}} GB<\/code>, and <code>{{ ${(PiData.data.cpu_mem_total\/1000000000).toPrecision(2)} ?? 0 }} GB<\/code> for the three Stat Box widgets.<\/li>\n<\/ul>\n<p>For Disk, bindings on the Progress Bar, and Stat Box widgets change respectively to:<\/p>\n<ul>\n<li><code>{{ PiData.data.disk_usage_percent ?? 0 }}<\/code><\/li>\n<li><code>{{ ${(PiData.data.disk_usage_used\/1000000000).toPrecision(2)} ?? 0 }} GB<\/code><\/li>\n<li><code>{{ ${(PiData.data.disk_usage_free\/1000000000).toPrecision(2)} ?? 0 }} GB<\/code> and <code>{{ ${(PiData.data.disk_usage_total\/1000000000).toPrecision(2)} ?? 0 }} GB<\/code> for the three Stat Box widgets.<\/li>\n<\/ul>\n<p>The Chart here needs updating the <code>utils<\/code> object you created for CPU Stats with a <code>storeValue<\/code> key called <code>disk_util_data<\/code> nested under <code>getLiveData<\/code> that follows the same logic as <code>cpu_util_data<\/code>.\u00a0For the disk utilization chart, we store disk_util_data that follows the same logic as that of the CPU utilization trend chart.<\/p>\n<pre>\n<code>export default {\n  getLiveData: () =&gt; {\n  \/\/When switch is on:\n    if (Switch1.isSwitchedOn) {\n      setInterval(() =&gt; {\n       const cpuUtilData = appsmith.store.cpu_util_data;\n       const diskUtilData = appsmith.store.disk_util_data;                   \n       \n       PiData.run();\n       \n       storeValue(\"cpu_util_data\", [...cpuUtilData, { x: PiData.data.cpu_percent,y: PiData.data.cpu_percent }]);\n       storeValue(\"disk_util_data\", [...diskUtilData, { x: PiData.data.disk_usage_percent,y: PiData.data.disk_usage_percent }]);\n    }, 1500, 'timerId')\n  } else {\n    clearInterval('timerId');\n  }\n},\n  initialOnPageLoad: () =&gt; {\n    storeValue(\"cpu_util_data\", []);\n    storeValue(\"disk_util_data\", []);\n  }\n}<\/code><\/pre>\n<p>Visualizing the flow of data triggered by the Switch toggling live data on and off with the <code>utils<\/code> Javascript object looks like this:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/03\/toggle.gif\" width=\"1280\" height=\"720\" alt=\"Toggling\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<p>Toggled on, the charts change like this:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/03\/final.gif\" width=\"1280\" height=\"720\" alt=\"Live data display\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Keyur Paralkar, CC BY-SA 4.0) <\/p>\n<\/div>\n<\/article>\n<div class=\"embedded-resource-list callout-float-right\">\n<div class=\"field field--name-title field--type-string field--label-hidden field__item\">More on Raspberry Pi<\/div>\n<div class=\"field field--name-links field--type-link field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/resources\/what-raspberry-pi?intcmp=7016000000127cYAAQ\">What is Raspberry Pi?<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/raspberry-pi-guide?intcmp=7016000000127cYAAQ\">eBook: Guide to Raspberry Pi<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/getting-started-raspberry-pi-cheat-sheet?intcmp=7016000000127cYAAQ\">Getting started with Raspberry Pi cheat sheet<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/kubernetes-raspberry-pi?intcmp=7016000000127cYAAQ\">eBook: Running Kubernetes on your Raspberry Pi<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/www.redhat.com\/en\/resources\/data-intensive-applications-hybrid-cloud-blueprint-detail?intcmp=7016000000127cYAAQ\">Whitepaper: Data-intensive intelligent applications in a hybrid cloud blueprint<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/www.redhat.com\/en\/topics\/edge-computing?intcmp=7016000000127cYAAQ\">Understanding edge computing<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/raspberry-pi?intcmp=7016000000127cYAAQ\">Our latest on Raspberry Pi<\/a><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Pretty, minimalistic, and totally useful.<\/p>\n<h2>Enjoy<\/h2>\n<p>As you get more comfortable with <code>psutils<\/code>, Javascript, and Appsmith, I think you\u2019ll find you can tweak your dashboard easily and endlessly to do really cool things like:<\/p>\n<ul>\n<li>See trends from the previous week, month, quarter, year, or any custom range that your RPi data allows<\/li>\n<li>Build an alert bot for threshold breaches on any stat<\/li>\n<li>Monitor other devices connected to your Raspberry Pi<\/li>\n<li>Extend <code>psutils<\/code> to another computer with Python installed<\/li>\n<li>Monitor your home or office network using another library<\/li>\n<li>Monitor your garden<\/li>\n<li>Track your own life habits<\/li>\n<\/ul>\n<p>Until the next awesome build, happy hacking!<\/p>\n<\/div>\n<div class=\"clearfix text-formatted field field--name-field-article-subhead field--type-text-long field--label-hidden field__item\">\n<p>Use Python to make an API for monitoring your Raspberry Pi hardware and build a dashboard with Appsmith.<\/p>\n<\/div>\n<div class=\"field field--name-field-lead-image field--type-entity-reference field--label-hidden field__item\">\n<article class=\"media media--type-image media--view-mode-caption\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/03\/pie-raspberry-bake-make-food.png\" width=\"520\" height=\"292\" alt=\"8 fun Raspberry Pi projects to try\" title=\"8 fun Raspberry Pi projects to try\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>Internet Archive Book Images. Modified by Opensource.com. CC BY-SA 4.0<\/p>\n<\/div>\n<\/article>\n<\/div>\n<div class=\"field field--name-field-tags field--type-entity-reference field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/raspberry-pi\" hreflang=\"en\">Raspberry Pi<\/a><\/div>\n<\/p><\/div>\n<div class=\"hidden field field--name-field-listicle-title field--type-string field--label-hidden field__item\">What to read next<\/div>\n<div class=\"field field--name-field-default-license field--type-list-string field--label-hidden field__item\"><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\"><br \/>\n        <img decoding=\"async\" alt=\"Creative Commons License\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/03\/cc-by-sa-4-7.png\" title=\"This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.\"><\/a>This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.<\/div>\n<section class=\"field field--name-field-comments field--type-comment field--label-hidden comment-wrapper\">\n<div class=\"comments__count\">\n<div class=\"login\"><a href=\"https:\/\/opensource.com\/user\/register?absolute=1\">Register<\/a> or <a href=\"https:\/\/opensource.com\/user\/login?destination=\/feed&amp;absolute=1\">Login<\/a> to post a comment.<\/div>\n<\/p><\/div>\n<\/section>\n<p class=\"wpematico_credit\"><small>Powered by <a href=\"http:\/\/www.wpematico.com\" target=\"_blank\" rel=\"noopener\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Build a Raspberry Pi monitoring dashboard in under 30 minutes Keyur Paralkar Mon, 03\/06\/2023 &#8211; 03:00 If you\u2019ve ever wondered about the performance of your Raspberry Pi, then you might need a dashboard for your Pi. In this article, I demonstrate how to quickly building an on-demand monitoring dashboard for your Raspberry Pi so you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":71710,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[307],"tags":[],"class_list":["post-71709","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-open-source"],"_links":{"self":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/71709","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=71709"}],"version-history":[{"count":0,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/71709\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/media\/71710"}],"wp:attachment":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=71709"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=71709"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=71709"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}