feat: Add autodl for Hue (partial) (#663)

This commit is contained in:
Nerivec
2025-02-01 21:52:10 +01:00
committed by GitHub
parent 7890e5f5de
commit 482ecc98ef
6 changed files with 121 additions and 12 deletions
+11 -11
View File
@@ -78,18 +78,18 @@ Any field not in this list will be ignored. Any field not matching the required
###### To place restrictions ###### To place restrictions
- "force": boolean _(ignore `fileVersion` and always present as 'available')_ - "force": boolean _(ignore `fileVersion` and always present as 'available')_
- "hardwareVersionMax": number - "hardwareVersionMax": number
- "hardwareVersionMin": number - "hardwareVersionMin": number
- "manufacturerName": array of strings _(target only devices with one of these manufacturer names)_ - "manufacturerName": array of strings _(target only devices with one of these manufacturer names)_
- "maxFileVersion": number _(target only devices with this version or below)_ - "maxFileVersion": number _(target only devices with this version or below)_
- "minFileVersion": number _(target only devices with this version or above)_ - "minFileVersion": number _(target only devices with this version or above)_
- "modelId": string _(target only devices with this model ID)_ - "modelId": string _(target only devices with this model ID)_
###### For record purpose ###### For record purpose
- "originalUrl": string - "originalUrl": string
- "releaseNotes": string - "releaseNotes": string
If the pull request contains multiple files, the metadata is added for all files. If some files require different metadata, add the matching `fileName` to the JSON using an encompassing array instead. It will be used to assign metadata as directed. If the pull request contains multiple files, the metadata is added for all files. If some files require different metadata, add the matching `fileName` to the JSON using an encompassing array instead. It will be used to assign metadata as directed.
@@ -114,8 +114,8 @@ Example:
### Notes for maintainers & developers ### Notes for maintainers & developers
- `images` and `index.json` contain added (PR or auto download) "upgrade" images. - `images` and `index.json` contain added (PR or auto download) "upgrade" images.
- `images1` and `index1.json` contain automatically archived "downgrade" images (automatically moved from `images`/`index.json` after a merged PR introduced a newer version, or during auto download). - `images1` and `index1.json` contain automatically archived "downgrade" images (automatically moved from `images`/`index.json` after a merged PR introduced a newer version, or during auto download).
If a manual modification of the manifests is necessary, it should be done in a PR that does not trigger the `update_ota_pr` workflow (no changes in `images/**` directory). As a last resort, the label `ignore-ota-workflow` can be added to prevent the workflow from running. If a manual modification of the manifests is necessary, it should be done in a PR that does not trigger the `update_ota_pr` workflow (no changes in `images/**` directory). As a last resort, the label `ignore-ota-workflow` can be added to prevent the workflow from running.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "zigbee-ota", "name": "zigbee-ota",
"version": "1.1.1", "version": "1.2.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/Koenkk/zigbee-OTA.git" "url": "git+https://github.com/Koenkk/zigbee-OTA.git"
+105
View File
@@ -0,0 +1,105 @@
import {getJson, getLatestImage, readCacheJson, writeCacheJson} from '../common.js';
import {processFirmwareImage} from '../process_firmware_image.js';
type ImageJson = {
createdAt: string;
updatedAt: string;
fileSize: number;
md5: string;
binaryUrl: string;
version: number;
versionName: string;
releaseNotes: string;
};
type PageJson = {updates: ImageJson[]};
const NAME = 'Hue';
const BASE_URL = 'https://firmware.meethue.com/v1/checkupdate?version=0&deviceTypeId=';
const DEVICE_TYPE_IDS: string[] = [
'100b-111',
'100b-112',
// '100b-113',
'100b-114',
'100b-115',
// '100b-116',
'100b-117',
'100b-118',
// '100b-119',
'100b-11a',
// '100b-11b',
// '100b-11c',
'100b-11d',
'100b-11e',
'100b-11f',
'100b-120',
// '100b-121',
// '100b-122',
'100b-123',
// '100b-124',
'100b-125',
// '100b-126',
'100b-127',
// '100b-128',
'100b-129',
// '100b-12a',
// '100b-12b',
// '100b-12c',
// '100b-12d',
// '100b-12e',
// '100b-12f',
];
function sortByVersion(a: ImageJson, b: ImageJson): number {
return a.version < b.version ? -1 : a.version > b.version ? 1 : 0;
}
function isDifferent(newData: PageJson, cachedData?: PageJson): boolean {
return (
Boolean(process.env.IGNORE_CACHE) ||
!cachedData?.updates.length ||
getLatestImage(cachedData.updates, sortByVersion)?.version !== getLatestImage(newData.updates, sortByVersion)?.version
);
}
export async function writeCache(): Promise<void> {
for (const deviceTypeId of DEVICE_TYPE_IDS) {
const url = `${BASE_URL}${deviceTypeId}`;
const page = await getJson<PageJson>(NAME, url);
if (page?.updates.length) {
writeCacheJson(`${NAME}_${deviceTypeId}`, page);
}
}
}
export async function download(): Promise<void> {
for (const deviceTypeId of DEVICE_TYPE_IDS) {
const logPrefix = `[${NAME}:${deviceTypeId}]`;
const url = `${BASE_URL}${deviceTypeId}`;
const page = await getJson<PageJson>(NAME, url);
if (!page?.updates.length) {
console.error(`${logPrefix} No image data.`);
continue;
}
const cacheFileName = `${NAME}_${deviceTypeId}`;
if (!isDifferent(page, readCacheJson(cacheFileName))) {
console.log(`${logPrefix} No change from last run.`);
continue;
}
writeCacheJson(cacheFileName, page);
const image = getLatestImage(page.updates, sortByVersion);
if (!image) {
continue;
}
const firmwareFileName = image.binaryUrl.split('/').pop()!;
await processFirmwareImage(NAME, firmwareFileName, image.binaryUrl, {releaseNotes: image.releaseNotes || undefined});
}
}
+1
View File
@@ -31,6 +31,7 @@ export const PR_ARTIFACT_NUMBER_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_NUMBER_
*/ */
export const ALL_AUTODL_MANUFACTURERS = [ export const ALL_AUTODL_MANUFACTURERS = [
'gammatroniques', 'gammatroniques',
'hue',
'ikea_new', 'ikea_new',
'ikea', 'ikea',
'inovelli', 'inovelli',
+2
View File
@@ -462,6 +462,7 @@ describe('Github Workflow: Re-Process All Images', () => {
ok: fetchReturnedStatus.ok, ok: fetchReturnedStatus.ok,
status: fetchReturnedStatus.status, status: fetchReturnedStatus.status,
body: fetchReturnedStatus.body, body: fetchReturnedStatus.body,
// @ts-expect-error Buffer <> ArrayBuffer (props not used)
arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath((input as string).split('/').pop()!)), arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath((input as string).split('/').pop()!)),
}; };
}, },
@@ -762,6 +763,7 @@ describe('Github Workflow: Re-Process All Images', () => {
ok: fetchReturnedStatus.ok, ok: fetchReturnedStatus.ok,
status: fetchReturnedStatus.status, status: fetchReturnedStatus.status,
body: fetchReturnedStatus.body, body: fetchReturnedStatus.body,
// @ts-expect-error Buffer <> ArrayBuffer (props not used)
arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath(fileName)), arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath(fileName)),
}; };
}, },
+1
View File
@@ -134,6 +134,7 @@ describe('Process Firmware Image', () => {
ok: fetchReturnedStatus.ok, ok: fetchReturnedStatus.ok,
status: fetchReturnedStatus.status, status: fetchReturnedStatus.status,
body: fetchReturnedStatus.body, body: fetchReturnedStatus.body,
// @ts-expect-error Buffer <> ArrayBuffer (props not used)
arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath(input as string)), arrayBuffer: (): ArrayBuffer => readFileSync(getImageOriginalDirPath(input as string)),
}; };
}, },