@hello.nrfcloud.com/proto-map 16.1.6 → 16.1.8
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/README.md +3 -0
- package/dist/senml/SenMLSchema.js +3 -0
- package/dist/senml/hasName.js +9 -0
- package/dist/senml/senMLtoLwM2M.js +24 -1
- package/dist/senml/senMLtoLwM2M.spec.js +149 -0
- package/package.json +6 -6
- package/senml/SenMLSchema.ts +3 -0
- package/senml/hasName.ts +5 -0
- package/senml/senMLtoLwM2M.spec.ts +16 -1
- package/senml/senMLtoLwM2M.ts +26 -3
package/README.md
CHANGED
|
@@ -63,6 +63,9 @@ The conformity to the rules is checked using the script
|
|
|
63
63
|
- Timestamps are to be expressed in the **base time** property `bt` and are
|
|
64
64
|
mapped to the LwM2M object's timestamp property and must not be send as a
|
|
65
65
|
property.
|
|
66
|
+
- SenML records may be a Time only, in case it is sufficient to express the
|
|
67
|
+
object as a combination of InstanceID and timestamp, for example in case of
|
|
68
|
+
the [Button Press (14220) object](./lwm2m/14220.xml).
|
|
66
69
|
|
|
67
70
|
### Model definition rules
|
|
68
71
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
function _type_of(obj) {
|
|
2
|
+
"@swc/helpers - typeof";
|
|
3
|
+
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
4
|
+
}
|
|
5
|
+
export var hasName = function(m) {
|
|
6
|
+
if (m === null) return false;
|
|
7
|
+
if ((typeof m === "undefined" ? "undefined" : _type_of(m)) !== 'object') return false;
|
|
8
|
+
return 'n' in m;
|
|
9
|
+
};
|
|
@@ -51,8 +51,9 @@ function _object_spread_props(target, source) {
|
|
|
51
51
|
return target;
|
|
52
52
|
}
|
|
53
53
|
import { timestampResources } from '../lwm2m/timestampResources.js';
|
|
54
|
-
import {
|
|
54
|
+
import { hasName } from './hasName.js';
|
|
55
55
|
import { hasValue } from './hasValue.js';
|
|
56
|
+
import { parseResourceId } from './parseResourceId.js';
|
|
56
57
|
var isInfoForDifferentInstance = function(currentObject, resourceID, currentBaseTime, tsRes) {
|
|
57
58
|
var _currentObject_Resources;
|
|
58
59
|
if (currentObject === undefined) return true;
|
|
@@ -76,6 +77,13 @@ export var senMLtoLwM2M = function(senML) {
|
|
|
76
77
|
var currentBaseTime = undefined;
|
|
77
78
|
var currentObject = undefined;
|
|
78
79
|
var lwm2m = [];
|
|
80
|
+
// Special case for timestamp only object
|
|
81
|
+
var maybeTimestampOnly = parseTimestampOnly(senML);
|
|
82
|
+
if (maybeTimestampOnly !== null) return {
|
|
83
|
+
lwm2m: [
|
|
84
|
+
maybeTimestampOnly
|
|
85
|
+
]
|
|
86
|
+
};
|
|
79
87
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
80
88
|
try {
|
|
81
89
|
for(var _iterator = senML[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
@@ -83,6 +91,7 @@ export var senMLtoLwM2M = function(senML) {
|
|
|
83
91
|
if ('bn' in item && item.bn !== undefined) currentBaseName = item.bn;
|
|
84
92
|
if ('bt' in item && item.bt !== undefined) currentBaseTime = item.bt;
|
|
85
93
|
if (!hasValue(item)) continue;
|
|
94
|
+
if (!hasName(item)) continue;
|
|
86
95
|
var _item_n;
|
|
87
96
|
var itemResourceId = "".concat(currentBaseName).concat((_item_n = item.n) !== null && _item_n !== void 0 ? _item_n : '', "/0");
|
|
88
97
|
var resourceId = parseResourceId(itemResourceId);
|
|
@@ -136,3 +145,17 @@ export var senMLtoLwM2M = function(senML) {
|
|
|
136
145
|
lwm2m: lwm2m
|
|
137
146
|
};
|
|
138
147
|
};
|
|
148
|
+
var parseTimestampOnly = function(senML) {
|
|
149
|
+
if (senML.length !== 1) return null;
|
|
150
|
+
var item = senML[0];
|
|
151
|
+
if (!('bn' in item) || !('bt' in item)) return null;
|
|
152
|
+
var objectInfo = parseResourceId("".concat(item.bn, "0/0"));
|
|
153
|
+
if (objectInfo === null) return null;
|
|
154
|
+
var tsRes = timestampResources.get(objectInfo.ObjectID);
|
|
155
|
+
if (tsRes === undefined) return null;
|
|
156
|
+
return {
|
|
157
|
+
ObjectID: objectInfo.ObjectID,
|
|
158
|
+
ObjectInstanceID: objectInfo.ObjectInstanceID,
|
|
159
|
+
Resources: _define_property({}, tsRes, item.bt)
|
|
160
|
+
};
|
|
161
|
+
};
|
|
@@ -1,3 +1,127 @@
|
|
|
1
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
2
|
+
try {
|
|
3
|
+
var info = gen[key](arg);
|
|
4
|
+
var value = info.value;
|
|
5
|
+
} catch (error) {
|
|
6
|
+
reject(error);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (info.done) {
|
|
10
|
+
resolve(value);
|
|
11
|
+
} else {
|
|
12
|
+
Promise.resolve(value).then(_next, _throw);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function _async_to_generator(fn) {
|
|
16
|
+
return function() {
|
|
17
|
+
var self = this, args = arguments;
|
|
18
|
+
return new Promise(function(resolve, reject) {
|
|
19
|
+
var gen = fn.apply(self, args);
|
|
20
|
+
function _next(value) {
|
|
21
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
22
|
+
}
|
|
23
|
+
function _throw(err) {
|
|
24
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
25
|
+
}
|
|
26
|
+
_next(undefined);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function _ts_generator(thisArg, body) {
|
|
31
|
+
var f, y, t, g, _ = {
|
|
32
|
+
label: 0,
|
|
33
|
+
sent: function() {
|
|
34
|
+
if (t[0] & 1) throw t[1];
|
|
35
|
+
return t[1];
|
|
36
|
+
},
|
|
37
|
+
trys: [],
|
|
38
|
+
ops: []
|
|
39
|
+
};
|
|
40
|
+
return g = {
|
|
41
|
+
next: verb(0),
|
|
42
|
+
"throw": verb(1),
|
|
43
|
+
"return": verb(2)
|
|
44
|
+
}, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
45
|
+
return this;
|
|
46
|
+
}), g;
|
|
47
|
+
function verb(n) {
|
|
48
|
+
return function(v) {
|
|
49
|
+
return step([
|
|
50
|
+
n,
|
|
51
|
+
v
|
|
52
|
+
]);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function step(op) {
|
|
56
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
57
|
+
while(_)try {
|
|
58
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
59
|
+
if (y = 0, t) op = [
|
|
60
|
+
op[0] & 2,
|
|
61
|
+
t.value
|
|
62
|
+
];
|
|
63
|
+
switch(op[0]){
|
|
64
|
+
case 0:
|
|
65
|
+
case 1:
|
|
66
|
+
t = op;
|
|
67
|
+
break;
|
|
68
|
+
case 4:
|
|
69
|
+
_.label++;
|
|
70
|
+
return {
|
|
71
|
+
value: op[1],
|
|
72
|
+
done: false
|
|
73
|
+
};
|
|
74
|
+
case 5:
|
|
75
|
+
_.label++;
|
|
76
|
+
y = op[1];
|
|
77
|
+
op = [
|
|
78
|
+
0
|
|
79
|
+
];
|
|
80
|
+
continue;
|
|
81
|
+
case 7:
|
|
82
|
+
op = _.ops.pop();
|
|
83
|
+
_.trys.pop();
|
|
84
|
+
continue;
|
|
85
|
+
default:
|
|
86
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
87
|
+
_ = 0;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
91
|
+
_.label = op[1];
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
95
|
+
_.label = t[1];
|
|
96
|
+
t = op;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (t && _.label < t[2]) {
|
|
100
|
+
_.label = t[2];
|
|
101
|
+
_.ops.push(op);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (t[2]) _.ops.pop();
|
|
105
|
+
_.trys.pop();
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
op = body.call(thisArg, _);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
op = [
|
|
111
|
+
6,
|
|
112
|
+
e
|
|
113
|
+
];
|
|
114
|
+
y = 0;
|
|
115
|
+
} finally{
|
|
116
|
+
f = t = 0;
|
|
117
|
+
}
|
|
118
|
+
if (op[0] & 5) throw op[1];
|
|
119
|
+
return {
|
|
120
|
+
value: op[0] ? op[1] : void 0,
|
|
121
|
+
done: true
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
1
125
|
import assert from 'node:assert/strict';
|
|
2
126
|
import { describe, it } from 'node:test';
|
|
3
127
|
import { senMLtoLwM2M } from './senMLtoLwM2M.js';
|
|
@@ -227,4 +351,29 @@ void describe('senMLtoLwM2M()', function() {
|
|
|
227
351
|
var res = senMLtoLwM2M(input);
|
|
228
352
|
assert.deepEqual('lwm2m' in res && res.lwm2m, expected);
|
|
229
353
|
});
|
|
354
|
+
void it('should allow timestamp only values', /*#__PURE__*/ _async_to_generator(function() {
|
|
355
|
+
var input, expected, res;
|
|
356
|
+
return _ts_generator(this, function(_state) {
|
|
357
|
+
input = [
|
|
358
|
+
{
|
|
359
|
+
bn: '14220/1/',
|
|
360
|
+
bt: 1699049600
|
|
361
|
+
}
|
|
362
|
+
];
|
|
363
|
+
expected = [
|
|
364
|
+
{
|
|
365
|
+
ObjectID: 14220,
|
|
366
|
+
ObjectInstanceID: 1,
|
|
367
|
+
Resources: {
|
|
368
|
+
99: 1699049600
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
];
|
|
372
|
+
res = senMLtoLwM2M(input);
|
|
373
|
+
assert.deepEqual('lwm2m' in res && res.lwm2m, expected);
|
|
374
|
+
return [
|
|
375
|
+
2
|
|
376
|
+
];
|
|
377
|
+
});
|
|
378
|
+
}));
|
|
230
379
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hello.nrfcloud.com/proto-map",
|
|
3
|
-
"version": "16.1.
|
|
3
|
+
"version": "16.1.8",
|
|
4
4
|
"description": "Documents the communication protocol between devices, the hello.nrfcloud.com/map backend and web application",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"prepublishOnly": "./compile.sh"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@bifravst/eslint-config-typescript": "6.1.
|
|
39
|
-
"@bifravst/prettier-config": "1.1.
|
|
38
|
+
"@bifravst/eslint-config-typescript": "6.1.16",
|
|
39
|
+
"@bifravst/prettier-config": "1.1.1",
|
|
40
40
|
"@commitlint/config-conventional": "19.5.0",
|
|
41
41
|
"@swc/cli": "0.4.0",
|
|
42
|
-
"@swc/core": "1.7.
|
|
43
|
-
"@types/node": "22.
|
|
42
|
+
"@swc/core": "1.7.28",
|
|
43
|
+
"@types/node": "22.7.3",
|
|
44
44
|
"@types/xml2js": "0.4.14",
|
|
45
45
|
"chalk": "5.3.0",
|
|
46
46
|
"globstar": "1.0.0",
|
|
@@ -98,6 +98,6 @@
|
|
|
98
98
|
"lwm2m"
|
|
99
99
|
],
|
|
100
100
|
"peerDependencies": {
|
|
101
|
-
"@sinclair/typebox": "^0.33.
|
|
101
|
+
"@sinclair/typebox": "^0.33.12"
|
|
102
102
|
}
|
|
103
103
|
}
|
package/senml/SenMLSchema.ts
CHANGED
package/senml/hasName.ts
ADDED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
2
|
import { describe, it } from 'node:test'
|
|
3
|
-
import { senMLtoLwM2M } from './senMLtoLwM2M.js'
|
|
4
3
|
import { type LwM2MObjectInstance } from '../lwm2m/LwM2MObjectInstance.js'
|
|
5
4
|
import type { SenMLType } from './SenMLSchema.js'
|
|
5
|
+
import { senMLtoLwM2M } from './senMLtoLwM2M.js'
|
|
6
6
|
|
|
7
7
|
void describe('senMLtoLwM2M()', () => {
|
|
8
8
|
void it('should resolve a senML message into objects', () => {
|
|
@@ -183,4 +183,19 @@ void describe('senMLtoLwM2M()', () => {
|
|
|
183
183
|
const res = senMLtoLwM2M(input)
|
|
184
184
|
assert.deepEqual('lwm2m' in res && res.lwm2m, expected)
|
|
185
185
|
})
|
|
186
|
+
|
|
187
|
+
void it('should allow timestamp only values', async () => {
|
|
188
|
+
const input: SenMLType = [{ bn: '14220/1/', bt: 1699049600 }]
|
|
189
|
+
const expected: LwM2MObjectInstance[] = [
|
|
190
|
+
{
|
|
191
|
+
ObjectID: 14220,
|
|
192
|
+
ObjectInstanceID: 1,
|
|
193
|
+
Resources: {
|
|
194
|
+
99: 1699049600,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
]
|
|
198
|
+
const res = senMLtoLwM2M(input)
|
|
199
|
+
assert.deepEqual('lwm2m' in res && res.lwm2m, expected)
|
|
200
|
+
})
|
|
186
201
|
})
|
package/senml/senMLtoLwM2M.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LwM2MObjectInstance } from '../lwm2m/LwM2MObjectInstance.js'
|
|
2
2
|
import { timestampResources } from '../lwm2m/timestampResources.js'
|
|
3
|
-
import {
|
|
3
|
+
import { hasName } from './hasName.js'
|
|
4
4
|
import { hasValue } from './hasValue.js'
|
|
5
|
-
import type
|
|
5
|
+
import { parseResourceId, type ResourceID } from './parseResourceId.js'
|
|
6
|
+
import type { MeasurementType, SenMLType } from './SenMLSchema.js'
|
|
6
7
|
|
|
7
8
|
const isInfoForDifferentInstance = (
|
|
8
9
|
currentObject: LwM2MObjectInstance,
|
|
@@ -41,10 +42,15 @@ export const senMLtoLwM2M = (
|
|
|
41
42
|
let currentObject: LwM2MObjectInstance | undefined = undefined
|
|
42
43
|
const lwm2m: Array<LwM2MObjectInstance> = []
|
|
43
44
|
|
|
45
|
+
// Special case for timestamp only object
|
|
46
|
+
const maybeTimestampOnly = parseTimestampOnly(senML)
|
|
47
|
+
if (maybeTimestampOnly !== null) return { lwm2m: [maybeTimestampOnly] }
|
|
48
|
+
|
|
44
49
|
for (const item of senML) {
|
|
45
50
|
if ('bn' in item && item.bn !== undefined) currentBaseName = item.bn
|
|
46
51
|
if ('bt' in item && item.bt !== undefined) currentBaseTime = item.bt
|
|
47
52
|
if (!hasValue(item)) continue
|
|
53
|
+
if (!hasName(item)) continue
|
|
48
54
|
const itemResourceId = `${currentBaseName}${item.n ?? ''}/0`
|
|
49
55
|
const resourceId = parseResourceId(itemResourceId)
|
|
50
56
|
if (resourceId === null) {
|
|
@@ -101,3 +107,20 @@ export const senMLtoLwM2M = (
|
|
|
101
107
|
|
|
102
108
|
return { lwm2m }
|
|
103
109
|
}
|
|
110
|
+
|
|
111
|
+
const parseTimestampOnly = (senML: SenMLType): LwM2MObjectInstance | null => {
|
|
112
|
+
if (senML.length !== 1) return null
|
|
113
|
+
const item = senML[0]!
|
|
114
|
+
if (!('bn' in item) || !('bt' in item)) return null
|
|
115
|
+
const objectInfo = parseResourceId(`${item.bn}0/0`)
|
|
116
|
+
if (objectInfo === null) return null
|
|
117
|
+
const tsRes = timestampResources.get(objectInfo.ObjectID)
|
|
118
|
+
if (tsRes === undefined) return null
|
|
119
|
+
return {
|
|
120
|
+
ObjectID: objectInfo.ObjectID,
|
|
121
|
+
ObjectInstanceID: objectInfo.ObjectInstanceID,
|
|
122
|
+
Resources: {
|
|
123
|
+
[tsRes]: item.bt,
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
}
|