How to use Home Assistant to display Linux apt update counts

by Pete
13 minutes read

Keeping Linux systems up-to-date is crucial for security and performance. Yet, regularly checking updates manually can be a tedious task. Efficiently managing multiple systems calls for automation. In this article, I will guide you through setting up a simple yet effective automated monitoring system using a BASH script, a web server, and Home Assistant.

This setup not only automates the update checks but also displays the results on a user-friendly dashboard. This feature makes it easy to keep track of system health at a glance. Whether you’re managing a few desktops or a fleet of servers, this solution will streamline your operations and keep you well-informed about the latest updates.

Logic

This solution employs a BASH script that runs automatically at startup on desktops and every three hours on servers—since servers rarely reboot or shut down. Here’s how the process unfolds:

  1. Script Execution: The BASH script performs apt update and simulates an upgrade. It then uses grep to determine the count of available updates.
  2. Data Transmission: The script sends this update count, along with the hostname, to a web server using a simple curl command.
  3. Data Storage: The web server creates a .txt file named after the hostname. It records the latest update count within this file.
  4. Data Retrieval: Home Assistant, through its Scrape integration, retrieves the update count from the .txt file via an HTTP call. It then stores this value in a sensor displayed on a Lovelace dashboard.

The end result is:

What you’ll need

To implement this system, you will need the following:

  1. Web Server: Apache or NGINX running PHP 8 or higher.
  2. Home Assistant: Make sure to install the Scrape Integration.
  3. Linux Systems: Several Linux servers or desktops to monitor.
  4. Command Line Access: Ability to modify cron jobs and access the command line on each system.
  5. Basic Knowledge: Understanding of Linux, command line operations, scripting, and basic web server setup.

Steps

1
Setup Web Server & PHP Script

  • Installation: Set up Apache or NGINX on your server if it’s not already installed. Make sure PHP 8 or higher is active.
  • Configuration: Configure your web server to manage incoming requests and serve files securely and efficiently.
  • Script Hosting: Establish a directory on your web server to store and update the scripts and text files used by the BASH script. I created a default LAMP server with an internally facing site location pointing (ie: DocumentRoot in Apache) to /var/www/html/output

output directory is where the clients will save their APT updates and where scrape will retrieve them from.

Within the output directory, I created a php script called endpoint.php:

<?php
// Get the update count from POST data
$update_count = $_POST['data'];
// Get the source name (hostname) from POST data
$source_name = $_POST['source'];
// Get the sending address from POST data
$sending_address = $_POST['sending_address'];
// Create a file name based on the source name, sending address, and a timestamp
$file_name = $sending_address .'.txt';
// Define the directory where you want to save the file
$directory = '/var/www/html/output/';
// Create the full path to the file
$file_path = $file_name;
// Save the update count to the file
// file_put_contents($file_path, $update_count . PHP_EOL, FILE_APPEND);
file_put_contents($file_path, $update_count);

// Respond to the client
echo "Update count saved to $file_path";
?>

Make sure the directory and the script have www-data:www-data permissions (for Apache).

2
Configure BASH Script

Client-side Script Creation

The BASH script will run apt update and simulates an upgrade using apt list --upgradable. Use grep to extract the number of available updates. A sample, and working script is as follows:

#!/bin/bash
# Script Version 1.6
# Get the hostname of the system
hostname=$(hostname)
# Run apt-get update silently
sudo apt-get update &>/dev/null
# Simulate the upgrade process and store the output in a variable
upgrade_output=$(sudo apt-get upgrade --dry-run 2>&1)
# Use grep to extract the line containing "to upgrade" or "upgraded"
upgrade_line=$(echo "$upgrade_output" | grep -oE "[0-9]+ (to upgrade|upgraded)")
# Extract the number of upgraded packages
if [[ "$upgrade_line" =~ ([0-9]+) ]]; then
    update_count="${BASH_REMATCH[1]}"
else
    # If the format is not recognized, set update_count to 0
    update_count="0"
fi
# Print the update count
echo "$hostname:$update_count"
# Define the URL of your server endpoint
server_url="http://peepingtom.internal.domain/output/endpoint.php"
# Specify the sending address (e.g., IP address or unique identifier)
sending_address="$hostname"
# Use curl to send the update count to the server
curl -X POST -d "data=$update_count&source=$hostname&sending_address=$sending_address" $server_url

Script Deployment

Install this script in an appropriate location on each Linux system you monitor. Ensure it has proper execution permissions. I installed mine under /opt/scripts and called it updates_available.sh. Don’t forget to give it run permissions eg:

chmod +x updates_available.sh

Cron Job

Create a cron job for this script to run at system boot and every three hours thereafter. Use the crontab -e command to edit the system’s cron job. eg:

sudo crontab -e

Once in crontab, enter the following lines at the bottom (using your own location and script name).

Note: for desktops, use the @reboot line only. for servers, include both lines.

0 */3 * * * /bin/bash /opt/scripts/updates_available.sh
@reboot /bin/bash /opt/scripts/updates_available.sh

Save that and continue to test running the script.

Data Transmission

The curl command in your script will send the update count and the hostname to your web server, where it gets saved in a text file.

sudo ./updates_available.sh

If all goes well, you should see a similar output. I have 0 (zero) updates on my computer – yay!

To replicate the script – basically rinse and repeat for desktops and servers. The script will take care of the naming for you.

3
Configure Home Assistant

Integration Setup

Set up the Scrape integration in Home Assistant if it’s not already active.

  1. Once Scrape is installed, head over to your integrations page within Home Assistant and click Add Entry.
  2. The Resource Name is the full URL of the hosted txt file. In my case, its: http://<myservername>/output/DESKTOP-PF1S4D7.txt
  3. My web server isn’t publicly available, so I’m not worried about SSL just yet.
  4. Disable SSL Verify and click Submit
  5. On the next screen, give it a common name like Pete’s PC Updates or something.
  6. For select, simply enter “p” (that’s p without quotation marks)
  7. Leave everything else default and click Submit
  8. You should see integration entries like so:

Dashboard Design

Design your dashboard to display update counts clearly and attractively. Use conditional color coding or icons to indicate different update statuses, like green for up-to-date and red for updates needed.

My Lovelace Dashboard will only show when there’s 0 updates (Ie: when the value of the text file is 0):

cards:
  - type: custom:mushroom-title-card
    title: Linux Updates
    subtitle: ''
  - square: false
    type: grid
    cards:
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.octopi_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.octopi_updates
          name: Octopi
          icon: mdi:update
          vertical: false
          show_entity_picture: false
          hide_state: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.fantomas_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.fantomas_updates
          name: Fantomas
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.minecraft_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.minecraft_updates
          name: Minecraft
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.peepingtom_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.peepingtom_updates
          name: Peepingtom
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.urbackup_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.urbackup_updates
          name: Urbackup
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.desktop_pf1s4d7_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.desktop_pf1s4d7_updates
          name: Pete's PC
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.desktop_j5f2s01_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.desktop_j5f2s01_updates
          name: Pete's Tablet
          icon: mdi:update
          vertical: false
          hide_state: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.desktop_d54fxa_updates
            state_not: '0'
        card:
          type: tile
          entity: sensor.desktop_d54fxa_updates
          name: Shed PC
          icon: mdi:update
          vertical: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.steamos
            state_not: '0'
        card:
          type: tile
          entity: sensor.steamos
          name: STEAMOS
          icon: mdi:update
          vertical: false
    columns: 2
type: vertical-stack

Conclusion

This automated monitoring solution harnesses scripting, web technology, and Home Assistant to keep your Linux systems updated with the latest security patches and performance improvements. By integrating these tools, we transform the challenging task of manually checking updates across multiple systems into a streamlined, automated process. This approach not only saves time but also boosts your operational capabilities. With real-time updates on a Home Assistant dashboard, you immediately see each system’s health, enabling proactive maintenance and management.

Furthermore, this setup shows how simple technologies can combine to form robust solutions in a networked environment. It fosters a proactive approach to system management, reducing the risks of delayed updates and neglected maintenance. As you refine this system, consider adding more advanced monitoring metrics like system load and security audits. This enhancement can turn your basic update monitor into a comprehensive system health dashboard.