<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="UTF-8">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<title>Home Assistant 人员感应器卡片生成器</title>
|
<style>
|
body {
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
max-width: 800px;
|
margin: 0 auto;
|
padding: 20px;
|
background-color: #f5f5f5;
|
}
|
.container {
|
background: white;
|
padding: 30px;
|
border-radius: 10px;
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
}
|
h1 {
|
color: #333;
|
text-align: center;
|
margin-bottom: 30px;
|
}
|
.form-group {
|
margin-bottom: 20px;
|
}
|
label {
|
display: block;
|
margin-bottom: 5px;
|
font-weight: bold;
|
color: #555;
|
}
|
input[type="text"] {
|
width: 100%;
|
padding: 10px;
|
border: 2px solid #ddd;
|
border-radius: 5px;
|
font-size: 14px;
|
box-sizing: border-box;
|
}
|
input[type="text"]:focus {
|
border-color: #4CAF50;
|
outline: none;
|
}
|
.btn {
|
background-color: #4CAF50;
|
color: white;
|
padding: 12px 24px;
|
border: none;
|
border-radius: 5px;
|
cursor: pointer;
|
font-size: 16px;
|
width: 100%;
|
margin-top: 20px;
|
}
|
.btn:hover {
|
background-color: #45a049;
|
}
|
.btn:nth-child(2):hover {
|
background-color: #d32f2f !important;
|
}
|
.output {
|
margin-top: 30px;
|
padding: 20px;
|
background-color: #f9f9f9;
|
border: 1px solid #ddd;
|
border-radius: 5px;
|
display: none;
|
}
|
.output h3 {
|
margin-top: 0;
|
color: #333;
|
}
|
pre {
|
background-color: #2d3748;
|
color: #e2e8f0;
|
padding: 15px;
|
border-radius: 5px;
|
overflow-x: auto;
|
white-space: pre-wrap;
|
word-wrap: break-word;
|
}
|
.copy-btn {
|
background-color: #2196F3;
|
color: white;
|
padding: 8px 16px;
|
border: none;
|
border-radius: 3px;
|
cursor: pointer;
|
margin-top: 10px;
|
}
|
.copy-btn:hover {
|
background-color: #1976D2;
|
}
|
.help-text {
|
font-size: 12px;
|
color: #666;
|
margin-top: 5px;
|
}
|
</style>
|
</head>
|
<body>
|
<div class="container">
|
<h1>🏠 Home Assistant 人员感应器卡片生成器</h1>
|
|
<form id="yamlForm">
|
<div class="form-group">
|
<label for="roomName">卫生间名称:</label>
|
<input type="text" id="roomName" name="roomName" placeholder="例如: 男卫、女卫、主卫等" required>
|
<div class="help-text">显示在卡片顶部的房间标识</div>
|
</div>
|
|
<div class="form-group">
|
<label for="occupancySensor">有人无人触发状态实体ID:</label>
|
<input type="text" id="occupancySensor" name="occupancySensor"
|
placeholder="例如: binary_sensor.xiaomi_cn_blt_3_1magboil90c01_03_occupancy_status_p_2_1078" required>
|
<div class="help-text">二进制传感器,用于检测是否有人</div>
|
</div>
|
|
<div class="form-group">
|
<label for="illuminationSensor">光照度实体ID:</label>
|
<input type="text" id="illuminationSensor" name="illuminationSensor"
|
placeholder="例如: sensor.xiaomi_cn_blt_3_1magboil90c01_03_illumination_p_2_1005" required>
|
<div class="help-text">光照度传感器,显示当前光照强度</div>
|
</div>
|
|
<div class="form-group">
|
<label for="someoneDurationSensor">有人持续时长实体ID:</label>
|
<input type="text" id="someoneDurationSensor" name="someoneDurationSensor"
|
placeholder="例如: sensor.xiaomi_cn_blt_3_1magboil90c01_03_has_someone_duration_p_2_1081" required>
|
<div class="help-text">记录有人状态持续时间的传感器</div>
|
</div>
|
|
<div class="form-group">
|
<label for="noOneDurationSensor">无人持续时长实体ID:</label>
|
<input type="text" id="noOneDurationSensor" name="noOneDurationSensor"
|
placeholder="例如: sensor.xiaomi_cn_blt_3_1magboil90c01_03_no_one_duration_p_2_1082" required>
|
<div class="help-text">记录无人状态持续时间的传感器</div>
|
</div>
|
|
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
<button type="submit" class="btn" style="flex: 1;">🚀 生成 YAML 配置</button>
|
<button type="button" class="btn" style="flex: 1; background-color: #f44336;" onclick="clearForm()">🗑️ 清空表单</button>
|
</div>
|
</form>
|
|
<div id="output" class="output">
|
<h3>📋 生成的 YAML 配置:</h3>
|
<pre id="yamlOutput"></pre>
|
<button class="copy-btn" onclick="copyToClipboard()">📄 复制到剪贴板</button>
|
</div>
|
</div>
|
|
<script>
|
// YAML模板
|
const yamlTemplate = `type: markdown
|
content: >
|
^卫生间名称^{% if
|
is_state('^有人无人触发状态实体ID^',
|
'on') or is_state('^有人无人触发状态实体ID^',
|
'有人') %}
|
# 🔴 有人-不可用
|
{% else %}
|
# 🟢 无人-可用
|
{% endif %}
|
|
|
**光照度:** {{
|
states('^光照度实体ID^') |
|
default('未知') }} lx
|
|
{% if
|
is_state('^有人无人触发状态实体ID^',
|
'on') or is_state('^有人无人触发状态实体ID^',
|
'有人') %} **有人持续:** {% set duration =
|
states('^有人持续时长实体ID^')
|
%}{{ '未知' if duration in ['unknown', 'unavailable', ''] else duration }} {%
|
else %} **无人持续:** {% set duration =
|
states('^无人持续时长实体ID^')
|
%}{{ '未知' if duration in ['unknown', 'unavailable', ''] else duration }} {%
|
endif %}
|
card_mod:
|
style: |
|
ha-card {
|
text-align: center;
|
}
|
ha-card h1 {
|
font-size: 48px !important;
|
margin: 10px 0 !important;
|
}
|
ha-card p {
|
font-size: 18px !important;
|
margin: 5px 0 !important;
|
}
|
grid_options:
|
columns: 6
|
rows: 3`;
|
|
document.getElementById('yamlForm').addEventListener('submit', function(e) {
|
e.preventDefault();
|
|
// 获取表单数据
|
const formData = new FormData(e.target);
|
const data = Object.fromEntries(formData);
|
|
// 替换模板中的变量
|
let result = yamlTemplate;
|
result = result.replace(/\^卫生间名称\^/g, data.roomName);
|
result = result.replace(/\^有人无人触发状态实体ID\^/g, data.occupancySensor);
|
result = result.replace(/\^光照度实体ID\^/g, data.illuminationSensor);
|
result = result.replace(/\^有人持续时长实体ID\^/g, data.someoneDurationSensor);
|
result = result.replace(/\^无人持续时长实体ID\^/g, data.noOneDurationSensor);
|
|
// 显示结果
|
document.getElementById('yamlOutput').textContent = result;
|
document.getElementById('output').style.display = 'block';
|
|
// 滚动到结果区域
|
document.getElementById('output').scrollIntoView({ behavior: 'smooth' });
|
});
|
|
function clearForm() {
|
// 清空所有输入字段
|
document.getElementById('roomName').value = '';
|
document.getElementById('occupancySensor').value = '';
|
document.getElementById('illuminationSensor').value = '';
|
document.getElementById('someoneDurationSensor').value = '';
|
document.getElementById('noOneDurationSensor').value = '';
|
|
// 隐藏输出结果
|
document.getElementById('output').style.display = 'none';
|
|
// 聚焦到第一个输入框
|
document.getElementById('roomName').focus();
|
}
|
|
function copyToClipboard() {
|
const yamlText = document.getElementById('yamlOutput').textContent;
|
const btn = event.target;
|
const originalText = btn.textContent;
|
|
// 尝试使用现代 Clipboard API
|
if (navigator.clipboard && window.isSecureContext) {
|
navigator.clipboard.writeText(yamlText).then(function() {
|
// 成功复制
|
btn.textContent = '✅ 已复制!';
|
btn.style.backgroundColor = '#4CAF50';
|
|
setTimeout(function() {
|
btn.textContent = originalText;
|
btn.style.backgroundColor = '#2196F3';
|
}, 2000);
|
}).catch(function(err) {
|
console.error('复制失败:', err);
|
fallbackCopyTextToClipboard(yamlText, btn, originalText);
|
});
|
} else {
|
// 降级到传统方法
|
fallbackCopyTextToClipboard(yamlText, btn, originalText);
|
}
|
}
|
|
function fallbackCopyTextToClipboard(text, btn, originalText) {
|
// 创建临时文本区域
|
const textArea = document.createElement("textarea");
|
textArea.value = text;
|
|
// 避免滚动到底部
|
textArea.style.top = "0";
|
textArea.style.left = "0";
|
textArea.style.position = "fixed";
|
textArea.style.opacity = "0";
|
|
document.body.appendChild(textArea);
|
textArea.focus();
|
textArea.select();
|
|
try {
|
const successful = document.execCommand('copy');
|
if (successful) {
|
btn.textContent = '✅ 已复制!';
|
btn.style.backgroundColor = '#4CAF50';
|
|
setTimeout(function() {
|
btn.textContent = originalText;
|
btn.style.backgroundColor = '#2196F3';
|
}, 2000);
|
} else {
|
throw new Error('execCommand 返回 false');
|
}
|
} catch (err) {
|
console.error('降级复制也失败:', err);
|
// 显示选择文本的提示
|
alert('自动复制失败,请手动选择文本并按 Ctrl+C 复制');
|
// 选中文本让用户手动复制
|
const outputElement = document.getElementById('yamlOutput');
|
if (window.getSelection && document.createRange) {
|
const selection = window.getSelection();
|
const range = document.createRange();
|
range.selectNodeContents(outputElement);
|
selection.removeAllRanges();
|
selection.addRange(range);
|
}
|
}
|
|
document.body.removeChild(textArea);
|
}
|
|
// 预填充示例数据(可选)
|
window.addEventListener('load', function() {
|
document.getElementById('roomName').value = '男卫';
|
document.getElementById('occupancySensor').value = 'binary_sensor.xiaomi_cn_blt_3_1magboil90c01_03_occupancy_status_p_2_1078';
|
document.getElementById('illuminationSensor').value = 'sensor.xiaomi_cn_blt_3_1magboil90c01_03_illumination_p_2_1005';
|
document.getElementById('someoneDurationSensor').value = 'sensor.xiaomi_cn_blt_3_1magboil90c01_03_has_someone_duration_p_2_1081';
|
document.getElementById('noOneDurationSensor').value = 'sensor.xiaomi_cn_blt_3_1magboil90c01_03_no_one_duration_p_2_1082';
|
});
|
</script>
|
</body>
|
</html>
|