Over-the-Air Updates

This section documents the OTA software update mechanism used to update the controller software independently of the TEG Gateway runtime.

Docker Client

Docker runtime management for the Edge Gateway controller.

This module provides the GatewayDockerClient, a thin wrapper around the Docker Engine API used by the Edge Gateway to manage the controller container.

Responsibilities

  • Detect whether the controller container is running and determine its version.

  • Start/stop the controller container in a controlled way.

  • Build controller images from a Git tag or commit hash if the image is not available.

  • Publish ThingsBoard OTA-related software state updates via MQTT (sw_state).

The controller is deployed as a Docker container (teg_controller) with images tagged as teg-controller-<version>:latest. Versions may be Git tags (e.g. v1.2.3) or full commit hashes.

Notes

  • This client is implemented as a process-level singleton to avoid repeated Docker client initialization.

  • The implementation assumes host networking and a privileged container, as required for the deployed Raspberry Pi environment.

class modules.docker_client.GatewayDockerClient[source]

Bases: object

Manage the controller Docker container for an Edge Gateway device.

The gateway and controller are intentionally separated: the Edge Gateway remains stable while controller versions can be updated independently (e.g. via OTA packages in ThingsBoard).

This class wraps Docker operations (list, stop, run, build) and integrates with the gateway’s Git and MQTT clients to support automated controller updates.

last_launched_version

Cached version string of the last successfully launched controller.

docker_client

Docker SDK client instance created via docker.from_env(), or None if Docker is unavailable.

docker_client: DockerClient | None = None
get_controller_version()[source]

Return the controller version inferred from the running container image.

Return type:

Optional[str]

Returns:

The Git tag/commit hash parsed from the image name, or None if the controller is not running or the version cannot be determined.

get_edge_startup_timestamp_ms()[source]

Return the controller container start time as Unix milliseconds.

Return type:

Optional[int]

Returns:

Start timestamp in milliseconds (UTC) if the controller is running, else None.

get_last_launched_controller_version()[source]

Return the last launched controller version.

The value is cached in-memory and persisted in $GATEWAY_DATA_PATH/last_launched_controller_version.txt. If the file is not available, the environment variable TEG_DEFAULT_CONTROLLER_VERSION is used as a fallback.

Return type:

Optional[str]

Returns:

The version tag/commit hash, or None if unknown.

is_controller_running()[source]

Check whether the controller container is running.

Return type:

bool

Returns:

True if the container exists and is running, otherwise False.

is_image_available(image_tag)[source]

Check whether a Docker image tag exists locally.

Parameters:

image_tag (str) – Full Docker image tag to look up (e.g. teg-controller-v1.0.0:latest).

Return type:

bool

Returns:

True if the image tag exists locally, otherwise False.

last_launched_version: str | None = None
prune_containers()[source]

Remove stopped containers to keep the Docker environment clean.

Return type:

None

set_last_launched_controller_version(last_launched_controller_version)[source]

Persist the last launched controller version.

Parameters:

last_launched_controller_version (str) – Git tag or commit hash to store.

start_controller(version_to_launch)[source]

Start the controller container for a given version.

If the requested version is already running, the method is a no-op. If the required image is not available locally, the controller repository is fetched, reset to the referenced commit, and a Docker image is built from the local Docker context.

During the update lifecycle, the method publishes OTA-related states via MQTT (e.g. DOWNLOADING, DOWNLOADED, UPDATING, UPDATED).

Parameters:

version_to_launch (str) – Git tag (e.g. v1.0.0) or full commit hash.

Return type:

None

Returns:

None

start_controller_safely(version_to_launch)[source]

Start the controller and suppress unexpected exceptions.

Parameters:

version_to_launch (str) – Git tag or commit hash to run.

stop_controller()[source]

Stop the running controller container (if any).

This stores the currently running controller version as the last-launched version before stopping the container.

Return type:

None

Returns:

None

Git Client

Git repository access utilities for the Edge Gateway controller.

This module provides the GatewayGitClient, a lightweight wrapper around the local Git repository of the Edge Gateway controller.

It is primarily used during controller software updates (e.g. OTA updates) to resolve version identifiers, fetch updates from the remote repository, and reset the working tree to a specific Git tag or commit hash.

Responsibilities

  • Resolve Git tags to commit hashes.

  • Verify the existence of commit hashes or tags.

  • Query the currently checked-out commit.

  • Fetch updates from the remote repository.

  • Reset the controller repository to a specific commit in a reproducible way.

Notes

  • All Git commands are executed via subprocess calls.

  • The client operates on the controller repository path defined by CONTROLLER_GIT_PATH.

  • The class is implemented as a singleton to avoid repeated initialization.

class modules.git_client.GatewayGitClient[source]

Bases: object

Access and manage the local controller Git repository.

This class encapsulates all Git interactions required by the Edge Gateway to manage controller versions during updates. It provides helper methods to resolve tags, validate commit hashes, and safely reset the repository state.

The class follows a singleton pattern to ensure that Git operations are coordinated across the gateway process.

execute_fetch()[source]

Fetch updates from the remote Git repository.

Return type:

bool

Returns:

True if the fetch operation succeeded, otherwise False.

execute_reset_to_commit(commit_hash)[source]

Reset the controller repository to a specific commit.

This performs a forced checkout, hard reset, and clean to ensure a reproducible repository state.

Parameters:

commit_hash (str) – Commit hash to reset to.

Return type:

bool

Returns:

True if the reset succeeded, otherwise False.

get_commit_for_tag(tag)[source]

Return the commit hash associated with a Git tag.

Parameters:

tag – Git tag name.

Return type:

Optional[str]

Returns:

Commit hash for the tag, or None if the tag does not exist.

get_commit_from_hash_or_tag(hash_or_tag)[source]

Resolve a Git tag or commit hash to a commit hash.

Parameters:

hash_or_tag (str) – Git tag name or commit hash.

Return type:

Optional[str]

Returns:

Commit hash if resolvable, otherwise None.

get_current_commit()[source]

Return the currently checked-out Git commit.

Return type:

Optional[str]

Returns:

Commit hash string, or None if it cannot be determined.

verify_commit_hash_or_tag_exists(commit_hash)[source]

Verify that a commit hash or tag exists in the repository.

Parameters:

commit_hash (str) – Commit hash or tag to verify.

Return type:

bool

Returns:

True if the reference exists and points to a commit, otherwise False.

OTA Message Handling

Handle OTA software update notifications received via MQTT.

This module processes ThingsBoard OTA-related attribute updates (sw_title, sw_version and legacy sf_* keys) and triggers controller software updates on the Edge Gateway when a new version is available.

It represents the decision and orchestration stage of the OTA workflow: - Detect whether a software update is available. - Compare the requested version against the currently running controller. - Trigger a safe controller restart/update via the Docker client. - Record the last successfully launched controller version.

Notes

  • The actual Docker image build and container lifecycle are handled by modules.docker_client.GatewayDockerClient.

  • OTA state reporting (sw_state) is published by the Docker client during the update lifecycle.

on_mqtt_msg.check_for_ota_updates.on_msg_check_for_ota_update(msg_payload)[source]

Process an incoming OTA update notification.

Parameters:

msg_payload (Optional[Any]) – MQTT message payload containing OTA-related attributes.

Return type:

bool

Returns:

True if the message was handled as an OTA update notification, False otherwise.

Controller Supervision

Controller restart watchdog for the Edge Gateway.

This module implements a lightweight watchdog that ensures the controller Docker container is running. If the controller is not running, it attempts to restart it using the last successfully launched controller version.

To avoid rapid restart loops, restarts are rate-limited and use an exponential backoff strategy. If no previous version is known, the watchdog requests OTA version information from ThingsBoard and reports a FAILED software state.

Notes

  • Controller lifecycle operations are executed via modules.docker_client.GatewayDockerClient.

  • OTA software state reporting is published via modules.mqtt.GatewayMqttClient.

utils.controller_restart.restart_controller_if_needed()[source]

Restart the controller container if it is not running.

The watchdog checks whether the controller container is running. If it is not, it waits briefly and attempts to restart it using the last launched version. Restart attempts are rate-limited and use exponential backoff to avoid repeated rapid restarts.

Return type:

bool

Returns:

True if the watchdog performed an action that should delay or influence the main loop (restart attempt, OTA request), otherwise False.