Skip to content

Commit

Permalink
Copy ota binaries and build ota section of manifest (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesserockz authored Jun 20, 2024
1 parent c9782d7 commit 77e3617
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
venv
*.bin
*.json
config/
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,43 @@

![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/esphome/build-action)


This action takes a yaml file for an ESPHome device and will compile and output
the build firmware file and a partial `manifest.json` file that can be used to flash
the build firmware file and a partial `manifest.json` file that can be used to flash
a device via [ESP Web Tools](https://esphome.github.io/esp-web-tools).

## Example usage

```yaml

uses: esphome/build-action@v1
with:
yaml_file: my_configuration.yaml

```
This action is used by the [ESPHome publish workflow](https://github.com/esphome/workflows/blob/main/.github/workflows/publish.yml) that is used to compile firmware and publish simple GitHub pages sites for projects.
## Inputs
Name | Default | Description
------------|---------------|------------
`yaml_file` | _None_ | The YAML file to be compiled.
`version` | `latest` | The ESPHome version to build using.
`platform` | `linux/amd64` | The docker platform to use during build. (linux/amd64, linux/arm64, linux/arm/v7)
`cache` | `false` | Whether to cache the build folder.
| Name | Default | Description |
| ----------------- | ------------- | --------------------------------------------------------------------------------- |
| `yaml_file` | _None_ | The YAML file to be compiled. |
| `version` | `latest` | The ESPHome version to build using. |
| `platform` | `linux/amd64` | The docker platform to use during build. (linux/amd64, linux/arm64, linux/arm/v7) |
| `cache` | `false` | Whether to cache the build folder. |
| `release_summary` | _None_ | A small summary of the release that will be added to the manifest file. |
| `release_url` | _None_ | A URL to the release page that will be added to the manifest file. |

## Outputs

Name | Description
----------|------------
`name` | The name of the device in yaml with the platform (eg. ESP32 or ESP8266) appended.
`version` | The ESPHome version used during build.
| Name | Description |
| --------------- | --------------------------------------------------------------------------------- |
| `name` | The name of the device in yaml with the platform (eg. ESP32 or ESP8266) appended. |
| `version` | The ESPHome version used during build. |
| `original_name` | The original name of the device in yaml. |

## Output files

This action will output a folder named with the output `name` and will contain two files, `{name}.bin` and `manifest.json`.
This action will output a folder named with the output `name` and will contain three files:

- `manifest.json` - This goes into the `builds` section of an esp-web-tools manifest.json.
- `{name}.factory.bin` - The firmware to be flashed with esp-web-tools.
- `{name}.ota.bin` - The firmware that can be flashed over-the-air to the device using the [Managed Updated via HTTP Request](https://esphome.io/components/update/http_request).
14 changes: 13 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,25 @@ inputs:
description: Cache build directory
required: false
default: false
release_summary:
description: Release summary
required: false
default: ""
release_url:
description: Release URL
required: false
default: ""

outputs:
name:
description: Name of device extracted from configuration
description: Name of device extracted from configuration with the platform appended
value: ${{ steps.build-step.outputs.name }}
version:
description: ESPHome version
value: ${{ steps.build-step.outputs.esphome-version }}
original_name:
description: Original name of device extracted from configuration
value: ${{ steps.build-step.outputs.original_name }}

runs:
using: composite
Expand Down Expand Up @@ -79,6 +90,7 @@ runs:
-v "$(pwd)":"/github/workspace" -v "$HOME:$HOME" \
--user $(id -u):$(id -g) \
-e INPUT_YAML_FILE -e HOME \
-e INPUT_RELEASE_SUMMARY -e INPUT_RELEASE_URL \
-e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY \
-e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER \
-e GITHUB_ACTOR -e GITHUB_OUTPUT \
Expand Down
49 changes: 38 additions & 11 deletions entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pathlib import Path
import re
import yaml
import hashlib


ESP32_CHIP_FAMILIES = {
Expand Down Expand Up @@ -62,6 +63,9 @@

name = config["esphome"]["name"]

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as github_output:
print(f"original_name={name}", file=github_output)

platform = ""
if "esp32" in config:
platform = config["esp32"]["variant"].lower()
Expand Down Expand Up @@ -91,48 +95,71 @@

elf = Path(data["prog_path"])
if platform == "rp2040":
source_bin = elf.with_name("firmware.uf2")
dest_bin = file_base / f"{name}.uf2"
source_factory_bin = elf.with_name("firmware.uf2")
dest_factory_bin = file_base / f"{name}.uf2"
else:
source_bin = elf.with_name("firmware.factory.bin")
dest_bin = file_base / f"{name}.bin"
source_factory_bin = elf.with_name("firmware.factory.bin")
dest_factory_bin = file_base / f"{name}.factory.bin"

source_ota_bin = elf.with_name("firmware.ota.bin")
dest_ota_bin = file_base / f"{name}.ota.bin"

print("::endgroup::")

print("::group::Copy firmware file(s) to folder")
file_base.mkdir(parents=True, exist_ok=True)

shutil.copyfile(source_bin, dest_bin)
shutil.copyfile(source_factory_bin, dest_factory_bin)
shutil.copyfile(source_ota_bin, dest_ota_bin)

print("::endgroup::")

if platform == "rp2040":
sys.exit(0)

print("::group::Write manifest.json file")


chip_family = None
define: str
has_factory_part = False
for define in data["defines"]:
if define == "USE_ESP8266":
chip_family = "ESP8266"
has_factory_part = True
break
if define == "USE_RP2040":
chip_family = "RP2040"
break
if m := re.match(r"USE_ESP32_VARIANT_(\w+)", define):
chip_family = m.group(1)
if chip_family not in ESP32_CHIP_FAMILIES:
raise Exception(f"Unsupported chip family: {chip_family}")

chip_family = ESP32_CHIP_FAMILIES[chip_family]
has_factory_part = True
break

ota_md5 = hashlib.md5(open(dest_ota_bin, "rb").read()).hexdigest()

manifest = {
"chipFamily": chip_family,
"parts": [
"ota": {
"path": str(dest_ota_bin),
"md5": ota_md5,
},
}

if release_summary := os.environ.get("INPUT_RELEASE_SUMMARY"):
manifest["ota"]["summary"] = release_summary
if release_url := os.environ.get("INPUT_RELEASE_URL"):
manifest["ota"]["release_url"] = release_url

if has_factory_part:
manifest["parts"] = [
{
"path": str(dest_bin),
"path": str(dest_factory_bin),
"offset": 0x00,
}
],
}
]

print("Writing manifest file:")
print(json.dumps(manifest, indent=2))
Expand Down

0 comments on commit 77e3617

Please sign in to comment.