Use Python to create an API to monitor your Raspberry Pi hardware, and build a dashboard with Appsmith.
If you want to know how your Raspberry Pi is performing, you might need a Raspberry Pi dashboard. In this article, I will demonstrate how to quickly build an on-demand monitoring dashboard to view your Raspberry Pi’s CPU performance, memory, and disk usage in real-time, and add more views and actions as needed.
If you have already used Appsmith, you can directly import sample application and get started.
Appsmith
Appsmith is an open-source low-code application building tool that helps developers easily and quickly build internal applications, such as dashboards and management panels. It is a great choice for dashboards and reduces the time and complexity required by traditional coding methods.
In the dashboard for this example, I display the following statistics:
Create an Endpoint
You need a way to get this data from the Raspberry Pi and pass it to Appsmith. psutil is a Python library for monitoring and analyzing, while Flask-RESTful is a Flask extension for creating REST APIs.
Appsmith calls the REST API every few seconds to automatically refresh the data, responding with a JSON object containing all the required statistics, as shown below:
{ "cpu_count": 4,
"cpu_freq": [
600.0,
600.0,
1200.0 ],
"cpu_mem_avail": 463953920,
"cpu_mem_free": 115789824,
"cpu_mem_total": 971063296,
"cpu_mem_used": 436252672,
"cpu_percent": 1.8,
"disk_usage_free": 24678121472,
"disk_usage_percent": 17.7,
"disk_usage_total": 31307206656,
"disk_usage_used": 5292728320,
"sensor_temperatures": 52.616 }
1. Set Up the REST API
If your Raspberry Pi does not have Python installed, open a terminal on the Raspberry Pi and run this installation command:
$ sudo apt install python3
Now set up a Python virtual environment for your development:
$ python -m venv PiData
Next, activate the environment. You must do this after restarting the Raspberry Pi.
$ source PiData/bin/activate
$ cd PiData
To install Flask, Flask-RESTful, and other dependencies needed later, create a file named requirements.txt
in your Python virtual environment and add the following content:
flask
flask-restful
gunicorn
Save the file, then use pip
to install them all at once. You must do this after restarting the Raspberry Pi.
(PyData)$ python -m pip install -r requirements.txt
Next, create a file named pi_stats.py
to hold the logic for retrieving system statistics from the Raspberry Pi using psutil
. Paste the following code into the pi_stats.py
file:
from flask import Flask
from flask_restful import Resource, Api
import psutil
app = Flask(__name__)
api = Api(app)
class PiData(Resource):
def get(self):
return "RPI Stat dashboard"
api.add_resource(PiData, '/get-stats')
if __name__ == '__main__':
app.run(debug=True)
This code does the following:
app = Flask(name)
to define an application object for the nested API.PiData
as a specific Resource class in Flask-RESTful to expose each supported HTTP method.api.add_resource(PiData, '/get-stats')
to attach the resource PiData
to the API object api
.PiData
as a response whenever you access the URL /get-stats
.2. Read Statistics Using psutil
To get statistics from your Raspberry Pi, you can use the built-in functions provided by psutil
:
cpu_percentage
, cpu_count
, cpu_freq
, and sensors_temperatures
functions are used to get the CPU usage percentage, count, clock speed, and temperature, respectively. The sensors_temperatures
reports the temperature of all devices connected to the Raspberry Pi. To get only the CPU temperature, use the key cpu-thermal
.virtual_memory
function returns statistics for total memory, available memory, used memory, and free memory (in bytes).disk_usage
function returns statistics for total disk space, used space, and available space (in bytes).Here is an example of combining all functions into a Python dictionary:
system_info_data = {
'cpu_percent': psutil.cpu_percent(1),
'cpu_count': psutil.cpu_count(),
'cpu_freq': psutil.cpu_freq(),
'cpu_mem_total': memory.total,
'cpu_mem_avail': memory.available,
'cpu_mem_used': memory.used,
'cpu_mem_free': memory.free,
'disk_usage_total': disk.total,
'disk_usage_used': disk.used,
'disk_usage_free': disk.free,
'disk_usage_percent': disk.percent,
'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current,
}
The next section will use this dictionary.
3. Get Data from Flask-RESTful API
To see the data from the Raspberry Pi in the API response, update the pi_stats.py
file to include the dictionary system_info_data
in the PiData
class:
from flask import Flask
from flask_restful import Resource, Api
import psutil
app = Flask(__name__)
api = Api(app)
class PiData(Resource):
def get(self):
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
system_info_data = {
'cpu_percent': psutil.cpu_percent(1),
'cpu_count': psutil.cpu_count(),
'cpu_freq': psutil.cpu_freq(),
'cpu_mem_total': memory.total,
'cpu_mem_avail': memory.available,
'cpu_mem_used': memory.used,
'cpu_mem_free': memory.free,
'disk_usage_total': disk.total,
'disk_usage_used': disk.used,
'disk_usage_free': disk.free,
'disk_usage_percent': disk.percent,
'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current, }
return system_info_data
api.add_resource(PiData, '/get-stats')
if __name__ == '__main__':
app.run(debug=True)
Your script is ready, now run PiData.py
:
$ python PyData.py
* Serving Flask app "PiData" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not run this in a production environment.
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
You have a working API.
4. Expose the API to the Internet
You can interact with the API on your local network. However, to access it over the internet, you need to open a port in your firewall and forward incoming traffic to the port provided by Flask. However, as your test output suggests, running the Flask app in Flask is only suitable for development, not for production. To safely expose the API to the internet, you can use the gunicorn
production server installed during the setup.
Now you can start the Flask API. You need to do this every time you restart the Raspberry Pi.
$ gunicorn -w 4 'PyData:app'
Serving on http://0.0.0.0:8000
To access your Raspberry Pi from the outside world, open a port in your network firewall and direct traffic to your Raspberry Pi’s IP address on port 8000.
First, get the internal IP address of the Raspberry Pi:
$ ip addr show | grep inet
The internal IP address typically starts with 10, 192, or 172.
Next, you must configure the firewall. Usually, the router you get from your Internet Service Provider (ISP) has a built-in firewall. Typically, you can access your home router through a web browser. The router’s address is sometimes printed on the bottom, starting with 192.168 or 10. However, every device is different, so I can’t tell you which options to click to adjust the settings. For a complete description of how to configure the firewall, read Seth Kenlon’s article “Open ports and route traffic through your firewall“.
Alternatively, you can use localtunnel to use dynamic port forwarding services.
Once your traffic reaches the Raspberry Pi, you can query your API:
$ curl https://example.com/get-stats
{
"cpu_count": 4,
"cpu_freq": [
600.0,
600.0,
1200.0 ],
"cpu_mem_avail": 386273280,
...
If you have made it this far, the hardest part is over.
5. Repeat Steps
If you restart the Raspberry Pi, you must follow these steps:
source
to reactivate the Python environmentpip
to refresh the application’s dependenciesgunicorn
to start the Flask applicationYour firewall settings are persistent, but if you used localtunnel, you must start a new tunnel after restarting.
If you wish, you can automate these tasks, but that’s a topic for another tutorial. The final part of this tutorial is building a user interface on Appsmith, binding your Raspberry Pi data to the user interface using drag-and-drop widgets and some JavaScript. Trust me, it will be easy from now on!
Building a Dashboard on Appsmith
Hardware Monitoring Dashboard
To create a dashboard like this, you need to connect the public API endpoint to Appsmith, build a user interface using Appsmith’s widget library, and bind the API’s response to the widgets. If you have already used Appsmith, you can directly import sample application and get started.
If you haven’t, please register for a free Appsmith account. Alternatively, you can choose to self-host Appsmith.
Connect the API as a Data Source in Appsmith
Log into your Appsmith account.
localtunnel.me
address, always adding /get-stats
at the end to get the statistics. Paste it into the first blank field on the page and click the βRUNβ button.Make sure to see a successful response in the βResponseβ panel.
Appsmith Interface
Building User Interface
The Appsmith interface is very intuitive, but if you feel lost, I recommend checking out the Build your first app on Appsmith tutorial.
For the title, drag and drop the βTextβ, βImageβ, and βDividerβ widgets onto the canvas. Arrange them as follows:
Setting Project Title
The βTextβ widget contains the actual title of your page. Type something cooler than βRaspberry Pi Statsβ.
The βImageβ widget is used to showcase the unique logo of the dashboard. You can use any logo you like.
Use the βSwitchβ widget to toggle real-time data mode. Configure it in the βPropertyβ panel to get data from the API you built.
For the main section, create a CPU statistics area using the following widgets from the left widget library:
For the memory and disk statistics sections, repeat the same steps. The disk statistics section does not require a chart, but you can use it if you find a purpose for it.
Your final widget layout should look similar to the following:
Appsmith Property Settings
The final step is to bind the API’s data to your widgets.
Binding Data to Widgets
Return to the canvas and find your widgets in the three category sections. First, set up the CPU statistics.
To bind data to the βProgress Barβ widget:
{{PiData.data.cpu_percent ?? 0}}
in the βProgressβ field. This code references the data stream from your API named PiData
. The key cpu_percent
contains the data that Appsmith uses to display the CPU utilization percentage.Binding Data in the Configuration Screen
In the CPU section, there are three βStat Boxβ widgets. The steps to bind data to each widget are exactly the same as the steps to bind the βProgress Barβ widget, except you need to bind different data properties from the .data
operator. Follow the same steps, but with the following exceptions:
{{${PiData.data.cpu_freq[0]} ?? 0 }}
to display the clock speed.{{${PiData.data.cpu_count} ?? 0 }}
to display the CPU count.{{${(PiData.data.sensor_temperatures).toPrecision(3)} ?? 0 }}
to display the CPU temperature data.If everything goes smoothly, you will get a beautiful dashboard as shown below:
Raspberry Pi Dashboard
CPU Utilization Trend Chart
You can use the βChartβ widget to display CPU utilization as a trend line and have it automatically update over time.
First, click on the widget, find the βChart Typeβ property on the right, and change it to βLine Chartβ. To display the trend line, you need to store cpu_percent
in an array of data points. Your API currently returns it as a single time data point, so you can use Appsmith’s storeValue
function (a native implementation of Appsmith’s built-in setItem
method) to obtain an array.
Click the β+β button next to βQuery or JSβ and name it βutilsβ.
Paste the following JavaScript code into the βCodeβ field:
export default {
getLiveData: () => {
//When switch is on:
if (Switch1.isSwitchedOn) {
setInterval(() => {
let utilData = appsmith.store.cpu_util_data;
PiData.run()
storeValue("cpu_util_data", [...utilData, {
x: PiData.data.cpu_percent,
y: PiData.data.cpu_percent
}]);
}, 1500, 'timerId')
} else {
clearInterval('timerId');
}
},
initialOnPageLoad: () => {
storeValue("cpu_util_data", []);
}
}
To initialize the Store
, you create a JavaScript function in the initialOnPageLoad
object and put the storeValue
function in it.
You use storeValue("cpu_util_data", []);
to store the value in cpu_util_data
using the storeValue
function. This function runs when the page loads.
So far, every time the page refreshes, the code will store a data point in cpu_util_data
in the Store
. To store an array, you use the index variables x
and y
, both storing the values from the cpu_percent
data property.
You also want to automatically store this data by setting a fixed time interval between stored values. When executing the setInterval function:
cpu_util_data
.PiData
.cpu_util_data
using the latest cpu_percent
data returned.cpu_util_data
in the key utilData
.getLiveData
.In the βSettingsβ tab, find all parent functions in the object and set initialOnPageLoad
to βYesβ in the βRun on Page Loadβ option.
Setting Functions to Run on Page Load
Now refresh the page to confirm.
Return to the canvas. Click the βChartβ widget and find the βChart Dataβ property. Paste {{ appsmith.store.disk_util_data }}
to bind it. This way, if you run the object utils
multiple times, you will get chart data. To run this automatically:
onChange
event.{{ utils.getLiveData() }}
. The JavaScript object is utils
, and getLiveData
is the function that activates when you toggle the switch, fetching real-time data from your Raspberry Pi. However, there are other real-time data, so the same switch applies to them as well. Keep reading for more details.Binding data to the memory and disk sections of the widgets is similar to what you did in the CPU statistics section.
For the memory section, bind as follows:
{{( PiData.data.cpu_mem_avail/1000000000).toPrecision(2) * 100 ?? 0 }}
.{{ ${PiData.data.cpu_mem_used/1000000000).toPrecision(2)} ?? 0 }} GB
, {{ ${PiData.data.cpu_mem_free/1000000000).toPrecision(2)} ?? 0}} GB
, and {{ ${PiData.data.cpu_mem_total/1000000000).toPrecision(2)} ?? 0 }} GB
.For the disk section, the bindings for the progress bar and stat box widgets are:
{{ PiData.data.disk_usage_percent ?? 0 }}
.{{ ${PiData.data.disk_usage_used/1000000000).toPrecision(2)} ?? 0 }} GB
, {{ ${PiData.data.disk_usage_free/1000000000).toPrecision(2)} ?? 0 }} GB
, and {{ ${PiData.data.disk_usage_total/1000000000).toPrecision(2)} ?? 0 }} GB
.The chart here needs to update the utils
object you created for CPU statistics, using storeValue
with the key named disk_util_data
, nested under getLiveData
, with logic similar to that of cpu_util_data
. For the disk utilization chart, the logic for storing disk_util_data
is the same as that for the CPU utilization trend chart.
export default {
getLiveData: () => {
//When switch is on:
if (Switch1.isSwitchedOn) {
const cpuUtilData = appsmith.store.cpu_util_data;
const diskUtilData = appsmith.store.disk_util_data;
PiData.run();
storeValue("cpu_util_data", [...cpuUtilData, { x: PiData.data.cpu_percent,y: PiData.data.cpu_percent }]);
storeValue("disk_util_data", [...diskUtilData, { x: PiData.data.disk_usage_percent,y: PiData.data.disk_usage_percent }]);
}, 1500, 'timerId')
} else {
clearInterval('timerId');
}
},
initialOnPageLoad: () => {
storeValue("cpu_util_data", []);
storeValue("disk_util_data", []);
}
}
Overall, it looks beautiful, minimal, and very useful.
Enjoy using it!
As you become more familiar with psutils
, JavaScript, and Appsmith, I believe you will find it easy to infinitely tweak your dashboard to implement very cool features, such as:
psutils
to another computer with Python installedHave fun with your next exciting project!
(Cover Image: MJ/9754eb1f-1722-4897-9c35-3f20c285c332)
via: https://opensource.com/article/23/3/build-raspberry-pi-dashboard-appsmith
Author: Keyur Paralkar Topic: lkxed Translator: ChatGPT Proofreader: wxy
This article is originally compiled by LCTT and honorably presented by Linux China
Leave a Comment
Your email address will not be published. Required fields are marked *