diff --git a/src/actions/genericEntityAction.ts b/src/actions/genericEntityAction.ts index 2150633..92c74a1 100644 --- a/src/actions/genericEntityAction.ts +++ b/src/actions/genericEntityAction.ts @@ -329,6 +329,7 @@ export class GenericEntityAction extends SingletonAction { private async onReconnect(ev: ReconnectEvent) { await this.homeAssistant.connect(ev.serverUrl, ev.accessToken) + await this.entityConfigFactory.setDisplayConfigurationUrl(ev.customDisplayConfigurationUrl) await this.sendConnectionState() } diff --git a/src/models/events/sendToPluginEvents.ts b/src/models/events/sendToPluginEvents.ts index e770644..2e47fbd 100644 --- a/src/models/events/sendToPluginEvents.ts +++ b/src/models/events/sendToPluginEvents.ts @@ -14,6 +14,7 @@ export type ReconnectEvent = SendToPluginBaseEvent & { event: 'reconnect' serverUrl: string accessToken: string + customDisplayConfigurationUrl: Nullable } export type GetEntityEvent = SendToPluginBaseEvent & { diff --git a/src/render/entityConfigFactoryNg.ts b/src/render/entityConfigFactoryNg.ts index 8bae2be..bc260f1 100644 --- a/src/render/entityConfigFactoryNg.ts +++ b/src/render/entityConfigFactoryNg.ts @@ -1,3 +1,5 @@ +import fs from 'fs' + import streamDeck, { type FeedbackPayload } from '@elgato/streamdeck' import axios from 'axios' import type { HassEntity } from 'home-assistant-js-websocket' @@ -27,12 +29,20 @@ export class EntityConfigFactory { } async setDisplayConfigurationUrl(url: Nullable) { - if (!url) return + if (!url) { + this.displayConfiguration = defaultDisplayConfiguration as DisplayConfig + return + } streamDeck.logger.info(`Loading display configuration from ${url}`) try { - const response = await axios.get(url) - this.displayConfiguration = yaml.load(response.data) as DisplayConfig + let response: string + if (url.startsWith('file://')) { + response = fs.readFileSync(url.replace('file://', ''), 'utf8') + } else { + response = (await axios.get(url)).data + } + this.displayConfiguration = yaml.load(response) as DisplayConfig } catch (error) { streamDeck.logger.error(`Failed to download display configuration from ${url}`, error) } @@ -96,7 +106,12 @@ export class EntityConfigFactory { const feedbackLayout = this.render(feedbackLayoutString, stateObject) const renderedFeedback = this.render(feedbackValueString, stateObject) - const feedback = renderedFeedback ? (JSON.parse(renderedFeedback) as FeedbackPayload) : {} + let feedback: FeedbackPayload = {} + try { + feedback = renderedFeedback ? (JSON.parse(renderedFeedback) as FeedbackPayload) : {} + } catch (error) { + streamDeck.logger.error('Failed to parse feedback template', error) + } const icon = this.render(iconString, stateObject) const color = this.render(colorString, stateObject) diff --git a/src/view/components/PiComponent.vue b/src/view/components/PiComponent.vue index ba12604..3b598ca 100644 --- a/src/view/components/PiComponent.vue +++ b/src/view/components/PiComponent.vue @@ -427,7 +427,8 @@ async function saveGlobalSettings() { await streamDeckClient.send('sendToPlugin', { event: 'reconnect', serverUrl: serverUrl.value, - accessToken: accessToken.value + accessToken: accessToken.value, + customDisplayConfigurationUrl: displayConfigurationUrlOverride.value }) } diff --git a/test/render/entityConfigFactoryNg.test.ts b/test/render/entityConfigFactoryNg.test.ts index 3ac77a4..999d04d 100644 --- a/test/render/entityConfigFactoryNg.test.ts +++ b/test/render/entityConfigFactoryNg.test.ts @@ -152,3 +152,21 @@ it('test setting bad custom display configuration', async () => { const renderConfig = entityConfigFactory.buildRenderConfig(entity, settings) expect(renderConfig.icon).toBe('mdi:lightbulb') }) + +it('test setting custom display configuration with file', async () => { + const entityConfigFactory = new EntityConfigFactory() + const entity = buildTestEntity() + const settings = buildTestSettings() + + // Set the display configuration URL to a local file + await entityConfigFactory.setDisplayConfigurationUrl( + 'file://resources/custom-display-configuration.yml' + ) + const renderConfig1 = entityConfigFactory.buildRenderConfig(entity, settings) + expect(renderConfig1.icon).toBe('mdi:ceiling-light') + + // Set the display configuration URL back to the default + await entityConfigFactory.setDisplayConfigurationUrl('') + const renderConfig2 = entityConfigFactory.buildRenderConfig(entity, settings) + expect(renderConfig2.icon).toBe('mdi:lightbulb') +}) diff --git a/test/resources/custom-display-configuration.yml b/test/resources/custom-display-configuration.yml new file mode 100644 index 0000000..c037774 --- /dev/null +++ b/test/resources/custom-display-configuration.yml @@ -0,0 +1,2 @@ +light: + icon: mdi:ceiling-light