41 Commits

Author SHA1 Message Date
xiaoshi
da16f27cf2 Update xiaoshi-pad-card.js 2025-11-28 12:15:39 +08:00
xiaoshi
df6a678043 Update xiaoshi-device-ha-info-card.js 2025-11-28 12:15:25 +08:00
xiaoshi
82930f4e41 Update xiaoshi-device-update-card.js 2025-11-28 12:15:06 +08:00
xiaoshi
4a2ffb628d Create xiaoshi-device-consumables-button2.js 2025-11-28 00:31:54 +08:00
xiaoshi
3d5f6028c2 Update xiaoshi-device-todo-card.js 2025-11-27 21:10:40 +08:00
xiaoshi
765b0a1367 Update README.md 2025-11-27 15:50:13 +08:00
xiaoshi
df66608d7f Update xiaoshi-pad-card.js 2025-11-27 15:47:56 +08:00
xiaoshi
6ed3bca2cc Create xiaoshi-device-consumables-button.js 2025-11-27 15:47:20 +08:00
xiaoshi
f1d0b52bd7 Update xiaoshi-pad-card.js 2025-11-27 15:46:51 +08:00
xiaoshi
528eaf1cd1 Create xiaoshi-device-ha-info-card.js 2025-11-27 15:46:02 +08:00
xiaoshi
59268a91f8 Update xiaoshi-device-consumables-card.js 2025-11-27 15:45:29 +08:00
xiaoshi
f768186379 Update xiaoshi-device-balance-card.js 2025-11-26 14:21:37 +08:00
xiaoshi
2371475eca Update xiaoshi-device-consumables-card.js 2025-11-26 14:18:03 +08:00
xiaoshi
befca5ece5 Update xiaoshi-pad-card.js 2025-11-26 14:13:44 +08:00
xiaoshi
24848db29b Update xiaoshi-device-consumables-card.js 2025-11-26 14:13:25 +08:00
xiaoshi
be232dc056 Update README.md 2025-11-26 13:06:57 +08:00
xiaoshi
96fb548262 Update README.md 2025-11-26 13:06:09 +08:00
xiaoshi
16831e5102 Update xiaoshi-pad-card.js 2025-11-26 13:04:30 +08:00
xiaoshi
b05f7de548 Update xiaoshi-device-consumables-card.js 2025-11-26 13:04:02 +08:00
xiaoshi
d8d4389549 Update xiaoshi-device-update-card.js 2025-11-26 12:07:35 +08:00
xiaoshi
bca500c945 Update xiaoshi-device-balance-card.js 2025-11-26 11:56:44 +08:00
xiaoshi
5f36835adb Update xiaoshi-pad-card.js 2025-11-26 01:00:55 +08:00
xiaoshi
05d083c259 Update README.md 2025-11-26 00:59:56 +08:00
xiaoshi
3738b0b092 Update xiaoshi-device-consumables-card.js 2025-11-25 19:51:37 +08:00
xiaoshi
87e9e68b79 Update xiaoshi-pad-card.js 2025-11-25 19:22:55 +08:00
xiaoshi
7ddd378b9a Create xiaoshi-device-consumables-card.js 2025-11-25 19:22:06 +08:00
xiaoshi
23b6e5b8a3 Update xiaoshi-device-balance-card.js 2025-11-25 19:15:23 +08:00
xiaoshi
4067518d0d Update xiaoshi-device-todo-card.js 2025-11-25 18:30:32 +08:00
xiaoshi
53e06aacf7 Update xiaoshi-device-todo-card.js 2025-11-25 13:35:29 +08:00
xiaoshi
9a59c2bb90 Create xiaoshi-device-todo-card.js 2025-11-25 13:34:43 +08:00
xiaoshi
0ae5851361 Update xiaoshi-pad-card.js 2025-11-25 13:34:07 +08:00
xiaoshi
a17033c0f0 Update README.md 2025-11-25 13:33:09 +08:00
xiaoshi
44a1d81265 Update xiaoshi-pad-card.js 2025-11-24 15:34:14 +08:00
xiaoshi
2de0668d37 Update xiaoshi-device-balance-card.js 2025-11-24 15:33:59 +08:00
xiaoshi
a03a54663b Update README.md 2025-11-24 14:59:22 +08:00
xiaoshi
6efa2864cc Update xiaoshi-pad-card.js 2025-11-24 14:56:54 +08:00
xiaoshi
f4a37ff29c Update xiaoshi-device-balance-card.js 2025-11-24 14:55:54 +08:00
xiaoshi
1c5717f5d5 Create xiaoshi-device-balance-card.js 2025-11-24 13:27:17 +08:00
xiaoshi
15fcbf0250 Update xiaoshi-pad-card.js 2025-11-24 13:25:31 +08:00
xiaoshi
de31cf6464 Update xiaoshi-pad-card.js 2025-11-24 11:38:36 +08:00
xiaoshi
9f6a31f1df Update xiaoshi-device-offline-card.js 2025-11-24 11:38:21 +08:00
10 changed files with 9325 additions and 85 deletions

View File

@@ -24,21 +24,76 @@ max: 80 # 当前地区最大值
mode: 湿度 # 【温度】或者【湿度】
~~~
## 功能2HA版本更新卡(手机平板端通用)
## 功能2HA信息卡(手机平板端通用)
**引用示例**
~~~
type: custom:xiaoshi-update-card
width: 100p%
width: 100%
skip_updates: false #是否包含已跳过的更新
theme: on
~~~
## 功能3HA离线设备卡(手机平板端通用)
**引用示例**
~~~
type: custom:xiaoshi-offline-card
width: 320px
exclude_devices:
- *设备*
exclude_entities:
- *shiti*
~~~
## 功能3电话信息余额卡(手机平板端通用)
**引用示例**
~~~
type: custom:xiaoshi-balance-card
name: 电话余额信息
width: 100%
theme: on
entities:
- entity_id: sensor.999
attribute: null
overrides:
icon: ""
name: ""
unit_of_measurement: ""
warning: ""
- entity_id: input_boolean.777
attribute: friendly_name
overrides:
name: ""
icon: ""
unit_of_measurement: ""
warning: "99"
~~~
## 功能4待办事项卡(手机平板端通用)
**引用示例**
~~~
type: custom:xiaoshi-todo-card
width: 100%
theme: on
entities:
- todo.kuai_di
- todo.ji_shi_ben
~~~
## 功能5耗材信息卡片(手机平板端通用)
**引用示例**
~~~
type: custom:xiaoshi-consumables-card
width: 100%
global_warning: <8
columns: "2"
entities:
- entity_id: input_text.aaa
overrides:
name: 奥斯卡德拉萨达实打实实打实
unit_of_measurement: "%"
warning: <10
conversion: "*2"
icon: ""
- entity_id: input_text.aaa1
- entity_id: input_text.aaa2
- entity_id: input_text.aaa3
- entity_id: input_text.aaa4
- entity_id: input_text.aaa5
- entity_id: input_text.aaa6
- entity_id: input_text.aaa7
~~~

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -425,6 +425,12 @@ export class XiaoshiOfflineCard extends LitElement {
const offlineDevices = [];
// 获取设备排除模式
const excludeDevicePatterns = this.config.exclude_devices || [];
// 记录被排除的设备ID集合
const excludedDeviceIds = new Set();
// 并行检查所有设备
const deviceChecks = devices.map(device => {
const deviceEntities = entitiesByDevice[device.id] || [];
@@ -435,12 +441,6 @@ export class XiaoshiOfflineCard extends LitElement {
};
});
// 获取设备排除模式
const excludeDevicePatterns = this.config.exclude_devices || [];
// 记录被排除的设备ID集合
const excludedDeviceIds = new Set();
// 过滤离线设备并构建数据
deviceChecks.forEach(({ device, deviceEntities, isOffline }) => {
if (isOffline) {
@@ -453,17 +453,26 @@ export class XiaoshiOfflineCard extends LitElement {
return; // 跳过匹配排除模式的设备
}
// 再次确保设备有有效实体
const validEntities = deviceEntities.filter(entityReg => {
const entity = entityMap[entityReg.entity_id];
return entity && !entityReg.disabled_by;
});
// 只有当设备有有效实体时才添加到离线设备列表
if (validEntities.length > 0) {
offlineDevices.push({
device_id: device.id,
name: deviceName,
model: device.model,
manufacturer: device.manufacturer,
area_id: device.area_id,
entities: deviceEntities,
last_seen: this._getDeviceLastSeen(deviceEntities, entityMap),
icon: this._getDeviceIcon(device, deviceEntities)
entities: validEntities, // 使用有效实体而不是所有实体
last_seen: this._getDeviceLastSeen(validEntities, entityMap),
icon: this._getDeviceIcon(device, validEntities)
});
}
}
});
// 按最后看到时间排序
@@ -537,7 +546,7 @@ export class XiaoshiOfflineCard extends LitElement {
_checkDeviceAvailabilitySync(device, deviceEntities, entityMap) {
if (!deviceEntities || deviceEntities.length === 0) {
return true; // 没有实体的设备视为离线
return false; // 没有实体的设备视为离线,直接排除
}
// 检查设备的可用性状态
@@ -545,15 +554,22 @@ export class XiaoshiOfflineCard extends LitElement {
return false; // 被禁用的设备不算离线
}
// 过滤出有效的实体未被禁用且在entityMap中存在
const validEntities = deviceEntities.filter(entityReg => {
const entity = entityMap[entityReg.entity_id];
return entity && !entityReg.disabled_by;
});
// 如果没有有效实体,则不视为离线设备,直接排除
if (validEntities.length === 0) {
return false;
}
let hasAvailableEntity = false;
let hasUnavailableEntity = false;
for (const entityReg of deviceEntities) {
for (const entityReg of validEntities) {
const entity = entityMap[entityReg.entity_id];
if (!entity) continue;
// 跳过被禁用的实体
if (entityReg.disabled_by) continue;
if (entity.state !== 'unavailable' ) {
hasAvailableEntity = true;
@@ -563,7 +579,7 @@ export class XiaoshiOfflineCard extends LitElement {
}
}
// 如果设备有实体但所有实体都不可用,则设备离线
// 如果设备有有效实体但所有实体都不可用,则设备离线
return hasUnavailableEntity && !hasAvailableEntity;
}

1305
xiaoshi-device-todo-card.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -68,6 +68,19 @@ class XiaoshiUpdateCardEditor extends LitElement {
</select>
</div>
<div class="form-group">
<label>
<input
type="checkbox"
@change=${this._entityChanged}
.checked=${this.config.skip_updates !== false}
name="skip_updates"
/>
包含已跳过的更新
</label>
<div class="help-text">如果勾选,将包含标记为跳过的版本更新</div>
</div>
</div>
@@ -75,10 +88,17 @@ class XiaoshiUpdateCardEditor extends LitElement {
}
_entityChanged(e) {
const { name, value } = e.target;
if (!value && name !== 'theme' && name !== 'width') return;
const { name, value, type, checked } = e.target;
let finalValue = value;
let finalValue;
// 处理复选框
if (type === 'checkbox') {
finalValue = checked;
} else {
if (!value && name !== 'theme' && name !== 'width') return;
finalValue = value;
}
// 处理不同字段的默认值
if (name === 'width') {
@@ -139,7 +159,6 @@ export class XiaoshiUpdateCard extends LitElement {
align-items: center;
padding: 16px;
background: var(--bg-color, #fff);
border-radius: 12px;
}
@@ -169,7 +188,6 @@ export class XiaoshiUpdateCard extends LitElement {
display: flex;
align-items: center;
justify-content: center;
}
/*标题统计数字*/
@@ -251,7 +269,8 @@ export class XiaoshiUpdateCard extends LitElement {
align-items: center;
padding: 0px;
border-bottom: 1px solid rgb(150,150,150,0.2);
margin: 0 24px 8px 32px;
margin: 0 32px 4px 32px;
padding: 4px 0 0 0;
}
/*设备、实体明细背景*/
@@ -259,7 +278,7 @@ export class XiaoshiUpdateCard extends LitElement {
flex: 1;
overflow-y: auto;
min-height: 0;
padding: 0 0 8px 0;
padding: 4px 0;
}
.device-icon {
@@ -274,7 +293,7 @@ export class XiaoshiUpdateCard extends LitElement {
.device-name {
font-weight: 500;
color: var(--fg-color, #000);
margin-bottom: 4px;
margin: 2px 0;
}
.device-entity {
@@ -286,7 +305,6 @@ export class XiaoshiUpdateCard extends LitElement {
.device-details {
font-size: 10px;
color: var(--fg-color, #000);
margin-top: 4px;
}
.device-last-seen {
@@ -307,13 +325,13 @@ export class XiaoshiUpdateCard extends LitElement {
.no-devices {
text-align: center;
padding: 8px 0 0 0;
padding: 8px 0;
color: var(--fg-color, #000);
}
.loading {
text-align: center;
padding: 0px;
padding: 10px 0px;
color: var(--fg-color, #000);
}
@@ -389,12 +407,12 @@ export class XiaoshiUpdateCard extends LitElement {
/* 备份信息独立容器 */
.backup-info {
padding: 4px 0 4px 16px;
margin: 0 16px 0 30px;
border-bottom: 1px solid rgb(150,150,150,0.2);
margin: 0 32px 8px 32px;
display: grid;
grid-template-columns: auto auto auto;
gap: 4px;
align-items: center;
border-bottom: 1px solid rgb(150,150,150,0.2);
}
`;
}
@@ -449,6 +467,17 @@ export class XiaoshiUpdateCard extends LitElement {
}
}
_handleEntityClick(entity) {
navigator.vibrate(50);
// 点击实体时打开实体详情页
if (entity.entity_id) {
// 使用您建议的第一种方式
const evt = new Event('hass-more-info', { composed: true });
evt.detail = { entityId: entity.entity_id };
this.dispatchEvent(evt);
}
}
async _loadUpdateData() {
if (!this.hass) return;
@@ -459,19 +488,10 @@ export class XiaoshiUpdateCard extends LitElement {
const haUpdates = [];
const otherUpdates = [];
// 获取update.开头的实体更新信息
try {
const entities = Object.values(this.hass.states);
const skipUpdates = this.config.skip_updates !== false; // 默认为true
entities.forEach(entity => {
// 筛选以update.开头的实体
@@ -484,6 +504,15 @@ export class XiaoshiUpdateCard extends LitElement {
attributes.installed_version &&
attributes.latest_version !== attributes.installed_version) {
// 如果不跳过更新检查skipped_version属性
if (!skipUpdates) {
const skippedVersion = attributes.skipped_version;
// 如果skipped_version不为null且等于latest_version则跳过此更新
if (skippedVersion !== null && skippedVersion === attributes.latest_version) {
return; // 跳过此更新
}
}
const updateData = {
name: attributes.friendly_name || entity.entity_id.replace('update.', ''),
current_version: attributes.installed_version,
@@ -493,7 +522,8 @@ export class XiaoshiUpdateCard extends LitElement {
entity_id: entity.entity_id,
title: attributes.title || '',
release_url: attributes.release_url || '',
entity_picture: attributes.entity_picture || ''
entity_picture: attributes.entity_picture || '',
skipped_version: attributes.skipped_version || null
};
// 检查是否为home_assistant开头的实体
@@ -521,15 +551,11 @@ export class XiaoshiUpdateCard extends LitElement {
this._loading = false;
}
_handleRefresh() {
this._loadUpdateData();
navigator.vibrate(50);
}
_handleUpdateClick(update) {
navigator.vibrate(50);
// 点击更新项时弹出实体详情
@@ -560,6 +586,10 @@ export class XiaoshiUpdateCard extends LitElement {
if (confirmed) {
this._executeUpdate(update);
// 延迟3秒后刷新数据给更新操作足够时间完成
setTimeout(() => {
this._loadUpdateData();
}, 1000);
}
}
@@ -765,9 +795,6 @@ export class XiaoshiUpdateCard extends LitElement {
return html`${backupElements}`;
}
render() {
if (!this.hass) {
return html`<div class="loading">等待Home Assistant连接...</div>`;
@@ -804,19 +831,9 @@ export class XiaoshiUpdateCard extends LitElement {
${this._renderHAVersionInfo()}
</div>
<!-- 备份信息 -->
<div class="section-divider">
<div class="section-title">
<span> • 备份信息</span>
</div>
</div>
<div class="backup-info">
${this._renderBackupInfo()}
</div>
<div class="devices-list">
${this._loading ?
html`<div class="loading">加载中...</div>` :
html`<div class="loading">HA版本信息加载中...</div>` :
(this._haUpdates.length === 0 && this._otherUpdates.length === 0) ?
html`<div class="no-devices">✅ 所有组件都是最新版本</div>` :
@@ -829,7 +846,7 @@ export class XiaoshiUpdateCard extends LitElement {
</div>
</div>
${this._haUpdates.map(update => html`
<div class="device-item">
<div class="device-item" @click=${() => this._handleEntityClick(update)}>
<div class="device-icon">
<ha-icon icon="${update.icon}"></ha-icon>
</div>
@@ -837,6 +854,7 @@ export class XiaoshiUpdateCard extends LitElement {
<div class="device-name">${update.name}</div>
<div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''}
</div>
</div>
<div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}>
@@ -848,12 +866,12 @@ export class XiaoshiUpdateCard extends LitElement {
${this._otherUpdates.length > 0 ? html`
<div class="section-divider">
<div class="section-title">
<span> • 加载项、卡片更新</span>
<span> • HACS更新</span>
<span class="section-count ${this._otherUpdates.length > 0 ? 'non-zero' : 'zero'}">${this._otherUpdates.length}</span>
</div>
</div>
${this._otherUpdates.map(update => html`
<div class="device-item">
<div class="device-item" @click=${() => this._handleEntityClick(update)}>
<div class="device-icon">
<ha-icon icon="${update.icon}"></ha-icon>
</div>
@@ -861,6 +879,7 @@ export class XiaoshiUpdateCard extends LitElement {
<div class="device-name">${update.name}</div>
<div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''}
</div>
</div>
<div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}>
@@ -870,6 +889,16 @@ export class XiaoshiUpdateCard extends LitElement {
`)}\n ` : ''}
`
}
</div>
<!-- 备份信息 -->
<div class="section-divider">
<div class="section-title">
<span> • 备份信息</span>
</div>
</div>
<div class="backup-info">
${this._renderBackupInfo()}
</div>
</ha-card>
`;

View File

@@ -1,7 +1,12 @@
console.info("%c 消逝卡-平板端 \n%c v 0.0.3 ", "color: red; font-weight: bold; background: black", "color: white; font-weight: bold; background: black");
console.info("%c 消逝卡-平板端 \n%c v 0.1.4 ", "color: red; font-weight: bold; background: black", "color: white; font-weight: bold; background: black");
const loadCards = async () => {
await import('./xiaoshi-pad-grid-card.js');
await import('./xiaoshi-device-balance-card.js');
await import('./xiaoshi-device-todo-card.js');
await import('./xiaoshi-device-consumables-card.js');
await import('./xiaoshi-device-consumables-button.js');
await import('./xiaoshi-device-ha-info-card.js');
await import('./xiaoshi-device-update-card.js');
await import('./xiaoshi-device-offline-card.js');
@@ -16,15 +21,27 @@ const cardConfigs = [
description: '温度分布、湿度分布'
},
{
type: 'xiaoshi-update-card',
name: '消逝卡HA更新监控卡片',
description: '显示需要更新的组件和版本',
type: 'xiaoshi-ha-info-card',
name: '消逝卡HA信息卡片',
description: '消逝卡HA信息卡片',
preview: true
},
{
type: 'xiaoshi-offline-card',
name: '消逝卡HA离线设备卡片',
description: '显示所有离线的设备和实体',
type: 'xiaoshi-balance-card',
name: '消逝电话余额卡',
description: '消逝电话余额卡',
preview: true
},
{
type: 'xiaoshi-todo-card',
name: '消逝待办事项',
description: '消逝待办事项',
preview: true
},
{
type: 'xiaoshi-consumables-card',
name: '消逝耗材统计',
description: '消逝耗材统计',
preview: true
}
];