Skip to content

Commit 691659d

Browse files
committed
Add support for showing specific sensors to HomeAssistant
1 parent 308deb9 commit 691659d

2 files changed

Lines changed: 105 additions & 7 deletions

File tree

docs/customservices.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ The Healthchecks API key can be found in Settings > API Access > API key (read-o
226226

227227
You need to set the type to HomeAssistant, provide an api key and enable cors on Home Assistant.
228228

229+
**Basic configuration:**
229230
```yaml
230231
- name: "HomeAssistant"
231232
logo: "assets/tools/sample.png"
@@ -236,6 +237,35 @@ You need to set the type to HomeAssistant, provide an api key and enable cors on
236237
separator: " " # optional, how to separate items
237238
```
238239

240+
**Custom sensors configuration:**
241+
```yaml
242+
- name: "Home Assistant"
243+
logo: "assets/tools/sample.png"
244+
url: "http://192.168.0.151/"
245+
type: "HomeAssistant"
246+
apikey: "<---insert-api-key-here--->"
247+
showUnits: true # Optional: Show units from Home Assistant (default: true)
248+
updateInterval: 30000 # Optional: Sensor refresh interval in ms (default: 30000)
249+
sensors: # Optional: Display custom sensors instead of default stats
250+
- id: "sensor.living_room_temperature"
251+
icon: "fas fa-home"
252+
- id: "sensor.bedroom_humidity"
253+
icon: "fas fa-bed"
254+
- id: "sensor.power_consumption"
255+
icon: "fas fa-bolt"
256+
- id: "sensor.outdoor_air_quality"
257+
icon: "fas fa-cloud-sun"
258+
```
259+
260+
**Configuration Options:**
261+
262+
- When `sensors` is provided, the service displays sensor readings with custom icons instead of the default version/entity information
263+
- `showUnits`: Controls whether to display units from Home Assistant (default: `true`)
264+
- `updateInterval`: How often to refresh sensor data in milliseconds (default: `30000`)
265+
- Sensor values are automatically formatted to 1 decimal place with units (when enabled)
266+
- Supports any numeric sensor type (temperature, humidity, power, etc.)
267+
- Falls back to original behavior if `sensors` is not configured
268+
239269
To create an API token on HomeAssistant, follow the [official documentation here](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token).
240270
To enable cors on HomeAssistant, edit your `configuration.yml` and add the IP of Homer to `https: cors_allowed_origins`
241271

src/components/services/HomeAssistant.vue

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
<template v-if="item.subtitle">
77
{{ item.subtitle }}
88
</template>
9+
<template v-else-if="item.sensors && sensors.length > 0">
10+
<span class="sensors">
11+
<span
12+
v-for="(sensor, index) in sensors"
13+
:key="index"
14+
class="sensor"
15+
>
16+
<i :class="sensor.icon"></i>
17+
<span class="sensor-value">{{ sensor.value }}</span>
18+
</span>
19+
</span>
20+
</template>
921
<template v-else>
1022
{{ details }}
1123
</template>
@@ -35,6 +47,7 @@ export default {
3547
location_name: "",
3648
separator: " ",
3749
items: ["name", "version"],
50+
sensors: [],
3851
}),
3952
computed: {
4053
headers: function () {
@@ -70,16 +83,54 @@ export default {
7083
},
7184
},
7285
created() {
73-
this.fetchServerStatus().then(() => {
74-
if (!this.item.subtitle && this.status !== "dead") {
75-
if (this.item.items) this.items = this.item.items;
76-
if (this.item.separator) this.separator = this.item.separator;
86+
if (this.item.sensors) {
87+
// If sensors are configured, fetch sensor data
88+
this.fetchSensors();
89+
90+
// Set up configurable refresh interval (default 30 seconds)
91+
const updateInterval = parseInt(this.item.updateInterval, 10) || 30000;
92+
setInterval(() => this.fetchSensors(), updateInterval);
93+
} else {
94+
// Original behavior for status/stats
95+
this.fetchServerStatus().then(() => {
96+
if (!this.item.subtitle && this.status !== "dead") {
97+
if (this.item.items) this.items = this.item.items;
98+
if (this.item.separator) this.separator = this.item.separator;
7799
78-
this.fetchServerStats();
79-
}
80-
});
100+
this.fetchServerStats();
101+
}
102+
});
103+
}
81104
},
82105
methods: {
106+
fetchSensors: async function () {
107+
const headers = this.headers;
108+
109+
try {
110+
const response = await this.fetch("/api/states", { headers });
111+
112+
// Use configurable sensors from item.sensors
113+
this.sensors = this.item.sensors
114+
.map((sensorConfig) => {
115+
const match = response.find((s) => s.entity_id === sensorConfig.id);
116+
if (match && !isNaN(parseFloat(match.state))) {
117+
const value = parseFloat(match.state).toFixed(1);
118+
const unit = match.attributes?.unit_of_measurement || "";
119+
const showUnits = this.item.showUnits !== false; // Default to true
120+
return {
121+
icon: sensorConfig.icon,
122+
value: (showUnits && unit) ? `${value}${unit}` : value,
123+
};
124+
} else {
125+
return null;
126+
}
127+
})
128+
.filter(Boolean); // Remove null entries
129+
} catch (error) {
130+
console.error("Failed to fetch sensors:", error);
131+
this.sensors = [];
132+
}
133+
},
83134
fetchServerStatus: async function () {
84135
const headers = this.headers;
85136
@@ -151,4 +202,21 @@ export default {
151202
border-radius: 7px;
152203
}
153204
}
205+
206+
.sensors {
207+
display: flex;
208+
flex-wrap: wrap;
209+
gap: 8px;
210+
}
211+
212+
.sensor {
213+
display: inline-flex;
214+
align-items: center;
215+
gap: 4px;
216+
217+
.sensor-value {
218+
font-weight: 500;
219+
color: var(--text-title);
220+
}
221+
}
154222
</style>

0 commit comments

Comments
 (0)