Hello guys,
the is a problem with sending TTS messages to speakers because if you send one message before another finished, first one will be interrupted.
Here is a Flow that sovles this problem:
So looks Subflow:
Input is
msg.payload.message - text message to speak (example: Hey, lets check the TTS queue!)
msg.payload.speaker - media entity of speaker (example: media_player.google_home_mini_livingroom)
Here is Flow
[{"id":"6f575682.81c368","type":"subflow","name":"Send to TTS","info":"","category":"","in":[{"x":65,"y":120,"wires":[{"id":"5ed64d1.143ceb4"}]}],"out":[],"env":[],"color":"#DDAA99"},{"id":"ef0df12a.430d5","type":"debug","z":"6f575682.81c368","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":905,"y":105,"wires":[]},{"id":"5ed64d1.143ceb4","type":"function","z":"6f575682.81c368","name":"Simple triggered queue","func":"// if queue doesn't exist, create it\ncontext.queue = context.queue || [];\ncontext.busy = context.busy || false;\n\n// if the msg is a trigger one release next message\nif (msg.hasOwnProperty(\"trigger\")) {\n if (context.queue.length > 0) {\n var m = context.queue.shift();\n return {payload:m};\n }\n else {\n context.busy = false;\n }\n}\nelse {\n if (context.busy) {\n // if busy add to queue\n context.queue.push(msg.payload);\n }\n else {\n // otherwise we are empty so just pass through and set busy flag\n context.busy = true;\n return msg;\n }\n}\n\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":260,"y":120,"wires":[["167e0e74.2831a2"]]},{"id":"a321ec48.9fd84","type":"function","z":"6f575682.81c368","name":"set trigger","func":"// handle the return from the exec in here \n// if all is good then set msg.trigger property to exist\nmsg.trigger = 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":210,"y":240,"wires":[["5ed64d1.143ceb4"]]},{"id":"4f7e3bd4.1641c4","type":"api-current-state","z":"6f575682.81c368","name":"Speaker IDLE?","server":"63f11f83.adf4c","version":1,"outputs":2,"halt_if":"idle","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.google_home_mini_livingroom","state_type":"str","state_location":"","override_payload":"none","entity_location":"","override_data":"none","blockInputOverrides":false,"x":680,"y":195,"wires":[["ef0df12a.430d5","bb1af182.a4b3d"],["eb3f920e.d527c"]]},{"id":"eb3f920e.d527c","type":"delay","z":"6f575682.81c368","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":660,"y":165,"wires":[["4f7e3bd4.1641c4"]]},{"id":"43aa6bd0.9375a4","type":"api-current-state","z":"6f575682.81c368","name":"Speaker OFF?","server":"63f11f83.adf4c","version":1,"outputs":2,"halt_if":"off","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.google_home_mini_livingroom","state_type":"str","state_location":"","override_payload":"none","entity_location":"","override_data":"none","blockInputOverrides":false,"x":470,"y":165,"wires":[["6c4b258a.50c4fc"],["4f7e3bd4.1641c4"]]},{"id":"6c4b258a.50c4fc","type":"delay","z":"6f575682.81c368","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":670,"y":120,"wires":[["bb1af182.a4b3d"]]},{"id":"167e0e74.2831a2","type":"delay","z":"6f575682.81c368","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":460,"y":120,"wires":[["43aa6bd0.9375a4"]]},{"id":"bb1af182.a4b3d","type":"api-call-service","z":"6f575682.81c368","name":"Google say","server":"63f11f83.adf4c","version":1,"debugenabled":false,"service_domain":"tts","service":"aaa_google_cloud_say","entityId":"","data":"{\"entity_id\":\"{{payload.speaker}}\",\"message\":\"{{payload.message}}\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":895,"y":195,"wires":[["a321ec48.9fd84"]]},{"id":"e1449c98.5f274","type":"inject","z":"6f575682.81c368","name":"Reset Queue","props":[{"p":"trigger","v":"1","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","x":115,"y":30,"wires":[["5ed64d1.143ceb4"]]},{"id":"991d20e4.095d6","type":"comment","z":"6f575682.81c368","name":"input data","info":"msg.payload.message - text message to speak\nmsg.payload.speaker - media entity of speaker","x":105,"y":75,"wires":[]},{"id":"63f11f83.adf4c","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true},{"id":"980f29c.49036d8","type":"inject","z":"2e070ed2.a68682","name":"","props":[{"p":"payload.message","v":"Hey, let's check the TTS queue!","vt":"str"},{"p":"payload.speaker","v":"media_player.google_home_mini_livingroom","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","x":140,"y":75,"wires":[["d55a17e5.e696b8"]]},{"id":"d55a17e5.e696b8","type":"subflow:6f575682.81c368","z":"2e070ed2.a68682","name":"","env":[],"x":295,"y":75,"wires":[]}]
Just inject so fast and so many times as you want
Have a nice day!
PS
I forgot to say, that if you have problem with changing of default language in Cloud TTS (mostly when using Nabu Casa Cloud), you need to change service to service_name: aaa_google_cloud_say. My config is:
tts:
- platform: google_translate
- platform: google_cloud
service_name: aaa_google_cloud_say
key_file: key.json
language: ru-RU
gender: female
voice: ru-RU-Wavenet-A
encoding: linear16
#speed: 0.9
#pitch: -2.5
gain: 5.0
profiles:
- small-bluetooth-speaker-class-device
Because of this i have here “aaa_google_cloud_say”
and not just “cloud_say”.