Skip to content

Commit 39f51eb

Browse files
Merge pull request #725 from Screenly/ew-demo/additional-sensor-data-on-operator-view
feat(peripheral-demo): add Sensor Data card to operator view
2 parents 8445984 + d33ff6f commit 39f51eb

File tree

9 files changed

+183
-11
lines changed

9 files changed

+183
-11
lines changed

edge-apps/peripheral-integration-demo/bun.lock

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

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

Lines changed: 66 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 -->
@@ -321,6 +363,30 @@
321363
</div>
322364
</div>
323365
</div>
366+
367+
<div class="glass-card glass-card--left">
368+
<div class="glass-card-heading">
369+
<svg
370+
class="glass-card-icon"
371+
width="48"
372+
height="48"
373+
viewBox="0 0 24 24"
374+
fill="none"
375+
stroke="currentColor"
376+
stroke-width="1.5"
377+
stroke-linecap="round"
378+
stroke-linejoin="round"
379+
>
380+
<polyline points="16 18 22 12 16 6" />
381+
<polyline points="8 6 2 12 8 18" />
382+
</svg>
383+
<span class="glass-card-title">Raw Peripheral State</span>
384+
</div>
385+
<pre
386+
id="maintenance-raw-state"
387+
class="maintenance-raw-state"
388+
><code class="language-json">No data yet</code></pre>
389+
</div>
324390
</div>
325391
</main>
326392

edge-apps/peripheral-integration-demo/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,8 @@
3131
"npm-run-all2": "^8.0.4",
3232
"prettier": "^3.8.1",
3333
"typescript": "^5.9.3"
34+
},
35+
"dependencies": {
36+
"highlight.js": "^11.11.1"
3437
}
3538
}

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,25 @@ import {
66
getTimeZone,
77
} from '@screenly/edge-apps'
88
import { Hardware } from '@screenly/edge-apps'
9+
import hljs from 'highlight.js/lib/core'
10+
import json from 'highlight.js/lib/languages/json'
911

10-
import { subscribe, getState, setScreen, type ScreenType } from './state'
12+
import {
13+
subscribe,
14+
getState,
15+
setScreen,
16+
type ScreenType,
17+
getLastPeripheralState,
18+
} from './state'
1119
import {
1220
waitForScreenDataPrepared,
1321
dispatchScreenDataPrepared,
1422
} from './screen-events'
1523
import { getNetworkStatus } from '../utils/network'
1624
import { updateOperatorDashboard } from '../features/operator-dashboard'
1725

26+
hljs.registerLanguage('json', json)
27+
1828
function delay(ms: number): Promise<void> {
1929
return new Promise((resolve) => setTimeout(resolve, ms))
2030
}
@@ -52,7 +62,8 @@ function syncScreensToState(state: ReturnType<typeof getState>) {
5262
}
5363

5464
const publicTemp = getEl('public-temperature')
55-
publicTemp.textContent = `${Math.round(state.temperature)}°C`
65+
publicTemp.textContent =
66+
state.temperature !== null ? `${Math.round(state.temperature)}°C` : '--'
5667

5768
if (state.currentScreen === 'maintenance') {
5869
getEl('maintenance-network').textContent = getNetworkStatus()
@@ -78,6 +89,14 @@ async function loadMaintenanceInfo() {
7889
} catch {
7990
getEl('maintenance-timezone').textContent = '—'
8091
}
92+
93+
const rawState = getLastPeripheralState()
94+
const codeEl = getEl('maintenance-raw-state').querySelector('code')!
95+
if (rawState) {
96+
codeEl.innerHTML = hljs.highlight(JSON.stringify(rawState, null, 2), {
97+
language: 'json',
98+
}).value
99+
}
81100
}
82101

83102
async function preloadScreenData(role: ScreenType): Promise<void> {

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

Lines changed: 26 additions & 4 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
@@ -45,11 +49,29 @@ export function setLocale(locale: string) {
4549
notify()
4650
}
4751

48-
export function setTemperature(value: number) {
49-
state.temperature = value
52+
export function setSensorReadings(readings: {
53+
temperature?: number | null
54+
humidity?: number | null
55+
airPressure?: number | null
56+
}) {
57+
if (readings.temperature !== undefined)
58+
state.temperature = readings.temperature
59+
if (readings.humidity !== undefined) state.humidity = readings.humidity
60+
if (readings.airPressure !== undefined)
61+
state.airPressure = readings.airPressure
5062
notify()
5163
}
5264

5365
export function getState(): Readonly<AppState> {
5466
return { ...state }
5567
}
68+
69+
let lastPeripheralState: unknown = null
70+
71+
export function setLastPeripheralState(raw: unknown) {
72+
lastPeripheralState = raw
73+
}
74+
75+
export function getLastPeripheralState(): unknown {
76+
return lastPeripheralState
77+
}

edge-apps/peripheral-integration-demo/src/css/style.css

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,14 @@ auto-scaler {
370370

371371
/* Maintenance rows */
372372

373+
#screen-maintenance {
374+
flex: 1;
375+
}
376+
377+
#screen-maintenance .glass-card:last-child {
378+
flex: 0 1 auto;
379+
}
380+
373381
.maintenance-rows {
374382
display: flex;
375383
flex-direction: column;
@@ -425,3 +433,20 @@ auto-scaler {
425433
font-weight: 600;
426434
color: #e33876;
427435
}
436+
437+
.maintenance-raw-state {
438+
width: 100%;
439+
flex: 1;
440+
overflow: hidden;
441+
border-radius: 16px;
442+
font-size: 18px;
443+
line-height: 1.6;
444+
margin: 0;
445+
}
446+
447+
.maintenance-raw-state code {
448+
display: block;
449+
height: 100%;
450+
padding: 1.5rem;
451+
white-space: pre;
452+
}

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

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

95+
function updateSensorData(state: ReturnType<typeof getState>) {
96+
getEl('sensor-temperature').textContent =
97+
state.temperature !== null ? `${state.temperature.toFixed(2)}°C` : 'No Data'
98+
getEl('sensor-humidity').textContent =
99+
state.humidity !== null ? `${state.humidity.toFixed(2)}%` : 'No Data'
100+
getEl('sensor-air-pressure').textContent =
101+
state.airPressure !== null
102+
? `${state.airPressure.toFixed(2)} hPa`
103+
: 'No Data'
104+
}
105+
95106
function onStateChange(state: ReturnType<typeof getState>) {
96107
if (state.currentScreen === 'operator') {
97108
startUpdates()
98109
} else {
99110
stopUpdates()
100111
}
112+
updateSensorData(state)
101113
}
102114

103115
export function initOperatorDashboard() {
104116
subscribe(onStateChange)
105-
if (getState().currentScreen === 'operator') startUpdates()
117+
const state = getState()
118+
if (state.currentScreen === 'operator') startUpdates()
119+
updateSensorData(state)
106120
}
107121

108122
export function updateOperatorDashboard() {

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
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+
setSensorReadings,
7+
setLastPeripheralState,
8+
} from '../core/state'
59
import { showWelcomeThenSwitch } from '../core/screen'
610
import { restartLogoutTimer } from '../core/timer'
711
import { authenticate } from './authenticate'
@@ -14,12 +18,25 @@ export function initPeripherals() {
1418
client.register(edgeAppId)
1519

1620
client.watchState((msg: PeripheralStateMessage) => {
21+
setLastPeripheralState(msg.request.edge_app_source_state)
22+
1723
const readings = msg.request.edge_app_source_state.states
1824

1925
const tempReading = readings.find((r) => 'ambient_temperature' in r)
20-
if (tempReading) {
21-
setTemperature(tempReading.ambient_temperature as number)
22-
}
26+
const humidityReading = readings.find((r) => 'humidity' in r)
27+
const pressureReading = readings.find((r) => 'air_pressure' in r)
28+
29+
setSensorReadings({
30+
temperature: tempReading
31+
? (tempReading.ambient_temperature as number)
32+
: undefined,
33+
humidity: humidityReading
34+
? (humidityReading.humidity as number)
35+
: undefined,
36+
airPressure: pressureReading
37+
? (pressureReading.air_pressure as number)
38+
: undefined,
39+
})
2340

2441
const cardReading = readings.find((r) => 'secure_card' in r)
2542
if (cardReading) {

edge-apps/peripheral-integration-demo/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import './css/style.css'
2+
import 'highlight.js/styles/monokai.css'
23
import '@screenly/edge-apps/components'
34

45
import {

0 commit comments

Comments
 (0)