mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2024-11-15 09:58:45 -07:00
* ota * Bla * Update converters.
This commit is contained in:
parent
99dc214fbe
commit
83291e242e
@ -21,6 +21,7 @@ const ExtensionDeviceAvailability = require('./extension/deviceAvailability');
|
||||
const ExtensionDeviceBind = require('./extension/deviceBind');
|
||||
const ExtensionDeviceReport = require('./extension/deviceReport');
|
||||
const ExtensionDeviceEvent = require('./extension/deviceEvent');
|
||||
const ExtensionOTAUpdate = require('./extension/otaUpdate');
|
||||
|
||||
class Controller {
|
||||
constructor() {
|
||||
@ -45,6 +46,7 @@ class Controller {
|
||||
new ExtensionGroups(this.zigbee, this.mqtt, this.state, this.publishEntityState, this.eventBus),
|
||||
new ExtensionDeviceBind(this.zigbee, this.mqtt, this.state, this.publishEntityState, this.eventBus),
|
||||
new ExtensionDeviceEvent(this.zigbee, this.mqtt, this.state, this.publishEntityState, this.eventBus),
|
||||
new ExtensionOTAUpdate(this.zigbee, this.mqtt, this.state, this.publishEntityState, this.eventBus),
|
||||
];
|
||||
|
||||
if (settings.get().advanced.report) {
|
||||
|
@ -1200,6 +1200,7 @@ const mapping = {
|
||||
'BDHM8E27W70-I1': [cfg.light_brightness_colortemp],
|
||||
'M420': [cfg.sensor_battery],
|
||||
'8718696167991': [cfg.light_brightness_colortemp_colorxy],
|
||||
'GP-LBU019BBAWU': [cfg.light_brightness],
|
||||
};
|
||||
|
||||
Object.keys(mapping).forEach((key) => {
|
||||
|
48
lib/extension/otaUpdate.js
Normal file
48
lib/extension/otaUpdate.js
Normal file
@ -0,0 +1,48 @@
|
||||
const settings = require('../util/settings');
|
||||
const logger = require('../util/logger');
|
||||
const assert = require('assert');
|
||||
const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/ota_update/.+$`);
|
||||
const BaseExtension = require('./baseExtension');
|
||||
|
||||
class OTAUpdate extends BaseExtension {
|
||||
onMQTTConnected() {
|
||||
this.mqtt.subscribe(`${settings.get().mqtt.base_topic}/bridge/ota_update/check`);
|
||||
this.mqtt.subscribe(`${settings.get().mqtt.base_topic}/bridge/ota_update/update`);
|
||||
}
|
||||
|
||||
async onMQTTMessage(topic, message) {
|
||||
if (!topic.match(topicRegex)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const device = this.zigbee.resolveEntity(message);
|
||||
assert(device != null && device.type === 'device', 'Device not found or not a device');
|
||||
|
||||
if (!device.mapped || !device.mapped.ota) {
|
||||
logger.error(`Device '${device.name}' does not support OTA updates`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`Checking if update available for '${device.name}'`);
|
||||
|
||||
const updateAvailable = await device.mapped.ota.isUpdateAvailable(device.device, logger);
|
||||
const type = topic.split('/')[3];
|
||||
|
||||
if (updateAvailable) {
|
||||
logger.info(`Update available for '${device.name}'`);
|
||||
} else {
|
||||
const level = type === 'update' ? 'error' : 'info';
|
||||
logger[level](`No update available for '${device.name}'`);
|
||||
}
|
||||
|
||||
if (type === 'update' && updateAvailable) {
|
||||
logger.info(`Starting update of '${device.name}'`);
|
||||
const onProgress = (progress) => logger.info(`Update of '${device.name}' at ${progress}%`);
|
||||
const result = await device.mapped.ota.updateToLatest(device.device, logger, onProgress);
|
||||
const [from, to] = [JSON.stringify(result.from), JSON.stringify(result.to)];
|
||||
logger.info(`Finished update of '${device.name}', from '${from}' to '${to}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OTAUpdate;
|
4336
npm-shrinkwrap.json
generated
4336
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -45,8 +45,8 @@
|
||||
"rimraf": "*",
|
||||
"semver": "*",
|
||||
"winston": "*",
|
||||
"zigbee-herdsman": "0.12.45",
|
||||
"zigbee-herdsman-converters": "12.0.18"
|
||||
"zigbee-herdsman": "0.12.46",
|
||||
"zigbee-herdsman-converters": "12.0.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "*",
|
||||
|
87
test/otaUpdate.test.js
Normal file
87
test/otaUpdate.test.js
Normal file
@ -0,0 +1,87 @@
|
||||
const data = require('./stub/data');
|
||||
const logger = require('./stub/logger');
|
||||
const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
const MQTT = require('./stub/mqtt');
|
||||
const settings = require('../lib/util/settings');
|
||||
const Controller = require('../lib/controller');
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
||||
|
||||
describe('OTA update', () => {
|
||||
let controller;
|
||||
|
||||
mockClear = (mapped) => {
|
||||
mapped.ota.updateToLatest = jest.fn();
|
||||
mapped.ota.isUpdateAvailable = jest.fn();
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
data.writeDefaultConfiguration();
|
||||
settings._reRead();
|
||||
data.writeEmptyState();
|
||||
controller = new Controller();
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
MQTT.publish.mockClear();
|
||||
});
|
||||
|
||||
it('Should subscribe to nested topics', async () => {
|
||||
expect(MQTT.subscribe).toHaveBeenCalledWith('zigbee2mqtt/bridge/ota_update/check');
|
||||
expect(MQTT.subscribe).toHaveBeenCalledWith('zigbee2mqtt/bridge/ota_update/update');
|
||||
});
|
||||
|
||||
it('Should OTA update a device', async () => {
|
||||
const device = zigbeeHerdsman.devices.bulb;
|
||||
const mapped = zigbeeHerdsmanConverters.findByZigbeeModel(device.modelID)
|
||||
mockClear(mapped);
|
||||
logger.info.mockClear();
|
||||
mapped.ota.isUpdateAvailable.mockReturnValueOnce(true);
|
||||
mapped.ota.updateToLatest.mockImplementationOnce((a, b, onUpdate) => {
|
||||
onUpdate(2);
|
||||
return {from: {softwareBuildID: 1}, to: {softwareBuildID: 2}};
|
||||
});
|
||||
|
||||
MQTT.events.message('zigbee2mqtt/bridge/ota_update/update', 'bulb');
|
||||
await flushPromises();
|
||||
expect(logger.info).toHaveBeenCalledWith(`Update available for 'bulb'`);
|
||||
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
|
||||
expect(mapped.ota.updateToLatest).toHaveBeenCalledTimes(1);
|
||||
expect(mapped.ota.updateToLatest).toHaveBeenCalledWith(device, logger, expect.any(Function));
|
||||
expect(logger.info).toHaveBeenCalledWith(`Update of 'bulb' at 2%`);
|
||||
expect(logger.info).toHaveBeenCalledWith(`Finished update of 'bulb', from '{"softwareBuildID":1}' to '{"softwareBuildID":2}'`);
|
||||
});
|
||||
|
||||
it('Should refuse to OTA update a device when no update is available', async () => {
|
||||
const device = zigbeeHerdsman.devices.bulb;
|
||||
const mapped = zigbeeHerdsmanConverters.findByZigbeeModel(device.modelID)
|
||||
mockClear(mapped);
|
||||
logger.info.mockClear();
|
||||
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
|
||||
|
||||
MQTT.events.message('zigbee2mqtt/bridge/ota_update/update', 'bulb');
|
||||
await flushPromises();
|
||||
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
|
||||
expect(mapped.ota.updateToLatest).toHaveBeenCalledTimes(0);
|
||||
expect(logger.error).toHaveBeenCalledWith(`No update available for 'bulb'`);
|
||||
});
|
||||
|
||||
it('Should be able to check if OTA update is available', async () => {
|
||||
const device = zigbeeHerdsman.devices.bulb;
|
||||
const mapped = zigbeeHerdsmanConverters.findByZigbeeModel(device.modelID)
|
||||
mockClear(mapped);
|
||||
logger.info.mockClear();
|
||||
mapped.ota.isUpdateAvailable.mockReturnValueOnce(false);
|
||||
|
||||
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'bulb');
|
||||
await flushPromises();
|
||||
expect(mapped.ota.isUpdateAvailable).toHaveBeenCalledTimes(1);
|
||||
expect(mapped.ota.updateToLatest).toHaveBeenCalledTimes(0);
|
||||
expect(logger.info).toHaveBeenCalledWith(`No update available for 'bulb'`);
|
||||
});
|
||||
|
||||
it('Should not check for OTA when device does not support it', async () => {
|
||||
MQTT.events.message('zigbee2mqtt/bridge/ota_update/check', 'bulb_color_2');
|
||||
await flushPromises();
|
||||
expect(logger.error).toHaveBeenCalledWith(`Device 'bulb_color_2' does not support OTA updates`);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user