From 7d6cbf4b98eac361e003641652049f60ba9b28d5 Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 08:21:44 -0800 Subject: [PATCH 1/7] chore(edge-apps-library): create a helper function for checking if a screen is an Anywhere screen or not --- .../src/utils/metadata.test.ts | 20 +++++++++++++++++++ .../edge-apps-library/src/utils/metadata.ts | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.test.ts b/edge-apps/edge-apps-library/src/utils/metadata.test.ts index c570d8cab..70761b98e 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.test.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.test.ts @@ -9,6 +9,7 @@ import { getScreenlyVersion, getTags, hasTag, + isAnywhereScreen, } from './metadata' import { setupScreenlyMock, resetScreenlyMock } from '../test/mock' @@ -100,4 +101,23 @@ describe('metadata utilities', () => { expect(hasTag('other')).toBe(false) }) }) + + describe('isAnywhereScreen', () => { + test('should return false when hardware is not empty', () => { + expect(isAnywhereScreen()).toBe(false) + }) + + test('should return true when hardware is empty string', () => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: '', + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(isAnywhereScreen()).toBe(true) + }) + }) }) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.ts b/edge-apps/edge-apps-library/src/utils/metadata.ts index 79317f3ad..96030628b 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.ts @@ -63,3 +63,13 @@ export function getTags(): string[] { export function hasTag(tag: string): boolean { return screenly.metadata.tags.includes(tag) } + +/** + * Check if the device is an Anywhere screen + */ +export function isAnywhereScreen(): boolean { + return ( + screenly.metadata.hardware === '' || + screenly.metadata.hardware === undefined + ) +} From a0c9bb6dc57f10641df90e151dab58d919b111f8 Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 09:28:44 -0800 Subject: [PATCH 2/7] chore(edge-apps-library): resolve type inconsistencies with `hardware`'s type --- .../edge-apps-library/src/types/index.ts | 2 +- .../src/utils/metadata.test.ts | 30 +++++++++++-------- .../edge-apps-library/src/utils/metadata.ts | 7 ++--- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/edge-apps/edge-apps-library/src/types/index.ts b/edge-apps/edge-apps-library/src/types/index.ts index 272340e9e..f0cfa7229 100644 --- a/edge-apps/edge-apps-library/src/types/index.ts +++ b/edge-apps/edge-apps-library/src/types/index.ts @@ -5,7 +5,7 @@ export interface ScreenlyMetadata { /** GPS coordinates [latitude, longitude] */ coordinates: [number, number] /** Hardware identifier */ - hardware: string + hardware: string | undefined /** Device hostname */ hostname: string /** Physical location description */ diff --git a/edge-apps/edge-apps-library/src/utils/metadata.test.ts b/edge-apps/edge-apps-library/src/utils/metadata.test.ts index 70761b98e..f79837b75 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.test.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.test.ts @@ -107,17 +107,23 @@ describe('metadata utilities', () => { expect(isAnywhereScreen()).toBe(false) }) - test('should return true when hardware is empty string', () => { - setupScreenlyMock({ - coordinates: [37.3861, -122.0839], - hostname: 'test-host', - location: 'Test Location', - hardware: '', - screenly_version: '1.2.3', - screen_name: 'Main Screen', - tags: [], - }) - expect(isAnywhereScreen()).toBe(true) - }) + test.each([ + ['empty string', ''], + ['undefined', undefined], + ])( + 'should return true when hardware is %s', + (_: string, hardware: string | undefined) => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: hardware as string | undefined, + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(isAnywhereScreen()).toBe(true) + }, + ) }) }) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.ts b/edge-apps/edge-apps-library/src/utils/metadata.ts index 96030628b..e9c20a2a1 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.ts @@ -39,7 +39,7 @@ export function getLocation(): string { /** * Get the hardware identifier */ -export function getHardware(): string { +export function getHardware(): string | undefined { return screenly.metadata.hardware } @@ -68,8 +68,5 @@ export function hasTag(tag: string): boolean { * Check if the device is an Anywhere screen */ export function isAnywhereScreen(): boolean { - return ( - screenly.metadata.hardware === '' || - screenly.metadata.hardware === undefined - ) + return getHardware() === '' || getHardware() === undefined } From 65772d67b7a061a75ff5625a57b3394f00dd013c Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 09:36:44 -0800 Subject: [PATCH 3/7] chore: update edge-apps/edge-apps-library/src/utils/metadata.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- edge-apps/edge-apps-library/src/utils/metadata.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.ts b/edge-apps/edge-apps-library/src/utils/metadata.ts index e9c20a2a1..d1493b6ba 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.ts @@ -68,5 +68,6 @@ export function hasTag(tag: string): boolean { * Check if the device is an Anywhere screen */ export function isAnywhereScreen(): boolean { - return getHardware() === '' || getHardware() === undefined + const hardware = getHardware() + return hardware === '' || hardware === undefined } From 37976ea54bb24844435d331e20556c293c62df7a Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 14:44:18 -0800 Subject: [PATCH 4/7] fix(edge-apps-library): update logic for checking for Anywhere screens `screenly.metadata.hardware` only returns `undefined` for Anywhere screens. --- .../src/utils/metadata.test.ts | 30 ++++++++----------- .../edge-apps-library/src/utils/metadata.ts | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.test.ts b/edge-apps/edge-apps-library/src/utils/metadata.test.ts index f79837b75..8a6540987 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.test.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.test.ts @@ -107,23 +107,17 @@ describe('metadata utilities', () => { expect(isAnywhereScreen()).toBe(false) }) - test.each([ - ['empty string', ''], - ['undefined', undefined], - ])( - 'should return true when hardware is %s', - (_: string, hardware: string | undefined) => { - setupScreenlyMock({ - coordinates: [37.3861, -122.0839], - hostname: 'test-host', - location: 'Test Location', - hardware: hardware as string | undefined, - screenly_version: '1.2.3', - screen_name: 'Main Screen', - tags: [], - }) - expect(isAnywhereScreen()).toBe(true) - }, - ) + test('should return true when hardware is undefined', () => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: undefined, + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(isAnywhereScreen()).toBe(true) + }) }) }) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.ts b/edge-apps/edge-apps-library/src/utils/metadata.ts index d1493b6ba..a9b6bba80 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.ts @@ -69,5 +69,5 @@ export function hasTag(tag: string): boolean { */ export function isAnywhereScreen(): boolean { const hardware = getHardware() - return hardware === '' || hardware === undefined + return hardware === undefined } From 06c8e830d04627608b547e25e7fbb312d5647d79 Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 16:45:57 -0800 Subject: [PATCH 5/7] refactor(edge-apps-library): refactor hardware detection to use enum and remove isAnywhereScreen - Create Hardware enum with Anywhere, RaspberryPi, and ScreenlyPlayerMax values - Update getHardware() to return Hardware enum instead of string - Map hardware strings to enum values with proper validation - Throw error for unknown hardware types - Remove isAnywhereScreen() function in favor of direct enum comparison - Update all tests to use Hardware enum - Simplify and clarify hardware type checking --- .../edge-apps-library/src/types/index.ts | 9 +++ .../src/utils/metadata.test.ts | 70 ++++++++++++------- .../edge-apps-library/src/utils/metadata.ts | 29 +++++--- 3 files changed, 73 insertions(+), 35 deletions(-) diff --git a/edge-apps/edge-apps-library/src/types/index.ts b/edge-apps/edge-apps-library/src/types/index.ts index f0cfa7229..831bc123f 100644 --- a/edge-apps/edge-apps-library/src/types/index.ts +++ b/edge-apps/edge-apps-library/src/types/index.ts @@ -1,3 +1,12 @@ +/** + * Hardware types for Screenly devices + */ +export enum Hardware { + Anywhere = 'Anywhere', + RaspberryPi = 'RaspberryPi', + ScreenlyPlayerMax = 'ScreenlyPlayerMax', +} + /** * Screenly metadata provided by the Edge Apps runtime */ diff --git a/edge-apps/edge-apps-library/src/utils/metadata.test.ts b/edge-apps/edge-apps-library/src/utils/metadata.test.ts index 8a6540987..0b2880076 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.test.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.test.ts @@ -9,8 +9,8 @@ import { getScreenlyVersion, getTags, hasTag, - isAnywhereScreen, } from './metadata' +import { Hardware } from '../types/index.js' import { setupScreenlyMock, resetScreenlyMock } from '../test/mock' describe('metadata utilities', () => { @@ -19,7 +19,7 @@ describe('metadata utilities', () => { coordinates: [37.3861, -122.0839], hostname: 'test-host', location: 'Test Location', - hardware: 'Raspberry Pi 4', + hardware: 'Raspberry Pi', screenly_version: '1.2.3', screen_name: 'Main Screen', tags: ['lobby', 'reception', 'main'], @@ -37,7 +37,7 @@ describe('metadata utilities', () => { coordinates: [37.3861, -122.0839], hostname: 'test-host', location: 'Test Location', - hardware: 'Raspberry Pi 4', + hardware: 'Raspberry Pi', screenly_version: '1.2.3', screen_name: 'Main Screen', tags: ['lobby', 'reception', 'main'], @@ -71,8 +71,49 @@ describe('metadata utilities', () => { }) describe('getHardware', () => { - test('should return hardware', () => { - expect(getHardware()).toBe('Raspberry Pi 4') + test('should return RaspberryPi enum value', () => { + expect(getHardware()).toBe(Hardware.RaspberryPi) + }) + + test('should return Anywhere enum value when hardware is undefined', () => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: undefined, + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(getHardware()).toBe(Hardware.Anywhere) + }) + + test('should return ScreenlyPlayerMax enum value for Screenly Player Max hardware', () => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: 'Screenly Player Max', + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(getHardware()).toBe(Hardware.ScreenlyPlayerMax) + }) + + test('should throw error for unknown hardware type', () => { + setupScreenlyMock({ + coordinates: [37.3861, -122.0839], + hostname: 'test-host', + location: 'Test Location', + hardware: 'Unknown Hardware', + screenly_version: '1.2.3', + screen_name: 'Main Screen', + tags: [], + }) + expect(() => getHardware()).toThrow( + 'Unknown hardware type: Unknown Hardware', + ) }) }) @@ -101,23 +142,4 @@ describe('metadata utilities', () => { expect(hasTag('other')).toBe(false) }) }) - - describe('isAnywhereScreen', () => { - test('should return false when hardware is not empty', () => { - expect(isAnywhereScreen()).toBe(false) - }) - - test('should return true when hardware is undefined', () => { - setupScreenlyMock({ - coordinates: [37.3861, -122.0839], - hostname: 'test-host', - location: 'Test Location', - hardware: undefined, - screenly_version: '1.2.3', - screen_name: 'Main Screen', - tags: [], - }) - expect(isAnywhereScreen()).toBe(true) - }) - }) }) diff --git a/edge-apps/edge-apps-library/src/utils/metadata.ts b/edge-apps/edge-apps-library/src/utils/metadata.ts index a9b6bba80..09480dbbb 100644 --- a/edge-apps/edge-apps-library/src/utils/metadata.ts +++ b/edge-apps/edge-apps-library/src/utils/metadata.ts @@ -1,4 +1,5 @@ import type { ScreenlyMetadata } from '../types/index.js' +import { Hardware } from '../types/index.js' import { formatCoordinates } from './locale.js' /** @@ -37,10 +38,24 @@ export function getLocation(): string { } /** - * Get the hardware identifier + * Get the hardware type */ -export function getHardware(): string | undefined { - return screenly.metadata.hardware +export function getHardware(): Hardware { + const hardware = screenly.metadata.hardware + + if (hardware === undefined) { + return Hardware.Anywhere + } + + if (hardware === 'Raspberry Pi') { + return Hardware.RaspberryPi + } + + if (hardware === 'Screenly Player Max') { + return Hardware.ScreenlyPlayerMax + } + + throw new Error(`Unknown hardware type: ${hardware}`) } /** @@ -63,11 +78,3 @@ export function getTags(): string[] { export function hasTag(tag: string): boolean { return screenly.metadata.tags.includes(tag) } - -/** - * Check if the device is an Anywhere screen - */ -export function isAnywhereScreen(): boolean { - const hardware = getHardware() - return hardware === undefined -} From e8220db823e12ebc9074528bcbfccb8df4d33902 Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 16:54:43 -0800 Subject: [PATCH 6/7] docs(edge-apps-library): update README.md for Hardware enum changes - Add Hardware enum documentation to metadata section - Include Hardware enum in types import example --- edge-apps/edge-apps-library/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/edge-apps/edge-apps-library/README.md b/edge-apps/edge-apps-library/README.md index 3618f6311..96f9e9ff3 100644 --- a/edge-apps/edge-apps-library/README.md +++ b/edge-apps/edge-apps-library/README.md @@ -59,7 +59,8 @@ signalReady() ### Metadata - `getMetadata()` - Get all screen metadata -- `getScreenName()`, `getHostname()`, `getLocation()`, `getHardware()`, `getScreenlyVersion()`, `getTags()`, `hasTag(tag)`, `getFormattedCoordinates()` +- `getScreenName()`, `getHostname()`, `getLocation()`, `getScreenlyVersion()`, `getTags()`, `hasTag(tag)`, `getFormattedCoordinates()` +- `getHardware()` - Get hardware type as `Hardware` enum (`Anywhere`, `RaspberryPi`, or `ScreenlyPlayerMax`) ### Location & Localization @@ -125,6 +126,7 @@ afterEach(() => { ```typescript import type { + Hardware, ScreenlyMetadata, ScreenlySettings, ScreenlyObject, From 25be3b1f979d28f165e7711e2bfc4d7ee0bd4682 Mon Sep 17 00:00:00 2001 From: Nico Miguelino Date: Wed, 31 Dec 2025 17:13:09 -0800 Subject: [PATCH 7/7] refactor(menu-board): update to use Hardware enum from getHardware() - Import Hardware enum from @screenly/edge-apps - Update hardware check to use Hardware.Anywhere enum value - Improve clarity of Anywhere screen detection logic --- edge-apps/menu-board/src/main.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/edge-apps/menu-board/src/main.ts b/edge-apps/menu-board/src/main.ts index 132d06187..832eabeb5 100644 --- a/edge-apps/menu-board/src/main.ts +++ b/edge-apps/menu-board/src/main.ts @@ -3,6 +3,7 @@ import { getSettingWithDefault, signalReady, } from '@screenly/edge-apps' +import { Hardware } from '@screenly/edge-apps' import { escapeHtml, calculateItemsPerPage, @@ -55,9 +56,9 @@ function renderPage( fragment.appendChild(itemElement) }) - // Disable transitions if hardware is undefined (running in an Anywhere screen) + // Disable transitions if hardware is Anywhere screen const hardware = getHardware() - if (!hardware) { + if (hardware === Hardware.Anywhere) { menuGrid.innerHTML = '' menuGrid.appendChild(fragment) } else {