How the TeslaMate Updater Module Checks for Software Updates

The TeslaMate Updater module queries the GitHub Releases API to compare the locally running version against the latest remote release, returning a structured update object that powers the in-app notification system.

The TeslaMate Updater module provides automated version detection that keeps users informed about new releases without manual intervention. This Elixir-based system reads the current application version from the repository, fetches release metadata from GitHub, and surfaces upgrade notifications directly in the Settings interface. Understanding how the Updater module checks for software updates reveals a lightweight yet robust pattern for self-hosted application version management.

Overview of the Update Detection Workflow

The update mechanism follows a deterministic pipeline designed to minimize external dependencies while providing reliable version comparison. When the Settings page loads, the system executes a series of operations to determine if the running instance is current.

The workflow involves:

  • Reading the local version from the VERSION file at the repository root
  • Issuing an HTTP GET request to the GitHub Releases API using the Tesla client
  • Parsing the JSON payload to extract the latest tag and release assets
  • Comparing semantic versions using Elixir's standard library
  • Returning a populated struct indicating availability and download links
  • Rendering conditional UI elements in the Phoenix LiveView interface

Step-by-Step Implementation in lib/teslamate/updater.ex

All core logic resides in lib/teslamate/updater.ex, where the module orchestrates external API communication and version arithmetic.

Reading the Current Version from the VERSION File

The module determines the running version by reading a plain-text file committed to the repository root. This approach avoids compile-time version injection and allows runtime detection across different deployment methods.

defp current_version do
  Path.join(:code.priv_dir(:teslamate), "../../VERSION")
  |> File.read!()
  |> String.trim()
end

The function constructs an absolute path to the VERSION file relative to the priv directory, ensuring compatibility with Mix releases and Docker containers.

Querying the GitHub Releases API

The Updater module uses the Tesla HTTP client (wrapped by TeslaMate.HTTP) to fetch release metadata. The request targets the latest release endpoint with a standard User-Agent header.

@github_release_api "https://api.github.com/repos/teslamate-org/teslamate/releases/latest"

def get_update do
  with {:ok, %Tesla.Env{status: 200, body: body}} <- Tesla.get(@github_release_api),
       {:ok, %{"tag_name" => tag, "assets" => assets}} <- Jason.decode(body) do
    # Version comparison logic...

  else
    _ -> %Update{available?: false}
  end
end

If the API returns a non-200 status or the JSON parsing fails, the function gracefully returns an update struct with available?: false, preventing UI errors during network outages.

Parsing and Comparing Semantic Versions

After extracting the tag_name (e.g., v1.27.0) from the GitHub response, the module strips the leading "v" prefix and compares versions using Version.compare/2.

latest_version = String.trim_leading(tag, "v")
current_version = current_version()

if Version.compare(latest_version, current_version) == :gt do
  %Update{
    available?: true,
    new_version: latest_version,
    release_url: "https://github.com/teslamate-org/teslamate/releases/tag/#{tag}",
    assets: assets
  }
else
  %Update{available?: false}
end

This comparison leverages Elixir's built-in semantic versioning support, correctly handling prerelease tags and build metadata according to the SemVer specification.

Returning the Update Struct

The module encapsulates results in a %TeslaMate.Updater.Update{} struct with four fields:

  • available? - boolean indicating if a newer version exists
  • new_version - the semantic version string from GitHub (nil if current)
  • release_url - direct link to the GitHub release page
  • assets - list of downloadable artifacts including Docker images and binaries

When the local version matches or exceeds the remote release, the struct returns with available?: false and nullified metadata fields.

Integrating Update Checks into the Web Interface

The Settings LiveView (lib/teslamate_web/live/settings_live/index.ex) consumes the Updater module to conditionally render upgrade banners. During the mount phase, the LiveView fetches update status and assigns it to the socket.

def mount(_params, _session, socket) do
  {:ok,
   socket
   |> assign(:update, TeslaMate.Updater.get_update())}
end

The template then pattern-matches against the struct to display contextual messaging:

<%= if @update.available? do %>
  <p>New version <%= @update.new_version %> is available!</p>
  <a href="<%= @update.release_url %>">View release</a>
<% else %>
  <p>You are running the latest version.</p>
<% end %>

This integration ensures users receive immediate visual feedback about available updates without leaving the application interface.

Summary

  • The TeslaMate.Updater module in lib/teslamate/updater.ex provides centralized version detection logic for the entire application.
  • Version detection relies on reading the VERSION file at the repository root and comparing it against the GitHub Releases API using semantic versioning rules.
  • API communication uses the Tesla HTTP client with graceful error handling that defaults to "no update available" when network requests fail.
  • Data encapsulation occurs through the %Update{} struct, which carries availability status, version strings, release URLs, and asset metadata.
  • UI integration happens in lib/teslamate_web/live/settings_live/index.ex, where the LiveView assigns update data for conditional rendering in the Settings interface.

Frequently Asked Questions

How does TeslaMate determine the currently installed version?

TeslaMate reads the VERSION file located at the repository root using a private function in lib/teslamate/updater.ex. The function constructs a path relative to the application priv directory, trims whitespace, and returns the semantic version string for comparison against GitHub releases.

What happens if the GitHub API is unavailable when checking for updates?

The get_update/0 function includes error handling in its with clause that catches HTTP failures or JSON parsing errors. When the API is unreachable, the function returns %Update{available?: false}, causing the Settings page to display the "latest version" message without crashing or hanging.

Which HTTP client does TeslaMate use for update checks?

The Updater module uses the Tesla HTTP client, specifically wrapped by TeslaMate.HTTP, to execute GET requests against https://api.github.com/repos/teslamate-org/teslamate/releases/latest. The request includes proper User-Agent headers required by the GitHub API.

Where does the Settings page display available updates?

The Settings LiveView in lib/teslamate_web/live/settings_live/index.ex calls TeslaMate.Updater.get_update/0 during the mount phase and assigns the result to the socket. The corresponding template renders a conditional block that displays the new version number and release URL when available? is true.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →