Skip to content

Commit

Permalink
feat(lwm2m): add converter from / to AWS IoT shadow
Browse files Browse the repository at this point in the history
Moved here from @hello.nrfcloud.com/backend
  • Loading branch information
coderbyheart committed Jul 1, 2024
1 parent 8ff9c92 commit cf03062
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lwm2m/aws/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './objectsToShadow.js'
export * from './shadowToObjects.js'
91 changes: 91 additions & 0 deletions lwm2m/aws/objectsToShadow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { objectsToShadow } from './objectsToShadow.js'
import { LwM2MObjectID } from '../LwM2MObjectID.js'

void describe('objectsToShadow()', () => {
void it('should convert a list of LwM2M objects to a shadow document', () =>
assert.deepEqual(
objectsToShadow([
{
ObjectID: 14205,
Resources: {
'0': 27.69,
'1': 18.9,
'2': 97.271,
'99': 1699197208,
},
},
{
ObjectID: 14202,
Resources: {
'0': 99,
'1': 4.174,
'2': 0,
'3': 25.9,
'99': 1699197208,
},
},
{
ObjectID: 14203,
Resources: {
'0': 'LTE-M',
'1': 20,
'2': -93,
'3': 2305,
'4': 34237196,
'5': 24202,
'6': '100.81.95.75',
'11': 7,
'99': 1699197229,
},
},
{
ObjectID: LwM2MObjectID.NRFCloudServiceInfo_14401,
ObjectVersion: '1.0',
Resources: {
0: ['BOOT', 'MODEM', 'APP'],
99: 1717409966 * 1000,
},
},
]),
{
'14205:1.0': {
0: {
'0': 27.69,
'1': 18.9,
'2': 97.271,
'99': 1699197208,
},
},
'14203:1.0': {
0: {
'0': 'LTE-M',
'1': 20,
'2': -93,
'3': 2305,
'4': 34237196,
'5': 24202,
'6': '100.81.95.75',
'11': 7,
'99': 1699197229,
},
},
'14202:1.0': {
0: {
'0': 99,
'1': 4.174,
'2': 0,
'3': 25.9,
'99': 1699197208,
},
},
'14401:1.0': {
0: {
0: ['BOOT', 'MODEM', 'APP'],
99: 1717409966 * 1000,
},
},
},
))
})
40 changes: 40 additions & 0 deletions lwm2m/aws/objectsToShadow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { LwM2MObjectInstance } from '../LwM2MObjectInstance.js'
import { instanceTs } from '../instanceTs.js'

export type LwM2MShadow = Record<
string,
Record<
number,
Record<
number,
string | number | boolean | Array<string> | Array<number> | Array<boolean>
>
>
>

export const objectsToShadow = (
objects: Array<LwM2MObjectInstance>,
): LwM2MShadow =>
objects
.sort((u1, u2) => {
const d1 = instanceTs(u1)
const d2 = instanceTs(u2)
return d1 - d2 ? 1 : -1
})
.reduce<LwM2MShadow>((shadow, update) => {
const key = `${update.ObjectID}:${update.ObjectVersion ?? '1.0'}`
return {
...shadow,
[key]: {
[update.ObjectInstanceID ?? 0]: update.Resources as Record<
number,
| string
| number
| boolean
| Array<string>
| Array<number>
| Array<boolean>
>,
},
}
}, {})
107 changes: 107 additions & 0 deletions lwm2m/aws/shadowToObjects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { shadowToObjects } from './shadowToObjects.js'
import { LwM2MObjectID } from '../LwM2MObjectID.js'

void describe('shadowToObjects()', () => {
void it('should convert a shadow to LwM2M objects', () =>
assert.deepEqual(
shadowToObjects({
'14205:1.0': {
0: {
'0': 27.63,
'1': 19.354,
'2': 97.465,
'99': 1699217636,
},
42: {
'0': 25,
'99': 1699217636,
},
},
'14203:1.0': {
0: {
'0': 'LTE-M',
'1': 20,
'2': -90,
'3': 2305,
'4': 34237196,
'5': 24202,
'6': '100.81.95.75',
'11': 7,
'99': 1699217637,
},
},
'14202:1.0': {
0: {
'0': 99,
'1': 4.174,
'2': 0,
'3': 25.9,
'99': 1699217657,
},
},
'14401:1.0': {
0: {
0: ['BOOT', 'MODEM', 'APP'],
99: 1717409966 * 1000,
},
},
}),
[
{
ObjectID: 14205,
ObjectVersion: '1.0',
Resources: {
'0': 27.63,
'1': 19.354,
'2': 97.465,
'99': 1699217636,
},
},
{
ObjectID: 14205,
ObjectInstanceID: 42,
ObjectVersion: '1.0',
Resources: {
'0': 25,
'99': 1699217636,
},
},
{
ObjectID: 14203,
ObjectVersion: '1.0',
Resources: {
'0': 'LTE-M',
'1': 20,
'2': -90,
'3': 2305,
'4': 34237196,
'5': 24202,
'6': '100.81.95.75',
'11': 7,
'99': 1699217637,
},
},
{
ObjectID: 14202,
ObjectVersion: '1.0',
Resources: {
'0': 99,
'1': 4.174,
'2': 0,
'3': 25.9,
'99': 1699217657,
},
},
{
ObjectID: LwM2MObjectID.NRFCloudServiceInfo_14401,
ObjectVersion: '1.0',
Resources: {
0: ['BOOT', 'MODEM', 'APP'],
99: 1717409966 * 1000,
},
},
],
))
})
28 changes: 28 additions & 0 deletions lwm2m/aws/shadowToObjects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { LwM2MObjectInstance } from '../LwM2MObjectInstance.js'
import type { LwM2MShadow } from './objectsToShadow.js'
import { timestampResources } from '../timestampResources.js'

export const shadowToObjects = (shadow: LwM2MShadow): LwM2MObjectInstance[] =>
Object.entries(shadow)
.map(([ObjectIdAndVersion, Instances]) => {
const [ObjectIDString, ObjectVersion] = ObjectIdAndVersion.split(':') as [
string,
string,
]
const ObjectID = parseInt(ObjectIDString, 10)
const tsResource = timestampResources.get(ObjectID)
if (tsResource === undefined) return null
return Object.entries(Instances).map(([instanceId, Resources]) => {
const ObjectInstanceID = parseInt(instanceId, 10)
const objectInstance: LwM2MObjectInstance = {
ObjectID,
ObjectVersion,
Resources,
}
if (ObjectInstanceID > 0)
objectInstance.ObjectInstanceID = ObjectInstanceID
return objectInstance
})
})
.flat()
.filter((o) => o !== null)
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"paths": {
"@hello.nrfcloud.com/proto-map/generator": ["generator/index.d.ts"],
"@hello.nrfcloud.com/proto-map/lwm2m": ["lwm2m/index.d.ts"],
"@hello.nrfcloud.com/proto-map/lwm2m/aws": ["lwm2m/aws/index.d.ts"],
"@hello.nrfcloud.com/proto-map/markdown": ["markdown/index.d.ts"],
"@hello.nrfcloud.com/proto-map/models": ["models/index.d.ts"],
"@hello.nrfcloud.com/proto-map/senml": ["senml/index.d.ts"]
Expand Down

0 comments on commit cf03062

Please sign in to comment.