kuzzle-device-manager 2.0.0-rc8 → 2.0.0-rc9

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.
@@ -158,7 +158,7 @@ class DeviceManagerPlugin extends kuzzle_1.Plugin {
158
158
  });
159
159
  this.assetService = new core_classes_1.AssetService(this, this.batchController);
160
160
  this.deviceService = new core_classes_1.DeviceService(this, this.batchController, this.assetService, this.decodersRegister);
161
- this.measuresService = new MeasureService_1.MeasureService(this, this.batchController, this.deviceService, this.assetService, this.measuresRegister);
161
+ this.measuresService = new MeasureService_1.MeasureService(this, this.batchController, this.assetService, this.measuresRegister);
162
162
  this.payloadService = new core_classes_1.PayloadService(this, this.batchController, this.measuresRegister, this.measuresService);
163
163
  this.deviceManagerEngine = new core_classes_1.DeviceManagerEngine(this, this.assetsRegister, this.devicesRegister, this.measuresRegister, this.adminConfigManager, this.engineConfigManager);
164
164
  this.decodersRegister.init(this.context);
@@ -2,8 +2,10 @@ import { HttpRoute, JSONObject, KuzzleRequest } from 'kuzzle';
2
2
  import { DecodedPayload } from '../types/DecodedPayload';
3
3
  import { DecoderContent } from '../types';
4
4
  import { MeasuresRegister } from './registers/MeasuresRegister';
5
- export declare type DecoderMeasures = Record<string, // deviceMeasureName
6
- string>;
5
+ /**
6
+ * Record<deviceMeasureName, type>
7
+ */
8
+ export declare type DecoderMeasures = Record<string, string>;
7
9
  /**
8
10
  * Base class to implement a decoder for a device model.
9
11
  * The device model must be passed to the parent constructor.
@@ -2,19 +2,16 @@ import { BatchController, JSONObject } from 'kuzzle';
2
2
  import { DeviceManagerPlugin } from '../DeviceManagerPlugin';
3
3
  import { DecodedPayload, MeasureContent } from '../types';
4
4
  import { AssetService } from './AssetService';
5
- import { DeviceService } from './DeviceService';
6
5
  import { MeasuresRegister } from './registers/MeasuresRegister';
7
6
  export declare class MeasureService {
8
7
  private config;
9
8
  private context;
10
9
  private batch;
11
- private deviceService;
12
10
  private assetService;
13
11
  private measuresRegister;
14
- private static eventId;
15
12
  private get sdk();
16
13
  private get app();
17
- constructor(plugin: DeviceManagerPlugin, batchController: BatchController, deviceService: DeviceService, assetService: AssetService, measuresRegister: MeasuresRegister);
14
+ constructor(plugin: DeviceManagerPlugin, batchController: BatchController, assetService: AssetService, measuresRegister: MeasuresRegister);
18
15
  /**
19
16
  * Register new measures from a device, updates :
20
17
  * - admin device
@@ -30,15 +27,12 @@ export declare class MeasureService {
30
27
  * reference a nonexisting device, create this device
31
28
  * @param options.refresh Wait for ES indexation
32
29
  */
33
- registerByDecodedPayload(deviceModel: string, decodedPayloads: DecodedPayload, payloadUuids: Array<string>, { autoProvisionDevice, refresh }?: {
34
- autoProvisionDevice?: boolean;
35
- refresh?: 'wait_for' | 'false';
36
- }): Promise<{}>;
37
- /**
38
- * Takes all informations to craft a Measure and insert it in
39
- * caching structures
40
- */
41
- private insertIntoSortingRecords;
30
+ processDecodedPayload(deviceModel: string, decodedPayloads: DecodedPayload, payloadUuids: string[], options: {
31
+ refresh?: string;
32
+ }): Promise<void>;
33
+ private buildMeasures;
34
+ private getDevices;
35
+ private provisionDevices;
42
36
  /**
43
37
  * Register new measures from a device, updates :
44
38
  * - linked asset
@@ -50,7 +44,6 @@ export declare class MeasureService {
50
44
  * @param assetId Asset id
51
45
  * @param jsonMeasurements `AssetMeasurement` array from a request
52
46
  * @param kuid Kuid of the user pushing the measurements
53
- * @param {object} options
54
47
  * @param options.refresh Wait for ES indexation
55
48
  * @param options.strict If true, throw if an operation isn't possible
56
49
  */
@@ -10,10 +10,9 @@ const InternalCollection_1 = require("../InternalCollection");
10
10
  const models_1 = require("../models");
11
11
  const types_1 = require("../types");
12
12
  class MeasureService {
13
- constructor(plugin, batchController, deviceService, assetService, measuresRegister) {
13
+ constructor(plugin, batchController, assetService, measuresRegister) {
14
14
  this.config = plugin.config;
15
15
  this.context = plugin.context;
16
- this.deviceService = deviceService;
17
16
  this.assetService = assetService;
18
17
  this.measuresRegister = measuresRegister;
19
18
  this.batch = batchController;
@@ -39,158 +38,100 @@ class MeasureService {
39
38
  * reference a nonexisting device, create this device
40
39
  * @param options.refresh Wait for ES indexation
41
40
  */
42
- async registerByDecodedPayload(deviceModel, decodedPayloads, payloadUuids, { autoProvisionDevice, refresh } = {}) {
43
- const eventId = `${MeasureService.eventId}:registerByDecodedPayload`;
44
- // Create caching structures
45
- const engineMeasures = {};
46
- const assetMeasuresInEngine = {};
47
- const deviceMeasuresInEngine = {};
48
- const measurementsWithoutDevice = {};
49
- const unknownTypeMeasurements = [];
50
- // Craft and insert measures in cache by each device
51
- // Need to be atomic (no Promise.all) because it would erase the array in `assetMeasuresInEngineCache` and `deviceMeasuresInEngineCache`
52
- for (const [reference, measurements] of Object.entries(decodedPayloads)) {
53
- await this.insertIntoSortingRecords(engineMeasures, assetMeasuresInEngine, deviceMeasuresInEngine, measurementsWithoutDevice, unknownTypeMeasurements, payloadUuids, deviceModel, reference, measurements, autoProvisionDevice);
54
- }
55
- const response = await this.app.trigger(`${eventId}:before`, {
56
- assetMeasuresInEngineCache: assetMeasuresInEngine,
57
- deviceMeasuresInEngineCache: deviceMeasuresInEngine,
58
- engineMeasuresCache: engineMeasures,
59
- unknownTypeMeasurements,
60
- });
61
- // Push measures in db
62
- // In Engine measures
63
- await Promise.all(Object.entries(response.engineMeasuresCache).map(([engineId, measures]) => {
64
- const measureArray = measures;
65
- return this.historizeEngineMeasures(engineId, measureArray, { refresh });
66
- }));
67
- // Update measures of assets and update documents
68
- await Promise.all(Object.entries(response.assetMeasuresInEngineCache).map(async ([engineId, assetMeasuresRecord]) => {
69
- for (const { asset, measures } of Object.values(assetMeasuresRecord)) {
70
- asset.updateMeasures(measures);
71
- }
72
- await this.sdk.document.mUpdate(engineId, InternalCollection_1.InternalCollection.ASSETS, Object.values(assetMeasuresRecord).map(({ asset }) => ({ _id: asset._id, body: asset._source })), { refresh });
73
- }));
74
- // Update measures of devices and update documents
75
- const devices = [];
76
- await Promise.all(Object.entries(response.deviceMeasuresInEngineCache).map(async ([engineId, deviceMeasuresRecord]) => {
77
- await Promise.all(Object.values(deviceMeasuresRecord).map(({ device, measures }) => {
78
- device.updateMeasures(measures);
79
- devices.push(device);
80
- }));
81
- if (engineId !== this.config.adminIndex) {
82
- await this.sdk.document.mUpdate(engineId, InternalCollection_1.InternalCollection.DEVICES, Object.values(deviceMeasuresRecord).map(({ device }) => ({ _id: device._id, body: device._source })), { refresh });
83
- }
84
- }));
85
- await this.sdk.document.mUpdate(this.config.adminIndex, InternalCollection_1.InternalCollection.DEVICES, devices.map(device => ({ _id: device._id, body: device._source })), { refresh });
86
- await this.app.trigger(`${eventId}:after`, {
87
- assetMeasuresInEngineCache: assetMeasuresInEngine,
88
- deviceMeasuresInEngineCache: deviceMeasuresInEngine,
89
- engineMeasuresCache: engineMeasures,
90
- });
91
- return {
92
- // TOSEE : What to return, how (serialization) ?
93
- // TOSEE : Stock updated assets, devices and measures for return result ?
94
- // engineMeasuresCache,
95
- // assetMeasuresInEngineCache,
96
- // deviceMeasuresInEngineCache,
97
- // unaivailableTypeMeasurements,
98
- // measurementsWithoutDevice,
99
- };
100
- }
101
- /**
102
- * Takes all informations to craft a Measure and insert it in
103
- * caching structures
104
- */
105
- async insertIntoSortingRecords(engineMeasuresCache, assetMeasuresInEngineCache, deviceMeasuresInEngineCache, measurementsWithoutDevice, unknownTypeMeasurements, payloadUuids, deviceModel, reference, measurements, autoProvisionDevice) {
106
- // Search device in cache or get in db
107
- const deviceId = models_1.Device.id(deviceModel, reference);
108
- let device = null;
109
- try {
110
- device = await this.deviceService.getDevice(this.config, deviceId);
111
- }
112
- catch (error) { }
113
- if (!device) {
114
- if (autoProvisionDevice) {
115
- // TODO : Optimize, ES request to create and then update at end
116
- device = await this.deviceService.create({
117
- model: deviceModel,
118
- reference,
119
- });
41
+ async processDecodedPayload(deviceModel, decodedPayloads, payloadUuids, options) {
42
+ const references = Object.keys(decodedPayloads);
43
+ const devices = await this.getDevices(deviceModel, references, options);
44
+ for (const device of devices) {
45
+ let asset = null;
46
+ if (device._source.assetId) {
47
+ try {
48
+ const { _source, _id } = await this.batch.get(device._source.engineId, InternalCollection_1.InternalCollection.ASSETS, device._source.assetId);
49
+ asset = new models_1.BaseAsset(_source, _id);
50
+ }
51
+ catch (error) {
52
+ this.app.log.error(`[${device._source.engineId}] Cannot find asset "${device._source.assetId}" linked to device "${device._id}".`);
53
+ }
120
54
  }
121
- else {
122
- measurementsWithoutDevice[reference] = measurements;
123
- return;
55
+ const measures = this.buildMeasures(device, asset, decodedPayloads[device._source.reference], payloadUuids);
56
+ const updatedMeasures = await this.app.trigger('device-manager:measures:receive', measures, { asset, device });
57
+ device.updateMeasures(updatedMeasures);
58
+ await this.sdk.document.update(this.config.adminIndex, InternalCollection_1.InternalCollection.DEVICES, device._id, { measures: device._source.measures });
59
+ if (device._source.engineId) {
60
+ await this.sdk.document.update(device._source.engineId, InternalCollection_1.InternalCollection.DEVICES, device._id, { measures: device._source.measures });
61
+ // @todo replace by batch.mCreate when available
62
+ await this.sdk.document.mCreate(device._source.engineId, InternalCollection_1.InternalCollection.MEASURES, updatedMeasures.map(measure => ({ body: measure })), { strict: true });
63
+ if (asset) {
64
+ asset.updateMeasures(updatedMeasures);
65
+ await this.sdk.document.update(device._source.engineId, InternalCollection_1.InternalCollection.ASSETS, asset._id, { measures: asset._source.measures });
66
+ }
124
67
  }
125
68
  }
126
- const engineId = device._source.engineId ?? this.config.adminIndex;
127
- const assetId = device._source.assetId;
128
- const deviceMeasures = { device, measures: [] };
129
- let deviceMeasuresInEngine = deviceMeasuresInEngineCache[engineId];
130
- if (!deviceMeasuresInEngine) {
131
- deviceMeasuresInEngine = { [deviceId]: deviceMeasures };
132
- deviceMeasuresInEngineCache[engineId] = deviceMeasuresInEngine;
133
- }
134
- // Search asset in cache or get in db
135
- let assetCacheEntity = null;
136
- if (assetId) {
137
- let assetMeasuresInEngine = assetMeasuresInEngineCache[engineId];
138
- if (!assetMeasuresInEngine) {
139
- assetMeasuresInEngine = {};
140
- assetMeasuresInEngineCache[engineId] = assetMeasuresInEngine;
141
- }
142
- assetCacheEntity = assetMeasuresInEngine[assetId];
143
- if (!assetCacheEntity) {
144
- assetCacheEntity = {
145
- asset: await this.assetService.getAsset(engineId, assetId),
146
- measures: [],
147
- };
148
- assetMeasuresInEngine[assetId] = assetCacheEntity;
69
+ }
70
+ buildMeasures(device, asset, measurements, payloadUuids) {
71
+ const measures = [];
72
+ for (const measurement of measurements) {
73
+ if (!this.measuresRegister.has(measurement.type)) {
74
+ this.app.log.warn(`Unknown measurement "${measurement.type}" from Decoder "${device._source.model}"`);
75
+ continue;
149
76
  }
77
+ const deviceMeasureName = measurement.deviceMeasureName || measurement.type;
78
+ const assetMeasureName = asset === null ? undefined : this.findAssetMeasureName(device, asset, deviceMeasureName);
79
+ const measureContent = {
80
+ assetMeasureName,
81
+ deviceMeasureName,
82
+ measuredAt: measurement.measuredAt,
83
+ origin: {
84
+ assetId: asset ? asset._id : undefined,
85
+ deviceModel: device._source.model,
86
+ id: device._id,
87
+ payloadUuids,
88
+ type: types_1.OriginType.DEVICE,
89
+ },
90
+ type: measurement.type,
91
+ unit: this.measuresRegister.get(measurement.type).unit,
92
+ values: measurement.values,
93
+ };
94
+ measures.push(measureContent);
150
95
  }
151
- // Search for engine in cache or see if index exist
152
- let engineMeasures = null;
153
- if (engineId !== this.config.adminIndex) {
154
- engineMeasures = engineMeasuresCache[engineId];
155
- if (!engineMeasures) {
156
- engineMeasures = [];
157
- engineMeasuresCache[engineId] = engineMeasures;
158
- }
96
+ return measures;
97
+ }
98
+ async getDevices(deviceModel, references, { refresh }) {
99
+ let devices = [];
100
+ // @todo replace with batch.mGet when available
101
+ const { successes, errors } = await this.sdk.document.mGet(this.config.adminIndex, InternalCollection_1.InternalCollection.DEVICES, references.map(reference => models_1.Device.id(deviceModel, reference)));
102
+ for (const { _source, _id } of successes) {
103
+ devices.push(new models_1.Device(_source, _id));
159
104
  }
160
- for (const measurement of measurements) {
161
- // Get type
162
- if (!this.measuresRegister.has(measurement.type)) {
163
- unknownTypeMeasurements.push(measurement);
105
+ // If we have unknown devices, let's check if we should register them
106
+ if (errors.length > 0) {
107
+ const { _source } = await this.batch.get(this.config.adminIndex, this.config.adminCollections.config.name, 'plugin--device-manager');
108
+ if (_source['device-manager'].provisioningStrategy === 'auto') {
109
+ const newDevices = await this.provisionDevices(deviceModel, errors, { refresh });
110
+ devices.push(...newDevices);
164
111
  }
165
112
  else {
166
- // Refine measurements in measures
167
- const deviceMeasureName = measurement.deviceMeasureName ?? measurement.type;
168
- const assetMeasureName = this.findAssetMeasureName(deviceId, measurement.deviceMeasureName, assetCacheEntity);
169
- const measureContent = {
170
- assetMeasureName,
171
- deviceMeasureName,
172
- measuredAt: measurement.measuredAt,
173
- origin: {
174
- assetId,
175
- deviceModel,
176
- id: deviceId,
177
- payloadUuids,
178
- type: types_1.OriginType.DEVICE,
179
- },
180
- type: measurement.type,
181
- unit: this.measuresRegister.get(measurement.type).unit,
182
- values: measurement.values,
183
- };
184
- // Insert measures in cache structs
185
- if (engineMeasures) {
186
- engineMeasures.push(measureContent);
187
- }
188
- if (assetMeasureName) {
189
- assetCacheEntity.measures.push(measureContent);
190
- }
191
- deviceMeasures.measures.push(measureContent);
113
+ this.app.log.info(`Skipping new devices "${errors.join(', ')}". Auto-provisioning is disabled.`);
192
114
  }
193
115
  }
116
+ return devices;
117
+ }
118
+ async provisionDevices(deviceModel, deviceIds, { refresh }) {
119
+ const newDevices = deviceIds.map(deviceId => {
120
+ // Reference may contains a "-"
121
+ const [, ...rest] = deviceId.split('-');
122
+ const reference = rest.join('');
123
+ return {
124
+ _id: models_1.Device.id(deviceModel, reference),
125
+ body: {
126
+ measures: [],
127
+ model: deviceModel,
128
+ reference,
129
+ }
130
+ };
131
+ });
132
+ // @todo replace with batch.mCreate when available
133
+ const { successes } = await this.sdk.document.mCreate(this.config.adminIndex, InternalCollection_1.InternalCollection.DEVICES, newDevices, { refresh, strict: true, });
134
+ return successes.map(({ _source, _id }) => new models_1.Device(_source, _id));
194
135
  }
195
136
  /**
196
137
  * Register new measures from a device, updates :
@@ -203,12 +144,10 @@ class MeasureService {
203
144
  * @param assetId Asset id
204
145
  * @param jsonMeasurements `AssetMeasurement` array from a request
205
146
  * @param kuid Kuid of the user pushing the measurements
206
- * @param {object} options
207
147
  * @param options.refresh Wait for ES indexation
208
148
  * @param options.strict If true, throw if an operation isn't possible
209
149
  */
210
150
  async registerByAsset(engineId, assetId, jsonMeasurements, kuid, { refresh, strict } = {}) {
211
- const eventId = `${MeasureService.eventId}:registerByAsset`;
212
151
  const invalidMeasurements = [];
213
152
  const validMeasures = [];
214
153
  const asset = await this.assetService.getAsset(engineId, assetId);
@@ -250,20 +189,8 @@ class MeasureService {
250
189
  };
251
190
  }
252
191
  asset.updateMeasures(validMeasures);
253
- const response = await this.app.trigger(`${eventId}:before`, {
254
- asset,
255
- engineId,
256
- invalidMeasurements,
257
- validMeasures,
258
- });
259
- await this.sdk.document.update(engineId, InternalCollection_1.InternalCollection.ASSETS, asset._id, { measures: response.asset._source.measures });
192
+ await this.sdk.document.update(engineId, InternalCollection_1.InternalCollection.ASSETS, asset._id, { measures: asset._source.measures });
260
193
  await this.historizeEngineMeasures(engineId, validMeasures, { refresh });
261
- await this.app.trigger(`${eventId}:after`, {
262
- asset,
263
- engineId,
264
- invalidMeasurements,
265
- validMeasures,
266
- });
267
194
  return {
268
195
  asset: asset.serialize,
269
196
  engineId,
@@ -284,19 +211,11 @@ class MeasureService {
284
211
  && lodash_1.default.has(toValidate, 'type')
285
212
  && this.measuresRegister.has(toValidate.type);
286
213
  }
287
- findAssetMeasureName(deviceId, deviceMeasureName, assetMeasures) {
288
- if (assetMeasures) {
289
- const link = assetMeasures.asset._source.deviceLinks.find(deviceLink => deviceLink.deviceId === deviceId);
290
- if (link) {
291
- const measureNameLink = link.measureNamesLinks.find(nameLink => nameLink.deviceMeasureName === deviceMeasureName);
292
- if (measureNameLink) {
293
- return measureNameLink.assetMeasureName;
294
- }
295
- }
296
- }
297
- return null;
214
+ findAssetMeasureName(device, asset, deviceMeasureName) {
215
+ const deviceLink = asset._source.deviceLinks.find(link => link.deviceId === device._id);
216
+ const measureLink = deviceLink.measureNamesLinks.find(nameLink => nameLink.deviceMeasureName === deviceMeasureName);
217
+ return measureLink.assetMeasureName;
298
218
  }
299
219
  }
300
220
  exports.MeasureService = MeasureService;
301
- MeasureService.eventId = 'device-manager:measure';
302
221
  //# sourceMappingURL=MeasureService.js.map
@@ -20,5 +20,7 @@ export declare class PayloadService {
20
20
  */
21
21
  process(request: KuzzleRequest, decoder: Decoder, { refresh }?: {
22
22
  refresh?: 'wait_for' | 'false';
23
- }): Promise<{}>;
23
+ }): Promise<void | {
24
+ valid: boolean;
25
+ }>;
24
26
  }
@@ -45,9 +45,7 @@ class PayloadService {
45
45
  }, uuid);
46
46
  }
47
47
  const decodedPayload = await decoder.decode(payload, request);
48
- const pluginConfig = await this.batch.get(this.config.adminIndex, this.config.adminCollections.config.name, 'plugin--device-manager');
49
- const autoProvisionDevice = pluginConfig._source['device-manager'].provisioningStrategy === 'auto';
50
- return this.measureService.registerByDecodedPayload(decoder.deviceModel, decodedPayload, [uuid], { autoProvisionDevice, refresh });
48
+ return this.measureService.processDecodedPayload(decoder.deviceModel, decodedPayload, [uuid], { refresh });
51
49
  }
52
50
  }
53
51
  exports.PayloadService = PayloadService;
@@ -9,7 +9,12 @@ export declare class BaseAsset {
9
9
  constructor(content: BaseAssetContent, _id?: string);
10
10
  linkToDevice(linkRequest: LinkRequest): void;
11
11
  unlinkDevice(device: Device): void;
12
- updateMeasures(measures: MeasureContent[]): void;
12
+ /**
13
+ * Updates the asset measures.
14
+ *
15
+ * Only keep the latest measures
16
+ */
17
+ updateMeasures(newMeasures: MeasureContent[]): void;
13
18
  removeMeasures(assetMeasureNames: string[]): {
14
19
  notFound: string[];
15
20
  removed: any[];
@@ -21,18 +21,21 @@ class BaseAsset {
21
21
  const linkToKeep = this._source.deviceLinks.filter((deviceLink) => deviceLink.deviceId !== device._id);
22
22
  this._source.deviceLinks = linkToKeep;
23
23
  }
24
- updateMeasures(measures) {
25
- const measuresByName = new Map();
26
- for (const existingMeasure of this._source.measures) {
27
- measuresByName.set(existingMeasure.assetMeasureName, existingMeasure);
28
- }
29
- for (const measure of measures) {
30
- const existingMeasure = measuresByName.get(measure.assetMeasureName);
31
- if (!existingMeasure || existingMeasure.measuredAt < measure.measuredAt) {
32
- measuresByName.set(measure.assetMeasureName, measure);
24
+ /**
25
+ * Updates the asset measures.
26
+ *
27
+ * Only keep the latest measures
28
+ */
29
+ updateMeasures(newMeasures) {
30
+ for (const newMeasure of newMeasures) {
31
+ const idx = this._source.measures.findIndex(measure => measure.assetMeasureName === newMeasure.assetMeasureName);
32
+ if (idx === -1) {
33
+ this._source.measures.push(newMeasure);
34
+ }
35
+ else if (newMeasure.measuredAt > this._source.measures[idx].measuredAt) {
36
+ this._source.measures[idx] = newMeasure;
33
37
  }
34
38
  }
35
- this._source.measures = Array.from(measuresByName.values());
36
39
  }
37
40
  removeMeasures(assetMeasureNames) {
38
41
  const removed = [];
@@ -11,5 +11,10 @@ export declare class Device {
11
11
  };
12
12
  unlinkToAsset(): void;
13
13
  linkToAsset(linkRequest: LinkRequest): void;
14
- updateMeasures(measures: MeasureContent[]): void;
14
+ /**
15
+ * Updates the asset measures.
16
+ *
17
+ * Only keep the latest measures
18
+ */
19
+ updateMeasures(newMeasures: MeasureContent[]): void;
15
20
  }
@@ -27,18 +27,21 @@ class Device {
27
27
  linkToAsset(linkRequest) {
28
28
  this._source.assetId = linkRequest.assetId;
29
29
  }
30
- updateMeasures(measures) {
31
- const measuresByName = new Map();
32
- for (const existingMeasure of this._source.measures) {
33
- measuresByName.set(existingMeasure.deviceMeasureName, existingMeasure);
34
- }
35
- for (const measure of measures) {
36
- const existingMeasure = measuresByName.get(measure.deviceMeasureName);
37
- if (!existingMeasure || existingMeasure.measuredAt < measure.measuredAt) {
38
- measuresByName.set(measure.deviceMeasureName, measure);
30
+ /**
31
+ * Updates the asset measures.
32
+ *
33
+ * Only keep the latest measures
34
+ */
35
+ updateMeasures(newMeasures) {
36
+ for (const newMeasure of newMeasures) {
37
+ const idx = this._source.measures.findIndex(measure => measure.deviceMeasureName === newMeasure.deviceMeasureName);
38
+ if (idx === -1) {
39
+ this._source.measures.push(newMeasure);
40
+ }
41
+ else if (newMeasure.measuredAt > this._source.measures[idx].measuredAt) {
42
+ this._source.measures[idx] = newMeasure;
39
43
  }
40
44
  }
41
- this._source.measures = Array.from(measuresByName.values());
42
45
  }
43
46
  }
44
47
  exports.Device = Device;
@@ -1,40 +1,21 @@
1
1
  import { Measurement } from './measures/MeasureContent';
2
2
  /**
3
- * Result of the `Decoder.decode` method.
3
+ * Record containing decoded measurements for each device.
4
4
  *
5
- * Contains the decoded measurements.
5
+ * Record<deviceReference, Measurement[]>
6
6
  *
7
7
  * @example
8
8
  * const decodedPayload: DecodedPayload = {
9
9
  * 'BZH42AZF': [
10
10
  * {
11
11
  * deviceMeasureName: 'battery',
12
- * measuredAt: Date.now(),
12
+ * measuredAt: 1655379939496,
13
13
  * type: 'battery',
14
14
  * values: { battery: 32 },
15
15
  * },
16
- * {
17
- * deviceMeasureName: 'internal_temperature',
18
- * measuredAt: Date.now(),
19
- * type: 'temperature',
20
- * values: { temperature: -3 },
21
- * },
22
- * {
23
- * deviceMeasureName: 'external_temperature',
24
- * measuredAt: Date.now(),
25
- * type: 'temperature',
26
- * values: { temperature: 39 },
27
- * },
28
16
  * ],
29
- *
30
17
  * 'IS7L8HK': [
31
18
  * {
32
- * deviceMeasureName: 'battery',
33
- * measuredAt: 1655379939496,
34
- * type: 'battery',
35
- * values: { battery: 92 },
36
- * },
37
- * {
38
19
  * deviceMeasureName: 'internal_temperature',
39
20
  * measuredAt: 1655379939496,
40
21
  * type: 'temperature',
@@ -49,5 +30,4 @@ import { Measurement } from './measures/MeasureContent';
49
30
  * ],
50
31
  * };
51
32
  */
52
- export declare type DecodedPayload = Record<string, // deviceReference
53
- Measurement[]>;
33
+ export declare type DecodedPayload = Record<string, Measurement[]>;
@@ -1,3 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ // @todo we should have an intermediary object
3
4
  //# sourceMappingURL=DecodedPayload.js.map
@@ -25,6 +25,8 @@ export interface Measurement {
25
25
  measuredAt?: number;
26
26
  /**
27
27
  * Name given by the decoder to the measure.
28
+ *
29
+ * By default, it's the type of the measure
28
30
  */
29
31
  deviceMeasureName?: string;
30
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kuzzle-device-manager",
3
- "version": "2.0.0-rc8",
3
+ "version": "2.0.0-rc9",
4
4
  "description": "Manage your IoT devices and assets. Choose a provisioning strategy, receive and decode payload, handle your IoT business logic.",
5
5
  "author": "The Kuzzle Team (support@kuzzle.io)",
6
6
  "repository": {