` : ''}
${this._availableModes?.hasSwingModes ? html`
-
+ ` : ''}
`)}
${(!this.config.buttons || this.config.buttons.length < 7) ? html`
@@ -871,6 +1153,19 @@ class XiaoshiPadClimateCardEditor extends LitElement {
+ ` : ''}
`)}
${(!this.config.buttons2 || this.config.buttons2.length < 7) ? html`
@@ -1019,6 +1314,34 @@ class XiaoshiPadClimateCardEditor extends LitElement {
delete this._showButtonLists[index];
}
+ // 清理该按钮的配置,并重新索引后面的配置
+ if (this.config.button_configs && this.config.button_configs.buttons) {
+ const newButtonConfigs = {};
+ Object.keys(this.config.button_configs.buttons).forEach(key => {
+ const keyIndex = parseInt(key);
+ if (keyIndex < index) {
+ // 保留索引小于被删除按钮的配置
+ newButtonConfigs[keyIndex] = this.config.button_configs.buttons[key];
+ } else if (keyIndex > index) {
+ // 将索引大于被删除按钮的配置前移
+ newButtonConfigs[keyIndex - 1] = this.config.button_configs.buttons[key];
+ }
+ // 等于的被删除按钮的配置不保留
+ });
+
+ // 更新配置
+ if (Object.keys(newButtonConfigs).length > 0) {
+ this.config.button_configs.buttons = newButtonConfigs;
+ } else {
+ // 如果没有配置了,删除整个 buttons 配置
+ delete this.config.button_configs.buttons;
+ // 如果 button_configs 为空,删除整个对象
+ if (Object.keys(this.config.button_configs).length === 0) {
+ delete this.config.button_configs;
+ }
+ }
+ }
+
this.config = {
...this.config,
buttons: buttons.length > 0 ? buttons : undefined
@@ -1042,6 +1365,34 @@ class XiaoshiPadClimateCardEditor extends LitElement {
delete this._showButton2Lists[index2];
}
+ // 清理该按钮的配置,并重新索引后面的配置
+ if (this.config.button_configs && this.config.button_configs.buttons2) {
+ const newButtonConfigs = {};
+ Object.keys(this.config.button_configs.buttons2).forEach(key => {
+ const keyIndex = parseInt(key);
+ if (keyIndex < index2) {
+ // 保留索引小于被删除按钮的配置
+ newButtonConfigs[keyIndex] = this.config.button_configs.buttons2[key];
+ } else if (keyIndex > index2) {
+ // 将索引大于被删除按钮的配置前移
+ newButtonConfigs[keyIndex - 1] = this.config.button_configs.buttons2[key];
+ }
+ // 等于的被删除按钮的配置不保留
+ });
+
+ // 更新配置
+ if (Object.keys(newButtonConfigs).length > 0) {
+ this.config.button_configs.buttons2 = newButtonConfigs;
+ } else {
+ // 如果没有配置了,删除整个 buttons2 配置
+ delete this.config.button_configs.buttons2;
+ // 如果 button_configs 为空,删除整个对象
+ if (Object.keys(this.config.button_configs).length === 0) {
+ delete this.config.button_configs;
+ }
+ }
+ }
+
this.config = {
...this.config,
buttons2: buttons2.length > 0 ? buttons2 : undefined
@@ -1213,6 +1564,364 @@ class XiaoshiPadClimateCardEditor extends LitElement {
this._fireEvent();
}
+ _toggleModeFilter(modeType) {
+ if (!this._modeFilterExpanded) {
+ this._modeFilterExpanded = {};
+ }
+ this._modeFilterExpanded[modeType] = !this._modeFilterExpanded[modeType];
+ this.requestUpdate();
+ }
+
+ _toggleModeItem(modeType, mode) {
+ if (!this._modeFilters) {
+ this._modeFilters = {};
+ }
+ if (!this._modeFilters[modeType]) {
+ this._modeFilters[modeType] = {};
+ }
+ this._modeFilters[modeType][mode] = !this._modeFilters[modeType][mode];
+
+ // 保存过滤配置到 config,只保存 false 的项
+ if (!this.config.mode_filters) {
+ this.config.mode_filters = {};
+ }
+ if (!this.config.mode_filters[modeType]) {
+ this.config.mode_filters[modeType] = {};
+ }
+
+ // 只设置为 false 的模式,不保存 true 的
+ if (this._modeFilters[modeType][mode] === false) {
+ this.config.mode_filters[modeType][mode] = false;
+ } else {
+ delete this.config.mode_filters[modeType][mode];
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _toggleShowName(modeType, mode, show) {
+ if (!this.config.mode_configs) {
+ this.config.mode_configs = {};
+ }
+ if (!this.config.mode_configs[modeType]) {
+ this.config.mode_configs[modeType] = {};
+ }
+ if (!this.config.mode_configs[modeType][mode]) {
+ this.config.mode_configs[modeType][mode] = {};
+ }
+
+ if (show) {
+ delete this.config.mode_configs[modeType][mode].show_name;
+ } else {
+ this.config.mode_configs[modeType][mode].show_name = false;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _updateCustomName(modeType, mode, name) {
+ if (!this.config.mode_configs) {
+ this.config.mode_configs = {};
+ }
+ if (!this.config.mode_configs[modeType]) {
+ this.config.mode_configs[modeType] = {};
+ }
+ if (!this.config.mode_configs[modeType][mode]) {
+ this.config.mode_configs[modeType][mode] = {};
+ }
+
+ if (name) {
+ this.config.mode_configs[modeType][mode].custom_name = name;
+ } else {
+ delete this.config.mode_configs[modeType][mode].custom_name;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _toggleShowIcon(modeType, mode, show) {
+ if (!this.config.mode_configs) {
+ this.config.mode_configs = {};
+ }
+ if (!this.config.mode_configs[modeType]) {
+ this.config.mode_configs[modeType] = {};
+ }
+ if (!this.config.mode_configs[modeType][mode]) {
+ this.config.mode_configs[modeType][mode] = {};
+ }
+
+ if (show) {
+ delete this.config.mode_configs[modeType][mode].show_icon;
+ } else {
+ this.config.mode_configs[modeType][mode].show_icon = false;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _updateCustomIcon(modeType, mode, icon) {
+ if (!this.config.mode_configs) {
+ this.config.mode_configs = {};
+ }
+ if (!this.config.mode_configs[modeType]) {
+ this.config.mode_configs[modeType] = {};
+ }
+ if (!this.config.mode_configs[modeType][mode]) {
+ this.config.mode_configs[modeType][mode] = {};
+ }
+
+ if (icon) {
+ this.config.mode_configs[modeType][mode].custom_icon = icon;
+ } else {
+ delete this.config.mode_configs[modeType][mode].custom_icon;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _toggleButtonConfig(buttonType, index) {
+ if (!this._buttonConfigExpanded) {
+ this._buttonConfigExpanded = {};
+ }
+ if (!this._buttonConfigExpanded[buttonType]) {
+ this._buttonConfigExpanded[buttonType] = {};
+ }
+ this._buttonConfigExpanded[buttonType][index] = !this._buttonConfigExpanded[buttonType][index];
+ this.requestUpdate();
+ }
+
+ _getButtonConfig(buttonType, index) {
+ if (!this.config.button_configs) {
+ return null;
+ }
+ if (!this.config.button_configs[buttonType]) {
+ return null;
+ }
+ return this.config.button_configs[buttonType][index] || {};
+ }
+
+ _updateButtonCustomName(buttonType, index, name) {
+ if (!this.config.button_configs) {
+ this.config.button_configs = {};
+ }
+ if (!this.config.button_configs[buttonType]) {
+ this.config.button_configs[buttonType] = {};
+ }
+ if (!this.config.button_configs[buttonType][index]) {
+ this.config.button_configs[buttonType][index] = {};
+ }
+
+ if (name) {
+ this.config.button_configs[buttonType][index].custom_name = name;
+ } else {
+ delete this.config.button_configs[buttonType][index].custom_name;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _updateButtonCustomIconOn(buttonType, index, icon) {
+ if (!this.config.button_configs) {
+ this.config.button_configs = {};
+ }
+ if (!this.config.button_configs[buttonType]) {
+ this.config.button_configs[buttonType] = {};
+ }
+ if (!this.config.button_configs[buttonType][index]) {
+ this.config.button_configs[buttonType][index] = {};
+ }
+
+ if (icon) {
+ this.config.button_configs[buttonType][index].custom_icon_on = icon;
+ } else {
+ delete this.config.button_configs[buttonType][index].custom_icon_on;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _updateButtonCustomIconOff(buttonType, index, icon) {
+ if (!this.config.button_configs) {
+ this.config.button_configs = {};
+ }
+ if (!this.config.button_configs[buttonType]) {
+ this.config.button_configs[buttonType] = {};
+ }
+ if (!this.config.button_configs[buttonType][index]) {
+ this.config.button_configs[buttonType][index] = {};
+ }
+
+ if (icon) {
+ this.config.button_configs[buttonType][index].custom_icon_off = icon;
+ } else {
+ delete this.config.button_configs[buttonType][index].custom_icon_off;
+ }
+
+ this._fireEvent();
+ this.requestUpdate();
+ }
+
+ _renderButtonConfig(buttonType, index) {
+ if (!this.hass) return html``;
+
+ const buttonId = buttonType === 'buttons' ? (this.config.buttons || [])[index] : (this.config.buttons2 || [])[index];
+ if (!buttonId) return html``;
+
+ const entity = this.hass.states[buttonId];
+ if (!entity) return html``;
+
+ const domain = buttonId.split('.')[0];
+ const config = this._getButtonConfig(buttonType, index) || {};
+
+ // light/switch/button 类型显示自定义名称、自定义开启图标、自定义关闭图标
+ if (['light', 'switch', 'button'].includes(domain)) {
+ return html`
+
+
+ this._updateButtonCustomName(buttonType, index, e.target.value)}
+ class="button-config-input"
+ />
+
+
+
+ this._updateButtonCustomIconOn(buttonType, index, e.target.value)}
+ class="button-config-input"
+ />
+
+
+
+ this._updateButtonCustomIconOff(buttonType, index, e.target.value)}
+ class="button-config-input"
+ />
+
+ `;
+ }
+ // select/sensor 类型只显示自定义名称
+ else if (['select', 'sensor'].includes(domain)) {
+ return html`
+
+
+ this._updateButtonCustomName(buttonType, index, e.target.value)}
+ class="button-config-input"
+ />
+
+ `;
+ }
+
+ return html``;
+ }
+
+ _renderModeFilter(modeType, title) {
+ if (!this.hass || !this.config.entity) return html``;
+ const entity = this.hass.states[this.config.entity];
+ if (!entity) return html``;
+
+ const attrs = entity.attributes;
+ let modes = [];
+ if (modeType === 'hvac_modes') modes = attrs.hvac_modes || [];
+ else if (modeType === 'fan_modes') modes = attrs.fan_modes || [];
+ else if (modeType === 'swing_modes') modes = attrs.swing_modes || [];
+ else if (modeType === 'preset_modes') modes = attrs.preset_modes || [];
+ else if (modeType === 'operation_list') modes = attrs.operation_list || [];
+
+ if (modes.length === 0) return html``;
+
+ const isExpanded = this._modeFilterExpanded?.[modeType] || false;
+ const filters = this._modeFilters?.[modeType] || {};
+ const modeConfig = this.config.mode_configs?.[modeType] || {};
+
+ // 计算选中的数量
+ const checkedCount = Object.values(filters).filter(v => v === true).length;
+ const totalCount = modes.length;
+
+ return html`
+
+
+ ${isExpanded ? html`
+
+ ${modes.map(mode => html`
+
+ `)}
+
+ ` : ''}
+
+ `;
+ }
+
_fireEvent() {
this.dispatchEvent(new CustomEvent('config-changed', {
detail: { config: this.config }
@@ -1237,6 +1946,9 @@ class XiaoshiPadClimateCardEditor extends LitElement {
this._filteredButton2Entities = {};
this._showButton2Lists = {};
this._availableModes = {};
+ this._modeFilterExpanded = {};
+ this._modeFilters = {};
+ this._buttonConfigExpanded = {};
}
updated(changedProperties) {
@@ -1371,6 +2083,8 @@ class XiaoshiPadClimateCard extends LitElement {
display: flex;
align-items: center;
justify-content: center;
+ flex-direction: column;
+ gap: 2px;
--mdc-icon-size: 20px;
}
@@ -1380,6 +2094,11 @@ class XiaoshiPadClimateCard extends LitElement {
color: var(--fg-color);
}
+ .mode-button .mode-text {
+ font-size: 10px;
+ color: var(--fg-color);
+ }
+
.mode-button.active-mode {
background: var(--active-color);
}
@@ -1388,7 +2107,7 @@ class XiaoshiPadClimateCard extends LitElement {
display: flex;
align-items: center;
justify-content: center;
- gap: 0px;
+ gap: 4px;
width: 100%;
height: 100%;
color: var(--fg-color);
@@ -1397,7 +2116,7 @@ class XiaoshiPadClimateCard extends LitElement {
}
.swing-text, .preset-text, .water-text {
- font-size: 12px;
+ font-size: 10px;
color: var(--fg-color);
}
@@ -1918,13 +2637,17 @@ _renderExtraButtons(buttonType = 1) {
else if (state === 'fan' || state === 'fan_only') activeColor = 'rgb(0,188,213)';
else if (state === 'auto') activeColor = 'rgb(147,112,219)';
- return buttonsToShow.map(buttonEntityId => {
+ const buttonConfigKey = buttonType === 1 ? 'buttons' : 'buttons2';
+
+ return buttonsToShow.map((buttonEntityId, index) => {
const entity = this.hass.states[buttonEntityId];
if (!entity) return html``;
const domain = buttonEntityId.split('.')[0];
const friendlyName = entity.attributes.friendly_name || '';
- const displayName = friendlyName.slice(0, 4);
+ const buttonConfig = this.config.button_configs?.[buttonConfigKey]?.[index] || {};
+ const customName = buttonConfig.custom_name || friendlyName;
+ const displayName = customName.slice(0, 4);
const displayValueColor = entity.state.includes('低') || entity.state.includes('少') || entity.state.includes('缺') ? 'red' : fgColor;
// 根据名称自定义图标
@@ -1946,7 +2669,11 @@ _renderExtraButtons(buttonType = 1) {
case 'light':
const isActive = entity.state === 'on';
const customIcon = _getCustomIcon(friendlyName, isActive);
- const icon = customIcon || (isActive ? 'mdi:toggle-switch' : 'mdi:toggle-switch-off');
+ const icon = buttonConfig.custom_icon_on && isActive ? buttonConfig.custom_icon_on
+ : buttonConfig.custom_icon_off && !isActive ? buttonConfig.custom_icon_off
+ : customIcon
+ ? customIcon
+ : (isActive ? 'mdi:toggle-switch' : 'mdi:toggle-switch-off');
const buttonColor = isActive ? activeColor : fgColor;
return html`
@@ -1954,7 +2681,7 @@ _renderExtraButtons(buttonType = 1) {
class="side-extra-button ${isActive ? 'active-extra' : ''}"
@click=${() => this._handleExtraButtonClick(buttonEntityId, domain)}
style="--active-color: ${buttonColor}; --bg-color: ${bgColor};"
- title="${friendlyName}"
+ title="${customName}"
>
${displayName}
@@ -1973,7 +2700,7 @@ _renderExtraButtons(buttonType = 1) {
`;
case 'button':
- const buttonIcon = 'mdi:button-pointer';
+ const buttonIcon = buttonConfig.custom_icon_on || buttonConfig.custom_icon_off || 'mdi:button-pointer';
return html`
`;
});
@@ -2131,11 +2871,23 @@ _renderExtraButtons(buttonType = 1) {
const entity = this.hass.states[this.config.entity];
const state = entity ? entity.state : 'off';
const theme = this._evaluateTheme();
+ const modeConfigs = this.config.mode_configs?.fan_modes || {};
- return fanModes.map((mode, index) => {
+ // 应用过滤器
+ const filters = this.config.mode_filters?.fan_modes || {};
+ const filteredModes = fanModes.filter(mode => filters[mode] !== false);
+
+ return filteredModes.map((mode, index) => {
const isActive = mode === currentFanMode;
let bgColor = 'rgb(0,0,0)';
-
+ const config = modeConfigs[mode] || {};
+
+ // 获取自定义配置
+ const showName = config.show_name !== false;
+ const showIcon = config.show_icon !== false;
+ const customName = config.custom_name || this._translateFanMode(mode);
+ const customIcon = config.custom_icon || 'mdi:fan';
+
if (isActive) {
if (state === 'cool') bgColor = 'rgb(33,150,243)';
else if (state === 'heat') bgColor = 'rgb(254,111,33)';
@@ -2151,13 +2903,15 @@ _renderExtraButtons(buttonType = 1) {
@click=${() => this._setFanMode(mode)}
style="--active-color: ${bgColor}; background: ${isActive ? bgColor : 'rgb(0,0,0,0)'}"
>
-
-
-
${this._translateFanMode(mode)}
+
+ ${showIcon ? html`
+
+ ` : ''}
+ ${showName ? html`${customName}` : ''}
`;
@@ -2170,11 +2924,23 @@ _renderExtraButtons(buttonType = 1) {
const entity = this.hass.states[this.config.entity];
const state = entity ? entity.state : 'off';
const theme = this._evaluateTheme();
+ const modeConfigs = this.config.mode_configs?.swing_modes || {};
- return swingModes.map(mode => {
+ // 应用过滤器
+ const filters = this.config.mode_filters?.swing_modes || {};
+ const filteredModes = swingModes.filter(mode => filters[mode] !== false);
+
+ return filteredModes.map(mode => {
const isActive = mode === currentSwingMode;
let bgColor = 'rgb(0,0,0,0)';
-
+ const config = modeConfigs[mode] || {};
+
+ // 获取自定义配置
+ const showName = config.show_name !== false;
+ const showIcon = config.show_icon !== false;
+ const customName = config.custom_name || this._translateSwingMode(mode);
+ const customIcon = config.custom_icon || this._getSwingIcon(mode);
+
if (isActive) {
if (state === 'cool') bgColor = 'rgb(33,150,243)';
else if (state === 'heat') bgColor = 'rgb(254,111,33)';
@@ -2190,8 +2956,8 @@ _renderExtraButtons(buttonType = 1) {
style="--active-color: ${bgColor}; background: ${isActive ? bgColor : 'rgb(0,0,0,0)'}"
>
-
- ${this._translateSwingMode(mode)}
+ ${showIcon ? html`` : ''}
+ ${showName ? html`${customName}` : ''}
`;
@@ -2204,11 +2970,23 @@ _renderExtraButtons(buttonType = 1) {
const entity = this.hass.states[this.config.entity];
const state = entity ? entity.state : 'off';
const theme = this._evaluateTheme();
+ const modeConfigs = this.config.mode_configs?.preset_modes || {};
- return presetModes.map(mode => {
+ // 应用过滤器
+ const filters = this.config.mode_filters?.preset_modes || {};
+ const filteredModes = presetModes.filter(mode => filters[mode] !== false);
+
+ return filteredModes.map(mode => {
const isActive = mode === currentPresetMode;
let bgColor = 'rgb(0,0,0,0)';
-
+ const config = modeConfigs[mode] || {};
+
+ // 获取自定义配置
+ const showName = config.show_name !== false;
+ const showIcon = config.show_icon !== false;
+ const customName = config.custom_name || this._translatePresetMode(mode);
+ const customIcon = config.custom_icon || this._getPresetIcon(mode);
+
if (isActive) {
if (state === 'cool') bgColor = 'rgb(33,150,243)';
else if (state === 'heat') bgColor = 'rgb(254,111,33)';
@@ -2224,8 +3002,8 @@ _renderExtraButtons(buttonType = 1) {
style="--active-color: ${bgColor}; background: ${isActive ? bgColor : 'rgb(0,0,0,0)'}"
>
-
- ${this._translatePresetMode(mode)}
+ ${showIcon ? html`` : ''}
+ ${showName ? html`${customName}` : ''}
`;
@@ -2238,11 +3016,23 @@ _renderExtraButtons(buttonType = 1) {
const entity = this.hass.states[this.config.entity];
const state = entity ? entity.state : 'off';
const theme = this._evaluateTheme();
+ const modeConfigs = this.config.mode_configs?.operation_list || {};
- return operation_list.map(mode => {
+ // 应用过滤器
+ const filters = this.config.mode_filters?.operation_list || {};
+ const filteredModes = operation_list.filter(mode => filters[mode] !== false);
+
+ return filteredModes.map(mode => {
const isActive = mode === operation_mode;
let bgColor = 'rgb(0,0,0,0)';
-
+ const config = modeConfigs[mode] || {};
+
+ // 获取自定义配置
+ const showName = config.show_name !== false;
+ const showIcon = config.show_icon !== false;
+ const customName = config.custom_name || mode;
+ const customIcon = config.custom_icon || 'mdi:water';
+
if (isActive) {
if (state === 'cool') bgColor = 'rgb(33,150,243)';
else if (state === 'heat') bgColor = 'rgb(254,111,33)';
@@ -2258,7 +3048,8 @@ _renderExtraButtons(buttonType = 1) {
style="--active-color: ${bgColor}; background: ${isActive ? bgColor : 'rgb(0,0,0,0)'}"
>
- ${mode}
+ ${showIcon ? html`` : ''}
+ ${showName ? html`${customName}` : ''}
`;