Skip to content

Commit bf65aea

Browse files
committed
Add a new device_name method and improve existent device methods
1 parent 15eb59f commit bf65aea

7 files changed

Lines changed: 247 additions & 64 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [5.12.0] - 2025-10-31
4+
5+
- Add a new method to return the device name from an entity id or a device id (`device_name`)
6+
- Add support to send an entity id to the `device_attr` method
7+
- Add support to send an entity id to the `is_device_attr` method
8+
- Add support to send a device name to the `device_id` method
9+
310
## [5.11.0] - 2025-10-30
411

512
- Add a new parameter to the `trackTemplate` method to send extra variables

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,26 +274,38 @@ devices['706ad0ebe27e105d7cd0b73386deefdd'] // returns the device that matches t
274274

275275
#### device_attr
276276

277-
Method that returns the value of an attribute for the given device id or `undefined` if it doesn’t exist.
277+
Method that returns the value of an attribute for the given entity or device id. It returns `undefined` if the entity or the device doesn’t exist.
278278

279279
```javascript
280+
device_attr('sensor.my_sensor', 'manufacturer')
280281
device_attr('706ad0ebe27e105d7cd0b73386deefdd', 'manufacturer')
281282
```
282283

283284
#### is_device_attr
284285

285-
Method to test if the value of a device attribute matches a value. It returns a `boolean`, if the device id doen‘t exist it returns `false`.
286+
Method to test if the value of a device attribute matches a value for a given entity or device id. It returns a `boolean`, if the entity or device doesn‘t exist it returns `false`.
286287

287288
```javascript
289+
is_device_attr('sensor.my_sensor', 'manufacturer', 'Synology')
288290
is_device_attr('706ad0ebe27e105d7cd0b73386deefdd', 'manufacturer', 'Synology')
289291
```
290292

291293
#### device_id
292294

293-
Method to return the device id for a given entity id or `undefined` if the entity doesn‘t exist.
295+
Method to return the device id for a given entity id or device name. It returns `undefined` if the entity or name doesn‘t exist.
294296

295297
```javascript
296298
device_id('sensor.my_sensor')
299+
device_id('My lamp')
300+
```
301+
302+
#### device_name
303+
304+
Method to return the device name for a given device id or entity id. It returns `undefined` if the entity or device doesn‘t exist.
305+
306+
```javascript
307+
device_name('sensor.my_sensor')
308+
device_name('706ad0ebe27e105d7cd0b73386deefdd')
297309
```
298310

299311
#### areas

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ class HomeAssistantJavaScriptTemplatesRenderer {
211211
'device_attr',
212212
'is_device_attr',
213213
'device_id',
214+
'device_name',
214215
'areas',
215216
'area_id',
216217
'area_name',
@@ -242,6 +243,7 @@ class HomeAssistantJavaScriptTemplatesRenderer {
242243
this._scopped.device_attr.bind(this._scopped),
243244
this._scopped.is_device_attr.bind(this._scopped),
244245
this._scopped.device_id.bind(this._scopped),
246+
this._scopped.device_name.bind(this._scopped),
245247
this._scopped.areas.bind(this._scopped),
246248
this._scopped.area_id.bind(this._scopped),
247249
this._scopped.area_name.bind(this._scopped),

src/types/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface Area {
1616

1717
export interface Device {
1818
id: string;
19+
name: string | null;
1920
area_id: string | null;
2021
[key: string]: unknown;
2122
}
@@ -131,9 +132,10 @@ export interface Scopped {
131132
is_entity_prop: (entityId: string, attr: string, value: unknown) => boolean;
132133
// devices
133134
devices: ProxiedDevices;
134-
device_attr: (deviceId: string, attr: string) => unknown | undefined;
135-
is_device_attr: (deviceId: string, attr: string, value: unknown) => boolean;
136-
device_id: (entityId: string) => string | undefined;
135+
device_attr: (entityIdOrDeviceId: string, attr: string) => unknown | undefined;
136+
is_device_attr: (entityIdOrDeviceId: string, attr: string, value: unknown) => boolean;
137+
device_id: (entityIdOrDeviceName: string) => string | undefined;
138+
device_name: (entityIdOrDeviceId: string) => string | undefined;
137139
// areas
138140
areas: () => string[];
139141
area_id: (lookupValue: string) => string | undefined;

src/utilities/index.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,32 @@ export function createScoppedFunctions(
256256
}
257257
),
258258

259-
device_attr(deviceId: string, attr: string): unknown {
260-
return ha.hass.devices[deviceId]?.[attr];
259+
device_attr(entityIdOrDeviceId: string, attr: string): unknown {
260+
if (hasDot(entityIdOrDeviceId)) {
261+
trackEntity(entityIdOrDeviceId);
262+
const id = ha.hass.entities[entityIdOrDeviceId]?.device_id;
263+
return ha.hass.devices[id]?.[attr];
264+
}
265+
return ha.hass.devices[entityIdOrDeviceId]?.[attr];
261266
},
262-
is_device_attr(deviceId: string, attr: string, value: unknown): boolean {
263-
return this.device_attr(deviceId, attr) === value;
267+
is_device_attr(entityIdOrDeviceId: string, attr: string, value: unknown): boolean {
268+
return this.device_attr(entityIdOrDeviceId, attr) === value;
264269
},
265-
device_id(entityId: string): string {
266-
trackEntity(entityId);
267-
return ha.hass.entities[entityId]?.device_id;
270+
device_id(entityIdOrDeviceName: string): string | undefined {
271+
if (hasDot(entityIdOrDeviceName)) {
272+
trackEntity(entityIdOrDeviceName);
273+
return ha.hass.entities[entityIdOrDeviceName]?.device_id;
274+
}
275+
const device = devicesEntries().find((entry): boolean => entry[1].name === entityIdOrDeviceName);
276+
return device?.[0];
277+
},
278+
device_name(entityIdOrDeviceId: string): string | undefined {
279+
if (hasDot(entityIdOrDeviceId)) {
280+
trackEntity(entityIdOrDeviceId);
281+
const id = ha.hass.entities[entityIdOrDeviceId]?.device_id;
282+
return ha.hass.devices[id]?.name;
283+
}
284+
return ha.hass.devices[entityIdOrDeviceId]?.name;
268285
},
269286

270287
// ---------------------- Areas

tests/03 - basic-templates.test.ts

Lines changed: 187 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -490,78 +490,214 @@ describe('Basic templates tests', () => {
490490

491491
describe('device_attr', () => {
492492

493-
it('device_attr should return the proper value', () => {
494-
expect(
495-
compiler.renderTemplate('device_attr("706ad0ebe27e105d7cd0b73386deefdd", "manufacturer")')
496-
).toBe('Synology');
497-
expect(
498-
compiler.renderTemplate('device_attr("4d584585f0eb89172ce1a71c8b0e74ae", "model")')
499-
).toBe('HHCCJCY01');
500-
});
493+
describe('using an entity id', () => {
494+
495+
it('device_attr should return the proper value', () => {
496+
expect(
497+
compiler.renderTemplate('device_attr("binary_sensor.koffiezetapparaat_aan", "manufacturer")')
498+
).toBe('Synology');
499+
expect(
500+
compiler.renderTemplate('device_attr("light.woonkamer_lamp", "model")')
501+
).toBe('HHCCJCY01');
502+
});
503+
504+
it('device_attr should return undefined if the attribute doesn\'t exist', () => {
505+
expect(
506+
compiler.renderTemplate('device_attr("binary_sensor.koffiezetapparaat_verbonden", "attr")')
507+
).toBe(undefined);
508+
});
509+
510+
it('device_attr should return undefined if the entity doesn\'t exist', () => {
511+
expect(
512+
compiler.renderTemplate('device_attr("sensor.non_existent", "attr")')
513+
).toBe(undefined);
514+
expect(consoleWarnMock).toHaveBeenCalledWith('Entity sensor.non_existent used in a JavaScript template doesn\'t exist');
515+
});
501516

502-
it('device_attr should return undefined if the attribute doesn\'t exist', () => {
503-
expect(
504-
compiler.renderTemplate('device_attr("b8c1c9dd23cb82bbfa09b5657f41d04f", "attr")')
505-
).toBe(undefined);
506517
});
507518

508-
it('device_attr should return undefined if the device doesn\'t exist', () => {
509-
expect(
510-
compiler.renderTemplate('device_attr("012345", "attr")')
511-
).toBe(undefined);
519+
describe('using a device id', () => {
520+
521+
it('device_attr should return the proper value', () => {
522+
expect(
523+
compiler.renderTemplate('device_attr("706ad0ebe27e105d7cd0b73386deefdd", "manufacturer")')
524+
).toBe('Synology');
525+
expect(
526+
compiler.renderTemplate('device_attr("4d584585f0eb89172ce1a71c8b0e74ae", "model")')
527+
).toBe('HHCCJCY01');
528+
});
529+
530+
it('device_attr should return undefined if the attribute doesn\'t exist', () => {
531+
expect(
532+
compiler.renderTemplate('device_attr("b8c1c9dd23cb82bbfa09b5657f41d04f", "attr")')
533+
).toBe(undefined);
534+
});
535+
536+
it('device_attr should return undefined if the device doesn\'t exist', () => {
537+
expect(
538+
compiler.renderTemplate('device_attr("012345", "attr")')
539+
).toBe(undefined);
540+
});
541+
512542
});
513543

514544
});
515545

516546
describe('is_device_attr', () => {
517547

518-
it('is_device_attr should return true if the attribute has the proper value', () => {
519-
expect(
520-
compiler.renderTemplate('is_device_attr("706ad0ebe27e105d7cd0b73386deefdd", "manufacturer", "Synology")')
521-
).toBe(true);
522-
523-
expect(
524-
compiler.renderTemplate('is_device_attr("4d584585f0eb89172ce1a71c8b0e74ae", "model", "HHCCJCY01")')
525-
).toBe(true);
548+
describe('using an entity id', () => {
549+
550+
it('is_device_attr should return true if the attribute has the proper value', () => {
551+
expect(
552+
compiler.renderTemplate('is_device_attr("binary_sensor.koffiezetapparaat_aan", "manufacturer", "Synology")')
553+
).toBe(true);
554+
555+
expect(
556+
compiler.renderTemplate('is_device_attr("light.woonkamer_lamp", "model", "HHCCJCY01")')
557+
).toBe(true);
558+
});
559+
560+
it('is_device_attr should return false if the attribute doesn\'t have the proper value', () => {
561+
expect(
562+
compiler.renderTemplate('is_device_attr("sensor.slaapkamer_temperatuur", "area_id", "woonkamer")')
563+
).toBe(false);
564+
});
565+
566+
it('is_device_attr should return false if the attribute doesn\'t exist', () => {
567+
expect(
568+
compiler.renderTemplate('is_device_attr("binary_sensor.koffiezetapparaat_verbonden", "attr", "value")')
569+
).toBe(false);
570+
});
571+
572+
it('is_device_attr should return false if the entity doesn\'t exist', () => {
573+
expect(
574+
compiler.renderTemplate('is_device_attr("sensor.non_existent", "attr", "value")')
575+
).toBe(false);
576+
expect(consoleWarnMock).toHaveBeenCalledWith('Entity sensor.non_existent used in a JavaScript template doesn\'t exist');
577+
});
578+
526579
});
527580

528-
it('is_device_attr should return false if the attribute doesn\'t have the proper value', () => {
529-
expect(
530-
compiler.renderTemplate('is_device_attr("dea1c4475b8dc901b7b33c7eac09896d", "area_id", "woonkamer")')
531-
).toBe(false);
581+
describe('using a device id', () => {
582+
583+
it('is_device_attr should return true if the attribute has the proper value', () => {
584+
expect(
585+
compiler.renderTemplate('is_device_attr("706ad0ebe27e105d7cd0b73386deefdd", "manufacturer", "Synology")')
586+
).toBe(true);
587+
588+
expect(
589+
compiler.renderTemplate('is_device_attr("4d584585f0eb89172ce1a71c8b0e74ae", "model", "HHCCJCY01")')
590+
).toBe(true);
591+
});
592+
593+
it('is_device_attr should return false if the attribute doesn\'t have the proper value', () => {
594+
expect(
595+
compiler.renderTemplate('is_device_attr("dea1c4475b8dc901b7b33c7eac09896d", "area_id", "woonkamer")')
596+
).toBe(false);
597+
});
598+
599+
it('is_device_attr should return false if the attribute doesn\'t exist', () => {
600+
expect(
601+
compiler.renderTemplate('is_device_attr("b8c1c9dd23cb82bbfa09b5657f41d04f", "attr", "value")')
602+
).toBe(false);
603+
});
604+
605+
it('is_device_attr should return false if the device doesn\'t exist', () => {
606+
expect(
607+
compiler.renderTemplate('is_device_attr("012345", "attr", "value")')
608+
).toBe(false);
609+
});
610+
532611
});
533612

534-
it('is_device_attr should return false if the attribute doesn\'t exist', () => {
535-
expect(
536-
compiler.renderTemplate('is_device_attr("b8c1c9dd23cb82bbfa09b5657f41d04f", "attr", "value")')
537-
).toBe(false);
613+
});
614+
615+
describe('device_id', () => {
616+
617+
describe('using an entity id', () => {
618+
619+
it('device_id should return the proper device id', () => {
620+
expect(
621+
compiler.renderTemplate('device_id("light.woonkamer_lamp")')
622+
).toBe('4d584585f0eb89172ce1a71c8b0e74ae');
623+
624+
expect(
625+
compiler.renderTemplate('device_id("binary_sensor.internetverbinding")')
626+
).toBe('a121a9414241f03ce6b3108b2716f9be');
627+
});
628+
629+
it('device_id should return undefined if the entity id doesn\'t exist', () => {
630+
expect(
631+
compiler.renderTemplate('device_id("sensor.non_existent")')
632+
).toBe(undefined);
633+
expect(consoleWarnMock).toHaveBeenCalledWith('Entity sensor.non_existent used in a JavaScript template doesn\'t exist');
634+
});
635+
538636
});
539637

540-
it('is_device_attr should return false if the device doesn\'t exist', () => {
541-
expect(
542-
compiler.renderTemplate('is_device_attr("012345", "attr", "value")')
543-
).toBe(false);
544-
});
638+
describe('using a device name', () => {
639+
640+
it('device_id should return the proper device id', () => {
641+
expect(
642+
compiler.renderTemplate('device_id("Woonkamer Lamp")')
643+
).toBe('4d584585f0eb89172ce1a71c8b0e74ae');
644+
645+
expect(
646+
compiler.renderTemplate('device_id("Eetkamer lampje")')
647+
).toBe('720a719fe7db1460b0e4cc9ffbb1488d');
648+
});
649+
650+
it('device_id should return undefined if the device name doesn\'t exist', () => {
651+
expect(
652+
compiler.renderTemplate('device_id("My camera")')
653+
).toBe(undefined);
654+
});
655+
656+
});
545657

546658
});
547659

548-
describe('device_id', () => {
660+
describe('device_name', () => {
661+
662+
describe('using an entity id', () => {
663+
664+
it('device_name should return the proper device name', () => {
665+
expect(
666+
compiler.renderTemplate('device_name("binary_sensor.koffiezetapparaat_aan")')
667+
).toBe('Mijn Koffiezetapparaat');
668+
669+
expect(
670+
compiler.renderTemplate('device_name("light.eetkamer_lampje")')
671+
).toBe('Eetkamer lampje');
672+
});
673+
674+
it('device_name should return undefined if the entity id doesn\'t exist', () => {
675+
expect(
676+
compiler.renderTemplate('device_name("sensor.non_existent")')
677+
).toBe(undefined);
678+
expect(consoleWarnMock).toHaveBeenCalledWith('Entity sensor.non_existent used in a JavaScript template doesn\'t exist');
679+
});
549680

550-
it('device_id should return the proper device id', () => {
551-
expect(
552-
compiler.renderTemplate('device_id("light.woonkamer_lamp")')
553-
).toBe('4d584585f0eb89172ce1a71c8b0e74ae');
554-
555-
expect(
556-
compiler.renderTemplate('device_id("binary_sensor.internetverbinding")')
557-
).toBe('a121a9414241f03ce6b3108b2716f9be');
558681
});
559682

560-
it('device_id should return undefined if the device doesn\'t exist', () => {
561-
expect(
562-
compiler.renderTemplate('device_id("sensor.non_existent")')
563-
).toBe(undefined);
564-
expect(consoleWarnMock).toHaveBeenCalledWith('Entity sensor.non_existent used in a JavaScript template doesn\'t exist');
683+
describe('using a device id', () => {
684+
685+
it('device_name using a device id should return the proper device name', () => {
686+
expect(
687+
compiler.renderTemplate('device_name("4d584585f0eb89172ce1a71c8b0e74ae")')
688+
).toBe('Woonkamer Lamp');
689+
690+
expect(
691+
compiler.renderTemplate('device_name("720a719fe7db1460b0e4cc9ffbb1488d")')
692+
).toBe('Eetkamer lampje');
693+
});
694+
695+
it('device_name should return undefined if the device id doesn\'t exist', () => {
696+
expect(
697+
compiler.renderTemplate('device_name("4d58451c8b0e74ae85f0eb89172ce1a7")')
698+
).toBe(undefined);
699+
});
700+
565701
});
566702

567703
});

0 commit comments

Comments
 (0)