Skip to content

Commit c84b3ad

Browse files
nicomiguelinoclaude
andcommitted
feat(peripheral-demo): add Sensor Data card to operator view
- Add humidity and airPressure fields to AppState (nullable, default null) - Add setHumidity and setAirPressure mutations to state - Parse humidity and air_pressure readings from peripheral WS messages - Add Sensor Data glass card to operator screen with temperature, humidity, air pressure - Show "No Data" fallback until first WS message arrives - Handle nullable temperature in public view temperature pill Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b04313d commit c84b3ad

File tree

5 files changed

+93
-5
lines changed

5 files changed

+93
-5
lines changed

edge-apps/peripheral-integration-demo/index.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,48 @@
251251
</div>
252252
</div>
253253
</div>
254+
255+
<!-- Sensor Data -->
256+
<div class="glass-card glass-card--left">
257+
<div class="glass-card-heading">
258+
<!-- Activity icon -->
259+
<svg
260+
class="glass-card-icon"
261+
width="48"
262+
height="48"
263+
viewBox="0 0 24 24"
264+
fill="none"
265+
stroke="currentColor"
266+
stroke-width="1.5"
267+
stroke-linecap="round"
268+
stroke-linejoin="round"
269+
>
270+
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
271+
</svg>
272+
<span class="glass-card-title">Sensor Data</span>
273+
</div>
274+
275+
<div class="operator-grid">
276+
<div class="operator-field">
277+
<span class="operator-label">Temperature</span>
278+
<span id="sensor-temperature" class="operator-value"
279+
>No Data</span
280+
>
281+
</div>
282+
<div class="operator-field">
283+
<span class="operator-label">Humidity</span>
284+
<span id="sensor-humidity" class="operator-value"
285+
>No Data</span
286+
>
287+
</div>
288+
<div class="operator-field">
289+
<span class="operator-label">Air Pressure</span>
290+
<span id="sensor-air-pressure" class="operator-value"
291+
>No Data</span
292+
>
293+
</div>
294+
</div>
295+
</div>
254296
</div>
255297

256298
<!-- Maintenance Screen -->

edge-apps/peripheral-integration-demo/src/core/screen.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ function syncScreensToState(state: ReturnType<typeof getState>) {
5252
}
5353

5454
const publicTemp = getEl('public-temperature')
55-
publicTemp.textContent = `${Math.round(state.temperature)}°C`
55+
publicTemp.textContent =
56+
state.temperature !== null ? `${Math.round(state.temperature)}°C` : '--'
5657

5758
if (state.currentScreen === 'maintenance') {
5859
getEl('maintenance-network').textContent = getNetworkStatus()

edge-apps/peripheral-integration-demo/src/core/state.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ export interface AppState {
44
currentScreen: ScreenType
55
timezone: string
66
locale: string
7-
temperature: number
7+
temperature: number | null
8+
humidity: number | null
9+
airPressure: number | null
810
}
911

1012
const state: AppState = {
1113
currentScreen: 'public',
1214
timezone: 'UTC',
1315
locale: 'en',
14-
temperature: 22,
16+
temperature: null,
17+
humidity: null,
18+
airPressure: null,
1519
}
1620

1721
type Listener = (state: AppState) => void
@@ -50,6 +54,16 @@ export function setTemperature(value: number) {
5054
notify()
5155
}
5256

57+
export function setHumidity(value: number) {
58+
state.humidity = value
59+
notify()
60+
}
61+
62+
export function setAirPressure(value: number) {
63+
state.airPressure = value
64+
notify()
65+
}
66+
5367
export function getState(): Readonly<AppState> {
5468
return { ...state }
5569
}

edge-apps/peripheral-integration-demo/src/features/operator-dashboard.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,33 @@ function stopUpdates() {
9292
}
9393
}
9494

95+
function updateSensorData(state: ReturnType<typeof getState>) {
96+
getEl('sensor-temperature').textContent =
97+
state.temperature !== null
98+
? `${Math.round(state.temperature)}°C`
99+
: 'No Data'
100+
getEl('sensor-humidity').textContent =
101+
state.humidity !== null ? `${Math.round(state.humidity)}%` : 'No Data'
102+
getEl('sensor-air-pressure').textContent =
103+
state.airPressure !== null
104+
? `${Math.round(state.airPressure)} hPa`
105+
: 'No Data'
106+
}
107+
95108
function onStateChange(state: ReturnType<typeof getState>) {
96109
if (state.currentScreen === 'operator') {
97110
startUpdates()
98111
} else {
99112
stopUpdates()
100113
}
114+
updateSensorData(state)
101115
}
102116

103117
export function initOperatorDashboard() {
104118
subscribe(onStateChange)
105-
if (getState().currentScreen === 'operator') startUpdates()
119+
const state = getState()
120+
if (state.currentScreen === 'operator') startUpdates()
121+
updateSensorData(state)
106122
}
107123

108124
export function updateOperatorDashboard() {

edge-apps/peripheral-integration-demo/src/features/peripherals.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { createPeripheralClient } from '@screenly/edge-apps'
22
import type { PeripheralStateMessage } from '@screenly/edge-apps'
33

4-
import { getState, setTemperature } from '../core/state'
4+
import {
5+
getState,
6+
setTemperature,
7+
setHumidity,
8+
setAirPressure,
9+
} from '../core/state'
510
import { showWelcomeThenSwitch } from '../core/screen'
611
import { restartLogoutTimer } from '../core/timer'
712
import { authenticate } from './authenticate'
@@ -21,6 +26,16 @@ export function initPeripherals() {
2126
setTemperature(tempReading.ambient_temperature as number)
2227
}
2328

29+
const humidityReading = readings.find((r) => 'humidity' in r)
30+
if (humidityReading) {
31+
setHumidity(humidityReading.humidity as number)
32+
}
33+
34+
const pressureReading = readings.find((r) => 'air_pressure' in r)
35+
if (pressureReading) {
36+
setAirPressure(pressureReading.air_pressure as number)
37+
}
38+
2439
const cardReading = readings.find((r) => 'secure_card' in r)
2540
if (cardReading) {
2641
const MAX_CARD_AGE_MS = 60_000

0 commit comments

Comments
 (0)