Skip to content

Commit

Permalink
Update home-assistant-javascript-templates and refactors the code to …
Browse files Browse the repository at this point in the history
…match the changes in this dependency
  • Loading branch information
elchininet committed Sep 20, 2024
1 parent 73aac54 commit e6ce660
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 118 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"postversion": "git push && git push --tags"
},
"dependencies": {
"home-assistant-javascript-templates": "^4.0.0",
"home-assistant-javascript-templates": "^5.0.0",
"home-assistant-query-selector": "^4.2.0"
},
"devDependencies": {
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,13 @@ export enum ELEMENT {
HA_DIALOG_ATTRIBUTES = 'ha-attributes'
}

export enum SUBSCRIBE_TYPE {
SUBSCRIBE_EVENTS = 'subscribe_events',
RENDER_TEMPLATE = 'render_template'
}

export const TRUE = 'true';
export const JS_TEMPLATE_REG = /^\s*\[\[\[([\s\S]+)\]\]\]\s*$/;
export const JINJA_TEMPLATE_REG = /\{\{[\s\S]*\}\}|\{%[\s\S]*%\}/;
export const DOMAIN_REGEXP = /^([a-z_]+)[\w.]*$/;
export const CUSTOM_MOBILE_WIDTH_DEFAULT = 812;
export const TOGGLE_MENU_EVENT = 'hass-toggle-menu';
export const CONTEXT_MENU_EVENT = 'contextmenu';
export const STATE_CHANGE_EVENT = 'state_changed';
export const RENDER_TEMPLATE_EVENT = 'render_template';
export const RESIZE_EVENT = 'resize';
export const MAX_ATTEMPTS = 500;
export const RETRY_DELAY = 50;
Expand Down
107 changes: 26 additions & 81 deletions src/kiosk-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import {
OnMoreInfoDialogOpenDetail,
OnHistoryAndLogBookDialogOpenDetail
} from 'home-assistant-query-selector';
import HomeAssistantJavaScriptTemplates from 'home-assistant-javascript-templates';
import HomeAssistantJavaScriptTemplates, {
HomeAssistantJavaScriptTemplatesRenderer,
HassConnection
} from 'home-assistant-javascript-templates';
import {
KioskModeRunner,
HomeAsssistantExtended,
Lovelace,
KioskConfig,
ConditionalKioskConfig,
Options,
HassConnection,
SubscriberTemplate,
SubscriberEvent,
MoreInfoDialog,
Version
} from '@types';
Expand All @@ -29,13 +30,12 @@ import {
TOGGLE_MENU_EVENT,
CONTEXT_MENU_EVENT,
RESIZE_EVENT,
STATE_CHANGE_EVENT,
RENDER_TEMPLATE_EVENT,
JS_TEMPLATE_REG,
JINJA_TEMPLATE_REG,
DOMAIN_REGEXP,
SUBSCRIBE_TYPE,
WINDOW_RESIZE_DELAY,
NAMESPACE,
RETRY_DELAY,
NON_CRITICAL_WARNING
} from '@constants';
import {
Expand Down Expand Up @@ -92,18 +92,12 @@ class KioskMode implements KioskModeRunner {
`${ELEMENT.HOME_ASSISTANT} > hass > user`
);

this.version = parseVersion(this.ha.hass?.config?.version);

this._renderer = new HomeAssistantJavaScriptTemplates(this.ha);
this._renderer = await new HomeAssistantJavaScriptTemplates(this.ha).getRenderer();

this._jsSuscriptions = new Map<string, Map<Options, () => void>>();
this.version = parseVersion(this.ha.hass?.config?.version);

// Start kiosk-mode
this.run();

// Watch for entities changes
this._watchForEntitiesChange();

});

selector.addEventListener(HAQuerySelectorEvent.ON_MORE_INFO_DIALOG_OPEN, (event) => {
Expand Down Expand Up @@ -134,8 +128,8 @@ class KioskMode implements KioskModeRunner {
private menuTranslations: Record<string, string>;
private resizeDelay: number;
private resizeWindowBinded: () => void;
private _renderer: HomeAssistantJavaScriptTemplates;
private _jsSuscriptions: Map<string, Map<Options, () => void>>;
private _renderer: HomeAssistantJavaScriptTemplatesRenderer;
private _runTimeout: number;
private version: Version | null;

// Kiosk Mode options
Expand All @@ -160,37 +154,12 @@ class KioskMode implements KioskModeRunner {
this.panelOptions.set(panelUrl, options);
}

private _watchForEntitiesChange() {
window.hassConnection.then((hassConnection: HassConnection): void => {
hassConnection.conn.subscribeMessage<SubscriberEvent>(
(event) => this._entityWatchCallback(event),
{
type: SUBSCRIBE_TYPE.SUBSCRIBE_EVENTS,
event_type: STATE_CHANGE_EVENT
}
);
});
}

private _entityWatchCallback(event: SubscriberEvent) {
if (this._jsSuscriptions?.size) {
const entityId = event.data.entity_id;
const domain = entityId.replace(DOMAIN_REGEXP, '$1');
if (this._jsSuscriptions.has(entityId)) {
const subscribedOptions = this._jsSuscriptions.get(entityId);
const callbacks = subscribedOptions.values();
Array.from(callbacks).forEach((callback) => {
callback();
});
}
if (this._jsSuscriptions.has(domain)) {
const subscribedOptions = this._jsSuscriptions.get(domain);
const callbacks = subscribedOptions.values();
Array.from(callbacks).forEach((callback) => {
callback();
});
}
}
private runThrottle() {
window.clearTimeout(this._runTimeout);
this._runTimeout = window.setTimeout(() => {
this.run();
this.runDialogs();
}, RETRY_DELAY);
}

public async run() {
Expand Down Expand Up @@ -755,46 +724,23 @@ class KioskMode implements KioskModeRunner {

} else if (JS_TEMPLATE_REG.test(value)) {

const callback = () => {

this._renderer.cleanTracked();
const compiled = this._renderer.renderTemplate(
value.replace(JS_TEMPLATE_REG, '$1')
);
const tracked = this._renderer.tracked;
const {entities, domains} = tracked;

// Store all tracked entities ids and domains ids
[...entities, ...domains].forEach((id: string): void => {
if (this._jsSuscriptions.has(id)) {
const subscribedOptions = this._jsSuscriptions.get(id);
if (!subscribedOptions.has(options)) {
subscribedOptions.set(options, callback);
}
} else {
this._jsSuscriptions.set(
id,
new Map([
[options, callback]
])
);
}
});

const renderingFunction = (result: unknown): void => {
// Set the compiled option
if (typeof compiled === 'boolean') {
options[option] = compiled;
if (typeof result === 'boolean') {
options[option] = result;
} else {
options[option] = false;
console.warn(`${NAMESPACE}: the JavaScript template "${value}" of the option "${option}" doesn't return a boolean value. The option has been set as false`);
}
if (this._getPanelUrl() === panelUrl) {
this.run();
this.runDialogs();
this.runThrottle();
}
};

callback();
this._renderer.trackTemplate(
value.replace(JS_TEMPLATE_REG, '$1'),
renderingFunction
);

} else if (JINJA_TEMPLATE_REG.test(value)) {

Expand All @@ -817,12 +763,11 @@ class KioskMode implements KioskModeRunner {
console.warn(`${NAMESPACE}: the Jinja template "${value}" of the option "${option}" doesn't return a boolean value. The option has been set as false`);
}
if (this._getPanelUrl() === panelUrl) {
this.run();
this.runDialogs();
this.runThrottle();
}
},
{
type: SUBSCRIBE_TYPE.RENDER_TEMPLATE,
type: RENDER_TEMPLATE_EVENT,
template: value,
variables: {
user_name: this.ha.hass.user.name,
Expand Down
25 changes: 1 addition & 24 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,8 @@ export class Lovelace extends HTMLElement {
};
}

export type SubscriberEvent = {
event_type: string;
data: {
entity_id: string;
old_state?: {
state: string;
};
new_state: {
state: string;
};
}
};

export type SubscriberTemplate = {
export interface SubscriberTemplate {
result: string;
};

export interface HassConnection {
conn: {
subscribeMessage: <T>(
callback: (response: T) => void,
options: Record<string, string | Record<string, string | boolean>>
) => void;
}
}

export type StyleElement = Element | ShadowRoot | Element[] | ShadowRoot[];
Expand All @@ -99,7 +77,6 @@ export interface MoreInfoDialog extends HTMLElement {
declare global {
interface Window {
KioskMode: KioskModeRunner;
hassConnection: Promise<HassConnection>;
}
}

Expand Down
4 changes: 4 additions & 0 deletions tests/main-options.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ test.describe('Option: block_context_menu', () => {

await haRequest(ENTITIES.BLOCK_CONTEXT_MENU, true);

await page.waitForTimeout(100);

await page.locator(SELECTORS.HEADER).click({
button: 'right'
});
Expand All @@ -266,6 +268,8 @@ test.describe('Option: block_context_menu', () => {

await haRequest(ENTITIES.BLOCK_CONTEXT_MENU, false);

await page.waitForTimeout(100);

await page.locator(SELECTORS.HEADER).click({
button: 'right'
});
Expand Down

0 comments on commit e6ce660

Please sign in to comment.