Skip to content

Commit 9db44fd

Browse files
committed
feat: simplify config
Use update interval in seconds instead of a mode
1 parent 73d457d commit 9db44fd

14 files changed

+169
-148
lines changed

content/models/PCA20035+solar.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ video:
2020
includedSIM:
2121
- vendor: iBasis
2222
freeMb: 10
23-
modeUsagePerDayMB:
24-
realTime: 3
25-
interactive: 1.5
26-
lowPower: 0.05
2723
defaultConfiguration:
28-
mode: interactive
24+
updateIntervalSeconds: 120
2925
gnssEnabled: true
26+
configurationPresets:
27+
- name: Real-time mode
28+
updateIntervalSeconds: 10
29+
dataUsagePerDayMB: 3
30+
- name: Interactive mode
31+
updateIntervalSeconds: 120
32+
dataUsagePerDayMB: 1.5
33+
- name: Low-power mode
34+
updateIntervalSeconds: 600
35+
dataUsagePerDayMB: 0.05
3036
---
3137

3238
The Nordic Thingy:91 Solar Shield is a plug-and-play prototyping platform.

content/models/PCA20065.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ includedSIM:
1919
freeMb: 10
2020
- vendor: Wireless Logic
2121
freeMb: 5
22-
modeUsagePerDayMB:
23-
realTime: 3
24-
interactive: 1.5
25-
lowPower: 0.05
2622
defaultConfiguration:
27-
mode: interactive
23+
updateIntervalSeconds: 3600
2824
gnssEnabled: true
25+
configurationPresets:
26+
- name: Real-time mode
27+
updateIntervalSeconds: 10
28+
dataUsagePerDayMB: 3
29+
- name: Low-power mode
30+
updateIntervalSeconds: 3600
31+
dataUsagePerDayMB: 0.01
2932
---
3033

3134
The Nordic Thingy:91 X is a Cellular IoT prototyping platform that's built

package-lock.json

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
},
2929
"dependencies": {
3030
"@hello.nrfcloud.com/proto": "13.0.5",
31-
"@hello.nrfcloud.com/proto-map": "10.0.0",
31+
"@hello.nrfcloud.com/proto-map": "10.0.2",
3232
"@sentry/browser": "8.5.0",
3333
"@sinclair/typebox": "0.32.31",
3434
"classnames": "2.5.1",

src/components/ConnectDevice.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@ import { Ago } from '#components/Ago.js'
22
import { WaitingForData } from '#components/WaitingForData.js'
33
import { SIMIcon } from '#components/icons/SIMIcon.js'
44
import { useDevice } from '#context/Device.js'
5-
import { SIMVendor, updateIntervalSeconds } from '#context/Models.js'
5+
import { SIMVendor } from '#context/Models.js'
66
import { BatteryFull, CloudOff, ToggleRight } from 'lucide-preact'
77

8-
// FIXME: make config dynamic
98
export const ConnectDevice = () => {
109
const {
1110
lastSeen,
1211
device,
13-
configuration: {
14-
reported: { mode },
15-
},
12+
configuration: { reported },
1613
} = useDevice()
1714
const hasIBasisSIM = device?.model.includedSIM?.find(
1815
({ vendor }) => vendor === SIMVendor.iBasis,
@@ -69,7 +66,10 @@ export const ConnectDevice = () => {
6966
<br />
7067
<small class="text-muted">
7168
Your device should send data to the cloud every{' '}
72-
{updateIntervalSeconds(mode)} seconds.
69+
{reported?.updateIntervalSeconds ??
70+
device?.model.defaultConfiguration
71+
.updateIntervalSeconds}{' '}
72+
seconds.
7373
</small>
7474
</p>
7575
{lastSeen === undefined && (

src/components/DeviceHeader.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import {
3232
toConnectionInformation,
3333
toDeviceInformation,
3434
} from '#proto/lwm2m.js'
35-
import { updateIntervalSeconds } from '#context/Models.js'
3635

3736
export const DeviceHeader = ({ device }: { device: Device }) => {
3837
const type = device.model
@@ -73,6 +72,7 @@ export const DeviceHeader = ({ device }: { device: Device }) => {
7372
</div>
7473
<div class="me-4 ms-lg-4 mb-2 mb-lg-4">
7574
<PublicationInterval
75+
device={device}
7676
onConfigure={() =>
7777
setModeConfigurationVisible((visible) => !visible)
7878
}
@@ -277,34 +277,44 @@ const Interact = () => {
277277
)
278278
}
279279

280-
// FIXME: make dynamic
281-
const PublicationInterval = ({ onConfigure }: { onConfigure?: () => void }) => {
280+
const PublicationInterval = ({
281+
device,
282+
onConfigure,
283+
}: {
284+
device: Device
285+
onConfigure?: () => void
286+
}) => {
282287
const {
283-
configuration: {
284-
reported: { mode },
285-
},
288+
configuration: { reported, desired },
286289
} = useDevice()
287-
const gnss = false
288-
const activeWaitTime = undefined
289290

290291
return (
291292
<span class="d-flex flex-column">
292293
<small class="text-muted">
293294
<strong>Publication interval</strong>
294295
</small>
295296
<span>
296-
<UploadCloud strokeWidth={1} /> {updateIntervalSeconds(mode)} seconds
297-
{gnss && <Satellite strokeWidth={1} class="ms-1" />}
297+
<UploadCloud strokeWidth={1} />{' '}
298+
{reported?.updateIntervalSeconds ??
299+
device.model.defaultConfiguration.updateIntervalSeconds}{' '}
300+
seconds
301+
{(reported?.gnssEnabled ??
302+
device.model.defaultConfiguration.gnssEnabled) && (
303+
<Satellite strokeWidth={1} class="ms-1" />
304+
)}
298305
</span>
299306
<small class="text-muted">
300307
<Transparent class="text-muted" onClick={onConfigure}>
301308
<Settings strokeWidth={1} /> configure
302309
</Transparent>
303310
</small>
304-
{activeWaitTime !== undefined && (
311+
{desired?.updateIntervalSeconds !== undefined && (
305312
<Applied
306-
desired={activeWaitTime}
307-
reported={updateIntervalSeconds(mode)}
313+
desired={desired.updateIntervalSeconds}
314+
reported={
315+
reported?.updateIntervalSeconds ??
316+
device.model.defaultConfiguration.updateIntervalSeconds
317+
}
308318
/>
309319
)}
310320
</span>

src/components/DeviceModeSelector.tsx

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@ import { Applied } from '#components/Applied.js'
22
import { Secondary, Transparent } from '#components/Buttons.js'
33
import { SIMIcon } from '#components/icons/SIMIcon.js'
44
import { useDevice, type Device } from '#context/Device.js'
5-
import { Mode, updateIntervalSeconds } from '#context/Models.js'
65
import type { ProblemDetail } from '@hello.nrfcloud.com/proto/hello'
76
import type { Static } from '@sinclair/typebox'
87
import cx from 'classnames'
98
import { Ban, HistoryIcon, Satellite, Settings2, X } from 'lucide-preact'
109
import { useState } from 'preact/hooks'
1110
import { Problem } from './Problem.js'
12-
13-
const modes: Array<[Mode, string]> = [
14-
[Mode.realTime, 'Real-time mode'],
15-
[Mode.interactive, 'Interactive mode'],
16-
[Mode.lowPower, 'Low-power mode'],
17-
]
11+
import { isEqual } from 'lodash-es'
1812

1913
export const DeviceModeSelector = ({
2014
device,
@@ -24,16 +18,24 @@ export const DeviceModeSelector = ({
2418
onClose?: () => void
2519
}) => {
2620
const {
27-
configuration: {
28-
reported: { mode: reportedMode, gnssEnabled: reportedGNSS },
29-
desired: { mode: desiredMode, gnssEnabled: desiredGNSS },
30-
},
21+
configuration: { reported: reportedConfig, desired: desiredConfig },
3122
configure,
3223
} = useDevice()
33-
const [selectedGNSS, setGNSS] = useState<boolean>(desiredGNSS)
34-
const [selectedMode, setMode] = useState<Mode>(reportedMode)
35-
const reportedUpdateInterval = updateIntervalSeconds(reportedMode)
36-
const desiredUpdateInterval = updateIntervalSeconds(desiredMode)
24+
const [selectedGNSS, setGNSS] = useState<boolean>(
25+
desiredConfig?.gnssEnabled ?? device.model.defaultConfiguration.gnssEnabled,
26+
)
27+
const [selectedUpdateIntervalSeconds, setUpdateIntervalSeconds] =
28+
useState<number>(
29+
desiredConfig?.updateIntervalSeconds ??
30+
device.model.defaultConfiguration.updateIntervalSeconds,
31+
)
32+
const reportedUpdateInterval =
33+
reportedConfig?.updateIntervalSeconds ??
34+
device.model.defaultConfiguration.updateIntervalSeconds
35+
const reportedGNSS =
36+
reportedConfig?.gnssEnabled ?? device.model.defaultConfiguration.gnssEnabled
37+
const desiredUpdateInterval = desiredConfig?.updateIntervalSeconds
38+
const desiredGNSS = desiredConfig?.gnssEnabled
3739
const [problem, setProblem] = useState<
3840
Static<typeof ProblemDetail> | undefined
3941
>()
@@ -62,8 +64,8 @@ export const DeviceModeSelector = ({
6264
</small>
6365
{desiredUpdateInterval !== undefined && (
6466
<Applied
65-
desired={desiredMode}
66-
reported={reportedMode}
67+
desired={desiredUpdateInterval}
68+
reported={reportedUpdateInterval}
6769
class="ms-2"
6870
/>
6971
)}
@@ -118,7 +120,7 @@ export const DeviceModeSelector = ({
118120
setProblem(undefined)
119121
configure({
120122
gnssEnabled: selectedGNSS,
121-
mode: selectedMode,
123+
updateIntervalSeconds: selectedUpdateIntervalSeconds,
122124
})
123125
.then((maybeUpdate) => {
124126
if ('problem' in maybeUpdate) {
@@ -138,26 +140,50 @@ export const DeviceModeSelector = ({
138140
usage.
139141
</p>
140142
<ul class="list-group mb-3">
141-
{modes.map(([mode, title]) => {
142-
const current = selectedMode === mode
143-
return (
144-
<li
145-
class={cx(
146-
'list-group-item d-flex align-items-center justify-content-between',
147-
{ active: current },
148-
)}
149-
aria-current={current}
150-
>
151-
<span>
152-
{title}
153-
<DataUsageInfo device={device} mode={mode} />
154-
</span>
155-
<Secondary onClick={() => setMode(mode)} disabled={current}>
156-
select
157-
</Secondary>
158-
</li>
159-
)
160-
})}
143+
{device.model.configurationPresets.map(
144+
({
145+
name: title,
146+
dataUsagePerDayMB,
147+
updateIntervalSeconds,
148+
gnssEnabled,
149+
}) => {
150+
const defaults = device.model.defaultConfiguration
151+
152+
const reported = {
153+
updateIntervalSeconds: reportedUpdateInterval,
154+
gnssEnabled: reportedGNSS,
155+
}
156+
const preset = {
157+
updateIntervalSeconds:
158+
updateIntervalSeconds ?? defaults.updateIntervalSeconds,
159+
gnssEnabled: gnssEnabled ?? defaults.gnssEnabled,
160+
}
161+
162+
const current = isEqual(reported, preset)
163+
return (
164+
<li
165+
class={cx(
166+
'list-group-item d-flex align-items-center justify-content-between',
167+
{ active: current },
168+
)}
169+
aria-current={current}
170+
>
171+
<span>
172+
{title}
173+
<DataUsageInfo dataUsagePerDayMB={dataUsagePerDayMB} />
174+
</span>
175+
<Secondary
176+
onClick={() =>
177+
setUpdateIntervalSeconds(updateIntervalSeconds)
178+
}
179+
disabled={current}
180+
>
181+
select
182+
</Secondary>
183+
</li>
184+
)
185+
},
186+
)}
161187
</ul>
162188
</div>
163189
</div>
@@ -166,18 +192,14 @@ export const DeviceModeSelector = ({
166192
}
167193

168194
const DataUsageInfo = ({
169-
device,
170-
mode,
195+
dataUsagePerDayMB,
171196
class: c,
172197
}: {
173-
device: Device
174-
mode: Mode
198+
dataUsagePerDayMB: number
175199
class?: string
176200
}) => {
177-
const dataUsagePerDay = device.model.modeUsagePerDayMB[mode]
178-
179201
// Show a warning if the current mode will use more than 1 MB per day
180-
const showDataWarning = dataUsagePerDay > 1
202+
const showDataWarning = dataUsagePerDayMB > 1
181203

182204
return (
183205
<span
@@ -187,7 +209,7 @@ const DataUsageInfo = ({
187209
>
188210
<SIMIcon class="me-2 flex-shrink-0" size={18} />
189211
<small>
190-
This mode uses around {dataUsagePerDay.toFixed(2)} MB of data per day.
212+
This mode uses around {dataUsagePerDayMB.toFixed(2)} MB of data per day.
191213
</small>
192214
</span>
193215
)

src/components/WaitingForConnection.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { ConnectDevice } from '#components/ConnectDevice.js'
22
import { useDevice } from '#context/Device.js'
3-
import { updateIntervalSeconds } from '#context/Models.js'
43

54
export const WaitingForConnection = () => {
65
const {
76
lastSeen,
8-
configuration: {
9-
reported: { mode },
10-
},
7+
configuration: { reported },
118
} = useDevice()
129

13-
const hasLiveData =
14-
lastSeen !== undefined &&
15-
Date.now() - lastSeen.getTime() < updateIntervalSeconds(mode) * 1000
10+
let hasLiveData = lastSeen !== undefined
11+
12+
if (lastSeen !== undefined && reported?.updateIntervalSeconds !== undefined) {
13+
hasLiveData =
14+
Date.now() - lastSeen.getTime() < reported.updateIntervalSeconds * 1000
15+
}
1616

1717
if (hasLiveData) return null
1818

0 commit comments

Comments
 (0)