Using Home Assistant and Node-RED I broadcast ringing Google Home alarms and timers to other media players.
Goal
- When a Google Home alarm or timer rings broadcast it to other devices
- Have a choice between TTS or playing a MP3 file
The subflow
The function
node finds ringing alarms or timers and creates the data for the service call, it will send a message for each defined media player.
Code
const defaults = {
timer: {
items: 'timers',
name: 'timer'
},
alarm: {
items: 'alarms',
name: 'alarms'
}
}
const mediaPlayers = env.get('media_players');
const mode = env.get('mode');
let type = '';
let callService = {}
if(!msg.data || !mediaPlayers || !mode) {
return null;
}
if(mode === 'tts') {
callService = {
domain: 'tts',
service: 'google_translate_say',
data: {
entity_id: '',
message: '',
}
}
} else if (mode === 'mp3') {
if(!env.get('file')) {
return null;
}
callService = {
domain: 'media_player',
service: 'play_media',
data: {
entity_id: '',
media_content_id: env.get('file'),
media_content_type: 'music',
}
}
}
// Determine type: alarm or timer
if(typeof msg.data.new_state.attributes.timers !== 'undefined' || typeof msg.data.old_state.attributes.timers !== 'undefined' ) {
type = 'timer';
} else if (typeof msg.data.new_state.attributes.alarms !== 'undefined' || typeof msg.data.old_state.attributes.alarms !== 'undefined') {
type = 'alarm';
} else {
return null;
}
const typeValues = defaults[type];
const activeItem = (msg.data.new_state.attributes[typeValues.items] || []).find(item => item.status === 'ringing');
if (!activeItem) {
return null;
}
mediaPlayers.trim().split(/,\s*/).forEach(player => {
if(!player) return;
callService.data.entity_id = player;
if(mode === 'tts') {
const deviceName = env.get('name') || msg.data.new_state.attributes.friendly_name;
const ttsMsg = `${activeItem.label || ''} ${typeValues.name} RINGING on ${deviceName}`;
callService.data.message = ttsMsg;
}
const message = {
payload: callService
};
node.send(message);
});
// All done
node.done();
current state
node checks if the media player is currently playing, if so we won't send anything to it.
How to use
- Import the subflow in NR:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
[{"id":"6e49404c.1c055","type":"subflow","name":"Broadcast ringing","info":"","category":"","in":[{"x":60,"y":380,"wires":[{"id":"fc48508e.6d5ea"}]}],"out":[],"env":[{"name":"media_players","type":"str","value":"","ui":{"icon":"font-awesome/fa-play-circle","label":{"en-US":"Media players ids"},"type":"input","opts":{"types":["str"]}}},{"name":"mode","type":"str","value":"tts","ui":{"icon":"font-awesome/fa-bullhorn","label":{"en-US":"Mode"},"type":"select","opts":{"opts":[{"l":{"en-US":"TTS"},"v":"tts"},{"l":{"en-US":"MP3"},"v":"mp3"}]}}},{"name":"name","type":"str","value":"","ui":{"icon":"font-awesome/fa-commenting","label":{"en-US":"Device name (TTS)"},"type":"input","opts":{"types":["str"]}}},{"name":"file","type":"str","value":"","ui":{"icon":"font-awesome/fa-file-audio-o","label":{"en-US":"File path (MP3)"},"type":"input","opts":{"types":["str"]}}}],"color":"#87A980","icon":"font-awesome/fa-bullhorn"},{"id":"d5359e36.d73f5","type":"api-call-service","z":"6e49404c.1c055","name":"Service","server":"","version":1,"debugenabled":true,"service_domain":"","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":800,"y":380,"wires":[[]]},{"id":"fc48508e.6d5ea","type":"function","z":"6e49404c.1c055","name":"For ringing items create service data","func":"const defaults = {\n timer: {\n items: 'timers',\n name: 'timer'\n },\n alarm: {\n items: 'alarms',\n name: 'alarms'\n }\n}\nconst mediaPlayers = env.get('media_players');\nconst mode = env.get('mode');\nlet type = '';\nlet callService = {}\n\nif(!msg.data || !mediaPlayers || !mode) {\n return null;\n}\n\nif(mode === 'tts') {\n callService = {\n domain: 'tts',\n service: 'google_translate_say',\n data: {\n entity_id: '',\n message: '', \n }\n }\n} else if (mode === 'mp3') {\n if(!env.get('file')) {\n return null;\n }\n callService = {\n domain: 'media_player',\n service: 'play_media',\n data: {\n entity_id: '', \n media_content_id: env.get('file'),\n media_content_type: 'music',\n }\n }\n}\n\n\n// Determine type: alarm or timer\nif(typeof msg.data.new_state.attributes.timers !== 'undefined' || typeof msg.data.old_state.attributes.timers !== 'undefined' ) {\n type = 'timer';\n} else if (typeof msg.data.new_state.attributes.alarms !== 'undefined' || typeof msg.data.old_state.attributes.alarms !== 'undefined') {\n type = 'alarm';\n} else {\n return null;\n}\n\nconst typeValues = defaults[type];\nconst activeItem = (msg.data.new_state.attributes[typeValues.items] || []).find(item => item.status === 'ringing');\nif (!activeItem) {\n return null;\n}\n\n\nmediaPlayers.trim().split(/,\\s*/).forEach(player => {\n if(!player) return;\n callService.data.entity_id = player;\n if(mode === 'tts') {\n const deviceName = env.get('name') || msg.data.new_state.attributes.friendly_name;\n const ttsMsg = `${activeItem.label || ''} ${typeValues.name} RINGING on ${deviceName}`;\n callService.data.message = ttsMsg;\n }\n\n const message = {\n payload: callService\n };\n node.send(message);\n});\n\n// All done\nnode.done();\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":290,"y":380,"wires":[["e85d1223.254ac"]]},{"id":"e85d1223.254ac","type":"api-current-state","z":"6e49404c.1c055","name":"Not playing?","server":"","version":1,"outputs":2,"halt_if":"playing","halt_if_type":"str","halt_if_compare":"is_not","override_topic":false,"entity_id":"{{payload.entity_id}}","state_type":"str","state_location":"","override_payload":"none","entity_location":"","override_data":"none","blockInputOverrides":false,"x":590,"y":380,"wires":[["d5359e36.d73f5"],[]]}] - Add the subflow and connect alarm and/or timer sensors from the same device as
events_state
nodes. - Set the properties for the subflow:
Property | Description | Example |
---|---|---|
Media player ids | Comma separated list of media_player entities |
media_player.mini, media_player.hub |
Mode | TTS or MP3 | TTS |
Device name (TTS) | Overwrite name for TTS | Hub |
File path (MP3) | Path to MP3 file | /local/audio/bell.mp3 |
Related flow
Make sure to check out my other flow as well:
Top comments (0)