Initial commit

This commit is contained in:
ange committed 2026-05-15 17:20:09 +02:00
1 parent 0660ca55ee
commit e625f8098e
16 files changed
+1900 -194

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
blueprint:
name: "IKEA STYRBAR - Contrôle groupe lumières"
description: "Contrôle ON/OFF, luminosité et température de couleur avec une télécommande STYRBAR"
domain: automation
input:
remote:
name: Télécommande STYRBAR
description: "L'entité action de la télécommande"
selector:
entity:
filter:
- integration: mqtt
domain: sensor
light_target:
name: Lumière ou groupe
description: "La lumière ou le groupe à contrôler"
selector:
target:
entity:
domain: light
brightness_step:
name: Pas de luminosité
description: "Pourcentage de changement par pas"
default: 10
selector:
number:
min: 5
max: 25
step: 5
unit_of_measurement: "%"
color_temp_step:
name: Pas de température couleur
description: "Changement de mireds par pas"
default: 25
selector:
number:
min: 10
max: 50
step: 5
trigger:
- platform: state
entity_id: !input remote
to:
- "on"
- "off"
- "brightness_move_up"
- "brightness_move_down"
- "arrow_left_click"
- "arrow_right_click"
action:
- choose:
# ON
- conditions:
- condition: state
entity_id: !input remote
state: "on"
sequence:
- service: light.turn_on
target: !input light_target
# OFF
- conditions:
- condition: state
entity_id: !input remote
state: "off"
sequence:
- service: light.turn_off
target: !input light_target
# BRIGHTNESS UP
- conditions:
- condition: state
entity_id: !input remote
state: "brightness_move_up"
sequence:
- service: light.turn_on
target: !input light_target
data:
brightness_step_pct: !input brightness_step
# BRIGHTNESS DOWN
- conditions:
- condition: state
entity_id: !input remote
state: "brightness_move_down"
sequence:
- service: light.turn_on
target: !input light_target
data:
brightness_step_pct: "{{ -1 * brightness_step }}"
# COLOR TEMP WARMER (left)
- conditions:
- condition: state
entity_id: !input remote
state: "arrow_left_click"
sequence:
- service: light.turn_on
target: !input light_target
data:
color_temp: >
{{ [state_attr(light_entity, 'color_temp') | int + color_temp_step, 500] | min }}
# COLOR TEMP COOLER (right)
- conditions:
- condition: state
entity_id: !input remote
state: "arrow_right_click"
sequence:
- service: light.turn_on
target: !input light_target
data:
color_temp: >
{{ [state_attr(light_entity, 'color_temp') | int - color_temp_step, 153] | max }}
mode: restart
@@ -0,0 +1,280 @@
"""Light Preset Manager integration."""
from __future__ import annotations
import logging
from typing import Any
import voluptuous as vol
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
from homeassistant.components import websocket_api
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_RGB_COLOR,
ATTR_XY_COLOR,
ATTR_HS_COLOR,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_ON,
SERVICE_TURN_ON,
SERVICE_TURN_OFF,
)
from .const import (
DOMAIN,
STORAGE_KEY,
STORAGE_VERSION,
SERVICE_SAVE_PRESET,
SERVICE_RECALL_PRESET,
SERVICE_RENAME_PRESET,
SERVICE_GET_PRESETS,
ATTR_CARD_ID,
ATTR_PRESET_ID,
ATTR_PRESET_NAME,
ATTR_LIGHTS,
DEFAULT_PRESET_NAMES,
MAX_PRESETS,
)
_LOGGER = logging.getLogger(__name__)
# Config schema
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: vol.Schema({})},
extra=vol.ALLOW_EXTRA,
)
# Service schemas
SAVE_PRESET_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CARD_ID): cv.string,
vol.Required(ATTR_PRESET_ID): vol.All(
vol.Coerce(int), vol.Range(min=1, max=MAX_PRESETS)
),
vol.Required(ATTR_LIGHTS): list,
}
)
RECALL_PRESET_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CARD_ID): cv.string,
vol.Required(ATTR_PRESET_ID): vol.All(
vol.Coerce(int), vol.Range(min=1, max=MAX_PRESETS)
),
}
)
RENAME_PRESET_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CARD_ID): cv.string,
vol.Required(ATTR_PRESET_ID): vol.All(
vol.Coerce(int), vol.Range(min=1, max=MAX_PRESETS)
),
vol.Required(ATTR_PRESET_NAME): cv.string,
}
)
GET_PRESETS_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CARD_ID): cv.string,
}
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Light Preset Manager component."""
# Initialize storage
store = Store(hass, STORAGE_VERSION, STORAGE_KEY)
data = await store.async_load() or {}
hass.data[DOMAIN] = {
"store": store,
"presets": data,
}
# Register WebSocket commands
websocket_api.async_register_command(hass, websocket_get_presets)
async def async_save_preset(call: ServiceCall) -> None:
"""Save current light states to a preset."""
card_id = call.data[ATTR_CARD_ID]
preset_id = call.data[ATTR_PRESET_ID]
lights = call.data[ATTR_LIGHTS]
# Initialize card data if not exists
if card_id not in hass.data[DOMAIN]["presets"]:
hass.data[DOMAIN]["presets"][card_id] = _create_default_presets()
# Update preset
preset_index = preset_id - 1
hass.data[DOMAIN]["presets"][card_id][preset_index]["lights"] = lights
# Save to storage
await store.async_save(hass.data[DOMAIN]["presets"])
_LOGGER.debug(f"Saved preset {preset_id} for card {card_id}")
# Fire event for frontend
hass.bus.async_fire(
f"{DOMAIN}_preset_updated",
{
"card_id": card_id,
"preset_id": preset_id,
"preset": hass.data[DOMAIN]["presets"][card_id][preset_index],
},
)
async def async_recall_preset(call: ServiceCall) -> None:
"""Apply a saved preset to lights."""
card_id = call.data[ATTR_CARD_ID]
preset_id = call.data[ATTR_PRESET_ID]
presets = hass.data[DOMAIN]["presets"].get(card_id)
if not presets:
_LOGGER.warning(f"No presets found for card {card_id}")
return
preset_index = preset_id - 1
preset = presets[preset_index]
lights = preset.get("lights", [])
if not lights:
_LOGGER.warning(f"Preset {preset_id} for card {card_id} is empty")
return
# Apply each light state
for light_state in lights:
entity_id = light_state.get("entity_id")
state = light_state.get("state")
if not entity_id:
continue
if state == STATE_ON:
# Build service data - only include ONE color descriptor
service_data = {ATTR_ENTITY_ID: entity_id}
if ATTR_BRIGHTNESS in light_state:
service_data[ATTR_BRIGHTNESS] = light_state[ATTR_BRIGHTNESS]
# Color descriptors are mutually exclusive - pick one based on priority
# Priority: color_temp > rgb_color > hs_color > xy_color
if ATTR_COLOR_TEMP in light_state:
service_data[ATTR_COLOR_TEMP] = light_state[ATTR_COLOR_TEMP]
elif ATTR_RGB_COLOR in light_state:
service_data[ATTR_RGB_COLOR] = light_state[ATTR_RGB_COLOR]
elif ATTR_HS_COLOR in light_state:
service_data[ATTR_HS_COLOR] = light_state[ATTR_HS_COLOR]
elif ATTR_XY_COLOR in light_state:
service_data[ATTR_XY_COLOR] = light_state[ATTR_XY_COLOR]
await hass.services.async_call("light", SERVICE_TURN_ON, service_data)
else:
await hass.services.async_call(
"light", SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}
)
_LOGGER.debug(f"Recalled preset {preset_id} for card {card_id}")
async def async_rename_preset(call: ServiceCall) -> None:
"""Rename a preset."""
card_id = call.data[ATTR_CARD_ID]
preset_id = call.data[ATTR_PRESET_ID]
preset_name = call.data[ATTR_PRESET_NAME]
# Initialize card data if not exists
if card_id not in hass.data[DOMAIN]["presets"]:
hass.data[DOMAIN]["presets"][card_id] = _create_default_presets()
# Update preset name
preset_index = preset_id - 1
hass.data[DOMAIN]["presets"][card_id][preset_index]["name"] = preset_name
# Save to storage
await store.async_save(hass.data[DOMAIN]["presets"])
_LOGGER.debug(
f"Renamed preset {preset_id} to '{preset_name}' for card {card_id}"
)
# Fire event for frontend
hass.bus.async_fire(
f"{DOMAIN}_preset_updated",
{
"card_id": card_id,
"preset_id": preset_id,
"preset": hass.data[DOMAIN]["presets"][card_id][preset_index],
},
)
@callback
def handle_get_presets(call: ServiceCall) -> dict:
"""Get all presets for a card."""
card_id = call.data[ATTR_CARD_ID]
presets = hass.data[DOMAIN]["presets"].get(card_id)
if not presets:
presets = _create_default_presets()
hass.data[DOMAIN]["presets"][card_id] = presets
return {"presets": presets}
# Register services
hass.services.async_register(
DOMAIN, SERVICE_SAVE_PRESET, async_save_preset, schema=SAVE_PRESET_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_RECALL_PRESET, async_recall_preset, schema=RECALL_PRESET_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_RENAME_PRESET, async_rename_preset, schema=RENAME_PRESET_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_GET_PRESETS, handle_get_presets, schema=GET_PRESETS_SCHEMA
)
_LOGGER.info("Light Preset Manager initialized")
return True
def _create_default_presets() -> list[dict]:
"""Create default preset structure."""
return [
{"id": i + 1, "name": DEFAULT_PRESET_NAMES[i], "lights": []}
for i in range(MAX_PRESETS)
]
# -----------------------------------------------------------------------------
# WebSocket API
# -----------------------------------------------------------------------------
@websocket_api.websocket_command(
{
vol.Required("type"): "light_preset_manager/get_presets",
vol.Required("card_id"): cv.string,
}
)
@callback
def websocket_get_presets(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Handle get presets WebSocket command."""
card_id = msg["card_id"]
presets = hass.data[DOMAIN]["presets"].get(card_id)
if not presets:
presets = _create_default_presets()
hass.data[DOMAIN]["presets"][card_id] = presets
connection.send_result(msg["id"], {"presets": presets})
@@ -0,0 +1,24 @@
"""Constants for Light Preset Manager."""
DOMAIN = "light_preset_manager"
VERSION = "0.6.0"
# Storage
STORAGE_KEY = f"{DOMAIN}.presets"
STORAGE_VERSION = 1
# Services
SERVICE_SAVE_PRESET = "save_preset"
SERVICE_RECALL_PRESET = "recall_preset"
SERVICE_RENAME_PRESET = "rename_preset"
SERVICE_GET_PRESETS = "get_presets"
# Attributes
ATTR_CARD_ID = "card_id"
ATTR_PRESET_ID = "preset_id"
ATTR_PRESET_NAME = "preset_name"
ATTR_LIGHTS = "lights"
# Defaults
DEFAULT_PRESET_NAMES = ["Preset 1", "Preset 2", "Preset 3", "Preset 4"]
MAX_PRESETS = 4
@@ -604,7 +604,7 @@ function r5(r6) {
// src/styles.ts
var mainStyles = i`
:host {
--lpm-temp-warm-color: #ffe600ff;
--lpm-temp-warm-color: #ffae00ff;
--lpm-temp-neutral-color: #ffffff;
--lpm-temp-cold-color: #2196f3;
--lpm-temp-inactive-color: rgba(255, 255, 255, 0.5);
@@ -1001,6 +1001,68 @@ var mainStyles = i`
line-height: 1.2;
max-width: 90%;
}
/* Presets Section */
.presets-section {
margin-top: var(--lpm-padding);
padding-top: var(--lpm-padding);
border-top: 1px solid var(--divider-color);
}
.presets-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--lpm-spacing);
}
.preset-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12px 8px;
min-height: 60px;
border: none;
border-radius: var(--lpm-button-radius);
cursor: pointer;
background: var(--primary-background-color);
color: var(--primary-text-color);
transition: all var(--lpm-transition);
font-family: inherit;
gap: 4px;
}
.preset-button:hover {
background: var(--secondary-background-color);
}
.preset-button:active {
transform: scale(0.95);
}
.preset-button.has-data {
border: 1px solid var(--primary-color);
}
.preset-button.has-data .preset-icon {
color: var(--primary-color);
}
.preset-button .preset-icon {
color: var(--disabled-text-color);
}
.preset-button .preset-icon ha-icon {
--mdc-icon-size: 24px;
}
.preset-button .preset-name {
font-size: 11px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
/* Popup */
.popup-overlay {
@@ -1104,6 +1166,9 @@ function normalizeLightConfig(light) {
return { entity: light.entity, name: light.name };
}
function validateConfig(config) {
if (!config.card_id) {
throw new Error('Config error: "card_id" is required');
}
if (!config.group) {
throw new Error('Config error: "group" is required');
}
@@ -1126,6 +1191,7 @@ function validateConfig(config) {
throw new Error('Config error: "presets" must be between 1 and 4');
}
return {
card_id: config.card_id,
group: config.group,
title: config.title,
lights,
@@ -1151,6 +1217,21 @@ var supportsColorTemp = (entity) => {
const modes = entity?.attributes.supported_color_modes || [];
return modes.includes("color_temp");
};
function captureLightState(entity) {
const state = {
entity_id: entity.entity_id,
state: entity.state === "on" ? "on" : "off"
};
if (entity.state === "on") {
const { brightness, color_temp, rgb_color, xy_color, hs_color } = entity.attributes;
if (brightness !== void 0) state.brightness = brightness;
if (color_temp !== void 0) state.color_temp = color_temp;
if (rgb_color !== void 0) state.rgb_color = rgb_color;
if (xy_color !== void 0) state.xy_color = xy_color;
if (hs_color !== void 0) state.hs_color = hs_color;
}
return state;
}
function getLightsFromGroup(groupEntity, configLights) {
if (configLights.length > 0) {
return configLights;
@@ -1257,6 +1338,13 @@ function getTranslations(locale) {
// src/editor.ts
var MAIN_SCHEMA = [
{
name: "card_id",
required: true,
selector: {
text: {}
}
},
{
name: "group",
required: true,
@@ -1288,6 +1376,7 @@ var LightPresetManagerEditor = class extends i4 {
super(...arguments);
this._computeLabel = (schema) => {
const labels = {
card_id: "Card ID (required, unique)",
group: "Group (required)",
title: "Title",
presets: "Number of Presets (1-4)"
@@ -1640,13 +1729,24 @@ LightPresetManagerEditor = __decorateClass([
t3("light-preset-manager-editor")
], LightPresetManagerEditor);
console.log(
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.5.0 ",
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.6.3 ",
"background: #9b59b6; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);
// src/light-preset-manager.ts
var HOLD_DURATION = 800;
var DOUBLE_TAP_DELAY = 300;
var LightPresetManager = class extends i4 {
constructor() {
super(...arguments);
this._presets = [];
this._popup = { type: null, presetId: 0, presetName: "" };
this._lastTap = 0;
this._tapCount = 0;
this._activePresetId = 0;
this._presetsLoaded = false;
}
// ---------------------------------------------------------------------------
// Static methods for HA card editor
// ---------------------------------------------------------------------------
@@ -1655,6 +1755,7 @@ var LightPresetManager = class extends i4 {
}
static getStubConfig() {
return {
card_id: "my_lights",
group: "light.example_group",
title: "My Lights"
};
@@ -1664,10 +1765,54 @@ var LightPresetManager = class extends i4 {
// ---------------------------------------------------------------------------
setConfig(config) {
this._config = validateConfig(config);
this._presetsLoaded = false;
this._initPresets();
}
async connectedCallback() {
super.connectedCallback();
await this._subscribeToEvents();
}
disconnectedCallback() {
super.disconnectedCallback();
this._clearTimers();
this._unsubscribeFromEvents();
}
updated(changedProps) {
if (changedProps.has("hass") && this.hass) {
this._t = getTranslations(detectLocale(this.hass.language));
if (!this._presetsLoaded && this._config) {
this._loadPresetsFromHA();
}
}
}
// ---------------------------------------------------------------------------
// Event Subscription
// ---------------------------------------------------------------------------
async _subscribeToEvents() {
if (!this.hass || this._unsubscribe) return;
try {
this._unsubscribe = await this.hass.connection.subscribeEvents(
(event) => this._handlePresetEvent(event),
"light_preset_manager_preset_updated"
);
} catch (e5) {
console.error("Failed to subscribe to events:", e5);
}
}
_unsubscribeFromEvents() {
if (this._unsubscribe) {
this._unsubscribe();
this._unsubscribe = void 0;
}
}
_handlePresetEvent(event) {
if (!this._config) return;
const { card_id, preset_id, preset } = event.data;
if (card_id !== this._config.card_id) return;
const presetIndex = preset_id - 1;
if (this._presets[presetIndex]) {
this._presets[presetIndex] = preset;
this._presets = [...this._presets];
}
}
// ---------------------------------------------------------------------------
@@ -1695,6 +1840,158 @@ var LightPresetManager = class extends i4 {
return getLightsFromGroup(this._group, this._config.lights);
}
// ---------------------------------------------------------------------------
// Presets - Init/Load/Save via HA Services
// ---------------------------------------------------------------------------
_initPresets() {
if (!this._config) return;
const count = this._config.presets;
this._presets = Array.from({ length: count }, (_2, i5) => ({
id: i5 + 1,
name: `Preset ${i5 + 1}`,
lights: []
}));
}
async _loadPresetsFromHA() {
if (!this.hass || !this._config) return;
try {
const response = await this.hass.callWS({
type: "light_preset_manager/get_presets",
card_id: this._config.card_id
});
if (response.presets) {
this._presets = response.presets.slice(0, this._config.presets);
this._presetsLoaded = true;
}
} catch (e5) {
console.error("Failed to load presets from HA:", e5);
}
}
async _savePreset(presetId) {
if (!this.hass || !this._config) return;
const lightStates = [];
for (const lightConfig of this._lights) {
const entity = this.hass.states[lightConfig.entity];
if (entity) {
lightStates.push(captureLightState(entity));
}
}
try {
await this.hass.callService("light_preset_manager", "save_preset", {
card_id: this._config.card_id,
preset_id: presetId,
lights: lightStates
});
this._closePopup();
} catch (e5) {
console.error("Failed to save preset:", e5);
}
}
async _recallPreset(presetId) {
if (!this.hass || !this._config) return;
const preset = this._presets[presetId - 1];
if (!preset || !preset.lights || preset.lights.length === 0) {
console.log(`Preset ${presetId} is empty`);
return;
}
try {
await this.hass.callService("light_preset_manager", "recall_preset", {
card_id: this._config.card_id,
preset_id: presetId
});
} catch (e5) {
console.error("Failed to recall preset:", e5);
}
}
async _renamePreset(presetId, name) {
if (!this.hass || !this._config) return;
try {
await this.hass.callService("light_preset_manager", "rename_preset", {
card_id: this._config.card_id,
preset_id: presetId,
preset_name: name
});
this._closePopup();
} catch (e5) {
console.error("Failed to rename preset:", e5);
}
}
// ---------------------------------------------------------------------------
// Gesture Handling (tap / hold / double-tap)
// ---------------------------------------------------------------------------
_clearTimers() {
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = void 0;
}
if (this._tapTimer) {
clearTimeout(this._tapTimer);
this._tapTimer = void 0;
}
}
_handlePointerDown(presetId) {
this._activePresetId = presetId;
this._clearTimers();
this._holdTimer = window.setTimeout(() => {
this._showSavePopup(presetId);
this._tapCount = 0;
}, HOLD_DURATION);
}
_handlePointerUp(presetId) {
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = void 0;
this._tapCount++;
if (this._tapTimer) {
clearTimeout(this._tapTimer);
}
this._tapTimer = window.setTimeout(() => {
if (this._tapCount === 1) {
this._recallPreset(presetId);
} else if (this._tapCount >= 2) {
this._showRenamePopup(presetId);
}
this._tapCount = 0;
}, DOUBLE_TAP_DELAY);
}
}
_handlePointerLeave() {
this._clearTimers();
this._tapCount = 0;
}
// ---------------------------------------------------------------------------
// Popup Management
// ---------------------------------------------------------------------------
_showSavePopup(presetId) {
const preset = this._presets[presetId - 1];
this._popup = {
type: "save",
presetId,
presetName: preset?.name || `Preset ${presetId}`
};
}
_showRenamePopup(presetId) {
const preset = this._presets[presetId - 1];
this._popup = {
type: "rename",
presetId,
presetName: preset?.name || `Preset ${presetId}`
};
}
_closePopup() {
this._popup = { type: null, presetId: 0, presetName: "" };
}
_handlePopupConfirm() {
if (this._popup.type === "save") {
this._savePreset(this._popup.presetId);
} else if (this._popup.type === "rename") {
this._renamePreset(this._popup.presetId, this._popup.presetName);
}
}
_handlePopupInput(e5) {
const target = e5.target;
this._popup = { ...this._popup, presetName: target.value };
}
// ---------------------------------------------------------------------------
// Actions - Global
// ---------------------------------------------------------------------------
_togglePower() {
@@ -1761,9 +2058,11 @@ var LightPresetManager = class extends i4 {
<div class="card-content">
${this._renderMainControls()}
${this._supportsColorTemp ? this._renderGlobalTemperature() : ""}
${this._renderPresetsSection()}
${this._lights.length > 1 ? this._renderLightsPanel() : ""}
</div>
</ha-card>
${this._renderPopup()}
`;
}
_renderMainControls() {
@@ -1831,6 +2130,34 @@ var LightPresetManager = class extends i4 {
</div>
`;
}
_renderPresetsSection() {
return b2`
<div class="presets-section">
<div class="presets-grid">
${this._presets.map((preset) => this._renderPresetButton(preset))}
</div>
</div>
`;
}
_renderPresetButton(preset) {
const hasData = preset.lights && preset.lights.length > 0;
return b2`
<button
class="preset-button ${hasData ? "has-data" : ""}"
@pointerdown=${() => this._handlePointerDown(preset.id)}
@pointerup=${() => this._handlePointerUp(preset.id)}
@pointerleave=${this._handlePointerLeave}
@pointercancel=${this._handlePointerLeave}
>
<span class="preset-icon">
<ha-icon
icon="${hasData ? "mdi:lightbulb-group" : "mdi:lightbulb-group-outline"}"
></ha-icon>
</span>
<span class="preset-name">${preset.name}</span>
</button>
`;
}
_renderLightsPanel() {
return b2`
<div class="lights-panel">
@@ -1912,8 +2239,44 @@ var LightPresetManager = class extends i4 {
</div>
`;
}
_renderPopup() {
if (!this._popup.type) return A;
const t4 = this._t;
const isSave = this._popup.type === "save";
return b2`
<div class="popup-overlay" @click=${this._closePopup}>
<div class="popup-content" @click=${(e5) => e5.stopPropagation()}>
<div class="popup-title">
${isSave ? t4.popup.confirmSaveTitle : t4.popup.renameTitle}
</div>
${isSave ? b2`<div class="popup-message">
${t4.popup.confirmSaveMessage} "${this._popup.presetName}"?
</div>` : b2`<input
type="text"
class="popup-input"
.value=${this._popup.presetName}
@input=${this._handlePopupInput}
@keyup=${(e5) => e5.key === "Enter" && this._handlePopupConfirm()}
/>`}
<div class="popup-buttons">
<button class="popup-btn cancel" @click=${this._closePopup}>
${t4.popup.cancel}
</button>
<button
class="popup-btn confirm"
@click=${this._handlePopupConfirm}
>
${isSave ? t4.popup.save : t4.popup.confirm}
</button>
</div>
</div>
</div>
`;
}
getCardSize() {
return 2 + Math.ceil(this._lights.length / 2);
return 3 + Math.ceil(this._lights.length / 2);
}
};
LightPresetManager.styles = mainStyles;
@@ -1926,6 +2289,12 @@ __decorateClass([
__decorateClass([
r5()
], LightPresetManager.prototype, "_t", 2);
__decorateClass([
r5()
], LightPresetManager.prototype, "_presets", 2);
__decorateClass([
r5()
], LightPresetManager.prototype, "_popup", 2);
LightPresetManager = __decorateClass([
t3("light-preset-manager")
], LightPresetManager);
@@ -1938,7 +2307,7 @@ window.customCards.push({
documentationURL: "https://github.com/your-repo/light-preset-manager"
});
console.log(
"%c LIGHT-PRESET-MANAGER %c v0.5.3 ",
"%c LIGHT-PRESET-MANAGER %c v0.6.4 ",
"background: #3498db; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);
@@ -0,0 +1,12 @@
{
"domain": "light_preset_manager",
"name": "Light Preset Manager",
"version": "0.6.0",
"documentation": "https://github.com/your-repo/light-preset-manager",
"issue_tracker": "https://github.com/your-repo/light-preset-manager/issues",
"dependencies": [],
"codeowners": ["@your-username"],
"requirements": [],
"iot_class": "local_push",
"integration_type": "service"
}
@@ -0,0 +1,91 @@
save_preset:
name: Save Preset
description: Save current light states to a preset
fields:
card_id:
name: Card ID
description: Unique identifier for the card instance
required: true
example: "kitchen_lights"
selector:
text:
preset_id:
name: Preset ID
description: Preset number (1-4)
required: true
example: 1
selector:
number:
min: 1
max: 4
mode: box
lights:
name: Lights
description: List of light states to save
required: true
example: '[{"entity_id": "light.kitchen", "state": "on", "brightness": 255}]'
selector:
object:
recall_preset:
name: Recall Preset
description: Apply a saved preset to lights
fields:
card_id:
name: Card ID
description: Unique identifier for the card instance
required: true
example: "kitchen_lights"
selector:
text:
preset_id:
name: Preset ID
description: Preset number (1-4)
required: true
example: 1
selector:
number:
min: 1
max: 4
mode: box
rename_preset:
name: Rename Preset
description: Change the name of a preset
fields:
card_id:
name: Card ID
description: Unique identifier for the card instance
required: true
example: "kitchen_lights"
selector:
text:
preset_id:
name: Preset ID
description: Preset number (1-4)
required: true
example: 1
selector:
number:
min: 1
max: 4
mode: box
preset_name:
name: Preset Name
description: New name for the preset
required: true
example: "Movie Night"
selector:
text:
get_presets:
name: Get Presets
description: Get all presets for a card
fields:
card_id:
name: Card ID
description: Unique identifier for the card instance
required: true
example: "kitchen_lights"
selector:
text:
+9 -1
View File
@@ -8,6 +8,13 @@ import type {
} from "./types";
const MAIN_SCHEMA = [
{
name: "card_id",
required: true,
selector: {
text: {},
},
},
{
name: "group",
required: true,
@@ -403,6 +410,7 @@ export class LightPresetManagerEditor extends LitElement {
private _computeLabel = (schema: { name: string }): string => {
const labels: Record<string, string> = {
card_id: "Card ID (required, unique)",
group: "Group (required)",
title: "Title",
presets: "Number of Presets (1-4)",
@@ -412,7 +420,7 @@ export class LightPresetManagerEditor extends LitElement {
}
console.log(
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.5.0 ",
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.6.3 ",
"background: #9b59b6; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);
+355 -3
View File
@@ -1,4 +1,4 @@
import { LitElement, html } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import type {
@@ -8,6 +8,8 @@ import type {
LightPresetManagerConfigInternal,
LightConfigInternal,
TemperatureType,
PresetData,
LightState,
} from "./types";
import type { Translations } from "./locales";
import { mainStyles } from "./styles";
@@ -20,17 +22,39 @@ import {
getLightsFromGroup,
supportsColorTemp,
getCurrentTempZone,
captureLightState,
} from "./utils";
import { detectLocale, getTranslations } from "./locales";
// Import editor
import "./editor";
// Constants for gesture detection
const HOLD_DURATION = 800; // ms
const DOUBLE_TAP_DELAY = 300; // ms
@customElement("light-preset-manager")
export class LightPresetManager extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@state() private _config?: LightPresetManagerConfigInternal;
@state() private _t?: Translations;
@state() private _presets: PresetData[] = [];
@state() private _popup: {
type: "save" | "rename" | null;
presetId: number;
presetName: string;
} = { type: null, presetId: 0, presetName: "" };
// Gesture tracking
private _holdTimer?: number;
private _lastTap: number = 0;
private _tapCount: number = 0;
private _tapTimer?: number;
private _activePresetId: number = 0;
// Event subscription
private _unsubscribe?: () => void;
private _presetsLoaded: boolean = false;
static styles = mainStyles;
@@ -44,6 +68,7 @@ export class LightPresetManager extends LitElement {
static getStubConfig() {
return {
card_id: "my_lights",
group: "light.example_group",
title: "My Lights",
};
@@ -55,11 +80,68 @@ export class LightPresetManager extends LitElement {
setConfig(config: LightPresetManagerConfig): void {
this._config = validateConfig(config);
this._presetsLoaded = false;
this._initPresets();
}
async connectedCallback(): Promise<void> {
super.connectedCallback();
await this._subscribeToEvents();
}
disconnectedCallback(): void {
super.disconnectedCallback();
this._clearTimers();
this._unsubscribeFromEvents();
}
updated(changedProps: Map<string, unknown>): void {
if (changedProps.has("hass") && this.hass) {
this._t = getTranslations(detectLocale(this.hass.language));
// Load presets from HA once hass is available
if (!this._presetsLoaded && this._config) {
this._loadPresetsFromHA();
}
}
}
// ---------------------------------------------------------------------------
// Event Subscription
// ---------------------------------------------------------------------------
private async _subscribeToEvents(): Promise<void> {
if (!this.hass || this._unsubscribe) return;
try {
this._unsubscribe = await this.hass.connection.subscribeEvents(
(event: any) => this._handlePresetEvent(event),
"light_preset_manager_preset_updated"
);
} catch (e) {
console.error("Failed to subscribe to events:", e);
}
}
private _unsubscribeFromEvents(): void {
if (this._unsubscribe) {
this._unsubscribe();
this._unsubscribe = undefined;
}
}
private _handlePresetEvent(event: any): void {
if (!this._config) return;
const { card_id, preset_id, preset } = event.data;
// Only update if this event is for our card
if (card_id !== this._config.card_id) return;
const presetIndex = preset_id - 1;
if (this._presets[presetIndex]) {
this._presets[presetIndex] = preset;
this._presets = [...this._presets]; // Trigger re-render
}
}
@@ -94,6 +176,199 @@ export class LightPresetManager extends LitElement {
return getLightsFromGroup(this._group, this._config.lights);
}
// ---------------------------------------------------------------------------
// Presets - Init/Load/Save via HA Services
// ---------------------------------------------------------------------------
private _initPresets(): void {
if (!this._config) return;
const count = this._config.presets;
this._presets = Array.from({ length: count }, (_, i) => ({
id: i + 1,
name: `Preset ${i + 1}`,
lights: [],
}));
}
private async _loadPresetsFromHA(): Promise<void> {
if (!this.hass || !this._config) return;
try {
const response = await this.hass.callWS<{ presets: PresetData[] }>({
type: "light_preset_manager/get_presets",
card_id: this._config.card_id,
});
if (response.presets) {
// Only take the number of presets configured
this._presets = response.presets.slice(0, this._config.presets);
this._presetsLoaded = true;
}
} catch (e) {
console.error("Failed to load presets from HA:", e);
}
}
private async _savePreset(presetId: number): Promise<void> {
if (!this.hass || !this._config) return;
// Capture current state of all lights
const lightStates: LightState[] = [];
for (const lightConfig of this._lights) {
const entity = this.hass.states[lightConfig.entity];
if (entity) {
lightStates.push(captureLightState(entity));
}
}
try {
await this.hass.callService("light_preset_manager", "save_preset", {
card_id: this._config.card_id,
preset_id: presetId,
lights: lightStates,
});
// Local state will be updated via event subscription
this._closePopup();
} catch (e) {
console.error("Failed to save preset:", e);
}
}
private async _recallPreset(presetId: number): Promise<void> {
if (!this.hass || !this._config) return;
// Check if preset has data
const preset = this._presets[presetId - 1];
if (!preset || !preset.lights || preset.lights.length === 0) {
console.log(`Preset ${presetId} is empty`);
return;
}
try {
await this.hass.callService("light_preset_manager", "recall_preset", {
card_id: this._config.card_id,
preset_id: presetId,
});
} catch (e) {
console.error("Failed to recall preset:", e);
}
}
private async _renamePreset(presetId: number, name: string): Promise<void> {
if (!this.hass || !this._config) return;
try {
await this.hass.callService("light_preset_manager", "rename_preset", {
card_id: this._config.card_id,
preset_id: presetId,
preset_name: name,
});
// Local state will be updated via event subscription
this._closePopup();
} catch (e) {
console.error("Failed to rename preset:", e);
}
}
// ---------------------------------------------------------------------------
// Gesture Handling (tap / hold / double-tap)
// ---------------------------------------------------------------------------
private _clearTimers(): void {
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = undefined;
}
if (this._tapTimer) {
clearTimeout(this._tapTimer);
this._tapTimer = undefined;
}
}
private _handlePointerDown(presetId: number): void {
this._activePresetId = presetId;
this._clearTimers();
// Start hold timer
this._holdTimer = window.setTimeout(() => {
// Hold detected -> show save popup
this._showSavePopup(presetId);
this._tapCount = 0;
}, HOLD_DURATION);
}
private _handlePointerUp(presetId: number): void {
// If hold timer still running, it was a tap
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = undefined;
this._tapCount++;
if (this._tapTimer) {
clearTimeout(this._tapTimer);
}
this._tapTimer = window.setTimeout(() => {
if (this._tapCount === 1) {
// Single tap -> recall
this._recallPreset(presetId);
} else if (this._tapCount >= 2) {
// Double tap -> rename
this._showRenamePopup(presetId);
}
this._tapCount = 0;
}, DOUBLE_TAP_DELAY);
}
}
private _handlePointerLeave(): void {
this._clearTimers();
this._tapCount = 0;
}
// ---------------------------------------------------------------------------
// Popup Management
// ---------------------------------------------------------------------------
private _showSavePopup(presetId: number): void {
const preset = this._presets[presetId - 1];
this._popup = {
type: "save",
presetId,
presetName: preset?.name || `Preset ${presetId}`,
};
}
private _showRenamePopup(presetId: number): void {
const preset = this._presets[presetId - 1];
this._popup = {
type: "rename",
presetId,
presetName: preset?.name || `Preset ${presetId}`,
};
}
private _closePopup(): void {
this._popup = { type: null, presetId: 0, presetName: "" };
}
private _handlePopupConfirm(): void {
if (this._popup.type === "save") {
this._savePreset(this._popup.presetId);
} else if (this._popup.type === "rename") {
this._renamePreset(this._popup.presetId, this._popup.presetName);
}
}
private _handlePopupInput(e: Event): void {
const target = e.target as HTMLInputElement;
this._popup = { ...this._popup, presetName: target.value };
}
// ---------------------------------------------------------------------------
// Actions - Global
// ---------------------------------------------------------------------------
@@ -171,9 +446,11 @@ export class LightPresetManager extends LitElement {
<div class="card-content">
${this._renderMainControls()}
${this._supportsColorTemp ? this._renderGlobalTemperature() : ""}
${this._renderPresetsSection()}
${this._lights.length > 1 ? this._renderLightsPanel() : ""}
</div>
</ha-card>
${this._renderPopup()}
`;
}
@@ -248,6 +525,39 @@ export class LightPresetManager extends LitElement {
`;
}
private _renderPresetsSection() {
return html`
<div class="presets-section">
<div class="presets-grid">
${this._presets.map((preset) => this._renderPresetButton(preset))}
</div>
</div>
`;
}
private _renderPresetButton(preset: PresetData) {
const hasData = preset.lights && preset.lights.length > 0;
return html`
<button
class="preset-button ${hasData ? "has-data" : ""}"
@pointerdown=${() => this._handlePointerDown(preset.id)}
@pointerup=${() => this._handlePointerUp(preset.id)}
@pointerleave=${this._handlePointerLeave}
@pointercancel=${this._handlePointerLeave}
>
<span class="preset-icon">
<ha-icon
icon="${hasData
? "mdi:lightbulb-group"
: "mdi:lightbulb-group-outline"}"
></ha-icon>
</span>
<span class="preset-name">${preset.name}</span>
</button>
`;
}
private _renderLightsPanel() {
return html`
<div class="lights-panel">
@@ -346,8 +656,50 @@ export class LightPresetManager extends LitElement {
`;
}
private _renderPopup() {
if (!this._popup.type) return nothing;
const t = this._t!;
const isSave = this._popup.type === "save";
return html`
<div class="popup-overlay" @click=${this._closePopup}>
<div class="popup-content" @click=${(e: Event) => e.stopPropagation()}>
<div class="popup-title">
${isSave ? t.popup.confirmSaveTitle : t.popup.renameTitle}
</div>
${isSave
? html`<div class="popup-message">
${t.popup.confirmSaveMessage} "${this._popup.presetName}"?
</div>`
: html`<input
type="text"
class="popup-input"
.value=${this._popup.presetName}
@input=${this._handlePopupInput}
@keyup=${(e: KeyboardEvent) =>
e.key === "Enter" && this._handlePopupConfirm()}
/>`}
<div class="popup-buttons">
<button class="popup-btn cancel" @click=${this._closePopup}>
${t.popup.cancel}
</button>
<button
class="popup-btn confirm"
@click=${this._handlePopupConfirm}
>
${isSave ? t.popup.save : t.popup.confirm}
</button>
</div>
</div>
</div>
`;
}
getCardSize(): number {
return 2 + Math.ceil(this._lights.length / 2);
return 3 + Math.ceil(this._lights.length / 2);
}
}
@@ -362,7 +714,7 @@ export class LightPresetManager extends LitElement {
});
console.log(
"%c LIGHT-PRESET-MANAGER %c v0.5.3 ",
"%c LIGHT-PRESET-MANAGER %c v0.6.4 ",
"background: #3498db; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);
+62
View File
@@ -399,6 +399,68 @@ export const mainStyles = css`
line-height: 1.2;
max-width: 90%;
}
/* Presets Section */
.presets-section {
margin-top: var(--lpm-padding);
padding-top: var(--lpm-padding);
border-top: 1px solid var(--divider-color);
}
.presets-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--lpm-spacing);
}
.preset-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12px 8px;
min-height: 60px;
border: none;
border-radius: var(--lpm-button-radius);
cursor: pointer;
background: var(--primary-background-color);
color: var(--primary-text-color);
transition: all var(--lpm-transition);
font-family: inherit;
gap: 4px;
}
.preset-button:hover {
background: var(--secondary-background-color);
}
.preset-button:active {
transform: scale(0.95);
}
.preset-button.has-data {
border: 1px solid var(--primary-color);
}
.preset-button.has-data .preset-icon {
color: var(--primary-color);
}
.preset-button .preset-icon {
color: var(--disabled-text-color);
}
.preset-button .preset-icon ha-icon {
--mdc-icon-size: 24px;
}
.preset-button .preset-name {
font-size: 11px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
/* Popup */
.popup-overlay {
+17 -8
View File
@@ -14,13 +14,16 @@ export interface LightConfig {
}
export interface LightPresetManagerConfig {
// Required: unique identifier for preset storage
card_id: string;
// Required: main group or light for global control
group: string;
// Optional: card header title
title?: string;
// Optional: individual lights for presets (string or object with name)
// Optional: individual lights for presets
lights?: (string | LightConfig)[];
// Optional: color temperatures in mireds
@@ -30,18 +33,18 @@ export interface LightPresetManagerConfig {
presets?: number;
}
export interface LightConfigInternal {
entity: string;
name?: string;
}
export interface LightPresetManagerConfigInternal {
card_id: string;
group: string;
title?: string;
lights: LightConfigInternal[];
temperatures: TemperaturesConfig;
presets: number;
}
export interface LightConfigInternal {
entity: string;
name?: string;
}
// -----------------------------------------------------------------------------
// Home Assistant
@@ -77,9 +80,15 @@ export interface HomeAssistant {
callService: (
domain: string,
service: string,
data?: object,
target?: object
data?: Record<string, any>
) => Promise<void>;
callWS: <T>(msg: Record<string, any>) => Promise<T>;
connection: {
subscribeEvents: (
callback: (event: any) => void,
eventType: string
) => Promise<() => void>;
};
}
// -----------------------------------------------------------------------------
+5
View File
@@ -36,6 +36,10 @@ function normalizeLightConfig(
export function validateConfig(
config: LightPresetManagerConfig
): LightPresetManagerConfigInternal {
if (!config.card_id) {
throw new Error('Config error: "card_id" is required');
}
if (!config.group) {
throw new Error('Config error: "group" is required');
}
@@ -66,6 +70,7 @@ export function validateConfig(
}
return {
card_id: config.card_id,
group: config.group,
title: config.title,
lights,
+1 -1
View File
@@ -1 +1 @@
{"pid": 67, "version": 1, "ha_version": "2025.12.5", "start_ts": 1767194043.955861}
{"pid": 68, "version": 1, "ha_version": "2025.12.5", "start_ts": 1767291664.449257}
+3 -3
View File
@@ -16,8 +16,6 @@ logger:
logs:
custom_components.light_preset_manager: debug
# Inclure les scènes
scene: !include scenes.yaml
@@ -30,4 +28,6 @@ api:
# Permettre les ressources locales
http:
use_x_forwarded_for: false
trusted_proxies: []
trusted_proxies: []
light_preset_manager:
+177 -170
View File
@@ -1,171 +1,178 @@
2025-12-31 16:08:23.624 INFO (MainThread) [homeassistant.setup] Setup of domain system_log took 0.02 seconds
2025-12-31 16:08:23.624 INFO (MainThread) [homeassistant.setup] Setup of domain http took 0.02 seconds
2025-12-31 16:08:23.624 INFO (MainThread) [homeassistant.setup] Setup of domain logger took 0.02 seconds
2025-12-31 16:08:23.624 INFO (MainThread) [homeassistant.setup] Setting up websocket_api
2025-12-31 16:08:23.624 INFO (MainThread) [homeassistant.setup] Setup of domain websocket_api took 0.00 seconds
2025-12-31 16:08:23.630 INFO (MainThread) [homeassistant.setup] Setting up network
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.setup] Setup of domain network took 0.00 seconds
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.bootstrap] Setting up stage labs: {'labs'}; already set up: {}
2026-01-01 19:15:41.401 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration light_preset_manager which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2026-01-01 19:15:41.405 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration light_preset_manager which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2026-01-01 19:15:41.915 INFO (MainThread) [homeassistant.setup] Setting up system_log
2026-01-01 19:15:41.915 INFO (MainThread) [homeassistant.setup] Setting up http
2026-01-01 19:15:41.939 INFO (MainThread) [homeassistant.setup] Setup of domain logger took 0.02 seconds
2026-01-01 19:15:41.940 INFO (MainThread) [homeassistant.setup] Setup of domain system_log took 0.02 seconds
2026-01-01 19:15:41.940 INFO (MainThread) [homeassistant.setup] Setup of domain http took 0.02 seconds
2026-01-01 19:15:41.940 INFO (MainThread) [homeassistant.setup] Setting up websocket_api
2026-01-01 19:15:41.940 INFO (MainThread) [homeassistant.setup] Setup of domain websocket_api took 0.00 seconds
2026-01-01 19:15:41.944 INFO (MainThread) [homeassistant.setup] Setting up network
2026-01-01 19:15:41.945 INFO (MainThread) [homeassistant.setup] Setup of domain network took 0.00 seconds
2026-01-01 19:15:41.945 INFO (MainThread) [homeassistant.bootstrap] Setting up stage labs: {'labs'}; already set up: {}
Dependencies: {}; already set up: {}
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.setup] Setting up labs
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.setup] Setup of domain labs took 0.00 seconds
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.bootstrap] Setting up stage frontend: {'frontend'}; already set up: {}
Dependencies: {'onboarding', 'file_upload', 'auth', 'diagnostics', 'device_automation', 'config', 'lovelace', 'api', 'repairs', 'search'}; already set up: {'websocket_api', 'system_log', 'http'}
2025-12-31 16:08:23.631 INFO (MainThread) [homeassistant.setup] Setting up auth
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setup of domain auth took 0.00 seconds
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setting up onboarding
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setup of domain onboarding took 0.00 seconds
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setting up file_upload
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setup of domain file_upload took 0.00 seconds
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setting up diagnostics
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setup of domain diagnostics took 0.00 seconds
2025-12-31 16:08:23.632 INFO (MainThread) [homeassistant.setup] Setting up api
2025-12-31 16:08:23.633 INFO (MainThread) [homeassistant.setup] Setup of domain api took 0.00 seconds
2025-12-31 16:08:23.633 INFO (MainThread) [homeassistant.setup] Setting up config
2025-12-31 16:08:23.635 INFO (MainThread) [homeassistant.setup] Setup of domain config took 0.00 seconds
2025-12-31 16:08:23.635 INFO (MainThread) [homeassistant.setup] Setting up device_automation
2025-12-31 16:08:23.635 INFO (MainThread) [homeassistant.setup] Setup of domain device_automation took 0.00 seconds
2025-12-31 16:08:23.635 INFO (MainThread) [homeassistant.setup] Setting up lovelace
2025-12-31 16:08:23.635 INFO (MainThread) [homeassistant.setup] Setting up repairs
2025-12-31 16:08:23.636 INFO (MainThread) [homeassistant.setup] Setup of domain repairs took 0.00 seconds
2025-12-31 16:08:23.636 INFO (MainThread) [homeassistant.setup] Setting up search
2025-12-31 16:08:23.636 INFO (MainThread) [homeassistant.setup] Setup of domain search took 0.00 seconds
2025-12-31 16:08:23.643 INFO (MainThread) [homeassistant.setup] Setup of domain lovelace took 0.01 seconds
2025-12-31 16:08:23.647 INFO (MainThread) [homeassistant.setup] Setting up frontend
2025-12-31 16:08:23.653 INFO (MainThread) [homeassistant.setup] Setup of domain frontend took 0.01 seconds
2025-12-31 16:08:23.653 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage recorder: {'recorder'}
2025-12-31 16:08:23.653 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage debugger: {'debugpy'}
2025-12-31 16:08:23.653 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage zeroconf: {'zeroconf'}
2025-12-31 16:08:23.654 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage 1: {'hassio', 'mqtt_eventstream', 'ssdp', 'dhcp', 'bluetooth', 'usb', 'cloud'}
2025-12-31 16:08:23.654 INFO (MainThread) [homeassistant.bootstrap] Setting up stage 2: {'schedule', 'backup', 'input_button', 'scene', 'application_credentials', 'person', 'system_health', 'script', 'counter', 'mqtt', 'input_select', 'hardware', 'analytics', 'input_number', 'input_boolean', 'shopping_list', 'google_translate', 'tag', 'zone', 'automation', 'timer', 'input_datetime', 'radio_browser', 'input_text'}; already set up: {'labs', 'http', 'frontend', 'config', 'homeassistant', 'api', 'logger', 'network'}
Dependencies: {'trace', 'image_upload', 'blueprint'}; already set up: {'file_upload', 'websocket_api', 'auth', 'device_automation', 'api', 'http'}
2025-12-31 16:08:23.654 INFO (MainThread) [homeassistant.setup] Setting up scene
2025-12-31 16:08:23.654 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2025-12-31 16:08:23.655 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2025-12-31 16:08:23.655 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2025-12-31 16:08:23.655 INFO (MainThread) [homeassistant.setup] Setup of domain scene took 0.00 seconds
2025-12-31 16:08:23.655 INFO (MainThread) [homeassistant.setup] Setting up input_number
2025-12-31 16:08:23.656 INFO (MainThread) [homeassistant.setup] Setup of domain input_number took 0.00 seconds
2025-12-31 16:08:23.656 INFO (MainThread) [homeassistant.setup] Setting up zone
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setup of domain zone took 0.00 seconds
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setting up system_health
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setup of domain system_health took 0.00 seconds
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setting up blueprint
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setup of domain blueprint took 0.00 seconds
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setting up trace
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setup of domain trace took 0.00 seconds
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setting up script
2025-12-31 16:08:23.657 INFO (MainThread) [homeassistant.setup] Setup of domain script took 0.00 seconds
2025-12-31 16:08:23.658 INFO (MainThread) [homeassistant.setup] Setting up automation
2025-12-31 16:08:23.658 INFO (MainThread) [homeassistant.setup] Setup of domain automation took 0.00 seconds
2025-12-31 16:08:23.661 INFO (MainThread) [homeassistant.components.http] Now listening on port 8123
2025-12-31 16:08:23.661 INFO (MainThread) [homeassistant.setup] Setup of domain http took 0.01 seconds
2025-12-31 16:08:23.662 INFO (MainThread) [homeassistant.setup] Setting up input_boolean
2025-12-31 16:08:23.663 INFO (MainThread) [homeassistant.setup] Setup of domain input_boolean took 0.00 seconds
2025-12-31 16:08:23.666 INFO (MainThread) [homeassistant.setup] Setting up schedule
2025-12-31 16:08:23.667 INFO (MainThread) [homeassistant.setup] Setup of domain schedule took 0.00 seconds
2025-12-31 16:08:23.676 INFO (MainThread) [homeassistant.setup] Setting up shopping_list
2025-12-31 16:08:23.676 INFO (MainThread) [homeassistant.setup] Setup of domain shopping_list took 0.00 seconds
2025-12-31 16:08:23.676 INFO (MainThread) [homeassistant.setup] Setting up input_button
2025-12-31 16:08:23.676 INFO (MainThread) [homeassistant.setup] Setup of domain input_button took 0.00 seconds
2025-12-31 16:08:23.680 INFO (MainThread) [homeassistant.setup] Setting up tag
2025-12-31 16:08:23.680 INFO (MainThread) [homeassistant.setup] Setup of domain tag took 0.00 seconds
2025-12-31 16:08:23.683 INFO (MainThread) [homeassistant.setup] Setting up application_credentials
2025-12-31 16:08:23.683 INFO (MainThread) [homeassistant.setup] Setup of domain application_credentials took 0.00 seconds
2025-12-31 16:08:23.686 INFO (MainThread) [homeassistant.setup] Setting up counter
2025-12-31 16:08:23.687 INFO (MainThread) [homeassistant.setup] Setup of domain counter took 0.00 seconds
2025-12-31 16:08:23.689 INFO (MainThread) [homeassistant.setup] Setting up timer
2025-12-31 16:08:23.690 INFO (MainThread) [homeassistant.setup] Setup of domain timer took 0.00 seconds
2025-12-31 16:08:23.694 INFO (MainThread) [homeassistant.setup] Setting up input_select
2025-12-31 16:08:23.695 INFO (MainThread) [homeassistant.setup] Setup of domain input_select took 0.00 seconds
2025-12-31 16:08:23.697 INFO (MainThread) [homeassistant.setup] Setting up input_datetime
2025-12-31 16:08:23.697 INFO (MainThread) [homeassistant.setup] Setup of domain input_datetime took 0.00 seconds
2025-12-31 16:08:23.699 INFO (MainThread) [homeassistant.setup] Setting up input_text
2025-12-31 16:08:23.700 INFO (MainThread) [homeassistant.setup] Setup of domain input_text took 0.00 seconds
2025-12-31 16:08:23.702 INFO (MainThread) [homeassistant.setup] Setting up image_upload
2025-12-31 16:08:23.702 INFO (MainThread) [homeassistant.setup] Setup of domain image_upload took 0.00 seconds
2025-12-31 16:08:23.702 INFO (MainThread) [homeassistant.setup] Setting up person
2025-12-31 16:08:23.703 INFO (MainThread) [homeassistant.setup] Setup of domain person took 0.00 seconds
2025-12-31 16:08:23.706 INFO (MainThread) [homeassistant.setup] Setting up todo
2025-12-31 16:08:23.708 INFO (MainThread) [homeassistant.setup] Setup of domain todo took 0.00 seconds
2025-12-31 16:08:23.710 INFO (MainThread) [homeassistant.components.todo] Setting up shopping_list.todo
2025-12-31 16:08:23.722 INFO (MainThread) [homeassistant.setup] Setting up backup
2025-12-31 16:08:23.726 INFO (MainThread) [homeassistant.setup] Setup of domain backup took 0.00 seconds
2025-12-31 16:08:23.735 INFO (MainThread) [homeassistant.setup] Setting up google_translate
2025-12-31 16:08:23.735 INFO (MainThread) [homeassistant.setup] Setup of domain google_translate took 0.00 seconds
2025-12-31 16:08:23.795 INFO (MainThread) [homeassistant.setup] Setting up radio_browser
2025-12-31 16:08:23.795 INFO (MainThread) [homeassistant.setup] Setup of domain radio_browser took 0.00 seconds
2025-12-31 16:08:23.800 INFO (MainThread) [homeassistant.setup] Setting up hardware
2025-12-31 16:08:23.815 INFO (MainThread) [homeassistant.setup] Setting up analytics
2025-12-31 16:08:23.815 INFO (MainThread) [homeassistant.setup] Setup of domain analytics took 0.00 seconds
2025-12-31 16:08:23.815 INFO (MainThread) [homeassistant.setup] Setup of domain hardware took 0.02 seconds
2025-12-31 16:08:23.838 INFO (MainThread) [homeassistant.setup] Setting up mqtt
2025-12-31 16:08:23.839 INFO (MainThread) [homeassistant.setup] Setup of domain mqtt took 0.00 seconds
2025-12-31 16:08:23.844 INFO (MainThread) [homeassistant.setup] Setting up ffmpeg
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setting up event
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setup of domain event took 0.00 seconds
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setting up sensor
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setup of domain sensor took 0.00 seconds
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setup of domain ffmpeg took 0.00 seconds
2025-12-31 16:08:23.848 INFO (MainThread) [homeassistant.setup] Setting up tts
2025-12-31 16:08:23.849 INFO (MainThread) [homeassistant.components.event] Setting up backup.event
2025-12-31 16:08:23.850 INFO (MainThread) [homeassistant.components.sensor] Setting up backup.sensor
2025-12-31 16:08:23.854 INFO (MainThread) [homeassistant.setup] Setup of domain tts took 0.01 seconds
2025-12-31 16:08:23.855 INFO (MainThread) [homeassistant.components.tts] Setting up google_translate.tts
2025-12-31 16:08:24.751 INFO (MainThread) [homeassistant.setup] Setting up binary_sensor
2025-12-31 16:08:24.751 INFO (MainThread) [homeassistant.setup] Setup of domain binary_sensor took 0.00 seconds
2025-12-31 16:08:24.752 INFO (MainThread) [homeassistant.setup] Setting up button
2025-12-31 16:08:24.752 INFO (MainThread) [homeassistant.setup] Setup of domain button took 0.00 seconds
2025-12-31 16:08:24.752 INFO (MainThread) [homeassistant.setup] Setting up update
2025-12-31 16:08:24.753 INFO (MainThread) [homeassistant.setup] Setup of domain update took 0.00 seconds
2025-12-31 16:08:24.753 INFO (MainThread) [homeassistant.setup] Setting up light
2025-12-31 16:08:24.754 INFO (MainThread) [homeassistant.setup] Setup of domain light took 0.00 seconds
2025-12-31 16:08:24.754 INFO (MainThread) [homeassistant.setup] Setting up select
2025-12-31 16:08:24.754 INFO (MainThread) [homeassistant.setup] Setup of domain select took 0.00 seconds
2025-12-31 16:08:24.754 INFO (MainThread) [homeassistant.setup] Setting up switch
2025-12-31 16:08:24.754 INFO (MainThread) [homeassistant.setup] Setup of domain switch took 0.00 seconds
2025-12-31 16:08:24.757 INFO (MainThread) [homeassistant.components.binary_sensor] Setting up mqtt.binary_sensor
2025-12-31 16:08:24.757 INFO (MainThread) [homeassistant.components.button] Setting up mqtt.button
2025-12-31 16:08:24.757 INFO (MainThread) [homeassistant.components.scene] Setting up mqtt.scene
2025-12-31 16:08:24.757 INFO (MainThread) [homeassistant.components.update] Setting up mqtt.update
2025-12-31 16:08:24.758 INFO (MainThread) [homeassistant.components.light] Setting up mqtt.light
2025-12-31 16:08:24.758 INFO (MainThread) [homeassistant.components.sensor] Setting up mqtt.sensor
2025-12-31 16:08:24.758 INFO (MainThread) [homeassistant.components.select] Setting up mqtt.select
2025-12-31 16:08:24.758 INFO (MainThread) [homeassistant.components.switch] Setting up mqtt.switch
2025-12-31 16:08:24.760 INFO (MainThread) [homeassistant.bootstrap] Home Assistant initialized in 1.72s
2025-12-31 16:08:24.760 INFO (MainThread) [homeassistant.core] Starting Home Assistant 2025.12.5
2025-12-31 16:08:25.366 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_asleep_screens_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_asleep_screens"` option with `"default_entity_id": "button.WARMACHINE-PAPA_asleep_screens"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.367 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_awake_screens_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_awake_screens"` option with `"default_entity_id": "button.WARMACHINE-PAPA_awake_screens"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.367 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_veille_prolonge_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_veille_prolonge"` option with `"default_entity_id": "button.WARMACHINE-PAPA_veille_prolonge"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.368 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_play_pause_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_play_pause"` option with `"default_entity_id": "button.WARMACHINE-PAPA_play_pause"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.368 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_volume_up_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_volume_up"` option with `"default_entity_id": "button.WARMACHINE-PAPA_volume_up"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.369 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_volume_down_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_volume_down"` option with `"default_entity_id": "button.WARMACHINE-PAPA_volume_down"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.369 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_right_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_right"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_right"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.370 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_left_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_left"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_left"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.370 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_up_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_up"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_up"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.371 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_down_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_down"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_down"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.371 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_alt_tab_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_alt_tab"` option with `"default_entity_id": "button.WARMACHINE-PAPA_alt_tab"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.372 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_mute_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_mute"` option with `"default_entity_id": "button.WARMACHINE-PAPA_mute"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.372 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_veille_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_veille"` option with `"default_entity_id": "button.WARMACHINE-PAPA_veille"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.705 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_chargecpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_chargecpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_chargecpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.706 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_chargegpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_chargegpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_chargegpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.707 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_temp_gpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_temp_gpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_temp_gpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.708 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_screen_state_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_screen_state"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_screen_state"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.709 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_status_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_status"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_status"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.710 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_full_charge_lifetime_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_full_charge_lifetime"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_full_charge_lifetime"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.710 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_remaining_percentage_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_remaining_percentage"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_remaining_percentage"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.716 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_remaining_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_remaining"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_remaining"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.718 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_powerline_status_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_powerline_status"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_powerline_status"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2025-12-31 16:08:25.739 INFO (MainThread) [homeassistant.components.websocket_api.http.connection] [139762306076640] Received unknown command: recorder/info
2025-12-31 16:08:30.537 INFO (MainThread) [homeassistant.components.websocket_api.http.connection] [139762306075520] Received unknown command: recorder/info
2025-12-31 16:08:31.333 INFO (MainThread) [homeassistant.components.mqtt.client] MQTT client initialized, birth message sent
2025-12-31 16:08:34.621 INFO (MainThread) [homeassistant.components.websocket_api.http.connection] [139762310016800] Received unknown command: recorder/info
2025-12-31 16:08:43.114 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:43.930 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:44.713 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:46.210 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:48.977 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:50.208 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:51.939 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:56.919 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2025-12-31 16:08:59.106 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2026-01-01 19:15:41.946 INFO (MainThread) [homeassistant.setup] Setting up labs
2026-01-01 19:15:41.946 INFO (MainThread) [homeassistant.setup] Setup of domain labs took 0.00 seconds
2026-01-01 19:15:41.946 INFO (MainThread) [homeassistant.bootstrap] Setting up stage frontend: {'frontend'}; already set up: {}
Dependencies: {'api', 'file_upload', 'auth', 'search', 'onboarding', 'device_automation', 'config', 'diagnostics', 'lovelace', 'repairs'}; already set up: {'websocket_api', 'http', 'system_log'}
2026-01-01 19:15:41.946 INFO (MainThread) [homeassistant.setup] Setting up api
2026-01-01 19:15:41.946 INFO (MainThread) [homeassistant.setup] Setup of domain api took 0.00 seconds
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setting up file_upload
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setup of domain file_upload took 0.00 seconds
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setting up auth
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setup of domain auth took 0.00 seconds
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setting up search
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setup of domain search took 0.00 seconds
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setting up onboarding
2026-01-01 19:15:41.947 INFO (MainThread) [homeassistant.setup] Setting up device_automation
2026-01-01 19:15:41.948 INFO (MainThread) [homeassistant.setup] Setup of domain device_automation took 0.00 seconds
2026-01-01 19:15:41.948 INFO (MainThread) [homeassistant.setup] Setting up config
2026-01-01 19:15:41.949 INFO (MainThread) [homeassistant.setup] Setup of domain config took 0.00 seconds
2026-01-01 19:15:41.949 INFO (MainThread) [homeassistant.setup] Setting up diagnostics
2026-01-01 19:15:41.950 INFO (MainThread) [homeassistant.setup] Setup of domain diagnostics took 0.00 seconds
2026-01-01 19:15:41.950 INFO (MainThread) [homeassistant.setup] Setting up repairs
2026-01-01 19:15:41.950 INFO (MainThread) [homeassistant.setup] Setup of domain repairs took 0.00 seconds
2026-01-01 19:15:41.955 INFO (MainThread) [homeassistant.setup] Setup of domain onboarding took 0.01 seconds
2026-01-01 19:15:41.955 INFO (MainThread) [homeassistant.setup] Setting up lovelace
2026-01-01 19:15:41.956 INFO (MainThread) [homeassistant.setup] Setup of domain lovelace took 0.00 seconds
2026-01-01 19:15:41.960 INFO (MainThread) [homeassistant.setup] Setting up frontend
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.setup] Setup of domain frontend took 0.01 seconds
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage recorder: {'recorder'}
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage debugger: {'debugpy'}
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage zeroconf: {'zeroconf'}
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.bootstrap] Nothing to set up in stage 1: {'dhcp', 'ssdp', 'bluetooth', 'hassio', 'usb', 'cloud', 'mqtt_eventstream'}
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.bootstrap] Setting up stage 2: {'input_boolean', 'input_datetime', 'automation', 'input_select', 'application_credentials', 'timer', 'script', 'backup', 'system_health', 'hardware', 'input_button', 'input_number', 'scene', 'tag', 'mqtt', 'shopping_list', 'counter', 'person', 'analytics', 'input_text', 'google_translate', 'schedule', 'zone', 'radio_browser', 'light_preset_manager'}; already set up: {'logger', 'api', 'homeassistant', 'http', 'config', 'network', 'labs', 'frontend'}
Dependencies: {'image_upload', 'trace', 'blueprint'}; already set up: {'api', 'file_upload', 'auth', 'http', 'device_automation', 'websocket_api'}
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.setup] Setting up scene
2026-01-01 19:15:41.966 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2026-01-01 19:15:41.967 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2026-01-01 19:15:41.967 INFO (MainThread) [homeassistant.components.scene] Setting up homeassistant.scene
2026-01-01 19:15:41.967 INFO (MainThread) [homeassistant.setup] Setup of domain scene took 0.00 seconds
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setting up blueprint
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setup of domain blueprint took 0.00 seconds
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setting up trace
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setup of domain trace took 0.00 seconds
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setting up automation
2026-01-01 19:15:41.968 INFO (MainThread) [homeassistant.setup] Setup of domain automation took 0.00 seconds
2026-01-01 19:15:41.969 INFO (MainThread) [homeassistant.setup] Setting up zone
2026-01-01 19:15:41.969 INFO (MainThread) [homeassistant.setup] Setup of domain zone took 0.00 seconds
2026-01-01 19:15:41.969 INFO (MainThread) [homeassistant.setup] Setting up script
2026-01-01 19:15:41.970 INFO (MainThread) [homeassistant.setup] Setup of domain script took 0.00 seconds
2026-01-01 19:15:41.970 INFO (MainThread) [homeassistant.setup] Setting up system_health
2026-01-01 19:15:41.970 INFO (MainThread) [homeassistant.setup] Setup of domain system_health took 0.00 seconds
2026-01-01 19:15:41.970 INFO (MainThread) [homeassistant.setup] Setting up input_number
2026-01-01 19:15:41.971 INFO (MainThread) [homeassistant.setup] Setup of domain input_number took 0.00 seconds
2026-01-01 19:15:41.973 INFO (MainThread) [homeassistant.setup] Setting up input_boolean
2026-01-01 19:15:41.973 INFO (MainThread) [homeassistant.setup] Setup of domain input_boolean took 0.00 seconds
2026-01-01 19:15:41.975 INFO (MainThread) [homeassistant.components.http] Now listening on port 8123
2026-01-01 19:15:41.976 INFO (MainThread) [homeassistant.setup] Setup of domain http took 0.01 seconds
2026-01-01 19:15:41.978 INFO (MainThread) [homeassistant.setup] Setting up input_datetime
2026-01-01 19:15:41.979 INFO (MainThread) [homeassistant.setup] Setup of domain input_datetime took 0.00 seconds
2026-01-01 19:15:41.981 INFO (MainThread) [homeassistant.setup] Setting up tag
2026-01-01 19:15:41.982 INFO (MainThread) [homeassistant.setup] Setup of domain tag took 0.00 seconds
2026-01-01 19:15:41.985 INFO (MainThread) [homeassistant.setup] Setting up image_upload
2026-01-01 19:15:41.986 INFO (MainThread) [homeassistant.setup] Setup of domain image_upload took 0.00 seconds
2026-01-01 19:15:41.986 INFO (MainThread) [homeassistant.setup] Setting up person
2026-01-01 19:15:41.986 INFO (MainThread) [homeassistant.setup] Setup of domain person took 0.00 seconds
2026-01-01 19:15:41.989 INFO (MainThread) [homeassistant.setup] Setting up input_select
2026-01-01 19:15:41.990 INFO (MainThread) [homeassistant.setup] Setup of domain input_select took 0.00 seconds
2026-01-01 19:15:41.992 INFO (MainThread) [homeassistant.setup] Setting up application_credentials
2026-01-01 19:15:41.992 INFO (MainThread) [homeassistant.setup] Setup of domain application_credentials took 0.00 seconds
2026-01-01 19:15:42.000 INFO (MainThread) [homeassistant.setup] Setting up shopping_list
2026-01-01 19:15:42.000 INFO (MainThread) [homeassistant.setup] Setup of domain shopping_list took 0.00 seconds
2026-01-01 19:15:42.002 INFO (MainThread) [homeassistant.setup] Setting up counter
2026-01-01 19:15:42.003 INFO (MainThread) [homeassistant.setup] Setup of domain counter took 0.00 seconds
2026-01-01 19:15:42.005 INFO (MainThread) [homeassistant.setup] Setting up timer
2026-01-01 19:15:42.005 INFO (MainThread) [homeassistant.setup] Setup of domain timer took 0.00 seconds
2026-01-01 19:15:42.011 INFO (MainThread) [homeassistant.setup] Setting up input_text
2026-01-01 19:15:42.011 INFO (MainThread) [homeassistant.setup] Setup of domain input_text took 0.00 seconds
2026-01-01 19:15:42.013 INFO (MainThread) [homeassistant.setup] Setting up backup
2026-01-01 19:15:42.016 INFO (MainThread) [homeassistant.setup] Setting up schedule
2026-01-01 19:15:42.016 INFO (MainThread) [homeassistant.setup] Setup of domain schedule took 0.00 seconds
2026-01-01 19:15:42.017 INFO (MainThread) [homeassistant.setup] Setup of domain backup took 0.00 seconds
2026-01-01 19:15:42.018 INFO (MainThread) [homeassistant.setup] Setting up input_button
2026-01-01 19:15:42.018 INFO (MainThread) [homeassistant.setup] Setup of domain input_button took 0.00 seconds
2026-01-01 19:15:42.046 WARNING (ImportExecutor_0) [homeassistant.components.light] The deprecated constant ATTR_COLOR_TEMP was used from light_preset_manager. It will be removed in HA Core 2026.1. Use kelvin equivalent (ATTR_COLOR_TEMP_KELVIN) instead, please report it to the author of the 'light_preset_manager' custom integration
2026-01-01 19:15:42.047 WARNING (ImportExecutor_0) [homeassistant.components.light] The deprecated constant ATTR_COLOR_TEMP was used from light_preset_manager. It will be removed in HA Core 2026.1. Use kelvin equivalent (ATTR_COLOR_TEMP_KELVIN) instead, please report it to the author of the 'light_preset_manager' custom integration
2026-01-01 19:15:42.060 INFO (MainThread) [homeassistant.setup] Setting up light_preset_manager
2026-01-01 19:15:42.071 INFO (MainThread) [custom_components.light_preset_manager] Light Preset Manager initialized
2026-01-01 19:15:42.071 INFO (MainThread) [homeassistant.setup] Setup of domain light_preset_manager took 0.01 seconds
2026-01-01 19:15:42.081 INFO (MainThread) [homeassistant.setup] Setting up mqtt
2026-01-01 19:15:42.081 INFO (MainThread) [homeassistant.setup] Setup of domain mqtt took 0.00 seconds
2026-01-01 19:15:42.085 INFO (MainThread) [homeassistant.setup] Setting up todo
2026-01-01 19:15:42.086 INFO (MainThread) [homeassistant.setup] Setup of domain todo took 0.00 seconds
2026-01-01 19:15:42.087 INFO (MainThread) [homeassistant.components.todo] Setting up shopping_list.todo
2026-01-01 19:15:42.108 INFO (MainThread) [homeassistant.setup] Setting up google_translate
2026-01-01 19:15:42.108 INFO (MainThread) [homeassistant.setup] Setup of domain google_translate took 0.00 seconds
2026-01-01 19:15:42.112 INFO (MainThread) [homeassistant.setup] Setting up hardware
2026-01-01 19:15:42.124 INFO (MainThread) [homeassistant.setup] Setup of domain hardware took 0.01 seconds
2026-01-01 19:15:42.176 INFO (MainThread) [homeassistant.setup] Setting up radio_browser
2026-01-01 19:15:42.176 INFO (MainThread) [homeassistant.setup] Setup of domain radio_browser took 0.00 seconds
2026-01-01 19:15:42.185 INFO (MainThread) [homeassistant.setup] Setting up analytics
2026-01-01 19:15:42.185 INFO (MainThread) [homeassistant.setup] Setup of domain analytics took 0.00 seconds
2026-01-01 19:15:42.188 INFO (MainThread) [homeassistant.setup] Setting up event
2026-01-01 19:15:42.188 INFO (MainThread) [homeassistant.setup] Setup of domain event took 0.00 seconds
2026-01-01 19:15:42.188 INFO (MainThread) [homeassistant.setup] Setting up sensor
2026-01-01 19:15:42.188 INFO (MainThread) [homeassistant.setup] Setup of domain sensor took 0.00 seconds
2026-01-01 19:15:42.189 INFO (MainThread) [homeassistant.components.event] Setting up backup.event
2026-01-01 19:15:42.190 INFO (MainThread) [homeassistant.components.sensor] Setting up backup.sensor
2026-01-01 19:15:42.230 INFO (MainThread) [homeassistant.setup] Setting up ffmpeg
2026-01-01 19:15:42.232 INFO (MainThread) [homeassistant.setup] Setup of domain ffmpeg took 0.00 seconds
2026-01-01 19:15:42.232 INFO (MainThread) [homeassistant.setup] Setting up tts
2026-01-01 19:15:42.241 INFO (MainThread) [homeassistant.setup] Setup of domain tts took 0.01 seconds
2026-01-01 19:15:42.247 INFO (MainThread) [homeassistant.components.tts] Setting up google_translate.tts
2026-01-01 19:15:43.097 INFO (MainThread) [homeassistant.setup] Setting up button
2026-01-01 19:15:43.097 INFO (MainThread) [homeassistant.setup] Setup of domain button took 0.00 seconds
2026-01-01 19:15:43.097 INFO (MainThread) [homeassistant.setup] Setting up select
2026-01-01 19:15:43.098 INFO (MainThread) [homeassistant.setup] Setup of domain select took 0.00 seconds
2026-01-01 19:15:43.098 INFO (MainThread) [homeassistant.setup] Setting up binary_sensor
2026-01-01 19:15:43.098 INFO (MainThread) [homeassistant.setup] Setup of domain binary_sensor took 0.00 seconds
2026-01-01 19:15:43.098 INFO (MainThread) [homeassistant.setup] Setting up switch
2026-01-01 19:15:43.098 INFO (MainThread) [homeassistant.setup] Setup of domain switch took 0.00 seconds
2026-01-01 19:15:43.099 INFO (MainThread) [homeassistant.setup] Setting up update
2026-01-01 19:15:43.099 INFO (MainThread) [homeassistant.setup] Setup of domain update took 0.00 seconds
2026-01-01 19:15:43.099 INFO (MainThread) [homeassistant.setup] Setting up light
2026-01-01 19:15:43.100 INFO (MainThread) [homeassistant.setup] Setup of domain light took 0.00 seconds
2026-01-01 19:15:43.102 INFO (MainThread) [homeassistant.components.scene] Setting up mqtt.scene
2026-01-01 19:15:43.102 INFO (MainThread) [homeassistant.components.button] Setting up mqtt.button
2026-01-01 19:15:43.102 INFO (MainThread) [homeassistant.components.select] Setting up mqtt.select
2026-01-01 19:15:43.103 INFO (MainThread) [homeassistant.components.binary_sensor] Setting up mqtt.binary_sensor
2026-01-01 19:15:43.103 INFO (MainThread) [homeassistant.components.switch] Setting up mqtt.switch
2026-01-01 19:15:43.103 INFO (MainThread) [homeassistant.components.update] Setting up mqtt.update
2026-01-01 19:15:43.103 INFO (MainThread) [homeassistant.components.sensor] Setting up mqtt.sensor
2026-01-01 19:15:43.103 INFO (MainThread) [homeassistant.components.light] Setting up mqtt.light
2026-01-01 19:15:43.106 INFO (MainThread) [homeassistant.bootstrap] Home Assistant initialized in 1.72s
2026-01-01 19:15:43.106 INFO (MainThread) [homeassistant.core] Starting Home Assistant 2025.12.5
2026-01-01 19:15:43.726 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_asleep_screens_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_asleep_screens"` option with `"default_entity_id": "button.WARMACHINE-PAPA_asleep_screens"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.727 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_awake_screens_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_awake_screens"` option with `"default_entity_id": "button.WARMACHINE-PAPA_awake_screens"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.727 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_veille_prolonge_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_veille_prolonge"` option with `"default_entity_id": "button.WARMACHINE-PAPA_veille_prolonge"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.728 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_play_pause_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_play_pause"` option with `"default_entity_id": "button.WARMACHINE-PAPA_play_pause"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.728 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_volume_up_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_volume_up"` option with `"default_entity_id": "button.WARMACHINE-PAPA_volume_up"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.729 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_volume_down_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_volume_down"` option with `"default_entity_id": "button.WARMACHINE-PAPA_volume_down"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.729 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_right_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_right"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_right"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.729 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_left_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_left"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_left"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.730 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_up_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_up"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_up"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.730 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_touche_down_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_touche_down"` option with `"default_entity_id": "button.WARMACHINE-PAPA_touche_down"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.731 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_alt_tab_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_alt_tab"` option with `"default_entity_id": "button.WARMACHINE-PAPA_alt_tab"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.731 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_mute_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_mute"` option with `"default_entity_id": "button.WARMACHINE-PAPA_mute"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:43.732 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity button.warmachine_papa_veille_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_veille"` option with `"default_entity_id": "button.WARMACHINE-PAPA_veille"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.041 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_chargecpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_chargecpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_chargecpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.042 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_chargegpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_chargegpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_chargegpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.042 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_temp_gpu_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_temp_gpu"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_temp_gpu"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.043 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_screen_state_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_screen_state"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_screen_state"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.043 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_status_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_status"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_status"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.044 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_full_charge_lifetime_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_full_charge_lifetime"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_full_charge_lifetime"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.045 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_remaining_percentage_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_remaining_percentage"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_remaining_percentage"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.045 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_charge_remaining_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_charge_remaining"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_charge_remaining"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.046 WARNING (MainThread) [homeassistant.components.mqtt.entity] The configuration for entity sensor.warmachine_papa_batterie_powerline_status_2 uses the deprecated option `object_id` to set the default entity id. Replace the `"object_id": "WARMACHINE-PAPA_batterie_powerline_status"` option with `"default_entity_id": "sensor.WARMACHINE-PAPA_batterie_powerline_status"` in your published discovery configuration to fix this issue, or contact the maintainer of the integration that published this config to fix this. This will stop working in Home Assistant Core 2026.4
2026-01-01 19:15:44.305 INFO (MainThread) [homeassistant.components.websocket_api.http.connection] [139775576393504] Received unknown command: recorder/info
2026-01-01 19:15:49.602 INFO (MainThread) [homeassistant.components.mqtt.client] MQTT client initialized, birth message sent
2026-01-01 19:16:30.483 INFO (MainThread) [homeassistant.components.websocket_api.http.connection] [139775576396064] Received unknown command: recorder/info
2026-01-01 19:16:35.482 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2026-01-01 19:16:38.333 DEBUG (MainThread) [custom_components.light_preset_manager] Saved preset 1 for card bureau_lightcard
2026-01-01 19:16:41.652 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2026-01-01 19:16:44.815 DEBUG (MainThread) [custom_components.light_preset_manager] Saved preset 2 for card bureau_lightcard
2026-01-01 19:16:48.408 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2026-01-01 19:16:51.549 DEBUG (MainThread) [custom_components.light_preset_manager] Saved preset 3 for card bureau_lightcard
2026-01-01 19:16:53.097 WARNING (MainThread) [homeassistant.components.light] Got `color_temp` argument in `turn_on` service, which is deprecated and will break in Home Assistant 2026.1, please use `color_temp_kelvin` argument
2026-01-01 19:16:55.879 DEBUG (MainThread) [custom_components.light_preset_manager] Saved preset 4 for card bureau_lightcard
Whitespace-only changes.
+373 -4
View File
@@ -604,7 +604,7 @@ function r5(r6) {
// src/styles.ts
var mainStyles = i`
:host {
--lpm-temp-warm-color: #ffe600ff;
--lpm-temp-warm-color: #ffae00ff;
--lpm-temp-neutral-color: #ffffff;
--lpm-temp-cold-color: #2196f3;
--lpm-temp-inactive-color: rgba(255, 255, 255, 0.5);
@@ -1001,6 +1001,68 @@ var mainStyles = i`
line-height: 1.2;
max-width: 90%;
}
/* Presets Section */
.presets-section {
margin-top: var(--lpm-padding);
padding-top: var(--lpm-padding);
border-top: 1px solid var(--divider-color);
}
.presets-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--lpm-spacing);
}
.preset-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12px 8px;
min-height: 60px;
border: none;
border-radius: var(--lpm-button-radius);
cursor: pointer;
background: var(--primary-background-color);
color: var(--primary-text-color);
transition: all var(--lpm-transition);
font-family: inherit;
gap: 4px;
}
.preset-button:hover {
background: var(--secondary-background-color);
}
.preset-button:active {
transform: scale(0.95);
}
.preset-button.has-data {
border: 1px solid var(--primary-color);
}
.preset-button.has-data .preset-icon {
color: var(--primary-color);
}
.preset-button .preset-icon {
color: var(--disabled-text-color);
}
.preset-button .preset-icon ha-icon {
--mdc-icon-size: 24px;
}
.preset-button .preset-name {
font-size: 11px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
/* Popup */
.popup-overlay {
@@ -1104,6 +1166,9 @@ function normalizeLightConfig(light) {
return { entity: light.entity, name: light.name };
}
function validateConfig(config) {
if (!config.card_id) {
throw new Error('Config error: "card_id" is required');
}
if (!config.group) {
throw new Error('Config error: "group" is required');
}
@@ -1126,6 +1191,7 @@ function validateConfig(config) {
throw new Error('Config error: "presets" must be between 1 and 4');
}
return {
card_id: config.card_id,
group: config.group,
title: config.title,
lights,
@@ -1151,6 +1217,21 @@ var supportsColorTemp = (entity) => {
const modes = entity?.attributes.supported_color_modes || [];
return modes.includes("color_temp");
};
function captureLightState(entity) {
const state = {
entity_id: entity.entity_id,
state: entity.state === "on" ? "on" : "off"
};
if (entity.state === "on") {
const { brightness, color_temp, rgb_color, xy_color, hs_color } = entity.attributes;
if (brightness !== void 0) state.brightness = brightness;
if (color_temp !== void 0) state.color_temp = color_temp;
if (rgb_color !== void 0) state.rgb_color = rgb_color;
if (xy_color !== void 0) state.xy_color = xy_color;
if (hs_color !== void 0) state.hs_color = hs_color;
}
return state;
}
function getLightsFromGroup(groupEntity, configLights) {
if (configLights.length > 0) {
return configLights;
@@ -1257,6 +1338,13 @@ function getTranslations(locale) {
// src/editor.ts
var MAIN_SCHEMA = [
{
name: "card_id",
required: true,
selector: {
text: {}
}
},
{
name: "group",
required: true,
@@ -1288,6 +1376,7 @@ var LightPresetManagerEditor = class extends i4 {
super(...arguments);
this._computeLabel = (schema) => {
const labels = {
card_id: "Card ID (required, unique)",
group: "Group (required)",
title: "Title",
presets: "Number of Presets (1-4)"
@@ -1640,13 +1729,24 @@ LightPresetManagerEditor = __decorateClass([
t3("light-preset-manager-editor")
], LightPresetManagerEditor);
console.log(
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.5.0 ",
"%c LIGHT-PRESET-MANAGER-EDITOR %c v0.6.3 ",
"background: #9b59b6; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);
// src/light-preset-manager.ts
var HOLD_DURATION = 800;
var DOUBLE_TAP_DELAY = 300;
var LightPresetManager = class extends i4 {
constructor() {
super(...arguments);
this._presets = [];
this._popup = { type: null, presetId: 0, presetName: "" };
this._lastTap = 0;
this._tapCount = 0;
this._activePresetId = 0;
this._presetsLoaded = false;
}
// ---------------------------------------------------------------------------
// Static methods for HA card editor
// ---------------------------------------------------------------------------
@@ -1655,6 +1755,7 @@ var LightPresetManager = class extends i4 {
}
static getStubConfig() {
return {
card_id: "my_lights",
group: "light.example_group",
title: "My Lights"
};
@@ -1664,10 +1765,54 @@ var LightPresetManager = class extends i4 {
// ---------------------------------------------------------------------------
setConfig(config) {
this._config = validateConfig(config);
this._presetsLoaded = false;
this._initPresets();
}
async connectedCallback() {
super.connectedCallback();
await this._subscribeToEvents();
}
disconnectedCallback() {
super.disconnectedCallback();
this._clearTimers();
this._unsubscribeFromEvents();
}
updated(changedProps) {
if (changedProps.has("hass") && this.hass) {
this._t = getTranslations(detectLocale(this.hass.language));
if (!this._presetsLoaded && this._config) {
this._loadPresetsFromHA();
}
}
}
// ---------------------------------------------------------------------------
// Event Subscription
// ---------------------------------------------------------------------------
async _subscribeToEvents() {
if (!this.hass || this._unsubscribe) return;
try {
this._unsubscribe = await this.hass.connection.subscribeEvents(
(event) => this._handlePresetEvent(event),
"light_preset_manager_preset_updated"
);
} catch (e5) {
console.error("Failed to subscribe to events:", e5);
}
}
_unsubscribeFromEvents() {
if (this._unsubscribe) {
this._unsubscribe();
this._unsubscribe = void 0;
}
}
_handlePresetEvent(event) {
if (!this._config) return;
const { card_id, preset_id, preset } = event.data;
if (card_id !== this._config.card_id) return;
const presetIndex = preset_id - 1;
if (this._presets[presetIndex]) {
this._presets[presetIndex] = preset;
this._presets = [...this._presets];
}
}
// ---------------------------------------------------------------------------
@@ -1695,6 +1840,158 @@ var LightPresetManager = class extends i4 {
return getLightsFromGroup(this._group, this._config.lights);
}
// ---------------------------------------------------------------------------
// Presets - Init/Load/Save via HA Services
// ---------------------------------------------------------------------------
_initPresets() {
if (!this._config) return;
const count = this._config.presets;
this._presets = Array.from({ length: count }, (_2, i5) => ({
id: i5 + 1,
name: `Preset ${i5 + 1}`,
lights: []
}));
}
async _loadPresetsFromHA() {
if (!this.hass || !this._config) return;
try {
const response = await this.hass.callWS({
type: "light_preset_manager/get_presets",
card_id: this._config.card_id
});
if (response.presets) {
this._presets = response.presets.slice(0, this._config.presets);
this._presetsLoaded = true;
}
} catch (e5) {
console.error("Failed to load presets from HA:", e5);
}
}
async _savePreset(presetId) {
if (!this.hass || !this._config) return;
const lightStates = [];
for (const lightConfig of this._lights) {
const entity = this.hass.states[lightConfig.entity];
if (entity) {
lightStates.push(captureLightState(entity));
}
}
try {
await this.hass.callService("light_preset_manager", "save_preset", {
card_id: this._config.card_id,
preset_id: presetId,
lights: lightStates
});
this._closePopup();
} catch (e5) {
console.error("Failed to save preset:", e5);
}
}
async _recallPreset(presetId) {
if (!this.hass || !this._config) return;
const preset = this._presets[presetId - 1];
if (!preset || !preset.lights || preset.lights.length === 0) {
console.log(`Preset ${presetId} is empty`);
return;
}
try {
await this.hass.callService("light_preset_manager", "recall_preset", {
card_id: this._config.card_id,
preset_id: presetId
});
} catch (e5) {
console.error("Failed to recall preset:", e5);
}
}
async _renamePreset(presetId, name) {
if (!this.hass || !this._config) return;
try {
await this.hass.callService("light_preset_manager", "rename_preset", {
card_id: this._config.card_id,
preset_id: presetId,
preset_name: name
});
this._closePopup();
} catch (e5) {
console.error("Failed to rename preset:", e5);
}
}
// ---------------------------------------------------------------------------
// Gesture Handling (tap / hold / double-tap)
// ---------------------------------------------------------------------------
_clearTimers() {
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = void 0;
}
if (this._tapTimer) {
clearTimeout(this._tapTimer);
this._tapTimer = void 0;
}
}
_handlePointerDown(presetId) {
this._activePresetId = presetId;
this._clearTimers();
this._holdTimer = window.setTimeout(() => {
this._showSavePopup(presetId);
this._tapCount = 0;
}, HOLD_DURATION);
}
_handlePointerUp(presetId) {
if (this._holdTimer) {
clearTimeout(this._holdTimer);
this._holdTimer = void 0;
this._tapCount++;
if (this._tapTimer) {
clearTimeout(this._tapTimer);
}
this._tapTimer = window.setTimeout(() => {
if (this._tapCount === 1) {
this._recallPreset(presetId);
} else if (this._tapCount >= 2) {
this._showRenamePopup(presetId);
}
this._tapCount = 0;
}, DOUBLE_TAP_DELAY);
}
}
_handlePointerLeave() {
this._clearTimers();
this._tapCount = 0;
}
// ---------------------------------------------------------------------------
// Popup Management
// ---------------------------------------------------------------------------
_showSavePopup(presetId) {
const preset = this._presets[presetId - 1];
this._popup = {
type: "save",
presetId,
presetName: preset?.name || `Preset ${presetId}`
};
}
_showRenamePopup(presetId) {
const preset = this._presets[presetId - 1];
this._popup = {
type: "rename",
presetId,
presetName: preset?.name || `Preset ${presetId}`
};
}
_closePopup() {
this._popup = { type: null, presetId: 0, presetName: "" };
}
_handlePopupConfirm() {
if (this._popup.type === "save") {
this._savePreset(this._popup.presetId);
} else if (this._popup.type === "rename") {
this._renamePreset(this._popup.presetId, this._popup.presetName);
}
}
_handlePopupInput(e5) {
const target = e5.target;
this._popup = { ...this._popup, presetName: target.value };
}
// ---------------------------------------------------------------------------
// Actions - Global
// ---------------------------------------------------------------------------
_togglePower() {
@@ -1761,9 +2058,11 @@ var LightPresetManager = class extends i4 {
<div class="card-content">
${this._renderMainControls()}
${this._supportsColorTemp ? this._renderGlobalTemperature() : ""}
${this._renderPresetsSection()}
${this._lights.length > 1 ? this._renderLightsPanel() : ""}
</div>
</ha-card>
${this._renderPopup()}
`;
}
_renderMainControls() {
@@ -1831,6 +2130,34 @@ var LightPresetManager = class extends i4 {
</div>
`;
}
_renderPresetsSection() {
return b2`
<div class="presets-section">
<div class="presets-grid">
${this._presets.map((preset) => this._renderPresetButton(preset))}
</div>
</div>
`;
}
_renderPresetButton(preset) {
const hasData = preset.lights && preset.lights.length > 0;
return b2`
<button
class="preset-button ${hasData ? "has-data" : ""}"
@pointerdown=${() => this._handlePointerDown(preset.id)}
@pointerup=${() => this._handlePointerUp(preset.id)}
@pointerleave=${this._handlePointerLeave}
@pointercancel=${this._handlePointerLeave}
>
<span class="preset-icon">
<ha-icon
icon="${hasData ? "mdi:lightbulb-group" : "mdi:lightbulb-group-outline"}"
></ha-icon>
</span>
<span class="preset-name">${preset.name}</span>
</button>
`;
}
_renderLightsPanel() {
return b2`
<div class="lights-panel">
@@ -1912,8 +2239,44 @@ var LightPresetManager = class extends i4 {
</div>
`;
}
_renderPopup() {
if (!this._popup.type) return A;
const t4 = this._t;
const isSave = this._popup.type === "save";
return b2`
<div class="popup-overlay" @click=${this._closePopup}>
<div class="popup-content" @click=${(e5) => e5.stopPropagation()}>
<div class="popup-title">
${isSave ? t4.popup.confirmSaveTitle : t4.popup.renameTitle}
</div>
${isSave ? b2`<div class="popup-message">
${t4.popup.confirmSaveMessage} "${this._popup.presetName}"?
</div>` : b2`<input
type="text"
class="popup-input"
.value=${this._popup.presetName}
@input=${this._handlePopupInput}
@keyup=${(e5) => e5.key === "Enter" && this._handlePopupConfirm()}
/>`}
<div class="popup-buttons">
<button class="popup-btn cancel" @click=${this._closePopup}>
${t4.popup.cancel}
</button>
<button
class="popup-btn confirm"
@click=${this._handlePopupConfirm}
>
${isSave ? t4.popup.save : t4.popup.confirm}
</button>
</div>
</div>
</div>
`;
}
getCardSize() {
return 2 + Math.ceil(this._lights.length / 2);
return 3 + Math.ceil(this._lights.length / 2);
}
};
LightPresetManager.styles = mainStyles;
@@ -1926,6 +2289,12 @@ __decorateClass([
__decorateClass([
r5()
], LightPresetManager.prototype, "_t", 2);
__decorateClass([
r5()
], LightPresetManager.prototype, "_presets", 2);
__decorateClass([
r5()
], LightPresetManager.prototype, "_popup", 2);
LightPresetManager = __decorateClass([
t3("light-preset-manager")
], LightPresetManager);
@@ -1938,7 +2307,7 @@ window.customCards.push({
documentationURL: "https://github.com/your-repo/light-preset-manager"
});
console.log(
"%c LIGHT-PRESET-MANAGER %c v0.5.3 ",
"%c LIGHT-PRESET-MANAGER %c v0.6.4 ",
"background: #3498db; color: white; font-weight: bold; border-radius: 4px 0 0 4px;",
"background: #2ecc71; color: white; border-radius: 0 4px 4px 0;"
);