Revert Inovelli GitHub firmware discovery (#1310)

This commit is contained in:
Jamie Magee
2026-09-19 08:06:14 +02:00
committed by GitHub
parent 74d8e7e3ce
commit c57ca55743
3 changed files with 5 additions and 164 deletions
-1
View File
@@ -1 +0,0 @@
[{"path":"Blue-Series/Zigbee/VZM30-SN-Switch/Beta/1.01/VZM30-SN_1.01.ota","sha":"5a6ccf5613694c477d612bb08524fcfcb20f7356"},{"path":"Blue-Series/Zigbee/VZM30-SN-Switch/Beta/1.02/VZM30-SN_1.02.ota","sha":"cf9799b5e0908bd32545d026a929721f78140196"},{"path":"Blue-Series/Zigbee/VZM30-SN-Switch/Production/1.00/VZM30-SN_1.00.ota","sha":"79017bc57bc70ec54bd7888386881b70cef03b67"},{"path":"Blue-Series/Zigbee/VZM30-SN-Switch/Production/1.01/VZM30-SN_1.01.ota","sha":"5a6ccf5613694c477d612bb08524fcfcb20f7356"},{"path":"Blue-Series/Zigbee/VZM30-SN-Switch/Production/1.03/VZM30-SN_1.03.ota","sha":"c0d092babe2bbcf6fa95b7b648241901276f7e74"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.02/VZM31-SN_2.02-Beta.ota","sha":"309f2f385aeac8b1a8fbaf0112d45567631363f7"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.03/VZM31-SN_2.03-Beta.ota","sha":"a62ff2e295fbdb6b091ae3ae35ccb9f7a4d7417f"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.05/VZM31-SN_2.05-Beta.ota","sha":"389240901e0b969331ada67a2ece4382d8b9e670"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.06/VZM31-SN_2.06-Beta.ota","sha":"43c964e65f87c20bfcf7a109ab6afd35652723f0"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.07/VZM31-SN_2.07-Beta.ota","sha":"75e5226ead7d0e585ed214bbf3c1c1d98986d233"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.10/VZM31-SN_2.10-Beta.ota","sha":"a1291243f9730f88f5bf21d4c17951ce9adfebad"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.12/VZM31-SN_2.12-Beta.ota","sha":"c7c5aa1f87b7989f6b7cdf178b3ba214bbb73fcd"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.13/VZM31-SN_2.13-Beta.ota","sha":"e94a9fb1f01156b52c0da9b1e565b0536dcc5c3c"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.14/VZM31-SN_2.14-Beta.ota","sha":"f31223f659772846722ffe93ff2f32d74f9ebd82"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/2.17/VZM31-SN_2.17-Beta.ota","sha":"4610130eaef2990608e2cdb00a6094079473acc7"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Beta/3.07/VZM31-SN_ota_V307_20260326.ota","sha":"772a94473c0cfbf7fe10134da5ead7a5e8890ccb"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Production/2.08/VZM31-SN_2.08-Production.ota","sha":"470caefbc7e23f16a93b15cab391ba9d6be30250"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Production/2.11/VZM31-SN_2.11-Production.ota","sha":"2e11ae38fb8818f6e417711b86bbddaf08817896"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Production/2.15/VZM31-SN_2.15-Production.ota","sha":"a01c72c10f67dda0ebd8c5d0ae5c36c64b165b48"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Production/2.18/VZM31-SN_2.18-Production.ota","sha":"af2dc93ee033ed301208fbbad3fa1768390dcff8"},{"path":"Blue-Series/Zigbee/VZM31-SN-2-1-Switch/Production/3.04/VZM31-SN_3.04.ota","sha":"4804f29ee619f64d9e6dad7735f7444a005beec3"},{"path":"Blue-Series/Zigbee/VZM32-SN-MMWave-Switch/Beta/1.01/VZM32-SN_1.01.ota","sha":"8a54df449a31ba23d7a603947e9c241411496f06"},{"path":"Blue-Series/Zigbee/VZM32-SN-MMWave-Switch/Beta/1.02/vzm32-sn_mmWave_OTA_V102_20260330.ota","sha":"4766df93ec971556c6840a63db24dab530a80aec"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Beta/1.00/VZM35-SN_1.00-Beta.ota","sha":"64762ddcc442cf457f62c1c0c2dae2e4524f74f4"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Beta/1.02/VZM35-SN_1.02-Beta.ota","sha":"839a5cff006c0ffaed88b3dd18d3931f18917c21"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Beta/1.05/VZM35-SN_1.05.ota","sha":"f6450ef1c721cf95e54cd9da5f377dd8218b193e"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Beta/1.07/VZM35-SN_1.07.ota","sha":"4a5f8e88cfebdc9be97a23c467fcbcd4f2231492"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Production/1.04/VZM35-SN_1.04-Production.ota","sha":"abc0afc3bcbe4a5db4d410da27c221fcef74aa4e"},{"path":"Blue-Series/Zigbee/VZM35-SN-Fan-Switch/Production/1.08/VZM35-SN_1.08.ota","sha":"2d5986ec858cd12bc7d3d71a000a45faf64a1376"},{"path":"Blue-Series/Zigbee/VZM36-Fan-Plus-Light/Beta/0.04/VZM36_0.04.ota","sha":"9c756944ec73bfd0eb1247b7d0ba1f017736599b"},{"path":"Blue-Series/Zigbee/VZM36-Fan-Plus-Light/Beta/1.01/VZM36_1.01-Beta.ota","sha":"bb191e9730bdaacff206e87c343f76ac08faa25e"}]
+5 -86
View File
@@ -1,5 +1,5 @@
import {getJson, getLatestImage, readCacheJson, writeCacheJson} from "../common.js";
import {ProcessFirmwareImageStatus, processFirmwareImage} from "../process_firmware_image.js";
import {processFirmwareImage} from "../process_firmware_image.js";
type DeviceImageJson = {
version: string;
@@ -11,27 +11,10 @@ type DeviceImageJson = {
type ModelsJson = {
[k: string]: DeviceImageJson[];
};
type GitHubTreeEntryJson = {
path: string;
sha: string;
type: "blob" | "commit" | "tree";
};
type GitHubTreeJson = {
tree: GitHubTreeEntryJson[];
truncated: boolean;
};
type GitHubFirmwareFile = {
path: string;
sha: string;
};
const NAME = "Inovelli";
const LOG_PREFIX = `[${NAME}]`;
const LEGACY_FIRMWARE_URL = "https://files.inovelli.com/firmware/firmware.json";
const GITHUB_FIRMWARE_TREE_URL = "https://api.github.com/repos/InovelliUSA/Firmware/git/trees/main?recursive=1";
const GITHUB_RAW_FIRMWARE_URL = "https://raw.githubusercontent.com/InovelliUSA/Firmware/main/";
const GITHUB_ZIGBEE_PATH_PREFIX = "Blue-Series/Zigbee/";
const GITHUB_CACHE_NAME = `${NAME}GitHub`;
const FIRMWARE_URL = "https://files.inovelli.com/firmware/firmware.json";
function sortByVersion(a: DeviceImageJson, b: DeviceImageJson): number {
const aRadix = a.version.match(/[a-fA-F]/) ? 16 : 10;
@@ -46,55 +29,16 @@ function isDifferent(newData: DeviceImageJson, cachedData?: DeviceImageJson): bo
return Boolean(process.env.IGNORE_CACHE) || !cachedData || cachedData.version !== newData.version;
}
export function getGitHubFirmwareFiles(githubTree: GitHubTreeJson): GitHubFirmwareFile[] {
if (githubTree.truncated) {
throw new Error(`${LOG_PREFIX} GitHub firmware tree is truncated.`);
}
return githubTree.tree
.filter((entry) => entry.type === "blob" && entry.path.startsWith(GITHUB_ZIGBEE_PATH_PREFIX) && entry.path.toLowerCase().endsWith(".ota"))
.map(({path, sha}) => ({path, sha}))
.sort((a, b) => a.path.localeCompare(b.path));
}
export function getChangedGitHubFirmwareFiles(
githubFiles: GitHubFirmwareFile[],
cachedFiles: GitHubFirmwareFile[] = [],
ignoreCache = Boolean(process.env.IGNORE_CACHE),
): GitHubFirmwareFile[] {
if (ignoreCache) {
return githubFiles;
}
const cachedFilesByPath = new Map(cachedFiles.map((file) => [file.path, file.sha]));
return githubFiles.filter((file) => cachedFilesByPath.get(file.path) !== file.sha);
}
export function getGitHubFirmwareUrl(filePath: string): string {
return GITHUB_RAW_FIRMWARE_URL + filePath.split("/").map(encodeURIComponent).join("/");
}
export async function writeCache(): Promise<void> {
const [models, githubTree] = await Promise.all([
getJson<ModelsJson>(NAME, LEGACY_FIRMWARE_URL),
getJson<GitHubTreeJson>(NAME, GITHUB_FIRMWARE_TREE_URL),
]);
const models = await getJson<ModelsJson>(NAME, FIRMWARE_URL);
if (models) {
writeCacheJson(NAME, models);
}
if (githubTree) {
writeCacheJson(GITHUB_CACHE_NAME, getGitHubFirmwareFiles(githubTree));
}
}
export async function download(): Promise<void> {
const [models, githubTree] = await Promise.all([
getJson<ModelsJson>(NAME, LEGACY_FIRMWARE_URL),
getJson<GitHubTreeJson>(NAME, GITHUB_FIRMWARE_TREE_URL),
]);
const models = await getJson<ModelsJson>(NAME, FIRMWARE_URL);
if (models) {
const cachedData = readCacheJson<ModelsJson>(NAME);
@@ -123,31 +67,6 @@ export async function download(): Promise<void> {
writeCacheJson(NAME, models);
} else {
console.error(`${LOG_PREFIX} No legacy image data.`);
}
if (githubTree) {
const githubFiles = getGitHubFirmwareFiles(githubTree);
const cachedFiles = readCacheJson<GitHubFirmwareFile[]>(GITHUB_CACHE_NAME);
const changedFiles = getChangedGitHubFirmwareFiles(githubFiles, cachedFiles);
const processedFiles = new Map(cachedFiles?.map((file) => [file.path, file]));
for (const file of changedFiles) {
const firmwareFileName = file.path.split("/").pop()!;
const status = await processFirmwareImage(NAME, firmwareFileName, getGitHubFirmwareUrl(file.path));
if (status === ProcessFirmwareImageStatus.Success) {
processedFiles.set(file.path, file);
} else {
processedFiles.delete(file.path);
}
}
writeCacheJson(
GITHUB_CACHE_NAME,
githubFiles.filter((file) => processedFiles.get(file.path)?.sha === file.sha),
);
} else {
console.error(`${LOG_PREFIX} No GitHub image data.`);
console.error(`${LOG_PREFIX} No image data.`);
}
}
-77
View File
@@ -1,77 +0,0 @@
import {describe, expect, it} from "vitest";
import {getChangedGitHubFirmwareFiles, getGitHubFirmwareFiles, getGitHubFirmwareUrl} from "../src/autodl/inovelli.js";
describe("Inovelli autodl", () => {
it("finds Zigbee OTA files in the GitHub tree", () => {
const files = getGitHubFirmwareFiles({
truncated: false,
tree: [
{
path: "Blue-Series/Zigbee/VZM31/Production/3.04/VZM31-SN_3.04.ota",
sha: "production",
type: "blob",
},
{
path: "Blue-Series/Zigbee/VZM31/Beta/3.07/VZM31-SN_3.07.OTA",
sha: "beta",
type: "blob",
},
{
path: "Blue-Series/Zigbee/VZM31/README.md",
sha: "readme",
type: "blob",
},
{
path: "Red-Series/Z-Wave/VZW31/VZW31-SN_2.04.ota",
sha: "z-wave",
type: "blob",
},
{
path: "Blue-Series/Zigbee/VZM31/Beta",
sha: "tree",
type: "tree",
},
],
});
expect(files).toStrictEqual([
{
path: "Blue-Series/Zigbee/VZM31/Beta/3.07/VZM31-SN_3.07.OTA",
sha: "beta",
},
{
path: "Blue-Series/Zigbee/VZM31/Production/3.04/VZM31-SN_3.04.ota",
sha: "production",
},
]);
});
it("rejects a truncated GitHub tree", () => {
expect(() => getGitHubFirmwareFiles({truncated: true, tree: []})).toThrow("GitHub firmware tree is truncated");
});
it("finds new and changed GitHub firmware files", () => {
const files = [
{path: "changed.ota", sha: "new"},
{path: "new.ota", sha: "new"},
{path: "unchanged.ota", sha: "same"},
];
const cachedFiles = [
{path: "changed.ota", sha: "old"},
{path: "removed.ota", sha: "old"},
{path: "unchanged.ota", sha: "same"},
];
expect(getChangedGitHubFirmwareFiles(files, cachedFiles, false)).toStrictEqual([
{path: "changed.ota", sha: "new"},
{path: "new.ota", sha: "new"},
]);
expect(getChangedGitHubFirmwareFiles(files, cachedFiles, true)).toStrictEqual(files);
});
it("builds an encoded raw GitHub URL", () => {
expect(getGitHubFirmwareUrl("Blue-Series/Zigbee/Fan Plus/Firmware 1.0.ota")).toBe(
"https://raw.githubusercontent.com/InovelliUSA/Firmware/main/Blue-Series/Zigbee/Fan%20Plus/Firmware%201.0.ota",
);
});
});