@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 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
 
@@ -36,6 +36,9 @@ var Time = Type.Integer({
36
36
  default: '1.0'
37
37
  }),
38
38
  bt: Type.Optional(Time)
39
+ }),
40
+ Type.Object({
41
+ bn: ResourceIDPart
39
42
  })
40
43
  ]),
41
44
  // Value combinations
@@ -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 { parseResourceId } from './parseResourceId.js';
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.6",
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.15",
39
- "@bifravst/prettier-config": "1.1.0",
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.26",
43
- "@types/node": "22.5.5",
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.11"
101
+ "@sinclair/typebox": "^0.33.12"
102
102
  }
103
103
  }
@@ -31,6 +31,9 @@ export const Measurement = Type.Intersect(
31
31
  }),
32
32
  bt: Type.Optional(Time),
33
33
  }),
34
+ Type.Object({
35
+ bn: ResourceIDPart,
36
+ }),
34
37
  ]),
35
38
  // Value combinations
36
39
  Type.Union([
@@ -0,0 +1,5 @@
1
+ export const hasName = (m: unknown): m is { n: string } => {
2
+ if (m === null) return false
3
+ if (typeof m !== 'object') return false
4
+ return 'n' in m
5
+ }
@@ -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
  })
@@ -1,8 +1,9 @@
1
- import type { MeasurementType, SenMLType } from './SenMLSchema.js'
1
+ import type { LwM2MObjectInstance } from '../lwm2m/LwM2MObjectInstance.js'
2
2
  import { timestampResources } from '../lwm2m/timestampResources.js'
3
- import { parseResourceId, type ResourceID } from './parseResourceId.js'
3
+ import { hasName } from './hasName.js'
4
4
  import { hasValue } from './hasValue.js'
5
- import type { LwM2MObjectInstance } from '../lwm2m/LwM2MObjectInstance.js'
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
+ }