ha-nunjucks 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -13
- package/dist/filters.js +6 -3
- package/dist/globals.js +6 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +59 -27
- package/dist/models/interfaces/hass.d.ts +42 -0
- package/dist/models/interfaces/hass.js +1 -0
- package/dist/models/interfaces/registries.d.ts +63 -0
- package/dist/models/interfaces/registries.js +1 -0
- package/dist/utils/areas.d.ts +1 -1
- package/dist/utils/devices.d.ts +2 -2
- package/dist/utils/distance.d.ts +1 -1
- package/dist/utils/entities.d.ts +1 -1
- package/dist/utils/floors.d.ts +1 -1
- package/dist/utils/groups.d.ts +1 -1
- package/dist/utils/iif.d.ts +1 -1
- package/dist/utils/integrations.d.ts +1 -1
- package/dist/utils/labels.d.ts +2 -2
- package/dist/utils/labels.js +14 -17
- package/dist/utils/state_translated.d.ts +6 -1
- package/dist/utils/state_translated.js +30 -0
- package/dist/utils/states.d.ts +2 -3
- package/dist/utils/states.js +8 -9
- package/dist/utils/type_checking.d.ts +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
[![Github][github]][github]
|
|
9
9
|
|
|
10
|
-
A wrapper for [nunjucks](https://www.npmjs.com/package/nunjucks) for use with Home Assistant frontend custom components to render [templates](https://www.home-assistant.io/docs/configuration/templating/) instanteneously at HTML render time. This repository offers
|
|
10
|
+
A wrapper for [nunjucks](https://www.npmjs.com/package/nunjucks) for use with Home Assistant frontend custom components to render [templates](https://www.home-assistant.io/docs/configuration/templating/) instanteneously at HTML render time. This repository offers a fast and easy way for developers to add templating support to Home Assistant custom cards.
|
|
11
11
|
|
|
12
12
|
## What is nunjucks?
|
|
13
13
|
|
|
14
14
|
[Nunjucks](https://mozilla.github.io/nunjucks/) is a templating engine for JavaScript that is heavily inspired by jinja2. Home Assistant uses jinja2 to process templates in card configurations on the backend, so the syntax of jinja2 and Nunjucks is virtually the same. This makes it an excellent alternative to Home Assistant core jinja2 templating for custom cards.
|
|
15
15
|
|
|
16
|
-
While some Home Assistant native cards support templating for certain fields, implementing proper Home Assistant jinja2 template support in custom cards can be difficult. Additionally Home Assistant jinja2 templates are processed by the Python backend, and
|
|
16
|
+
While some Home Assistant native cards support templating for certain fields, implementing proper Home Assistant jinja2 template support in custom cards can be difficult. Additionally Home Assistant jinja2 templates are processed by the Python backend, and use subscriptions which must be managed and do not play as well with dynamic custom variables. Nunjucks templates are processed by the frontend using the frontend [`hass`](https://developers.home-assistant.io/docs/frontend/data/) object before your custom card's HTML is rendered, making nunjucks templating synchronous, near instanteous, and easier to use than traditional jinja2 templates.
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
19
19
|
|
|
@@ -33,7 +33,7 @@ const renderedString = renderTemplate(this.hass, templateString);
|
|
|
33
33
|
|
|
34
34
|
That's it! The result of `renderTemplate` is the rendered template for you to use. In unit and integration testing render time is under 1 ms and shouldn't cause any latency in your projects.
|
|
35
35
|
|
|
36
|
-
Rather than rendering templates on the backend, nunjucks renders templates on the frontend. This repository uses the Home Assistant object present in all custom cards to read entity state data.
|
|
36
|
+
Rather than rendering templates on the backend, nunjucks renders templates on the frontend. This repository uses the Home Assistant object present in all custom cards to read entity state data. A single shared Nunjucks environment is used for the frontend across all custom element instances that use Nunjucks, which helps with initial load times.
|
|
37
37
|
|
|
38
38
|
You can also provide context to the `renderTemplate` function to pass to nunjucks if you want to make additional variables or project specific functions available to your users for use in templates.
|
|
39
39
|
|
|
@@ -54,6 +54,34 @@ const context = {
|
|
|
54
54
|
const renderedString = renderTemplate(this.hass, templateString, context);
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
`renderTemplate` will try to validate that inputs contain valid templates by default using the exported function `hasTemplate`. You can disable this by setting the fourth argument of `renderTemplate` to `false`. This way you can perform this check yourself before any additional templating setup you perform in your code.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { hasTemplate, renderTemplate } from 'ha-nunjucks';
|
|
61
|
+
|
|
62
|
+
if (!hasTemplate(templateString)) {
|
|
63
|
+
return templateString;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const context = {
|
|
67
|
+
foo: 'bar',
|
|
68
|
+
doThing(thing: string) {
|
|
69
|
+
return `doing ${thing}!`;
|
|
70
|
+
},
|
|
71
|
+
config: {
|
|
72
|
+
entity: 'foo.bar',
|
|
73
|
+
attribute: 'baz_bah',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const renderedString = renderTemplate(
|
|
78
|
+
this.hass,
|
|
79
|
+
templateString,
|
|
80
|
+
context,
|
|
81
|
+
false,
|
|
82
|
+
);
|
|
83
|
+
```
|
|
84
|
+
|
|
57
85
|
### Return Types
|
|
58
86
|
|
|
59
87
|
`renderTemplate` will return a string unless the result is `true` or `false` (_not_ case sensitive), in which case it will return a boolean.
|
|
@@ -115,6 +143,10 @@ Functions used to determine an entity's state or an attribute.
|
|
|
115
143
|
| state_translated | function, filter | entity_id, state (optional) | Returns the formatted and translated state of an entity or provided state using a language that is currently configured in the general settings. |
|
|
116
144
|
| attr_name_translated | function, filter | entity_id, attr_name | Returns the formatted and translated attribute name of an entity using a language that is currently configured in the general settings. |
|
|
117
145
|
| attr_value_translated | function, filter | entity_id, attr_name, attr_value (optional) | Returns the formatted and translated attribute value of an entity or provided attribute value using a language that is currently configured in the general settings. |
|
|
146
|
+
| number_translated | function, filter | value | Returns the formatted and translated input number using a language that is currently configured in the general settings. |
|
|
147
|
+
| date_translated | function, filter | value | Returns the formatted and translated input date or datetime as a date using a language that is currently configured in the general settings. |
|
|
148
|
+
| time_translated | function, filter | value | Returns the formatted and translated input time or datetime as a time using a language that is currently configured in the general settings. |
|
|
149
|
+
| datetime_translated | function, filter | value | Returns the formatted and translated input datetime using a language that is currently configured in the general settings. |
|
|
118
150
|
|
|
119
151
|
### [Groups](https://www.home-assistant.io/docs/configuration/templating/#working-with-groups)
|
|
120
152
|
|
|
@@ -164,7 +196,7 @@ Functions used to determine an entity's state or an attribute.
|
|
|
164
196
|
|
|
165
197
|
### [Labels](https://www.home-assistant.io/docs/configuration/templating/#labels)
|
|
166
198
|
|
|
167
|
-
**NOTE**: Labels are not available in the `hass` object and must be retrieved asynchronously from the Home Assistant backend the first time `
|
|
199
|
+
**NOTE**: Labels are not available in the `hass` object and must be retrieved asynchronously from the Home Assistant backend the first time `ha-nunjucks` is imported. Since this package is otherwise synchronous, this can cause a race condition where no labels are found the first time `renderTemplate` is run. This generally resolves itself once the template re-renders.
|
|
168
200
|
|
|
169
201
|
| Name | Type | Arguments | Description |
|
|
170
202
|
| -------------- | ---------------- | ----------------------- | ------------------------------------------------------------------------------------------ |
|
|
@@ -223,10 +255,10 @@ In addition to these functions, you have access to [a datetime library](https://
|
|
|
223
255
|
|
|
224
256
|
### [To/From JSON](https://www.home-assistant.io/docs/configuration/templating/#tofrom-json)
|
|
225
257
|
|
|
226
|
-
| Name | Type | Arguments | Description
|
|
227
|
-
| --------- | ------ | ------------------------------------------ |
|
|
228
|
-
| to_json | filter | obj, ensure_ascii, pretty_print, sort_keys | Turn an object into a JSON string. `ensure_ascii` converts unicode characters into escape sequences. `pretty_print` formats the output with new lines and an indent of two spaces. `sort_keys` sorts the keys of the JSON object. **Consider using the nunjucks `safe` filter with this
|
|
229
|
-
| from_json | filter | value | Parse a string as JSON.
|
|
258
|
+
| Name | Type | Arguments | Description |
|
|
259
|
+
| --------- | ------ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
260
|
+
| to_json | filter | obj, ensure_ascii, pretty_print, sort_keys | Turn an object into a JSON string. `ensure_ascii` converts unicode characters into escape sequences. `pretty_print` formats the output with new lines and an indent of two spaces. `sort_keys` sorts the keys of the JSON object. **Consider using the nunjucks `safe` filter with this, or the nunjucks `dump` filter instead.** |
|
|
261
|
+
| from_json | filter | value | Parse a string as JSON. |
|
|
230
262
|
|
|
231
263
|
### [Distance](https://www.home-assistant.io/docs/configuration/templating/#distance)
|
|
232
264
|
|
|
@@ -306,7 +338,7 @@ In addition to these functions, you have access to [a datetime library](https://
|
|
|
306
338
|
| ------------------- | ------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
307
339
|
| match | test | value, find | Matches the find string at the beginning of the value string using regex. |
|
|
308
340
|
| search | test | value, find | Matches the find string anywhere in the value string using regex. |
|
|
309
|
-
| test | test | value, find | Matches the find regular expression in the value string
|
|
341
|
+
| test | test | value, find | Matches the find regular expression in the value string using regex. Regular expressions should be preceded by r, like `r/foobar/g`. |
|
|
310
342
|
| regex_replace | filter | value, find (default ''), replace (default '') | Replaces the find expression with the replace expression string using RegEx. |
|
|
311
343
|
| regex_findall | filter | value, find (default '') | Finds all RegEx matches of the find expression in value and returns an array of matches. |
|
|
312
344
|
| regex_findall_index | filter | value, find (default ''), index (default 0) | Performs a RegEx find all but returns the match at a provided index. |
|
|
@@ -315,10 +347,10 @@ In addition to these functions, you have access to [a datetime library](https://
|
|
|
315
347
|
|
|
316
348
|
Functions that are not from the Home Assistant templating documentation.
|
|
317
349
|
|
|
318
|
-
| Name | Arguments
|
|
319
|
-
| ----------- |
|
|
320
|
-
| match_media |
|
|
321
|
-
| str |
|
|
350
|
+
| Name | Type | Arguments | Description |
|
|
351
|
+
| ----------- | ---------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
352
|
+
| match_media | function | value | Returns the boolean result of the provided [CSS media query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries). |
|
|
353
|
+
| str | function, filter | value | Return the string representation of the input. |
|
|
322
354
|
|
|
323
355
|
[last-commit-shield]: https://img.shields.io/github/last-commit/Nerwyn/ha-nunjucks?style=for-the-badge
|
|
324
356
|
[commits]: https://github.com/Nerwyn/ha-nunjucks/commits/main
|
package/dist/filters.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { HASS } from '.';
|
|
2
1
|
import { area_devices, area_entities, area_id, area_name } from './utils/areas';
|
|
3
2
|
import { contains } from './utils/contains';
|
|
4
3
|
import { device_attr, device_entities, device_id } from './utils/devices';
|
|
@@ -11,7 +10,7 @@ import { label_areas, label_devices, label_entities, label_id, label_name, label
|
|
|
11
10
|
import { str } from './utils/miscellaneous';
|
|
12
11
|
import { acos, add, asin, atan, atan2, average, bitwise_and, bitwise_not, bitwise_or, bitwise_xor, bool, cos, is_number, log, max, median, min, multiply, ord, sin, sqrt, statistical_mode, tan, } from './utils/numeric';
|
|
13
12
|
import { regex_findall, regex_findall_index, regex_replace, } from './utils/regexp';
|
|
14
|
-
import { attr_name_translated, attr_value_translated, state_translated, } from './utils/state_translated';
|
|
13
|
+
import { attr_name_translated, attr_value_translated, date_translated, datetime_translated, number_translated, state_translated, time_translated, } from './utils/state_translated';
|
|
15
14
|
import { has_value, state_attr, states } from './utils/states';
|
|
16
15
|
import { as_datetime, as_local, as_timestamp, time_since, time_until, timestamp_custom, timestamp_local, timestamp_utc, today_at, } from './utils/time';
|
|
17
16
|
export function addFilters(env) {
|
|
@@ -22,7 +21,7 @@ export function addFilters(env) {
|
|
|
22
21
|
}
|
|
23
22
|
for (const func in HASS_FILTERS) {
|
|
24
23
|
env.addFilter(func, function (...args) {
|
|
25
|
-
return HASS_FILTERS[func](
|
|
24
|
+
return HASS_FILTERS[func](window.haNunjucks.hass, ...args);
|
|
26
25
|
});
|
|
27
26
|
}
|
|
28
27
|
return env;
|
|
@@ -75,6 +74,9 @@ const FILTERS = {
|
|
|
75
74
|
timestamp_local,
|
|
76
75
|
timestamp_utc,
|
|
77
76
|
timestamp_custom,
|
|
77
|
+
date_translated,
|
|
78
|
+
time_translated,
|
|
79
|
+
datetime_translated,
|
|
78
80
|
// To/From JSON
|
|
79
81
|
to_json,
|
|
80
82
|
from_json,
|
|
@@ -108,6 +110,7 @@ const FILTERS = {
|
|
|
108
110
|
ord,
|
|
109
111
|
multiply,
|
|
110
112
|
add,
|
|
113
|
+
number_translated,
|
|
111
114
|
// Regular Expressions
|
|
112
115
|
regex_replace,
|
|
113
116
|
regex_findall,
|
package/dist/globals.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { HASS } from '.';
|
|
2
1
|
import { area_devices, area_entities, area_id, area_name, areas, } from './utils/areas';
|
|
3
2
|
import { device_attr, device_entities, device_id, is_device_attr, } from './utils/devices';
|
|
4
3
|
import { closest, distance } from './utils/distance';
|
|
@@ -10,7 +9,7 @@ import { integration_entities } from './utils/integrations';
|
|
|
10
9
|
import { label_areas, label_devices, label_entities, label_id, label_name, labels, } from './utils/labels';
|
|
11
10
|
import { match_media, str } from './utils/miscellaneous';
|
|
12
11
|
import { acos, asin, atan, atan2, average, bool, cos, e, float, inf, int, is_number, log, max, median, min, pi, sin, sqrt, statistical_mode, tan, tau, } from './utils/numeric';
|
|
13
|
-
import { attr_name_translated, attr_value_translated, state_translated, } from './utils/state_translated';
|
|
12
|
+
import { attr_name_translated, attr_value_translated, date_translated, datetime_translated, number_translated, state_translated, time_translated, } from './utils/state_translated';
|
|
14
13
|
import { has_value, is_state, is_state_attr, state_attr, states, } from './utils/states';
|
|
15
14
|
import { as_datetime, as_local, as_timedelta, as_timestamp, now, strptime, time_since, time_until, today_at, utcnow, } from './utils/time';
|
|
16
15
|
import { list, set } from './utils/type_conversions';
|
|
@@ -24,7 +23,7 @@ export function addGlobals(env) {
|
|
|
24
23
|
}
|
|
25
24
|
for (const func in HASS_GLOBALS) {
|
|
26
25
|
env.addGlobal(func, function (...args) {
|
|
27
|
-
return HASS_GLOBALS[func](
|
|
26
|
+
return HASS_GLOBALS[func](window.haNunjucks.hass, ...args);
|
|
28
27
|
});
|
|
29
28
|
}
|
|
30
29
|
for (const c in CONST_GLOBALS) {
|
|
@@ -96,6 +95,9 @@ const GLOBALS = {
|
|
|
96
95
|
time_since,
|
|
97
96
|
time_until,
|
|
98
97
|
as_timedelta,
|
|
98
|
+
date_translated,
|
|
99
|
+
time_translated,
|
|
100
|
+
datetime_translated,
|
|
99
101
|
// Numeric,
|
|
100
102
|
float,
|
|
101
103
|
is_number,
|
|
@@ -115,6 +117,7 @@ const GLOBALS = {
|
|
|
115
117
|
average,
|
|
116
118
|
median,
|
|
117
119
|
statistical_mode,
|
|
120
|
+
number_translated,
|
|
118
121
|
// Type Conversions
|
|
119
122
|
set,
|
|
120
123
|
list,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { HomeAssistant } from './models/hass';
|
|
2
|
-
export declare let HASS: HomeAssistant;
|
|
1
|
+
import { HomeAssistant } from './models/interfaces/hass';
|
|
3
2
|
/**
|
|
4
3
|
* Render a Home Assistant template string using nunjucks
|
|
5
4
|
* @param {HomeAssistant} hass The Home Assistant object
|
|
6
5
|
* @param {string} str The template string to render
|
|
7
6
|
* @param {object} [context] Additional context to expose to nunjucks
|
|
7
|
+
* @param {boolean} [validate=true] Validate that the input contains a template.
|
|
8
8
|
* @returns {string | boolean} The rendered template string if a string was provided, otherwise the unaltered input
|
|
9
9
|
*/
|
|
10
|
-
export declare function renderTemplate(hass: HomeAssistant, str: string, context?: object): string | boolean;
|
|
10
|
+
export declare function renderTemplate(hass: HomeAssistant, str: string, context?: object, validate?: boolean): string | boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Test if the input contains a valid template
|
|
13
|
+
* @param {any} str the variable to check
|
|
14
|
+
* @returns if the input is a string that contains a template
|
|
15
|
+
*/
|
|
16
|
+
export declare function hasTemplate(str: any): boolean;
|
package/dist/index.js
CHANGED
|
@@ -4,41 +4,73 @@ import { addGlobals } from './globals';
|
|
|
4
4
|
import { addTests } from './tests';
|
|
5
5
|
import { fetchLabelRegistry } from './utils/labels';
|
|
6
6
|
import { buildStatesObject } from './utils/states';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
if (!window.haNunjucks) {
|
|
8
|
+
window.haNunjucks = {
|
|
9
|
+
states: {},
|
|
10
|
+
labelRegistry: {},
|
|
11
|
+
};
|
|
12
|
+
// Async setup label registry and states object on import
|
|
13
|
+
const registrySetup = async () => {
|
|
14
|
+
const ha = document.querySelector('home-assistant');
|
|
15
|
+
if (!ha ||
|
|
16
|
+
!ha.hass ||
|
|
17
|
+
!ha.hass.connected ||
|
|
18
|
+
!ha.hass.connection ||
|
|
19
|
+
!ha.hass.connection.connected) {
|
|
20
|
+
setTimeout(registrySetup, 10);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Number and datetime translators
|
|
24
|
+
window.haNunjucks.numberFormat = new Intl.NumberFormat(ha.hass.language);
|
|
25
|
+
window.haNunjucks.dateFormat = new Intl.DateTimeFormat(ha.hass.language, { dateStyle: 'full' });
|
|
26
|
+
window.haNunjucks.timeFormat = new Intl.DateTimeFormat(ha.hass.language, { timeStyle: 'long' });
|
|
27
|
+
window.haNunjucks.datetimeFormat = new Intl.DateTimeFormat(ha.hass.language, { dateStyle: 'full', timeStyle: 'long' });
|
|
28
|
+
// Label registry and states object
|
|
29
|
+
window.haNunjucks.hass = ha.hass;
|
|
30
|
+
fetchLabelRegistry();
|
|
31
|
+
buildStatesObject();
|
|
32
|
+
};
|
|
33
|
+
registrySetup();
|
|
34
|
+
// Initialize global ha-nunjucks environment
|
|
35
|
+
nunjucks.installJinjaCompat();
|
|
36
|
+
window.haNunjucks.env = addTests(addFilters(addGlobals(new nunjucks.Environment())));
|
|
37
|
+
}
|
|
10
38
|
/**
|
|
11
39
|
* Render a Home Assistant template string using nunjucks
|
|
12
40
|
* @param {HomeAssistant} hass The Home Assistant object
|
|
13
41
|
* @param {string} str The template string to render
|
|
14
42
|
* @param {object} [context] Additional context to expose to nunjucks
|
|
43
|
+
* @param {boolean} [validate=true] Validate that the input contains a template.
|
|
15
44
|
* @returns {string | boolean} The rendered template string if a string was provided, otherwise the unaltered input
|
|
16
45
|
*/
|
|
17
|
-
export function renderTemplate(hass, str, context) {
|
|
18
|
-
if (!
|
|
19
|
-
fetchLabelRegistry(hass);
|
|
20
|
-
}
|
|
21
|
-
HASS = hass;
|
|
22
|
-
if (typeof str == 'string' &&
|
|
23
|
-
((str.includes('{{') && str.includes('}}')) ||
|
|
24
|
-
(str.includes('{%') && str.includes('%}')))) {
|
|
25
|
-
str = env
|
|
26
|
-
.renderString(structuredClone(str), {
|
|
27
|
-
hass,
|
|
28
|
-
_states: buildStatesObject(hass),
|
|
29
|
-
...context,
|
|
30
|
-
})
|
|
31
|
-
.trim();
|
|
32
|
-
if ([undefined, null, 'undefined', 'null', 'None'].includes(str)) {
|
|
33
|
-
return '';
|
|
34
|
-
}
|
|
35
|
-
if (str.toLowerCase() == 'true') {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
if (str.toLowerCase() == 'false') {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
46
|
+
export function renderTemplate(hass, str, context, validate = true) {
|
|
47
|
+
if (validate && !hasTemplate(str)) {
|
|
41
48
|
return str;
|
|
42
49
|
}
|
|
50
|
+
window.haNunjucks.hass = hass;
|
|
51
|
+
buildStatesObject();
|
|
52
|
+
str = window.haNunjucks.env
|
|
53
|
+
.renderString(structuredClone(str), {
|
|
54
|
+
hass,
|
|
55
|
+
_states: window.haNunjucks.states,
|
|
56
|
+
...context,
|
|
57
|
+
})
|
|
58
|
+
.trim();
|
|
59
|
+
if ([undefined, null, 'undefined', 'null', 'None'].includes(str)) {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
const lowerStr = str.toLowerCase();
|
|
63
|
+
if (['true', 'false'].includes(lowerStr)) {
|
|
64
|
+
return lowerStr == 'true';
|
|
65
|
+
}
|
|
43
66
|
return str;
|
|
44
67
|
}
|
|
68
|
+
const hasTemplateRegex = /{{.*?}}|{%.*?%}/;
|
|
69
|
+
/**
|
|
70
|
+
* Test if the input contains a valid template
|
|
71
|
+
* @param {any} str the variable to check
|
|
72
|
+
* @returns if the input is a string that contains a template
|
|
73
|
+
*/
|
|
74
|
+
export function hasTemplate(str) {
|
|
75
|
+
return hasTemplateRegex.test(str);
|
|
76
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Auth, Connection, HassConfig, HassEntities, HassEntity, HassServices, MessageBase } from 'home-assistant-js-websocket';
|
|
2
|
+
import { AreaRegistryEntry, DeviceRegistryEntry, EntityRegistryDisplayEntry, FloorRegistryEntry } from './registries';
|
|
3
|
+
export interface HomeAssistant {
|
|
4
|
+
auth: Auth;
|
|
5
|
+
connection: Connection;
|
|
6
|
+
connected: boolean;
|
|
7
|
+
states: HassEntities;
|
|
8
|
+
entities: {
|
|
9
|
+
[id: string]: EntityRegistryDisplayEntry;
|
|
10
|
+
};
|
|
11
|
+
devices: {
|
|
12
|
+
[id: string]: DeviceRegistryEntry;
|
|
13
|
+
};
|
|
14
|
+
areas: {
|
|
15
|
+
[id: string]: AreaRegistryEntry;
|
|
16
|
+
};
|
|
17
|
+
floors: {
|
|
18
|
+
[id: string]: FloorRegistryEntry;
|
|
19
|
+
};
|
|
20
|
+
services: HassServices;
|
|
21
|
+
config: HassConfig;
|
|
22
|
+
panelUrl: string;
|
|
23
|
+
language: string;
|
|
24
|
+
selectedLanguage: string | null;
|
|
25
|
+
suspendWhenHidden: boolean;
|
|
26
|
+
enableShortcuts: boolean;
|
|
27
|
+
vibrate: boolean;
|
|
28
|
+
debugConnection: boolean;
|
|
29
|
+
dockedSidebar: 'docked' | 'always_hidden' | 'auto';
|
|
30
|
+
defaultPanel: string;
|
|
31
|
+
moreInfoEntityId: string | null;
|
|
32
|
+
callApi<T>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, parameters?: Record<string, any>, headers?: Record<string, string>): Promise<T>;
|
|
33
|
+
fetchWithAuth(path: string, init?: Record<string, any>): Promise<Response>;
|
|
34
|
+
sendWS(msg: MessageBase): void;
|
|
35
|
+
callWS<T>(msg: MessageBase): Promise<T>;
|
|
36
|
+
formatEntityState(stateObj: HassEntity, state?: string): string;
|
|
37
|
+
formatEntityAttributeValue(stateObj: HassEntity, attribute: string, value?: any): string;
|
|
38
|
+
formatEntityAttributeName(stateObj: HassEntity, attribute: string): string;
|
|
39
|
+
}
|
|
40
|
+
export interface HassElement extends HTMLElement {
|
|
41
|
+
hass: HomeAssistant;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
interface RegistryEntry {
|
|
2
|
+
created_at: number;
|
|
3
|
+
modified_at: number;
|
|
4
|
+
}
|
|
5
|
+
export interface AreaRegistryEntry extends RegistryEntry {
|
|
6
|
+
area_id: string;
|
|
7
|
+
floor_id: string | null;
|
|
8
|
+
name: string;
|
|
9
|
+
picture: string | null;
|
|
10
|
+
icon: string | null;
|
|
11
|
+
labels: string[];
|
|
12
|
+
aliases: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface DeviceRegistryEntry extends RegistryEntry {
|
|
15
|
+
id: string;
|
|
16
|
+
config_entries: string[];
|
|
17
|
+
connections: Array<[string, string]>;
|
|
18
|
+
identifiers: Array<[string, string]>;
|
|
19
|
+
manufacturer: string | null;
|
|
20
|
+
model: string | null;
|
|
21
|
+
model_id: string | null;
|
|
22
|
+
name: string | null;
|
|
23
|
+
labels: string[];
|
|
24
|
+
sw_version: string | null;
|
|
25
|
+
hw_version: string | null;
|
|
26
|
+
serial_number: string | null;
|
|
27
|
+
via_device_id: string | null;
|
|
28
|
+
area_id: string | null;
|
|
29
|
+
name_by_user: string | null;
|
|
30
|
+
entry_type: 'service' | null;
|
|
31
|
+
disabled_by: 'user' | 'integration' | 'config_entry' | null;
|
|
32
|
+
configuration_url: string | null;
|
|
33
|
+
primary_config_entry: string | null;
|
|
34
|
+
}
|
|
35
|
+
type EntityCategory = 'config' | 'diagnostic';
|
|
36
|
+
export interface EntityRegistryDisplayEntry {
|
|
37
|
+
entity_id: string;
|
|
38
|
+
name?: string;
|
|
39
|
+
icon?: string;
|
|
40
|
+
device_id?: string;
|
|
41
|
+
area_id?: string;
|
|
42
|
+
labels: string[];
|
|
43
|
+
hidden?: boolean;
|
|
44
|
+
entity_category?: EntityCategory;
|
|
45
|
+
translation_key?: string;
|
|
46
|
+
platform?: string;
|
|
47
|
+
display_precision?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface FloorRegistryEntry extends RegistryEntry {
|
|
50
|
+
aliases: string[];
|
|
51
|
+
floor_id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
level?: number;
|
|
54
|
+
icon?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface LabelRegistryEntry extends RegistryEntry {
|
|
57
|
+
label_id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
icon?: string;
|
|
60
|
+
color?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
}
|
|
63
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils/areas.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
2
|
export declare function areas(hass: HomeAssistant): string[];
|
|
3
3
|
export declare function area_id(hass: HomeAssistant, lookup_value: string): string | null | undefined;
|
|
4
4
|
export declare function area_name(hass: HomeAssistant, lookup_value: string): string | undefined;
|
package/dist/utils/devices.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
2
|
-
import { DeviceRegistryEntry } from '../models/registries';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
|
+
import { DeviceRegistryEntry } from '../models/interfaces/registries';
|
|
3
3
|
export declare function device_entities(hass: HomeAssistant, device_id: string): string[];
|
|
4
4
|
export declare function device_attr(hass: HomeAssistant, device_or_entity_id: string, attr_name: keyof DeviceRegistryEntry): any;
|
|
5
5
|
export declare function is_device_attr(hass: HomeAssistant, device_or_entity_id: string, attr_name: keyof DeviceRegistryEntry, attr_value: string): boolean;
|
package/dist/utils/distance.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { HassEntities, HassEntity } from 'home-assistant-js-websocket';
|
|
2
|
-
import { HomeAssistant } from '../models/hass';
|
|
2
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
3
3
|
export declare function distance(hass: HomeAssistant, ...args: (string | HassEntity | number)[]): number | null | undefined;
|
|
4
4
|
export declare function closest(hass: HomeAssistant, ...args: (string | string[] | HassEntity | HassEntities)[]): HassEntity | null;
|
package/dist/utils/entities.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
2
|
export declare function is_hidden_entity(hass: HomeAssistant, entity_id: string): boolean;
|
package/dist/utils/floors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
2
|
export declare function floors(hass: HomeAssistant): string[];
|
|
3
3
|
export declare function floor_id(hass: HomeAssistant, lookup_value: string): string | null | undefined;
|
|
4
4
|
export declare function floor_name(hass: HomeAssistant, lookup_value: string): string | undefined;
|
package/dist/utils/groups.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { HassEntities, HassEntity } from 'home-assistant-js-websocket';
|
|
2
|
-
import { HomeAssistant } from '../models/hass';
|
|
2
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
3
3
|
export declare function expand(hass: HomeAssistant, ...args: (string | HassEntity | HassEntities)[]): HassEntity[];
|
package/dist/utils/iif.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
2
|
export declare function iif(hass: HomeAssistant, condition: string, if_true?: string | Record<string, string>, if_false?: string, if_none?: string): string | boolean;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
2
|
export declare function integration_entities(hass: HomeAssistant, integration: string): string[];
|
package/dist/utils/labels.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HomeAssistant } from '../models/hass';
|
|
2
|
-
export declare function fetchLabelRegistry(
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
|
+
export declare function fetchLabelRegistry(): Promise<void>;
|
|
3
3
|
export declare function labels(hass: HomeAssistant, lookup_value?: string): string[];
|
|
4
4
|
export declare function label_id(lookup_value: string): string | undefined;
|
|
5
5
|
export declare function label_name(lookup_value: string): string;
|
package/dist/utils/labels.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (const label of labels) {
|
|
9
|
-
labelRegistry[label.label_id] = label;
|
|
10
|
-
}
|
|
1
|
+
export async function fetchLabelRegistry() {
|
|
2
|
+
const labels = await window.haNunjucks.hass.connection.sendMessagePromise({
|
|
3
|
+
type: 'config/label_registry/list',
|
|
4
|
+
});
|
|
5
|
+
labels.sort((ent1, ent2) => ent1.name.localeCompare(ent2.name));
|
|
6
|
+
for (const label of labels) {
|
|
7
|
+
window.haNunjucks.labelRegistry[label.label_id] = label;
|
|
11
8
|
}
|
|
12
9
|
}
|
|
13
10
|
export function labels(hass, lookup_value) {
|
|
14
11
|
try {
|
|
15
12
|
if (!lookup_value) {
|
|
16
|
-
return Object.keys(labelRegistry);
|
|
13
|
+
return Object.keys(window.haNunjucks.labelRegistry);
|
|
17
14
|
}
|
|
18
15
|
return (hass.entities[lookup_value]?.labels ??
|
|
19
16
|
hass.devices[lookup_value]?.labels ??
|
|
@@ -25,22 +22,22 @@ export function labels(hass, lookup_value) {
|
|
|
25
22
|
}
|
|
26
23
|
}
|
|
27
24
|
export function label_id(lookup_value) {
|
|
28
|
-
for (const id in labelRegistry) {
|
|
29
|
-
if (labelRegistry[id].name == lookup_value) {
|
|
25
|
+
for (const id in window.haNunjucks.labelRegistry) {
|
|
26
|
+
if (window.haNunjucks.labelRegistry[id].name == lookup_value) {
|
|
30
27
|
return id;
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
return undefined;
|
|
34
31
|
}
|
|
35
32
|
export function label_name(lookup_value) {
|
|
36
|
-
return labelRegistry[lookup_value]?.name;
|
|
33
|
+
return window.haNunjucks.labelRegistry[lookup_value]?.name;
|
|
37
34
|
}
|
|
38
35
|
export function label_areas(hass, label_name_or_id) {
|
|
39
36
|
try {
|
|
40
37
|
const areaIds = [];
|
|
41
38
|
let labelId = undefined;
|
|
42
39
|
if (label_name_or_id) {
|
|
43
|
-
if (labelRegistry[label_name_or_id]) {
|
|
40
|
+
if (window.haNunjucks.labelRegistry[label_name_or_id]) {
|
|
44
41
|
labelId = label_name_or_id;
|
|
45
42
|
}
|
|
46
43
|
else {
|
|
@@ -67,7 +64,7 @@ export function label_devices(hass, label_name_or_id) {
|
|
|
67
64
|
const deviceIds = [];
|
|
68
65
|
if (label_name_or_id) {
|
|
69
66
|
let labelId = undefined;
|
|
70
|
-
if (labelRegistry[label_name_or_id]) {
|
|
67
|
+
if (window.haNunjucks.labelRegistry[label_name_or_id]) {
|
|
71
68
|
labelId = label_name_or_id;
|
|
72
69
|
}
|
|
73
70
|
else {
|
|
@@ -94,7 +91,7 @@ export function label_entities(hass, label_name_or_id) {
|
|
|
94
91
|
const entityIds = [];
|
|
95
92
|
if (label_name_or_id) {
|
|
96
93
|
let labelId = undefined;
|
|
97
|
-
if (labelRegistry[label_name_or_id]) {
|
|
94
|
+
if (window.haNunjucks.labelRegistry[label_name_or_id]) {
|
|
98
95
|
labelId = label_name_or_id;
|
|
99
96
|
}
|
|
100
97
|
else {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { date, datetime, time } from 'ts-py-datetime';
|
|
2
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
3
|
export declare function state_translated(hass: HomeAssistant, entity_id: string, state?: string): string;
|
|
3
4
|
export declare function attr_name_translated(hass: HomeAssistant, entity_id: string, attr_name: string): string;
|
|
4
5
|
export declare function attr_value_translated(hass: HomeAssistant, entity_id: string, attr_name: string, attr_value?: string): any;
|
|
6
|
+
export declare function number_translated(value: number): string | number;
|
|
7
|
+
export declare function date_translated(value: date | datetime): string | date | datetime;
|
|
8
|
+
export declare function time_translated(value: time | datetime): string | datetime | time;
|
|
9
|
+
export declare function datetime_translated(value: datetime): string | datetime;
|
|
@@ -26,3 +26,33 @@ export function attr_value_translated(hass, entity_id, attr_name, attr_value) {
|
|
|
26
26
|
undefined);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
export function number_translated(value) {
|
|
30
|
+
if (isNaN(value)) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
return window.haNunjucks.numberFormat.format(value);
|
|
34
|
+
}
|
|
35
|
+
export function date_translated(value) {
|
|
36
|
+
try {
|
|
37
|
+
return window.haNunjucks.dateFormat.format(value.jsDate);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function time_translated(value) {
|
|
44
|
+
try {
|
|
45
|
+
return window.haNunjucks.timeFormat.format(value.jsDate);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function datetime_translated(value) {
|
|
52
|
+
try {
|
|
53
|
+
return window.haNunjucks.datetimeFormat.format(value.jsDate);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
}
|
package/dist/utils/states.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { HomeAssistant } from '../models/interfaces/hass';
|
|
2
|
+
export declare function buildStatesObject(): void;
|
|
3
3
|
export declare function states(hass: HomeAssistant, entity_id: string, rounded?: boolean | Record<string, boolean>, with_unit?: boolean): string | undefined;
|
|
4
4
|
export declare function is_state(hass: HomeAssistant, entity_id: string, value: string | string[]): boolean;
|
|
5
5
|
export declare function state_attr(hass: HomeAssistant, entity_id: string, attribute: string): any;
|
|
6
6
|
export declare function is_state_attr(hass: HomeAssistant, entity_id: string, attribute: string, value: string): boolean;
|
|
7
7
|
export declare function has_value(hass: HomeAssistant, entity_id: string): boolean;
|
|
8
|
-
export declare function buildStatesObject(hass: HomeAssistant): Record<string, Record<string, HassEntity>>;
|
package/dist/utils/states.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
export function buildStatesObject() {
|
|
2
|
+
for (const entityId in window.haNunjucks.hass.states) {
|
|
3
|
+
const [domain, id] = entityId.split('.');
|
|
4
|
+
window.haNunjucks.states[domain] ??= {};
|
|
5
|
+
window.haNunjucks.states[domain][id] =
|
|
6
|
+
window.haNunjucks.hass.states[entityId];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
1
9
|
export function states(hass, entity_id, rounded, with_unit) {
|
|
2
10
|
if (typeof rounded == 'object' && !Array.isArray(rounded)) {
|
|
3
11
|
with_unit = rounded.with_unit ?? with_unit;
|
|
@@ -64,12 +72,3 @@ export function has_value(hass, entity_id) {
|
|
|
64
72
|
return false;
|
|
65
73
|
}
|
|
66
74
|
}
|
|
67
|
-
export function buildStatesObject(hass) {
|
|
68
|
-
const states = {};
|
|
69
|
-
for (const entityId in hass.states) {
|
|
70
|
-
const [domain, entity] = entityId.split('.');
|
|
71
|
-
states[domain] = states[domain] ?? {};
|
|
72
|
-
states[domain][entity] = hass.states[entityId];
|
|
73
|
-
}
|
|
74
|
-
return states;
|
|
75
|
-
}
|
|
@@ -2,4 +2,4 @@ import { datetime } from 'ts-py-datetime';
|
|
|
2
2
|
export declare function list(value: object[]): boolean;
|
|
3
3
|
export declare function set(value: object[]): value is object[] & Set<any>;
|
|
4
4
|
export declare function is_datetime(value: object): value is datetime;
|
|
5
|
-
export declare function string_like(value: object): value is Buffer | Uint8Array | Uint16Array | Uint32Array
|
|
5
|
+
export declare function string_like(value: object): value is ArrayBuffer | Buffer<ArrayBuffer> | Buffer<any> | Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ha-nunjucks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Wrapper for nunjucks for use with Home Assistant frontend custom components to render templates",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "ts-mocha
|
|
11
|
+
"test": "ts-mocha tests/**/*.test.ts --require fixtures.cjs",
|
|
12
12
|
"build": "tsc",
|
|
13
13
|
"prelint": "tsc --noemit",
|
|
14
14
|
"lint": "eslint --config ./.eslintrc.config.cjs"
|
|
@@ -39,12 +39,14 @@
|
|
|
39
39
|
"eslint": "latest",
|
|
40
40
|
"eslint-config-prettier": "latest",
|
|
41
41
|
"eslint-plugin-prettier": "latest",
|
|
42
|
+
"jsdom-global": "latest",
|
|
42
43
|
"lint-staged": "latest",
|
|
44
|
+
"mocha": "latest",
|
|
43
45
|
"prettier": "latest",
|
|
44
46
|
"prettier-plugin-organize-imports": "latest",
|
|
45
47
|
"ts-loader": "latest",
|
|
46
48
|
"ts-mocha": "latest",
|
|
47
|
-
"ts-node": "
|
|
49
|
+
"ts-node": "^10.9.2",
|
|
48
50
|
"tsx": "latest",
|
|
49
51
|
"typescript": "latest"
|
|
50
52
|
}
|