Add posibility to have local OTA index (#10141)

* Add a configuration option to override OTA index file

* Cleanup

* Code review corrections

* Move zigbee_ota_override_index_location to ota section of the configuration file

* Suport both local and remote (HTTP) OTA override index files

* Updates

* updates

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
This commit is contained in:
Oleksandr Masliuchenko 2022-01-04 21:29:17 +02:00 committed by GitHub
parent e88ceeec2e
commit 16842a3e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 1 deletions

View File

@ -3,9 +3,24 @@ import logger from '../util/logger';
import stringify from 'json-stable-stringify-without-jsonify';
import utils from '../util/utils';
import tradfriOTA from 'zigbee-herdsman-converters/lib/ota/tradfri';
import zigbeeOTA from 'zigbee-herdsman-converters/lib/ota/zigbeeOTA';
import Extension from './extension';
import bind from 'bind-decorator';
import Device from '../model/device';
import dataDir from '../util/data';
import * as URI from 'uri-js';
import path from 'path';
function isValidUrl(url: string): boolean {
let parsed;
try {
parsed = URI.parse(url);
} catch (_) {
// istanbul ignore next
return false;
}
return parsed.scheme === 'http' || parsed.scheme === 'https';
}
type UpdateState = 'updating' | 'idle' | 'available';
interface UpdatePayload {
@ -28,6 +43,16 @@ export default class OTAUpdate extends Extension {
tradfriOTA.useTestURL();
}
let overrideOTAIndex = settings.get().ota.zigbee_ota_override_index_location;
if (overrideOTAIndex) {
// If the file name is not a full path, then treat it as a relative to the data directory
if (!isValidUrl(overrideOTAIndex) && !path.isAbsolute(overrideOTAIndex)) {
overrideOTAIndex = dataDir.joinPath(overrideOTAIndex);
}
zigbeeOTA.useIndexOverride(overrideOTAIndex);
}
for (const device of this.zigbee.devices(false)) {
// In case Zigbee2MQTT is restared during an update, progress and remaining values are still in state.
// remove them.

View File

@ -266,7 +266,8 @@ declare global {
},
ota: {
update_check_interval: number,
disable_automatic_update_check: boolean
disable_automatic_update_check: boolean,
zigbee_ota_override_index_location?: string,
},
external_converters: string[],
}

View File

@ -11,3 +11,7 @@ declare module 'zigbee-herdsman-converters/lib/ota/tradfri' {
export function useTestURL(): void;
}
declare module 'zigbee-herdsman-converters/lib/ota/zigbeeOTA' {
export function useIndexOverride(indexFileName: string): void;
}

View File

@ -612,6 +612,13 @@
"title": "Disable automatic update check",
"description": "Zigbee devices may request a firmware update, and do so frequently, causing Zigbee2MQTT to reach out to third party servers. If you disable these device initiated checks, you can still initiate a firmware update check manually.",
"default": false
},
"zigbee_ota_override_index_location": {
"type": "string",
"title": "OTA index override file name",
"requiresRestart": true,
"description": "Location of override OTA index file",
"examples": ["index.json"]
}
}
},

View File

@ -54,6 +54,7 @@
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"source-map-support": "^0.5.21",
"uri-js": "^4.4.1",
"winston": "^3.3.3",
"winston-syslog": "^2.4.4",
"ws": "^8.4.0",

View File

@ -7,10 +7,18 @@ const Controller = require('../lib/controller');
const flushPromises = require('./lib/flushPromises');
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
const stringify = require('json-stable-stringify-without-jsonify');
const zigbeeOTA = require('zigbee-herdsman-converters/lib/ota/zigbeeOTA');
const spyUseIndexOverride = jest.spyOn(zigbeeOTA, 'useIndexOverride');
describe('OTA update', () => {
let controller;
let resetExtension = async () => {
await controller.enableDisableExtension(false, 'OTAUpdate');
await controller.enableDisableExtension(true, 'OTAUpdate');
}
const mockClear = (mapped) => {
mapped.ota.updateToLatest = jest.fn();
mapped.ota.isUpdateAvailable = jest.fn();
@ -453,4 +461,16 @@ describe('OTA update', () => {
await flushPromises();
expect(logger.info).toHaveBeenCalledWith(`Finished update of 'bulb'`);
});
it('Set zigbee_ota_override_index_location', async () => {
settings.set(['ota', 'zigbee_ota_override_index_location'], 'local.index.json');
await resetExtension();
expect(spyUseIndexOverride).toHaveBeenCalledWith(data.mockDir + '/local.index.json');
spyUseIndexOverride.mockClear();
settings.set(['ota', 'zigbee_ota_override_index_location'], 'http://my.site/index.json');
await resetExtension();
expect(spyUseIndexOverride).toHaveBeenCalledWith('http://my.site/index.json');
spyUseIndexOverride.mockClear();
});
});