From eeb73082c658ca554f9bd2c246e28ceacfbc88c4 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Tue, 19 Nov 2024 14:21:58 +0100 Subject: [PATCH 01/26] store last measure --- lib/services/devices/deviceRegistryMemory.js | 5 ++++ lib/services/devices/deviceRegistryMongoDB.js | 29 ++++++++++++++++--- lib/services/devices/deviceService.js | 9 ++++-- lib/services/ngsi/ngsiService.js | 4 ++- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/services/devices/deviceRegistryMemory.js b/lib/services/devices/deviceRegistryMemory.js index f191692a2..5631eb00b 100644 --- a/lib/services/devices/deviceRegistryMemory.js +++ b/lib/services/devices/deviceRegistryMemory.js @@ -210,8 +210,13 @@ function getDevicesByAttribute(name, value, service, subservice, callback) { } } +function storeDevice(measure, typeInformation, callback) { + callback(); +} + exports.getDevicesByAttribute = getDevicesByAttribute; exports.store = storeDevice; +exports.storeLastMeasure = storeLastMeasure; exports.update = update; exports.remove = removeDevice; exports.list = listDevices; diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index d966a4c62..c7b2d0372 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -220,7 +220,7 @@ function findOneInMongoDB(queryParams, id, callback) { * @param {String} subservice Division inside the service (optional). */ function getDeviceById(id, apikey, service, subservice, callback) { - let queryParams = { + const queryParams = { id, service, subservice @@ -252,9 +252,9 @@ function getDevice(id, apikey, service, subservice, callback) { function getByNameAndType(name, type, service, servicepath, callback) { context = fillService(context, { service, subservice: servicepath }); - let optionsQuery = { - name: name, - service: service, + const optionsQuery = { + name, + service, subservice: servicepath }; if (type) { @@ -371,8 +371,29 @@ function getDevicesByAttribute(name, value, service, subservice, callback) { }); } +function storeLastMeasure(measure, typeInformation, callback) { + getDevice( + typeInformation.id, + typeInformation.apikey, + typeInformation.service, + typeInformation.subservice, + function (error, data) { + if (error) { + callback(error); + } else { + data.measure = measure; + /* eslint-disable-next-line new-cap */ + const deviceObj = new Device.model(data); + deviceObj.isNew = false; + deviceObj.save(saveDeviceHandler(callback)); + } + } + ); +} + exports.getDevicesByAttribute = alarmsInt(constants.MONGO_ALARM, getDevicesByAttribute); exports.store = alarmsInt(constants.MONGO_ALARM, storeDevice); +exports.storeLastMeasure = alarmsInt(constants.MONGO_ALARM, storeLastMeasure); exports.update = alarmsInt(constants.MONGO_ALARM, update); exports.remove = alarmsInt(constants.MONGO_ALARM, removeDevice); exports.list = alarmsInt(constants.MONGO_ALARM, listDevices); diff --git a/lib/services/devices/deviceService.js b/lib/services/devices/deviceService.js index 03be2722c..0d8e2fd90 100644 --- a/lib/services/devices/deviceService.js +++ b/lib/services/devices/deviceService.js @@ -285,7 +285,7 @@ function registerDevice(deviceObj, callback) { let attrList = pluginUtils.getIdTypeServSubServiceFromDevice(deviceData); attrList = deviceData.staticAttributes ? attrList.concat(deviceData.staticAttributes) : attrList; attrList = configuration.staticAttributes ? attrList.concat(configuration.staticAttributes) : attrList; - let ctxt = expressionPlugin.extractContext(attrList); + const ctxt = expressionPlugin.extractContext(attrList); try { entityName = expressionPlugin.applyExpression(configuration.entityNameExp, ctxt, deviceData); } catch (e) { @@ -616,7 +616,7 @@ function findOrCreate(deviceId, apikey, group, callback) { } else if (error.name === 'DEVICE_NOT_FOUND') { const newDevice = { id: deviceId, - apikey: apikey, + apikey, service: group.service, subservice: group.subservice, type: group.type @@ -692,6 +692,10 @@ function retrieveDevice(deviceId, apiKey, callback) { } } +function storeLastMeasure(measure, typeInformation, callback) { + config.getRegistry().storeLastMeasure(measure, typeInformation, callback); +} + exports.listDevices = intoTrans(context, checkRegistry)(listDevices); exports.listDevicesWithType = intoTrans(context, checkRegistry)(listDevicesWithType); exports.getDevice = intoTrans(context, checkRegistry)(getDevice); @@ -708,4 +712,5 @@ exports.retrieveDevice = intoTrans(context, checkRegistry)(retrieveDevice); exports.mergeDeviceWithConfiguration = mergeDeviceWithConfiguration; exports.findOrCreate = findOrCreate; exports.findConfigurationGroup = findConfigurationGroup; +exports.storeLastMeasure = intoTrans(context, checkRegistry)(storeLastMeasure); exports.init = init; diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 4b57c53c1..e6671cd48 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -27,6 +27,7 @@ const async = require('async'); const apply = async.apply; const statsRegistry = require('../stats/statsRegistry'); +const deviceService = require('../devices/deviceService'); const intoTrans = require('../common/domain').intoTrans; const fillService = require('./../common/domain').fillService; const errors = require('../../errors'); @@ -69,7 +70,8 @@ function init() { */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + const newCallback2 = entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + deviceService.storeLastMeasure(attributes, typeInformation, newCallback2); } /** From aaffe7bd64fc60774ce47b495f36327f94e3361c Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Tue, 19 Nov 2024 15:43:14 +0100 Subject: [PATCH 02/26] fix storeLastMeasure --- lib/services/devices/deviceRegistryMemory.js | 25 +++++++++++- lib/services/devices/deviceRegistryMongoDB.js | 40 +++++++++++-------- lib/services/devices/deviceService.js | 2 +- lib/services/ngsi/ngsiService.js | 4 +- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/lib/services/devices/deviceRegistryMemory.js b/lib/services/devices/deviceRegistryMemory.js index 5631eb00b..2cb54722a 100644 --- a/lib/services/devices/deviceRegistryMemory.js +++ b/lib/services/devices/deviceRegistryMemory.js @@ -210,8 +210,29 @@ function getDevicesByAttribute(name, value, service, subservice, callback) { } } -function storeDevice(measure, typeInformation, callback) { - callback(); +function storeLastMeasure(measure, typeInformation, callback) { + if ( + typeInformation && + typeInformation.id && + typeInformation.apikey && + typeInformation.service && + typeInformation.subservice + ) { + getDevice( + typeInformation.id, + typeInformation.apikey, + typeInformation.service, + typeInformation.subservice, + function (error, data) { + if (data) { + data.measure = measure; + } + if (callback) { + callback(null, data); + } + } + ); + } } exports.getDevicesByAttribute = getDevicesByAttribute; diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index c7b2d0372..47fb0d427 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -372,23 +372,31 @@ function getDevicesByAttribute(name, value, service, subservice, callback) { } function storeLastMeasure(measure, typeInformation, callback) { - getDevice( - typeInformation.id, - typeInformation.apikey, - typeInformation.service, - typeInformation.subservice, - function (error, data) { - if (error) { - callback(error); - } else { - data.measure = measure; - /* eslint-disable-next-line new-cap */ - const deviceObj = new Device.model(data); - deviceObj.isNew = false; - deviceObj.save(saveDeviceHandler(callback)); + if ( + typeInformation && + typeInformation.id && + typeInformation.apikey && + typeInformation.service && + typeInformation.subservice + ) { + getDevice( + typeInformation.id, + typeInformation.apikey, + typeInformation.service, + typeInformation.subservice, + function (error, data) { + if (error) { + callback(error); + } else { + data.measure = measure; + /* eslint-disable-next-line new-cap */ + const deviceObj = new Device.model(data); + deviceObj.isNew = false; + deviceObj.save(saveDeviceHandler(callback)); + } } - } - ); + ); + } } exports.getDevicesByAttribute = alarmsInt(constants.MONGO_ALARM, getDevicesByAttribute); diff --git a/lib/services/devices/deviceService.js b/lib/services/devices/deviceService.js index 0d8e2fd90..bfa5cd924 100644 --- a/lib/services/devices/deviceService.js +++ b/lib/services/devices/deviceService.js @@ -712,5 +712,5 @@ exports.retrieveDevice = intoTrans(context, checkRegistry)(retrieveDevice); exports.mergeDeviceWithConfiguration = mergeDeviceWithConfiguration; exports.findOrCreate = findOrCreate; exports.findConfigurationGroup = findConfigurationGroup; -exports.storeLastMeasure = intoTrans(context, checkRegistry)(storeLastMeasure); +exports.storeLastMeasure = storeLastMeasure; exports.init = init; diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index e6671cd48..d30ec3a90 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -70,8 +70,8 @@ function init() { */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - const newCallback2 = entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); - deviceService.storeLastMeasure(attributes, typeInformation, newCallback2); + const updateCallback = entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + deviceService.storeLastMeasure(attributes, typeInformation, updateCallback); } /** From 28f29f0f37e42110059fdc0b388854449ea488e9 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Tue, 19 Nov 2024 17:26:42 +0100 Subject: [PATCH 03/26] move measure to lastMeasure --- lib/model/Device.js | 3 ++- lib/services/devices/deviceRegistryMemory.js | 2 +- lib/services/devices/deviceRegistryMongoDB.js | 2 +- lib/services/ngsi/ngsiService.js | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/model/Device.js b/lib/model/Device.js index 073211df7..0383df45e 100644 --- a/lib/model/Device.js +++ b/lib/model/Device.js @@ -53,7 +53,8 @@ const Device = new Schema({ autoprovision: Boolean, explicitAttrs: Group.ExplicitAttrsType, ngsiVersion: String, - payloadType: String + payloadType: String, + lastMeasure: Object }); function load(db) { diff --git a/lib/services/devices/deviceRegistryMemory.js b/lib/services/devices/deviceRegistryMemory.js index 2cb54722a..bac8da422 100644 --- a/lib/services/devices/deviceRegistryMemory.js +++ b/lib/services/devices/deviceRegistryMemory.js @@ -225,7 +225,7 @@ function storeLastMeasure(measure, typeInformation, callback) { typeInformation.subservice, function (error, data) { if (data) { - data.measure = measure; + data.lastMeasure = measure; } if (callback) { callback(null, data); diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 47fb0d427..459e99169 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -388,7 +388,7 @@ function storeLastMeasure(measure, typeInformation, callback) { if (error) { callback(error); } else { - data.measure = measure; + data.lastMeasure = measure; /* eslint-disable-next-line new-cap */ const deviceObj = new Device.model(data); deviceObj.isNew = false; diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index d30ec3a90..fb627ca02 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -69,9 +69,9 @@ function init() { * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { + deviceService.storeLastMeasure(attributes, typeInformation, function (error, data) {}); const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - const updateCallback = entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); - deviceService.storeLastMeasure(attributes, typeInformation, updateCallback); + entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); } /** From ba0ccab6d10e1710ae1b7af1a85ff98a08005ce1 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Tue, 19 Nov 2024 17:43:26 +0100 Subject: [PATCH 04/26] fix linter --- lib/services/ngsi/ngsiService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index fb627ca02..8812a149a 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -69,7 +69,7 @@ function init() { * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { - deviceService.storeLastMeasure(attributes, typeInformation, function (error, data) {}); + deviceService.storeLastMeasure(attributes, typeInformation, function () {}); const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); } From e1ab070fa0ff9868afd8691191e581abe5e30a48 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 20 Nov 2024 13:19:28 +0100 Subject: [PATCH 05/26] fix registy callbacks --- lib/services/devices/deviceRegistryMemory.js | 16 +++++++++++----- lib/services/devices/deviceRegistryMongoDB.js | 2 ++ lib/services/ngsi/ngsiService.js | 7 ++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/services/devices/deviceRegistryMemory.js b/lib/services/devices/deviceRegistryMemory.js index bac8da422..3a81aec49 100644 --- a/lib/services/devices/deviceRegistryMemory.js +++ b/lib/services/devices/deviceRegistryMemory.js @@ -224,14 +224,20 @@ function storeLastMeasure(measure, typeInformation, callback) { typeInformation.service, typeInformation.subservice, function (error, data) { - if (data) { - data.lastMeasure = measure; - } - if (callback) { - callback(null, data); + if (!error) { + if (data) { + data.lastMeasure = measure; + } + if (callback) { + callback(null, data); + } + } else { + callback(error, null); } } ); + } else { + callback(null, null); } } diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 459e99169..3f90f18d2 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -396,6 +396,8 @@ function storeLastMeasure(measure, typeInformation, callback) { } } ); + } else { + callback(null, null); } } diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 8812a149a..bf9b2f064 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -69,9 +69,10 @@ function init() { * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { - deviceService.storeLastMeasure(attributes, typeInformation, function () {}); - const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + deviceService.storeLastMeasure(attributes, typeInformation, function () { + const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); + return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + }); } /** From aced6695a83e768509446f056bfa3144fa51a27a Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 20 Nov 2024 16:16:55 +0100 Subject: [PATCH 06/26] add timestamp to lastMeasure --- lib/services/devices/deviceRegistryMongoDB.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 3f90f18d2..0bc41cc65 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -388,7 +388,7 @@ function storeLastMeasure(measure, typeInformation, callback) { if (error) { callback(error); } else { - data.lastMeasure = measure; + data.lastMeasure = { timestamp: new Date().toISOString(), measure }; /* eslint-disable-next-line new-cap */ const deviceObj = new Device.model(data); deviceObj.isNew = false; From 16860ce02060254ded741ff843a6008d98ab7587 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 20 Nov 2024 16:58:39 +0100 Subject: [PATCH 07/26] update CNR --- CHANGES_NEXT_RELEASE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index dc94d71be..799718d51 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1 +1,2 @@ -- Upgrade express de from 4.19.2 to 4.20.0 +- Upgrade express de from 4.19.2 to 4.20.0 +- Store last measure in device (by id, apikey, service and subservice) (#1669) From ea16a2c57634ffa402ce509c256efc7db023670d Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 21 Nov 2024 17:10:49 +0100 Subject: [PATCH 08/26] add and check store last measure config --- config.js | 3 ++- lib/commonConfig.js | 8 +++++++- lib/services/ngsi/ngsiService.js | 13 +++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/config.js b/config.js index 88b4e610d..d9ad2e7a4 100644 --- a/config.js +++ b/config.js @@ -77,7 +77,8 @@ var config = { providerUrl: 'http://192.168.56.1:4041', deviceRegistrationDuration: 'P1M', defaultType: 'Thing', - expressLimit: '1Mb' + expressLimit: '1Mb', + storeLastMeasure: false }; module.exports = config; diff --git a/lib/commonConfig.js b/lib/commonConfig.js index d16908615..3f166abdd 100644 --- a/lib/commonConfig.js +++ b/lib/commonConfig.js @@ -157,7 +157,8 @@ function processEnvironmentVariables() { 'IOTA_FALLBACK_PATH', 'IOTA_LD_SUPPORT_NULL', 'IOTA_LD_SUPPORT_DATASET_ID', - 'IOTA_EXPRESS_LIMIT' + 'IOTA_EXPRESS_LIMIT', + 'IOTA_STORE_LAST_MEASURE' ]; const iotamVariables = [ 'IOTA_IOTAM_URL', @@ -474,6 +475,11 @@ function processEnvironmentVariables() { } else { config.expressLimit = config.expressLimit ? config.expressLimit : '1mb'; } + if (process.env.IOTA_STORE_LAST_MEASURE) { + config.storeLastMeasure = process.env.IOTA_STORE_LAST_MEASURE === 'true'; + } else { + config.storeLastMeasure = config.storeLastMeasure === true; + } } function setConfig(newConfig) { diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index bf9b2f064..2b233de87 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -69,10 +69,15 @@ function init() { * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { - deviceService.storeLastMeasure(attributes, typeInformation, function () { - const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); - }); + // check config about store last measure + const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); + if (config.getConfig().storeLastMeasure) { + deviceService.storeLastMeasure(attributes, typeInformation, function () { + return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + }); + } else { + entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); + } } /** From 85c428f4fb644a19192fe7f1edf076dca660b098 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 25 Nov 2024 12:42:53 +0100 Subject: [PATCH 09/26] update doc --- doc/admin.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/admin.md b/doc/admin.md index b82c27f88..b5df9d381 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -125,9 +125,9 @@ allowing the computer to interpret the rest of the data with more clarity and de ``` Under mixed mode, **NGSI v2** payloads are used for context broker communications by default, but this payload may also -be switched to **NGSI LD** at group or device provisioning time using the `ngsiVersion` field in the -provisioning API. The `ngsiVersion` field switch may be added at either group or device level, with the device level -overriding the group setting. +be switched to **NGSI LD** at group or device provisioning time using the `ngsiVersion` field in the provisioning API. +The `ngsiVersion` field switch may be added at either group or device level, with the device level overriding the group +setting. #### `server` @@ -306,7 +306,8 @@ added `agentPath`: #### `types` -This parameter includes additional groups configuration as described into the [Config group API](api.md#config-group-api) section. +This parameter includes additional groups configuration as described into the +[Config group API](api.md#config-group-api) section. #### `service` @@ -415,7 +416,13 @@ IotAgents, as all Express applications that use the body-parser middleware, have size that the application will handle. This default limit for ioiotagnets are 1Mb. So, if your IotAgent receives a request with a body that exceeds this limit, the application will throw a “Error: Request entity too large”. -The 1Mb default can be changed setting the `expressLimit` configuration parameter (or equivalente `IOTA_EXPRESS_LIMIT` environment variable). +The 1Mb default can be changed setting the `expressLimit` configuration parameter (or equivalente `IOTA_EXPRESS_LIMIT` +environment variable). + +#### `storeLastMeasure` + +If this flag is activated, last measure arrived to Device IoTAgent without be processed will be stored in Device under +lastMeasure field with in timestamp. This flag is disabled by default. ### Configuration using environment variables @@ -479,6 +486,7 @@ overrides. | IOTA_DEFAULT_ENTITY_NAME_CONJUNCTION | `defaultEntityNameConjunction` | | IOTA_RELAX_TEMPLATE_VALIDATION | `relaxTemplateValidation` | | IOTA_EXPRESS_LIMIT | `expressLimit` | +| IOTA_STORE_LAST_MEASURE | `storeLastMeasure` | Note: From 60bad444fc5dd598ae57f689c3d514cc081a807b Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Tue, 17 Dec 2024 12:41:15 +0100 Subject: [PATCH 10/26] Update CHANGES_NEXT_RELEASE --- CHANGES_NEXT_RELEASE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index ac3a4af01..1dc6eb90e 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,3 +1,4 @@ - Store last measure in device (by id, apikey, service and subservice) (#1669) - Upgrade express de from 4.19.2 to 4.20.0 -- Upgrade mongodb devdep from 4.17.1 to 4.17.2 \ No newline at end of file +- Upgrade mongodb devdep from 4.17.1 to 4.17.2 +- Upgrade mongoose dep from 5.13.20 to 8.4.4 (solving vulnerability CVE-2024-53900) (#1674) From 564b40a876effc3442817f29ac0f26886ae244fb Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 8 Jan 2025 16:30:06 +0100 Subject: [PATCH 11/26] fix save device with last measure with mongodb 8 --- lib/services/devices/deviceRegistryMongoDB.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 1781982a2..71aafb57a 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -413,7 +413,19 @@ function storeLastMeasure(measure, typeInformation, callback) { /* eslint-disable-next-line new-cap */ const deviceObj = new Device.model(data); deviceObj.isNew = false; - deviceObj.save(saveDeviceHandler(callback)); + deviceObj + .save({}) + .then((deviceDao) => { + callback(null, deviceDao.toObject()); + }) + .catch((error) => { + logger.debug( + fillService(context, deviceObj), + 'Error storing device information: %s', + error + ); + callback(new errors.InternalDbError(error)); + }); } } ); From c190fad557d9be73276a5eb9382d091ee2f1e796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Jan 2025 16:32:50 +0100 Subject: [PATCH 12/26] Update CHANGES_NEXT_RELEASE --- CHANGES_NEXT_RELEASE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 1dc6eb90e..07c364e08 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,4 +1,4 @@ - Store last measure in device (by id, apikey, service and subservice) (#1669) -- Upgrade express de from 4.19.2 to 4.20.0 +- Upgrade express dep from 4.19.2 to 4.20.0 - Upgrade mongodb devdep from 4.17.1 to 4.17.2 - Upgrade mongoose dep from 5.13.20 to 8.4.4 (solving vulnerability CVE-2024-53900) (#1674) From ba058b135f7e9b588c5886990acb202e34a8adc2 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 8 Jan 2025 16:53:01 +0100 Subject: [PATCH 13/26] Update CHANGES_NEXT_RELEASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- CHANGES_NEXT_RELEASE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 07c364e08..8ece5410c 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,4 +1,5 @@ -- Store last measure in device (by id, apikey, service and subservice) (#1669) +- Add: store last measure in device (by id, apikey, service and subservice) (#1669) +- Add: IOTA_STORE_LAST_MEASURE env var to set default store last measure behaviour at instance level (#1669) - Upgrade express dep from 4.19.2 to 4.20.0 - Upgrade mongodb devdep from 4.17.1 to 4.17.2 - Upgrade mongoose dep from 5.13.20 to 8.4.4 (solving vulnerability CVE-2024-53900) (#1674) From df26df140eb0539394afaf527ab0e132ea845661 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 9 Jan 2025 08:36:18 +0100 Subject: [PATCH 14/26] make storeLastMeasure configurable at device and group level --- lib/commonConfig.js | 3 ++- lib/model/Device.js | 1 + lib/model/Group.js | 3 ++- lib/services/devices/deviceRegistryMongoDB.js | 4 +++- lib/services/devices/deviceService.js | 3 +++ lib/services/devices/devices-NGSI-v2.js | 4 +++- lib/services/groups/groupRegistryMongoDB.js | 3 ++- lib/services/ngsi/ngsiService.js | 2 +- lib/services/northBound/deviceProvisioningServer.js | 9 ++++++--- lib/templates/updateDevice.json | 4 ++++ lib/templates/updateDeviceLax.json | 4 ++++ 11 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/commonConfig.js b/lib/commonConfig.js index 3f166abdd..d10c26a9c 100644 --- a/lib/commonConfig.js +++ b/lib/commonConfig.js @@ -509,7 +509,8 @@ function getConfigForTypeInformation() { multiCore: config.multiCore, relaxTemplateValidation: config.relaxTemplateValidation, defaultEntityNameConjunction: config.defaultEntityNameConjunction, - defaultType: config.defaultType + defaultType: config.defaultType, + storeLastMeasure: config.storeLastMeasure }; return conf; } diff --git a/lib/model/Device.js b/lib/model/Device.js index 3435ef3ce..8513eba04 100644 --- a/lib/model/Device.js +++ b/lib/model/Device.js @@ -54,6 +54,7 @@ const Device = new Schema({ explicitAttrs: Group.ExplicitAttrsType, ngsiVersion: String, payloadType: String, + storeLastMeasure: Boolean, lastMeasure: Object }); diff --git a/lib/model/Group.js b/lib/model/Group.js index cf710be26..83b2e1a3f 100644 --- a/lib/model/Group.js +++ b/lib/model/Group.js @@ -65,7 +65,8 @@ const Group = new Schema({ defaultEntityNameConjunction: String, ngsiVersion: String, entityNameExp: String, - payloadType: String + payloadType: String, + storeLastMeasure: Boolean }); function load() { diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 71aafb57a..6d013df2e 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -57,7 +57,8 @@ const attributeList = [ 'explicitAttrs', 'ngsiVersion', 'subscriptions', - 'payloadType' + 'payloadType', + 'storeLastMeasure' ]; /** @@ -319,6 +320,7 @@ function update(previousDevice, device, callback) { data.timestamp = device.timestamp; data.subscriptions = device.subscriptions; data.payloadType = device.payloadType; + data.storeLastMeasure = device.storeLastMeasure; /* eslint-disable-next-line new-cap */ const deviceObj = new Device.model(data); diff --git a/lib/services/devices/deviceService.js b/lib/services/devices/deviceService.js index bfa5cd924..c3af24053 100644 --- a/lib/services/devices/deviceService.js +++ b/lib/services/devices/deviceService.js @@ -179,6 +179,9 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio if (configuration && configuration.payloadType !== undefined && deviceData.payloadType === undefined) { deviceData.payloadType = configuration.payloadType; } + if (configuration && configuration.storeLastMeasure !== undefined && deviceData.storeLastMeasure === undefined) { + deviceData.storeLastMeasure = configuration.storeLastMeasure; + } logger.debug(context, 'deviceData after merge with conf: %j', deviceData); callback(null, deviceData); } diff --git a/lib/services/devices/devices-NGSI-v2.js b/lib/services/devices/devices-NGSI-v2.js index f5942467f..52f4ab72f 100644 --- a/lib/services/devices/devices-NGSI-v2.js +++ b/lib/services/devices/devices-NGSI-v2.js @@ -285,7 +285,9 @@ function updateRegisterDeviceNgsi2(deviceObj, previousDevice, entityInfoUpdated, if ('transport' in newDevice && newDevice.transport !== undefined) { oldDevice.transport = newDevice.transport; } - + if ('storeLastMeasure' in newDevice && newDevice.storeLastMeasure !== undefined) { + oldDevice.storeLastMeasure = newDevice.storeLastMeasure; + } callback(null, oldDevice); } else { callback(new errors.DeviceNotFound(newDevice.id, newDevice)); diff --git a/lib/services/groups/groupRegistryMongoDB.js b/lib/services/groups/groupRegistryMongoDB.js index 4cd8c4fdb..20e408744 100644 --- a/lib/services/groups/groupRegistryMongoDB.js +++ b/lib/services/groups/groupRegistryMongoDB.js @@ -61,7 +61,8 @@ const attributeList = [ 'defaultEntityNameConjunction', 'ngsiVersion', 'entityNameExp', - 'payloadType' + 'payloadType', + 'storeLastMeasure' ]; function createGroup(group, callback) { diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 2b233de87..00efa806d 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -71,7 +71,7 @@ function init() { function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { // check config about store last measure const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); - if (config.getConfig().storeLastMeasure) { + if (typeInformation.storeLastMeasure) { deviceService.storeLastMeasure(attributes, typeInformation, function () { return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); }); diff --git a/lib/services/northBound/deviceProvisioningServer.js b/lib/services/northBound/deviceProvisioningServer.js index 2099cba45..d9ee1668e 100644 --- a/lib/services/northBound/deviceProvisioningServer.js +++ b/lib/services/northBound/deviceProvisioningServer.js @@ -64,7 +64,8 @@ const provisioningAPITranslation = { explicitAttrs: 'explicitAttrs', ngsiVersion: 'ngsiVersion', entityNameExp: 'entityNameExp', - payloadType: 'payloadType' + payloadType: 'payloadType', + storeLastMeasure: 'storeLastMeasure' }; /** @@ -143,7 +144,8 @@ function handleProvision(req, res, next) { autoprovision: body.autoprovision, explicitAttrs: body.explicitAttrs, ngsiVersion: body.ngsiVersion, - payloadType: body.payloadType + payloadType: body.payloadType, + storeLastMeasure: body.storeLastMeasure }); } @@ -220,7 +222,8 @@ function toProvisioningAPIFormat(device) { autoprovision: device.autoprovision, explicitAttrs: device.explicitAttrs, ngsiVersion: device.ngsiVersion, - payloadType: device.payloadType + payloadType: device.payloadType, + storeLastMeasure: device.storeLastMeasure }; } diff --git a/lib/templates/updateDevice.json b/lib/templates/updateDevice.json index 3b6c0835a..9a27f32a7 100644 --- a/lib/templates/updateDevice.json +++ b/lib/templates/updateDevice.json @@ -194,6 +194,10 @@ "payloadType": { "description": "Payload type allowed for measures for this device", "type": "string" + }, + "storeLastMeasure": { + "description": "Store last measure", + "type": "boolean" } } } diff --git a/lib/templates/updateDeviceLax.json b/lib/templates/updateDeviceLax.json index a40bf59ed..32e73ff2c 100644 --- a/lib/templates/updateDeviceLax.json +++ b/lib/templates/updateDeviceLax.json @@ -146,6 +146,10 @@ "payloadType": { "description": "Payload type allowed for measures for this device", "type": "string" + }, + "storeLastMeasure": { + "description": "Store last measure", + "type": "boolean" } } } From a8bf666d847248c8ea1d1306ac36ce6aafe84651 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 9 Jan 2025 10:01:33 +0100 Subject: [PATCH 15/26] update doc --- doc/admin.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/admin.md b/doc/admin.md index b5df9d381..84fdb2959 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -422,7 +422,8 @@ environment variable). #### `storeLastMeasure` If this flag is activated, last measure arrived to Device IoTAgent without be processed will be stored in Device under -lastMeasure field with in timestamp. This flag is disabled by default. +lastMeasure field with in timestamp. This flag is overwritten by `storeLastMeasure` flag in group or device. This flag +is disabled by default. ### Configuration using environment variables From 6d77aeee55c8c47a51514d43915fd0140b34269a Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 9 Jan 2025 11:03:28 +0100 Subject: [PATCH 16/26] add storeLastMeasure to iotagent-manager model --- lib/services/common/iotManagerService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/services/common/iotManagerService.js b/lib/services/common/iotManagerService.js index b56fe9858..911ed3e26 100644 --- a/lib/services/common/iotManagerService.js +++ b/lib/services/common/iotManagerService.js @@ -63,7 +63,8 @@ function register(callback) { entityNameExp: service.entityNameExp, payloadType: service.payloadType, endpoint: service.endpoint, - transport: service.transport + transport: service.transport, + storeLastMeasure: service.storeLastMeasure }; } From 1f6f3f4f481082c84f8970669e4c816aa5df5c24 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 9 Jan 2025 11:42:22 +0100 Subject: [PATCH 17/26] add example --- doc/admin.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/admin.md b/doc/admin.md index 84fdb2959..f07168244 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -425,6 +425,24 @@ If this flag is activated, last measure arrived to Device IoTAgent without be pr lastMeasure field with in timestamp. This flag is overwritten by `storeLastMeasure` flag in group or device. This flag is disabled by default. +For example in a device document stored in MongoDB will be extended with a subdocument named lastMeasure like this: + +```json +{ + "lastMeasure": { + "timestamp": "2025-01-09T10:35:33.079Z", + "measure": [ + [ + { + "name": "level", + "type": "Text" + } + ] + ] + } +} +``` + ### Configuration using environment variables Some of the configuration parameters can be overriden with environment variables, to ease the use of those parameters From c08b4272270c84cbfcfbfe3234b06ec030629a7d Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 10 Jan 2025 12:08:59 +0100 Subject: [PATCH 18/26] add log --- lib/services/ngsi/ngsiService.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 00efa806d..3f2619f55 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -72,6 +72,7 @@ function sendUpdateValue(entityName, attributes, typeInformation, token, callbac // check config about store last measure const newCallback = statsRegistry.withStats('updateEntityRequestsOk', 'updateEntityRequestsError', callback); if (typeInformation.storeLastMeasure) { + logger.debug(context, 'StoreLastMeasure for %j', typeInformation); deviceService.storeLastMeasure(attributes, typeInformation, function () { return entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, newCallback); }); From 65f5d3f6ebed1228a4ece1405354a0c112ce6a04 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 10 Jan 2025 13:06:03 +0100 Subject: [PATCH 19/26] add lastMeasure to device api --- lib/services/northBound/deviceProvisioningServer.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/services/northBound/deviceProvisioningServer.js b/lib/services/northBound/deviceProvisioningServer.js index d9ee1668e..bc5d468a6 100644 --- a/lib/services/northBound/deviceProvisioningServer.js +++ b/lib/services/northBound/deviceProvisioningServer.js @@ -65,7 +65,8 @@ const provisioningAPITranslation = { ngsiVersion: 'ngsiVersion', entityNameExp: 'entityNameExp', payloadType: 'payloadType', - storeLastMeasure: 'storeLastMeasure' + storeLastMeasure: 'storeLastMeasure', + lastMeasure: 'lastMeasure' }; /** @@ -145,7 +146,8 @@ function handleProvision(req, res, next) { explicitAttrs: body.explicitAttrs, ngsiVersion: body.ngsiVersion, payloadType: body.payloadType, - storeLastMeasure: body.storeLastMeasure + storeLastMeasure: body.storeLastMeasure, + lastMeasure: body.lastMeasure }); } @@ -223,7 +225,8 @@ function toProvisioningAPIFormat(device) { explicitAttrs: device.explicitAttrs, ngsiVersion: device.ngsiVersion, payloadType: device.payloadType, - storeLastMeasure: device.storeLastMeasure + storeLastMeasure: device.storeLastMeasure, + lastMeasure: device.lastMeasure }; } From ecc6df1e9583f66514edff8b9eef31810cd88826 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 10 Jan 2025 14:27:43 +0100 Subject: [PATCH 20/26] Update admin.md --- doc/admin.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/admin.md b/doc/admin.md index f07168244..c269d4d32 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -435,7 +435,8 @@ For example in a device document stored in MongoDB will be extended with a subdo [ { "name": "level", - "type": "Text" + "type": "Text", + "value": "33" } ] ] From 38743b548bba261d0d94c7ecefd2879946c93ab3 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 15:54:00 +0100 Subject: [PATCH 21/26] Update doc/admin.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- doc/admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/admin.md b/doc/admin.md index c269d4d32..c1366ebef 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -422,7 +422,7 @@ environment variable). #### `storeLastMeasure` If this flag is activated, last measure arrived to Device IoTAgent without be processed will be stored in Device under -lastMeasure field with in timestamp. This flag is overwritten by `storeLastMeasure` flag in group or device. This flag +`lastMeasure` field (composed of sub-fields `timestamp` and `measure` for the measure itself, in multi-measure format). This flag is overwritten by `storeLastMeasure` flag in group or device. This flag is disabled by default. For example in a device document stored in MongoDB will be extended with a subdocument named lastMeasure like this: From 10f0a945ac50297b12cf9563d1f730ff3dd19f76 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 15:54:09 +0100 Subject: [PATCH 22/26] Update doc/admin.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- doc/admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/admin.md b/doc/admin.md index c1366ebef..7f7b687f3 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -436,7 +436,7 @@ For example in a device document stored in MongoDB will be extended with a subdo { "name": "level", "type": "Text", - "value": "33" + "value": 33 } ] ] From 849474352d63a89e03079af1ced6cb2d0b891a8f Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 16:30:59 +0100 Subject: [PATCH 23/26] update api --- doc/api.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/api.md b/doc/api.md index 15807bf9d..6ea05c6a8 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1777,6 +1777,7 @@ Config group is represented by a JSON object with the following fields: | `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. | | `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. | | `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. | +| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. False by default | ### Config group operations @@ -1998,6 +1999,8 @@ the API resource fields and the same fields in the database model. | `ngsiVersion` | ✓ | `string` | | string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. The default is `v2`. When not running in mixed mode, this field is ignored. | | `payloadType` | ✓ | `string` | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. | +| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. False by default. | + ### Device operations #### Retrieve devices /iot/devices `GET /iot/devices` From 5ef6d15973910d2a79d1a8d79048112b3ddef9af Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 16:45:21 +0100 Subject: [PATCH 24/26] Update doc/api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- doc/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api.md b/doc/api.md index 6ea05c6a8..d335a1bd6 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1777,7 +1777,7 @@ Config group is represented by a JSON object with the following fields: | `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. | | `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. | | `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. | -| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. False by default | +| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. See more info [in this section](admin.md#storelastmeasure). False by default | ### Config group operations From 1cab967ffb697fbd524cc20edbbfd5eaffabdb49 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 16:45:29 +0100 Subject: [PATCH 25/26] Update doc/api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- doc/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api.md b/doc/api.md index d335a1bd6..30d05f06e 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1999,7 +1999,7 @@ the API resource fields and the same fields in the database model. | `ngsiVersion` | ✓ | `string` | | string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. The default is `v2`. When not running in mixed mode, this field is ignored. | | `payloadType` | ✓ | `string` | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. | -| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. False by default. | +| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. See more info [in this section](admin.md#storelastmeasure). False by default. | ### Device operations From b8c5b6e760a90395f79453ef2c92dc8322d97ea5 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 13 Jan 2025 16:45:43 +0100 Subject: [PATCH 26/26] Update CHANGES_NEXT_RELEASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fermín Galán Márquez --- CHANGES_NEXT_RELEASE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 8ece5410c..1582bfc6a 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,4 +1,4 @@ -- Add: store last measure in device (by id, apikey, service and subservice) (#1669) +- Add: store last measure in device (by id, apikey, service and subservice) and new API field storeLastMeasure at group and device levels (#1669) - Add: IOTA_STORE_LAST_MEASURE env var to set default store last measure behaviour at instance level (#1669) - Upgrade express dep from 4.19.2 to 4.20.0 - Upgrade mongodb devdep from 4.17.1 to 4.17.2