Documentation

This commit is contained in:
Justin Hammond 2022-11-28 01:13:49 +08:00
parent 2490177c4d
commit 24005abcce
13 changed files with 2945 additions and 12 deletions

View file

@ -19,7 +19,7 @@ jobs:
with:
submodules: 'recursive'
- name: esp-idf build
uses: Fishwaldo/esp-idf-ci-action@v1.1
uses: Fishwaldo/esp-idf-ci-action@v1.2
with:
esp_idf_version: v4.4.3
target: ${{ matrix.targets }}

4
.gitignore vendored
View file

@ -55,3 +55,7 @@ dkms.conf
build/
dependencies.lock
sdkconfig
docs/build
docs/latex
*~

View file

@ -118,14 +118,16 @@ jobs:
with:
submodules: 'recursive'
- name: esp-idf build
uses: espressif/esp-idf-ci-action@v1
uses: Fishwaldo/esp-idf-ci-action@v1.1
with:
esp_idf_version: v4.4
esp_idf_version: v4.4.3
target: ${{ matrix.targets }}
path: 'examples/esp_ghota_example'
- name: Rename artifact
run: |
cp build/GithubOTA.bin GithubOTA-${{ matrix.targets }}.bin
cp build/storage.bin storage-${{ matrix.targets }}.bin
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:

2579
docs/Doxyfile Normal file

File diff suppressed because it is too large Load diff

20
docs/Makefile Normal file
View file

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

151
docs/README.md Normal file
View file

@ -0,0 +1,151 @@
# 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
via the Espressif Component Registry:
```bash
idf.py add-dependency Fishwaldo/ghota^1.0.0
```
## Example
After Initilizing Network Access, Start a timer to periodically check for new releases:
```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: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: v4.4
target: ${{ matrix.targets }}
- name: Rename artifact
run: |
cp build/GithubOTA.bin GithubOTA-${{ matrix.targets }}.bin
cp 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 }}
```

11
docs/api/ghota.rst Normal file
View file

@ -0,0 +1,11 @@
.. _esp_ghota:
Main API
========
esp_ghota.h contains the main API for the library.
API Details
-----------
.. doxygenfile:: esp_ghota.h

12
docs/api/semver.rst Normal file
View file

@ -0,0 +1,12 @@
.. _semver:
semver.h
===========
The Semver support comes from https://github.com/h2non/semver.c
You can use this to compare released and installed versions of the firmware.
consult the above github repo for more information on using the functions defined in this header.
.. doxygenfile:: semver.h

8
docs/changelog.rst Normal file
View file

@ -0,0 +1,8 @@
Recent Changes
==============
Prior to Version 1.0.0, the following changes were made:
.. git_changelog::
:revisions: 500

116
docs/conf.py Normal file
View file

@ -0,0 +1,116 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import os
import re
project = 'Github OTA'
copyright = '2022, Justin Hammond'
author = 'Justin Hammond'
# The full version, including alpha/beta/rc tags.
release = re.sub('^v', '', os.popen('git describe').read().strip())
# The short X.Y version.
version = release
version = "0.0.1"
release = "0.0.1"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.imgmath',
'sphinx.ext.todo',
'breathe',
'sphinx_git',
'myst_parser',
]
# Add any paths that contain templates here, relative to this directory.
# templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
templates_path = ['_templates']
exclude_patterns = []
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
if not on_rtd: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
# html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
import subprocess
subprocess.call('make clean', shell=True)
subprocess.call('doxygen', shell=True)
breathe_projects = { "Github OTA": "build/xml/" }
breathe_default_project = "Github OTA"

27
docs/index.rst Normal file
View file

@ -0,0 +1,27 @@
.. Github OTA documentation master file, created by
sphinx-quickstart on Sun Nov 27 23:58:20 2022.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Github OTA's documentation!
======================================
This documentation is work in progress. Please refer to the [examples](https://github.com/Fishwaldo/esp_ghota/tree/master/examples) directory for working examples
.. toctree::
:maxdepth: 2
:caption: Contents:
../README.md
api/ghota.rst
api/semver.rst
changelog.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

3
docs/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
breathe
sphinx-git
myst-parser

View file

@ -35,13 +35,13 @@ typedef enum
* @brief Github OTA Configuration
*/
typedef struct ghota_config_t {
char filenamematch[CONFIG_MAX_FILENAME_LEN]; /**< Filename to match against on Github indicating this is a firmware file */
char storagenamematch[CONFIG_MAX_FILENAME_LEN]; /**< Filename to match against on Github indicating this is a storage file */
char storagepartitionname[17]; /**< Name of the storage partition to update */
char *hostname; /**< Hostname of the Github server. Defaults to api.github.com*/
char *orgname; /**< Name of the Github organization */
char *reponame; /**< Name of the Github repository */
uint32_t updateInterval; /**< Interval in Minutes to check for updates if using the ghota_start_update_timer function */
char filenamematch[CONFIG_MAX_FILENAME_LEN]; /*!< Filename to match against on Github indicating this is a firmware file */
char storagenamematch[CONFIG_MAX_FILENAME_LEN]; /*!< Filename to match against on Github indicating this is a storage file */
char storagepartitionname[17]; /*!< Name of the storage partition to update */
char *hostname; /*!< Hostname of the Github server. Defaults to api.github.com*/
char *orgname; /*!< Name of the Github organization */
char *reponame; /*!< Name of the Github repository */
uint32_t updateInterval; /*!< Interval in Minutes to check for updates if using the ghota_start_update_timer function */
} ghota_config_t;
typedef struct ghota_client_handle_t ghota_client_handle_t;