<!--order=7-->

<h1>Python Project: A System Information Report</h1>
<p>This project combines the ideas from the Python series into one useful command-line script. It gathers basic information about the machine, prints a readable report, and can save that report for later comparison.</p>

<h2>The Script</h2>
<p>Save this as <code>system_report.py</code>:</p>
<pre>
#!/usr/bin/env python3

import argparse
import platform
import shutil
import socket
from datetime import datetime, timezone
from pathlib import Path

def make_report():
    total, used, free = shutil.disk_usage("/")
    gigabyte = 1024 ** 3

    lines = [
        "System information report",
        "==========================",
        f"Collected: {datetime.now(timezone.utc).isoformat()}",
        f"Hostname:  {socket.gethostname()}",
        f"System:    {platform.system()} {platform.release()}",
        f"Machine:   {platform.machine()}",
        f"Python:    {platform.python_version()}",
        f"Disk used: {used / gigabyte:.1f} GB "
        f"of {total / gigabyte:.1f} GB",
        f"Disk free: {free / gigabyte:.1f} GB",
    ]
    return "\n".join(lines) + "\n"

def main():
    parser = argparse.ArgumentParser(
        description="Write a basic system information report."
    )
    parser.add_argument(
        "-o", "--output",
        type=Path,
        help="also save the report to this file",
    )
    args = parser.parse_args()

    report = make_report()
    print(report, end="")

    if args.output:
        args.output.write_text(report, encoding="utf-8")
        print(f"Saved report to {args.output}")

if __name__ == "__main__":
    main()
</pre>

<h2>Run It</h2>
<pre>
$ python3 system_report.py
System information report
==========================
Collected: 2025-...
Hostname:  pi-gateway
System:    Linux ...
Machine:   aarch64
Python:    3.13.2
Disk used: 12.4 GB of 59.6 GB
Disk free: 47.2 GB

$ python3 system_report.py --output reports/pi-gateway.txt
</pre>

<h2>What This Project Teaches</h2>
<ul>
  <li><code>argparse</code> makes the script useful from a terminal.</li>
  <li><code>pathlib.Path</code> handles the optional output file.</li>
  <li>Functions keep data collection separate from command-line behavior.</li>
  <li>Standard-library modules provide useful information without extra packages.</li>
  <li>A saved report gives you something to compare after maintenance or a deployment.</li>
</ul>

<p>From here, the report could be extended with memory usage, network interfaces, sensor readings, or a scheduled upload to a central machine. Add one measured feature at a time and keep the command useful when the network is unavailable.</p>

<h2>Adding Raspberry Pi Memory Information</h2>
<p>Linux exposes useful runtime information through virtual files under <code>/proc</code>. This is a simple way to add memory information without installing a package:</p>
<pre>
def memory_summary():
    values = {}
    for line in Path("/proc/meminfo").read_text().splitlines():
        name, value = line.split(":", 1)
        if name in {"MemTotal", "MemAvailable"}:
            values[name] = value.strip()
    return values
</pre>
<p>Keep Linux-specific code behind a platform check if the script should also run on macOS or Windows. A report should say when a value is unavailable rather than pretending every machine has the same files.</p>

<h2>Scheduling a Report</h2>
<p>For a report that runs unattended, first make sure it works interactively and writes to a directory the service user can access. A simple cron entry might run it every hour:</p>
<pre>
# Edit the user's crontab with: crontab -e
0 * * * * /home/pi/node-report/.venv/bin/python \
  /home/pi/node-report/system_report.py \
  --output /home/pi/reports/latest.txt
</pre>
<p>Use an absolute path, record errors somewhere you will inspect, and avoid placing passwords in the command line. For a long-running service, systemd provides better restart and logging controls.</p>

<h2>Next Improvements</h2>
<ul>
  <li>Add a JSON output option for another program to consume.</li>
  <li>Record the report in a dated file so changes can be compared over time.</li>
  <li>Add a warning when free disk space falls below a chosen percentage.</li>
  <li>Read a node name from a configuration file instead of hard-coding it.</li>
</ul>

<h2>References</h2>
<ul>
  <li><a href="https://docs.python.org/3/library/platform.html" target="_blank" rel="noopener">Python platform Module ↗</a></li>
  <li><a href="https://docs.python.org/3/library/shutil.html#shutil.disk_usage" target="_blank" rel="noopener">Python Disk Usage ↗</a></li>
</ul>