From 94a4ce3b77b42d48ec88c2b94b06a4dbf298424a Mon Sep 17 00:00:00 2001 From: Igor Kulman Date: Sun, 24 Aug 2025 11:05:17 +0200 Subject: [PATCH] Add support for showing specific sensors to HomeAssistant --- docs/customservices.md | 30 +++++++++ src/components/services/HomeAssistant.vue | 77 ++++++++++++++++++++--- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/docs/customservices.md b/docs/customservices.md index c1f0812..b053056 100644 --- a/docs/customservices.md +++ b/docs/customservices.md @@ -226,6 +226,7 @@ The Healthchecks API key can be found in Settings > API Access > API key (read-o You need to set the type to HomeAssistant, provide an api key and enable cors on Home Assistant. +**Basic configuration:** ```yaml - name: "HomeAssistant" 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 separator: " " # optional, how to separate items ``` +**Custom sensors configuration:** +```yaml +- name: "Home Assistant" + logo: "assets/tools/sample.png" + url: "http://192.168.0.151/" + type: "HomeAssistant" + apikey: "<---insert-api-key-here--->" + showUnits: true # Optional: Show units from Home Assistant (default: true) + updateInterval: 30000 # Optional: Sensor refresh interval in ms (default: 30000) + sensors: # Optional: Display custom sensors instead of default stats + - id: "sensor.living_room_temperature" + icon: "fas fa-home" + - id: "sensor.bedroom_humidity" + icon: "fas fa-bed" + - id: "sensor.power_consumption" + icon: "fas fa-bolt" + - id: "sensor.outdoor_air_quality" + icon: "fas fa-cloud-sun" +``` + +**Configuration Options:** + +- When `sensors` is provided, the service displays sensor readings with custom icons instead of the default version/entity information +- `showUnits`: Controls whether to display units from Home Assistant (default: `true`) +- `updateInterval`: How often to refresh sensor data in milliseconds (default: `30000`) +- Sensor values are automatically formatted to 1 decimal place with units (when enabled) +- Supports any numeric sensor type (temperature, humidity, power, etc.) +- Falls back to original behavior if `sensors` is not configured + To create an API token on HomeAssistant, follow the [official documentation here](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token). To enable cors on HomeAssistant, edit your `configuration.yml` and add the IP of Homer to `https: cors_allowed_origins` diff --git a/src/components/services/HomeAssistant.vue b/src/components/services/HomeAssistant.vue index 6bedbff..7108e8a 100644 --- a/src/components/services/HomeAssistant.vue +++ b/src/components/services/HomeAssistant.vue @@ -6,6 +6,18 @@ + @@ -35,6 +47,7 @@ export default { location_name: "", separator: " ", items: ["name", "version"], + sensors: [], }), computed: { headers: function () { @@ -70,16 +83,54 @@ export default { }, }, created() { - this.fetchServerStatus().then(() => { - if (!this.item.subtitle && this.status !== "dead") { - if (this.item.items) this.items = this.item.items; - if (this.item.separator) this.separator = this.item.separator; + if (this.item.sensors) { + // If sensors are configured, fetch sensor data + this.fetchSensors(); - this.fetchServerStats(); - } - }); + // Set up configurable refresh interval (default 30 seconds) + const updateInterval = parseInt(this.item.updateInterval, 10) || 30000; + setInterval(() => this.fetchSensors(), updateInterval); + } else { + // Original behavior for status/stats + this.fetchServerStatus().then(() => { + if (!this.item.subtitle && this.status !== "dead") { + if (this.item.items) this.items = this.item.items; + if (this.item.separator) this.separator = this.item.separator; + + this.fetchServerStats(); + } + }); + } }, methods: { + fetchSensors: async function () { + const headers = this.headers; + + try { + const response = await this.fetch("/api/states", { headers }); + + // Use configurable sensors from item.sensors + this.sensors = this.item.sensors + .map((sensorConfig) => { + const match = response.find((s) => s.entity_id === sensorConfig.id); + if (match && !isNaN(parseFloat(match.state))) { + const value = parseFloat(match.state).toFixed(1); + const unit = match.attributes?.unit_of_measurement || ""; + const showUnits = this.item.showUnits !== false; // Default to true + return { + icon: sensorConfig.icon, + value: (showUnits && unit) ? `${value}${unit}` : value, + }; + } else { + return null; + } + }) + .filter(Boolean); // Remove null entries + } catch (error) { + console.error("Failed to fetch sensors:", error); + this.sensors = []; + } + }, fetchServerStatus: async function () { const headers = this.headers; @@ -151,4 +202,16 @@ export default { border-radius: 7px; } } + +.sensors { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.sensor { + display: inline-flex; + align-items: center; + gap: 4px; +}