Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fishwaldo/esp_ghota

esp32 OTA Component to update firmware from Github Releases
https://github.com/fishwaldo/esp_ghota

esp esp-idf esp32 ota ota-firmware-updates

Last synced: 1 day ago
JSON representation

esp32 OTA Component to update firmware from Github Releases

Awesome Lists containing this project

README

        

# GITHUB OTA for ESP32 devices

Automate your OTA and CI/CD pipeline with Github Actions to update your ESP32 devices in the field direct from github releases

## Features
* Uses the esp_htps_ota library under the hood to update firmware images
* Can also update spiffs/littlefs/fatfs partitions
* Uses SemVer to compare versions and only update if a newer version is available
* Plays nicely with App rollback and anti-rollback features of the esp-idf bootloader
* Download firmware and partitiion images from the github release page directly
* Supports multiple devices with different firmware images
* Includes a sample Github Actions that builds and releases images when a new tag is pushed
* Updates can be triggered manually, or via a interval timer
* Uses a streaming JSON parser for to reduce memory usage (Github API responses can be huge)
* Supports Private Repositories (Github API token required*)
* Supports Github Enterprise
* Supports Github Personal Access Tokens to overcome Github API Ratelimits
* Sends progress of Updates via the esp_event_loop

Note:
You should be careful with your GitHub PAT and putting it in the source code. I would suggest that you store the PAT in NVS, and the user enters it when running, as otherwise the PAT would be easily extractable from your firmware images.

## Usage

### esp-idf via Espressif Component Registry:

```bash
idf.py add-dependency Fishwaldo/ghota^1.0.0
```

#### Platform IO Registry:

add this to your platform.ini file:

```ini
lib_deps =
fishwaldo/ghota@^1.0.0
```

You also need to copy the contents of [Kconfig](Kconfig) into your project's Kconfig file, and run pio run -t menuconfig to configure the component.

#### API Documentation:

More details on the API are available [here](https://esp-github-ota.readthedocs.io/en/latest/index.html)

## Example
After Initilizing Network Access, Start a timer to periodically check for new releases:

(if you a reading this from https://components.espressif.com, please note that this website munges the examples below. Please refer to https://github.com/Fishwaldo/esp_ghota for the correct examples)

```c
ghota_config_t ghconfig = {
.filenamematch = "GithubOTA-esp32.bin", // Glob Pattern to match against the Firmware file
.storagenamematch = "storage-esp32.bin", // Glob Pattern to match against the storage firmware file
.storagepartitionname = "storage", // Update the storage partition
.updateInterval = 60, // Check for updates every 60 minuites
};
ghota_client_handle_t *ghota_client = ghota_init(&ghconfig);
if (ghota_client == NULL) {
ESP_LOGE(TAG, "ghota_client_init failed");
return;
}
esp_event_handler_register(GHOTA_EVENTS, ESP_EVENT_ANY_ID, &ghota_event_callback, ghota_client); // Register a handler to get updates on progress
ESP_ERROR_CHECK(ghota_start_update_timer(ghota_client)); // Start the timer to check for updates
```

Manually Checking for updates:

```c
ghota_config_t ghconfig = {
.filenamematch = "GithubOTA-esp32.bin",
.storagenamematch = "storage-esp32.bin",
.storagepartitionname = "storage",
.updateInterval = 60,
};
ghota_client_handle_t *ghota_client = ghota_init(&ghconfig);
if (ghota_client == NULL) {
ESP_LOGE(TAG, "ghota_client_init failed");
return;
}
esp_event_handler_register(GHOTA_EVENTS, ESP_EVENT_ANY_ID, &ghota_event_callback, ghota_client);
ESP_ERROR_CHECK(ghota_check(ghota_client));

semver_t *cur = ghota_get_current_version(ghota_client);
if (cur) {
ESP_LOGI(TAG, "Current version: %d.%d.%d", cur->major, cur->minor, cur->patch);
semver_free(cur);
}

semver_t *new = ghota_get_latest_version(ghota_client);
if (new) {
ESP_LOGI(TAG, "New version: %d.%d.%d", new->major, new->minor, new->patch);
semver_free(new);
}
ESP_ERROR_CHECK(ghota_update(ghota_client));
ESP_ERROR_CHECK(ghota_free(ghota_client));
```

## Configuration
The following configuration options are available:

* config.filenamematch <- Glob pattern to match against the firmware file from the Github Releases page.
* config.storagenamematch <- Glob pattern to match against the storage file from the Github Releases page.
* config.storagepartitionname <- Name of the storage partition to update (as defined in partitions.csv)
* config.hostname <- Hostname of the Github API (default: api.github.com)
* config.orgname <- Name of the Github User or Organization
* config.reponame <- Name of the Github Repository
* config.updateInterval <- Interval in minutes to check for updates

## Github Actions
The Github Actions included in this repository can be used to build and release firmware images to Github Releases.
This is a good way to automate your CI/CD pipeline, and update your devices in the field.
In this example, we build two variants of the Firmware - on for a ESP32 and one for a ESP32-S3 device
Using the filenamematch and storagenamematch config options, we can match against the correct firmware image for the device.

```yaml
on:
push:
pull_request:
branches: [master]

permissions:
contents: write
name: Build
jobs:
build:
strategy:
fail-fast: true
matrix:
targets: [esp32, esp32s3]
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: esp-idf build
uses: Fishwaldo/[email protected]
with:
esp_idf_version: v4.4.3
target: ${{ matrix.targets }}
path: 'examples/esp_ghota_example'
- name: Rename artifact
run: |
ls -lah
cp examples/esp_ghota_example/build/esp_ghota_example.bin esp_ghota_example-${{ matrix.targets }}.bin
cp examples/esp_ghota_example/build/storage.bin storage-${{ matrix.targets }}.bin
- name: Archive Firmware Files
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.targets }}-firmware
path: "*-${{ matrix.targets }}.bin"

release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download Firmware Files
uses: actions/download-artifact@v2
with:
path: release
- name: Release Firmware
uses: ncipollo/release-action@v1
if: startsWith(github.ref, 'refs/tags/')
with:
artifacts: release/*/*.bin
generateReleaseNotes: true
allowUpdates: true
token: ${{ secrets.GITHUB_TOKEN }}
```