mirror of
https://github.com/Koenkk/zigbee-OTA.git
synced 2026-09-29 16:01:25 +00:00
Revert Inovelli GitHub firmware discovery (#1310)
This commit is contained in:
@@ -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
@@ -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.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user