iobroker.zigbee 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/groups.js CHANGED
@@ -1,25 +1,40 @@
1
1
  'use strict';
2
2
 
3
+ const json = require('iobroker.zigbee/lib/json');
3
4
  const statesMapping = require('./devices');
5
+ const { numberWithinRange } = require('zigbee-herdsman-converters/lib/utils');
6
+ const idRegExp = new RegExp(/group_(\d+)/);
7
+
8
+
4
9
 
5
10
  class Groups {
6
11
  constructor(adapter) {
7
12
  this.adapter = adapter;
8
13
  this.adapter.on('message', this.onMessage.bind(this));
14
+ this.log = this.adapter.log;
15
+ this.idRegex = new RegExp(/group_(\d+)/)
16
+ }
17
+
18
+ static extractGroupID(id) {
19
+ switch (typeof id) {
20
+ case 'number': return id;
21
+ case 'string': {
22
+ const regexResult = id.match(idRegExp);
23
+ if (regexResult) return Number(regexResult[1]);
24
+ break;
25
+ }
26
+ default: return -1;
27
+ }
9
28
  }
10
29
 
30
+ static generateGroupID(gnum) {
31
+ return `group_${gnum}`;
32
+ };
33
+
11
34
  start(zbController, stController) {
12
35
  this.zbController = zbController;
13
36
  this.stController = stController;
14
- this.adapter.getStateAsync('info.groups')
15
- .then(groupsState => {
16
- const groups = (groupsState && groupsState.val) ? JSON.parse(groupsState.val) : {};
17
- for (const gid in groups) {
18
- stController.storeDeviceName(`group_${gid}`, groups[gid]);
19
- }
20
- // this.Adapter.deleteState('info.groups');
21
- this.syncGroups();
22
- });
37
+ this.syncGroups();
23
38
  }
24
39
 
25
40
  stop() {
@@ -66,10 +81,22 @@ class Groups {
66
81
  }
67
82
  }
68
83
 
84
+
85
+ buildGroupID(id, withInstance) {
86
+ const parts = [];
87
+ if (withInstance) parts.push(this.adapter.namespace);
88
+ if (Number(id) > 0)
89
+ parts.push(Groups.generateGroupID(id));
90
+ else {
91
+ if (Groups.extractGroupID(id) > 0) parts.push(id);
92
+ }
93
+ return parts.join('.');
94
+ }
95
+
69
96
  async getGroupMembersFromController(id) {
70
97
  const members = [];
71
98
  try {
72
- const group = await this.zbController.getGroupByID(id);
99
+ const group = await this.zbController.getGroupByID(Number(id));
73
100
  if (group) {
74
101
  const groupmembers = group.members;
75
102
 
@@ -85,29 +112,32 @@ class Groups {
85
112
  }
86
113
 
87
114
  } catch (error) {
88
- if (error) this.error(`getGroupMembersFromController: error is ${(error && error.message ? error.message : 'no error message')} ${(error && error.stack ? error.stack : 'no call stack')}`);
115
+ if (error) this.error(`getGroupMembersFromController: error is ${JSON.stringify(error)} ${JSON.stringify(new Error().stack)}`);
89
116
  else this.error('unidentifed error in getGroupMembersFromController');
90
117
  }
91
118
  return members;
92
119
  }
93
120
 
94
121
  async getGroups(obj) {
122
+ this.debug('get groupes called with ' + JSON.stringify(obj));
95
123
  const response = {groups: {}};
96
124
 
97
125
  const isEnable = await this.adapter.getStateAsync('info.connection');
126
+ this.debug('get groupes called with ' + (obj ? JSON.stringify(obj) : 'no object') + ' ' + (isEnable.val ? 'connected' : 'disconnected'));
98
127
  if (isEnable.val) {
99
128
  try {
100
129
  const herdsmanGroups = await this.zbController.getGroups();
101
130
  const groups = {};
102
131
  if (typeof herdsmanGroups === 'object') {
103
132
  for (const group of herdsmanGroups) {
104
- const gid = group.groupID;
133
+ const gid = group.id;
105
134
  if (gid) {
106
- groups[gid] = this.stController.verifyDeviceName(`group_${gid}`, `Group ${gid}`);
135
+ const name = this.stController.verifyDeviceName(`group_${gid}`, `Group`, `Group ${gid}`);
136
+ groups[gid] = name;
107
137
  }
108
138
  }
109
139
  }
110
- this.debug(`getGroups result: ${JSON.stringify(groups)}`);
140
+ this.debug(`getGroups result: ${JSON.stringify(groups)} ( ${JSON.stringify(herdsmanGroups)})`);
111
141
  response.groups = groups;
112
142
  } catch (error) {
113
143
  response.error = `res getGroups: caught error: ${error}`;
@@ -123,7 +153,7 @@ class Groups {
123
153
  try {
124
154
  const groups = message && message.groups ? message.groups : {};
125
155
  const devId = message && message.id ? message.id : undefined;
126
- this.warn('updateGroupMembership called with ' + JSON.stringify(devId));
156
+ this.debug('updateGroupMembership called with ' + JSON.stringify(devId));
127
157
  if (devId === undefined) {
128
158
  this.adapter.sendTo(from, command, {error: 'No device specified'}, callback);
129
159
  }
@@ -138,30 +168,32 @@ class Groups {
138
168
  for (const gpid of groups[epid]) {
139
169
  const gpidn = parseInt(gpid);
140
170
  if (gpidn < 0) {
141
- this.debug(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
171
+ this.warn(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
142
172
  const response = await this.zbController.removeDevFromGroup(sysid, (-gpidn), epid);
143
173
  if (response && response.error) {
144
174
  errors.push(response.error);
145
175
  this.error(`remove dev from group Error: ${JSON.stringify(response.error)}`);
146
176
  }
147
-
177
+ const icon = this.stController.getDefaultGroupIcon(-gpidn)
148
178
  } else if (gpidn > 0) {
149
- this.debug(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
179
+ this.warn(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
150
180
  const response = await this.zbController.addDevToGroup(sysid, (gpidn), epid);
151
181
  if (response && response.error) {
152
182
  errors.push(response.error);
153
183
  this.error(`add dev to group Error: ${JSON.stringify(response.error)}`);
154
184
  }
155
185
  } else {
156
- this.warn('illegal group id 0');
186
+ this.error('illegal group id 0');
157
187
  }
158
188
  }
159
189
  }
160
190
  } catch (e) {
161
- this.warn('caught error ' + (e && e.message ? e.message : 'no error message') + ' in updateGroupMembership');
191
+ this.warn('caught error ' + JSON.stringify(e) + ' in updateGroupMembership');
162
192
  this.adapter.sendTo(from, command, {error: e}, callback);
163
193
  return;
164
194
  }
195
+ //await this.renameGroup(from, command, { name: undefined, id: message.id});
196
+ this.syncGroups();
165
197
  this.adapter.sendTo(from, command, {}, callback);
166
198
  }
167
199
 
@@ -211,28 +243,41 @@ class Groups {
211
243
  }
212
244
 
213
245
  async renameGroup(from, command, message) {
246
+ this.debug(`rename group called with ${from}, ${command}, ${JSON.stringify(message)}`);
214
247
  // const groupsEntry = await this.adapter.getStateAsync('info.groups');
215
248
  // const objGroups = (groupsEntry && groupsEntry.val ? JSON.parse(groupsEntry.val) : {});
216
249
  const name = message.name;
217
250
  const id = `group_${message.id}`;
218
- this.stController.storeDeviceName(id, name);
251
+ let icon = this.stController.localConfig.IconForId(id, 'group', await this.stController.getDefaultGroupIcon(id));
219
252
  try {
220
- await this.zbController.verifyGroupExists(message.id);
253
+ const group = await this.zbController.verifyGroupExists(message.id);
254
+ if (message.remove) {
255
+ for (const member of message.remove) {
256
+ const response = await this.zbController.removeDevFromGroup(member.id, id, member.ep);
257
+ this.warn('trying to remove ' + member.id + (member.ep ? '.'+member.ep : '') + ' ' + ' from group ' + message.id + ' response is '+JSON.stringify(response));
258
+ }
259
+ }
260
+ if (icon.match(/img\/group_\d+\.png/g)) {
261
+ this.warn('.');
262
+ icon = await this.zbController.rebuildGroupIcon(group);
263
+ }
221
264
  } catch (e) {
265
+ this.warn('renameGroup caught error ' + (e && e.message ? e.message : 'no message'));
222
266
  if (e && e.hasOwnProperty('code')) {
223
267
  this.warn(`renameGroup caught error ${JSON.stringify(e.code)}`);
224
268
  }
225
269
  }
226
-
227
- const group = await this.adapter.getStateAsync(id);
270
+ this.warn(`rename group name ${name}, id ${id}, icon ${icon} remove ${JSON.stringify(message.removeMembers)}`);
271
+ const group = await this.adapter.getObjectAsync(id);
228
272
  if (!group) {
273
+ this.warn('group object doesnt exist ')
229
274
  // assume we have to create the group
230
275
  this.adapter.setObjectNotExists(id, {
231
276
  type: 'device',
232
- common: {name: name, type: 'group'},
277
+ common: {name: (name ? name : `Group ${message.id}` ), type: 'group', icon: icon},
233
278
  native: {id}
234
279
  }, () => {
235
- this.adapter.extendObject(id, {common: {name, type: 'group'}});
280
+ this.adapter.extendObject(id, {common: {name, type: 'group', icon: icon}});
236
281
  // create writable states for groups from their devices
237
282
  for (const stateInd in statesMapping.groupStates) {
238
283
  if (!statesMapping.groupStates.hasOwnProperty(stateInd)) {
@@ -252,25 +297,35 @@ class Groups {
252
297
  };
253
298
  this.stController.updateState(id, statedesc.id, undefined, common);
254
299
  }
300
+ this.stController.storeDeviceName(id, name);
255
301
  });
256
302
  }
303
+ else {
304
+ this.warn('group object exists');
305
+ this.adapter.extendObject(id, {common: {name, type: 'group', icon: icon}});
306
+ }
257
307
  }
258
308
 
259
309
  async syncGroups() {
260
310
  const groups = await this.getGroups();
311
+ this.debug('sync Groups called: groups is '+ JSON.stringify(groups))
261
312
  const chain = [];
262
313
  const usedGroupsIds = [];
314
+ let GroupCount = 0;
263
315
  for (const j in groups) {
316
+ GroupCount++;
317
+ this.debug(`group ${GroupCount} is ${JSON.stringify(j)}`);
264
318
  if (groups.hasOwnProperty(j)) {
265
319
  const id = `group_${j}`;
266
320
  const name = groups[j];
321
+ const icon = this.stController.localConfig.IconForId(id, 'group', await this.stController.getDefaultGroupIcon(id));
267
322
  chain.push(new Promise(resolve => {
268
323
  this.adapter.setObjectNotExists(id, {
269
324
  type: 'device',
270
- common: {name: name, type: 'group'},
325
+ common: {name: name, type: 'group', icon: icon },
271
326
  native: {id: j}
272
327
  }, () => {
273
- this.adapter.extendObject(id, {common: {type: 'group'}});
328
+ this.adapter.extendObject(id, {common: {type: 'group', icon: icon}});
274
329
  // create writable states for groups from their devices
275
330
  for (const stateInd in statesMapping.groupStates) {
276
331
  if (!statesMapping.groupStates.hasOwnProperty(stateInd)) {
@@ -316,4 +371,4 @@ class Groups {
316
371
  }
317
372
  }
318
373
 
319
- module.exports = Groups;
374
+ module.exports = Groups ;
@@ -0,0 +1,301 @@
1
+ 'use strict';
2
+
3
+ /*eslint no-unused-vars: ['off']*/
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const utils = require('@iobroker/adapter-core'); // Get common adapter utils
7
+ // const { src } = require('gulp');
8
+
9
+ const EventEmitter = require('events').EventEmitter;
10
+
11
+ class localConfig extends EventEmitter {
12
+ constructor(adapter, options) {
13
+ super();
14
+ this.adapter = adapter;
15
+ this.name = 'localConfig';
16
+ this.localData = { by_id:{}, by_model:{} };
17
+ this.filename = undefined;
18
+ this.basefolder = undefined;
19
+ this.retTimeoutHanlde = undefined;
20
+ this.adapter.on('ready', () => this.onReady());
21
+ this.adapter.on('unload', callback => this.onUnload(callback));
22
+ }
23
+
24
+
25
+ async onReady()
26
+ {
27
+ }
28
+
29
+ async onUnload(callback)
30
+ {
31
+ this.info('local config saved');
32
+ this.retainData();
33
+ callback();
34
+ }
35
+
36
+ info(message) {
37
+ this.adapter.log.info(message);
38
+ this.emit('log', 'info',message);
39
+ }
40
+
41
+ error(message, errobj) {
42
+ this.adapter.log.error(`${this.name}:${message}`);
43
+ this.emit('log', 'error',`${this.name}:${message}`, errobj);
44
+ }
45
+
46
+ warn(message) {
47
+ this.adapter.log.warn(`${this.name}:${message}`);
48
+ this.emit('log', 'warn',`${this.name}:${message}`);
49
+ }
50
+
51
+ debug(message) {
52
+ this.adapter.log.debug(`${this.name}:${message}`);
53
+ this.emit('log', 'debug',`${this.name}:${message}`);
54
+ }
55
+
56
+ async updateDeviceName(id, name) {
57
+ this.debug('updateDev with ' + id + ' and .'+ name +'.');
58
+ if (typeof id != 'string') {
59
+ this.error(`update called with illegal device entry:${JSON.stringify(id)}`)
60
+ return true;
61
+ }
62
+ if (typeof name != 'string' || name.trim().length < 1)
63
+ {
64
+ if (this.localData.hasOwnProperty(id))
65
+ delete this.localData.by_id[id].name;
66
+ }
67
+ else {
68
+ if (this.localData.by_id.hasOwnProperty(id))
69
+ this.localData.by_id[id].name = name;
70
+ else
71
+ this.localData.by_id[id] = { name: name };
72
+ }
73
+ return true;
74
+ }
75
+
76
+ async updateLocalOverride(_target, model, key, data, global)
77
+ {
78
+ const target = (global ? model : _target);
79
+ this.info(`updating local data: (${global ? 'global':'local'}) : ${target}:${key}:${data}`);
80
+
81
+ if (typeof target != 'string' || typeof key != 'string') {
82
+ this.error(`update called with illegal id data:${JSON.stringify(target)}:${JSON.stringify(key)}:${JSON.stringify(data)}`)
83
+ return false;
84
+ }
85
+ const base = global ? this.localData.by_model[target] || {} : this.localData.by_id[target] || {};
86
+ if (data && data.length > 0 && data != 'none') {
87
+ if (key == 'icon')
88
+ base[key] = data.replace(this.basefolder, '.');
89
+ else
90
+ base[key] = data;
91
+ }
92
+ else
93
+ {
94
+ if (base.hasOwnProperty(key)) {
95
+ delete base[key]
96
+ }
97
+ }
98
+ if (global) {
99
+ if (base == {}) delete this.localData.by_model[target];
100
+ else this.localData.by_model[target] = base;
101
+ }
102
+ else {
103
+ if (base == {}) delete this.localData.by_id[target];
104
+ else this.localData.by_id[target] = base;
105
+ }
106
+ this.info(`Local Data for ${target} is ${JSON.stringify(base)}`);
107
+ return true;
108
+ }
109
+
110
+
111
+ NameForId(id, model, defaultName) {
112
+ this.debug('name for id with ' + id + ' and ' + defaultName + ' from ' + JSON.stringify(this.localData));
113
+ const localstorage = (this.localData.by_id[id] || this.localData.by_model[model]);
114
+ if (localstorage && localstorage.hasOwnProperty['name']) return localstorage.name;
115
+ return defaultName;
116
+ }
117
+
118
+ IconForId(id, model, defaultIcon) {
119
+ let modeloverride = {};
120
+ this.debug('Icon for id with ' + id + ', ' + model + ' and ' + defaultIcon);
121
+ if (this.localData.by_id.hasOwnProperty(id))
122
+ {
123
+ modeloverride = this.localData.by_id[id]
124
+ }
125
+ if (!modeloverride.icon) {
126
+ if (this.localData.by_model.hasOwnProperty(model))
127
+ modeloverride = this.localData.by_model[model];
128
+ }
129
+ const iconPath = modeloverride.icon;
130
+ this.debug('icon Path is '+ JSON.stringify(iconPath));
131
+ if (typeof iconPath != 'string') {
132
+ this.debug('icon path is no string, returning ' + JSON.stringify(defaultIcon));
133
+ return defaultIcon;
134
+ }
135
+ if (iconPath.startsWith('http')) return iconPath;
136
+ const namespace = `${this.adapter.name}.admin`;
137
+ const rv = `img/${path.basename(iconPath)}`;
138
+ try {
139
+ this.adapter.fileExists(namespace, rv, (err, result) => {
140
+ if (result) return;
141
+ const src = this.adapter.expandFileName(iconPath).replace('.','_');
142
+ fs.readFile(src, (err, data) => {
143
+ if (err) {
144
+ this.error('unable to read ' + src + ' : '+ (err && err.message? err.message:' no message given'))
145
+ return;
146
+ }
147
+ if (data) {
148
+ this.adapter.writeFile(namespace, rv, data, (err) => {
149
+ if (err) {
150
+ this.error('error writing file ' + path + JSON.stringify(err))
151
+ return;
152
+ }
153
+ this.info('Updated image file ' + rv)
154
+ })
155
+ }
156
+ })
157
+
158
+ })
159
+ } catch (error) {
160
+ this.error(`Error accessing target image: ${error && error.message ? error.message : 'no error message'}`);
161
+ }
162
+ return rv;
163
+ }
164
+
165
+
166
+ async copyDeviceImage(src) {
167
+ const dst = `${this.adapter.adapterDir}/admin/img/${path.basename(src)}`;
168
+ const _src = this.adapter.expandFileName(src);
169
+ if (fs.existsSync(src) && !fs.existsSync(dst))
170
+ {
171
+ try {
172
+ this.log.info(`copying image from :${src} to ${dst}`)
173
+ fs.copyFileSync(src, dst)
174
+ }
175
+ catch {
176
+ this.log.debug(`failed to copy from :${src} to ${dst}`)
177
+ }
178
+ }
179
+ }
180
+
181
+ getOverrideData(target, isGlobal) {
182
+ const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
183
+ if (base.hasOwnProperty(target)) return base[target];
184
+ return {};
185
+ }
186
+
187
+ setOverrideData(target, isGlobal, data) {
188
+ const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
189
+ if (typeof target != 'string') {
190
+ this.error('illegal target for override data: '+JSON.stringify(target));
191
+ return;
192
+ }
193
+ base[target]=data;
194
+ };
195
+
196
+ async getLegacyModels() {
197
+ const legacyModels = [];
198
+ for (const model in this.localData.by_model) {
199
+ if (this.localData.by_model[model].hasOwnProperty('legacy') && this.localData.by_model[model].legacy)
200
+ legacyModels.push(model);
201
+ }
202
+ return legacyModels;
203
+ }
204
+
205
+ getOverridesWithKey(key, isGlobal) {
206
+ const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
207
+ const rv = [];
208
+ for(const prop in base) {
209
+ if (base[prop].hasOwnProperty(key)) {
210
+ rv.push({key:prop, value:base[prop][key]});
211
+ }
212
+ }
213
+ return rv;
214
+ }
215
+
216
+ getOverrideWithKey(target, key, isGlobal) {
217
+ const targetdata = this.getOverrideData(target, isGlobal);
218
+ if (targetdata && targetdata.hasOwnProperty(key)) return targetdata[key];
219
+ return undefined;
220
+ }
221
+
222
+ async updateFromDeviceNames() {
223
+ this.warn('updateFromDeviceNames');
224
+ const fn = this.adapter.expandFileName('dev_names').replace('.', '_').concat('.json');
225
+ fs.readFile(fn, (err, content) => {
226
+ if (!err) {
227
+ let data_js = {};
228
+ try {
229
+ data_js = JSON.parse(content);
230
+ }
231
+ catch (error) {
232
+ this.error(`unable to parse data read from ${fn} : ${error.message ? error.message : 'undefined error'}`)
233
+ return;
234
+ }
235
+ try {
236
+ for (const prop in data_js) {
237
+ if (data_js[prop] != 'undefined')
238
+ this.updateDeviceName(prop, data_js[prop]);
239
+ }
240
+ }
241
+ catch (error) {
242
+ this.error(`error in updateFromDeviceNames : ${error.message ? error.message : 'undefined error'}`)
243
+ return;
244
+
245
+ }
246
+ this.retainData();
247
+ }
248
+ });
249
+ }
250
+
251
+ async init() {
252
+ this.info('init localConfig');
253
+ const fn = this.adapter.expandFileName('LocalOverrides').replace('.','_').concat('.json');
254
+ this.filename = fn;
255
+ this.basefolder = path.dirname(fn);
256
+
257
+ try {
258
+ const content = fs.readFileSync(fn);
259
+ try {
260
+ const data_js = JSON.parse(content);
261
+ this.localData = data_js;
262
+ }
263
+ catch (error) {
264
+ this.error(`unable to parse data read from ${fn} : ${error.message ? error.message : 'undefined error'}`);
265
+ }
266
+ } catch(error) {
267
+ await this.updateFromDeviceNames();
268
+ }
269
+ }
270
+
271
+ async retainData() {
272
+ //this.warn('retaining local config: ' + JSON.stringify(this.localData));
273
+ try {
274
+ fs.writeFileSync(this.filename, JSON.stringify(this.localData, null, 2))
275
+ this.info('Saved local configuration data');
276
+ }
277
+ catch (error) {
278
+ this.error(`error saving local config: ${error.message}`);
279
+ }
280
+ }
281
+
282
+ enumerateImages(_path) {
283
+ const rv = [];
284
+ try
285
+ {
286
+ const files= fs.readdirSync(_path, {withFileTypes: true, recursive: true}).filter(item => (!item.isDirectory() && item.name.endsWith('.png')));
287
+ files.forEach((item) => {
288
+ const fn = path.join(item.parentPath, item.name);
289
+ rv.push({file: fn, name: item.name, data: fs.readFileSync(path.join(item.parentPath, item.name), 'base64')})
290
+ });
291
+ //this.warn('enumerateImages for ' + _path + ' is ' + JSON.stringify(rv));
292
+ }
293
+ catch (error) {
294
+ this.error(`error in enumerateImages : ${error.message ? error.message : 'undefined error'}`)
295
+ }
296
+ return rv;
297
+ }
298
+
299
+ }
300
+
301
+ module.exports = localConfig;
package/lib/ota.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const getZbId = require('./utils').getZbId;
4
+ const zhc_ota = require('zigbee-herdsman-converters').ota;
4
5
 
5
6
  class Ota {
6
7
  constructor(adapter) {
@@ -24,7 +25,7 @@ class Ota {
24
25
  }
25
26
 
26
27
  warn(msg) {
27
- this.adapter.log.info(msg);
28
+ this.adapter.log.warn(msg);
28
29
  }
29
30
 
30
31
  error(msg) {
@@ -94,10 +95,10 @@ class Ota {
94
95
  this.debug(`Checking if firmware update is available for ${device.name}`);
95
96
 
96
97
  if (device && device.mapped.ota) {
97
- const available = await device.mapped.ota.isUpdateAvailable(device.device, null);
98
+ const available = await zhc_ota.isUpdateAvailable(device.device, device.mapped.ota, undefined, false);
98
99
  result.status = available.available ? 'available' : 'not_available';
99
100
  if (available.currentFileVersion !== available.otaFileVersion) {
100
- this.warn(`current Firmware for ${device.name} is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
101
+ this.debug(`current Firmware for ${device.name} is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
101
102
  }
102
103
  } else {
103
104
  result.status = 'not_supported';
@@ -155,7 +156,7 @@ class Ota {
155
156
  };
156
157
 
157
158
  const from_ = await this.readSoftwareBuildIDAndDateCode(device.device, false);
158
- const fileVersion = await device.mapped.ota.updateToLatest(device.device, onProgress);
159
+ const fileVersion = await zhc_ota.update(device.device, device.mapped.ota, false, onProgress)
159
160
  const to = await this.readSoftwareBuildIDAndDateCode(device.device, true);
160
161
  const [fromS, toS] = [JSON.stringify(from_), JSON.stringify(to)];
161
162
  result.status = 'success';