Enhance /notify with custom emote, color, animation, sound

- /notify now accepts optional: emote, color, animation, sound
- Backend passes custom properties to status response
- Frontend handles custom sounds (chime, alert, success, etc.)
- Added new sound effects: chime, alert, success
- Updated documentation with full notify options
- Added HA automation examples for doorbell and timer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 21:50:32 -06:00
parent 942cdad5b8
commit 1ec67b4033
4 changed files with 152 additions and 14 deletions

View File

@@ -282,14 +282,63 @@
playTone(600, 0.08, "sine", 0.06);
}
function handleStateChange(newState, newEmote) {
function playChimeSound() {
// Pleasant doorbell-like chime
playTone(659, 0.15);
setTimeout(() => playTone(784, 0.15), 150);
setTimeout(() => playTone(988, 0.2), 300);
}
function playAlertSound() {
// Attention-getting alert
playTone(880, 0.1);
setTimeout(() => playTone(880, 0.1), 150);
setTimeout(() => playTone(880, 0.15), 300);
}
function playSuccessSound() {
// Triumphant success fanfare
playTone(523, 0.1);
setTimeout(() => playTone(659, 0.1), 100);
setTimeout(() => playTone(784, 0.1), 200);
setTimeout(() => playTone(1047, 0.2), 300);
}
// Play sound by name
function playSoundByName(name) {
const sounds = {
chime: playChimeSound,
alert: playAlertSound,
warning: playWarningSound,
critical: playCriticalSound,
success: playSuccessSound,
notify: playNotifySound,
recovery: playRecoverySound,
};
if (sounds[name]) {
sounds[name]();
}
}
// Track which custom sounds we've played to avoid repeats
let lastCustomSound = null;
function handleStateChange(newState, newEmote, customSound) {
// Handle custom sound from notification
if (customSound && customSound !== "none" && customSound !== lastCustomSound) {
playSoundByName(customSound);
lastCustomSound = customSound;
} else if (!customSound) {
lastCustomSound = null;
}
if (!lastState) {
lastState = newState;
return;
}
// State transitions that trigger sounds
if (newState !== lastState) {
// State transitions that trigger sounds (only if no custom sound)
if (newState !== lastState && !customSound) {
if (newState === "critical") {
playCriticalSound();
} else if (newState === "warning") {
@@ -304,8 +353,8 @@
// Recovery - also check for celebration emote
playRecoverySound();
}
lastState = newState;
}
lastState = newState;
}
// Handle tap - enable sound and show reaction
@@ -373,7 +422,7 @@
if (isReacting) return;
// Check for state changes and play sounds
handleStateChange(data.current_state, data.active_emote);
handleStateChange(data.current_state, data.active_emote, data.sound);
emoteEl.textContent = data.active_emote;
emoteEl.style.color = data.color;