Fun with APIs – TTS Trivia and ‘Today in History’ Generators

I recently discovered how to use freely available APIs in NodeRED. This short guide covers how to set up a text to speech (TTS) trivia generator and a second TTS generator that reads a ‘Today in History’ event. I’ve been using both of these automations daily since configuring them.

Download – You can download a copy of all the NodeRED flow below:

(note – I used a scrubber program to hopefully make it easier to import the flow. Despite this, when I try to import it, I get an error message on all the Home Assistant nodes which are cleared when I double click on each one. If I figure out how to stop this, I’ll update the file.)

Text to speech usage:

Text to speech (TTS), when used in home automation, is usually configured to read out sensor values or relay information without user input. The drawback I’ve found for most TTS is that it can often come across as an interruption when speakers start talking out of the blue. There are so many times that I’d rather not be interrupted that I’ve limited TTS to only the most important notifications and those that occur as part of user interaction. Until recently, I was only using TTS as part of things like a bedtime routine where the next alarm and the time until the next alarm are read out when sleep mode is triggered. Since looking into freely available APIs, I’ve introduced a few new use cases for TTS.

Requirements:

Both of these automations rely on a Home Assistant and NodeRED installation. To send TTS and notifications you’ll need some type of both of those integrations implemented too. Other than that, you’ll only need to change a few things to use this code so this is perfect if you’re reasonably new to home automation and interested in learning more about NodeRED. I’ve commented each part of the code to explain how it all comes together.

Summary:

The projects I’ve described here do two things:

  1. ‘Today in History’: This automation generates a random notable event that happened on this same date in the past. A chosen media player plays a readable form of the event. The automation also sends the notable event to the person who requested the automation as a notification.
  2. Trivia: This automation grabs a random multiple choice question with four possible answers. A chosen media player then reads the question along with a list of the possible answers. The automation also sends the question and possible answers to the relevant person’s phone, without revealing the answer. Instead, the notification includes an actionable button that reveals the answer when pressed.

I’ve kept this guide pretty basic (ie. only triggering the automation via a frontend button). But in my day to day usage, I combine this with my room presence detection to have the TTS triggered wherever a user first enters the living room each day as part of a morning briefing. I prefer this type of interaction-free trigger. This way, automations happen when expected and are unlikely to interrupt you.

TTS ‘Today in History’ (Wikimedia REST API)

I’ll start with the ‘Today in History’ automation since that’s the simpler of the two. This uses the Wikimedia REST API (documented here). Check that your usage does not violate any API’s terms. Lots of APIs (like in these two cases) are provided free of charge so you shouldn’t abuse them.

This image describes the NodeRED flow used to generate a Today in History TTS event.
Today in History NodeRED flow – Generate a random notable event that happened on this same date in the past. Send the event to a chosen media player and as a notification to the person who requested it.

This NodeRED flow starts by setting a number of variables in a change node. This includes the intended audience (msg.person) and the media player (msg.entity_id) that should read the info. In NodeRED, I can pass various message properties along each flow and use them later when I need to set who to send a notification to or where to play the TTS.

It’s really easy to start detailed automations at the click of a button when a settings configuration sits at the start of an automation. Now, I have various settings files for where I want the automation to happen and who is requesting it. This eliminates the need for duplicate code that actually generates the notable event.

To use this particular API, the day and month must be in the URL of the call. To do this, I retrieve the current date from a Home Assistant sensor (sensor.time). Next, I modify it via the Date/Time formatter node, isolating just the month and date (output format set to: MM/DD). Then, I add the modified date to the formatted URL and save it under msg.url. After this, the change node just deletes a few msg properties that otherwise cause the API call to fail. The API call follows in the light green HTTP request node. The custom URL required is already set as msg.url in the incoming message so the node is left unfilled.

Following the request for the notable events from the past on this date, the automation picks a random one and formats the message in the function node. If you use a debug node to look at the full message returned, it’ll make the next few steps clear. The number of events generated on any given day varies, so I save all the returned events under a selected_articles variable. Then, I select a random one from this array and save it under the random_article variable. Since I only want the text summary and the year it happened, I save these as separate variables too.

Next, I manually add an array of possible phrases that the TTS voice could start with. This reduces the monotony of the information from day to day. The automation takes a random line from this array to start the message that the TTS will read. After this, I just save the generated event as a flow variable since it’s useful to be able to resend the last generated event.

Following the function node, the event info can go straight to a TTS node to be read. I found that it was important to use a final change node to set the format of the msg.data term for the TTS node. You could also set the message format in the call service node but in my use case I have several different types of TTS messages coming in and I wanted to use only one TTS node to make it easier to keep track of which automation sends TTS messages. I use the msg.entity_id, defined at the start in the settings config, to set the media player that the TTS is sent to. In a more detailed config, this allows me to send TTS messages to the room a given user is in based on room presence detection.

As well as sending the generated event to be read aloud, the same event is also sent to the user who requested the event. This is why the person needs to be specified at the start in the settings config (msg.person). To send the notification, I use another series of templates that feed into the final node that sends the message to the relevant person. I prefer having a change node set the various titles, messages and button functions followed by a function node that actually formats the message correctly. It’s made it easier for me to see what was being sent in each notification.

That’s pretty much it for this automation. To trigger it manually you could configure a button on the frontend to call an empty script when pressed. I’ve wired an events: all node to listen for all call_service events. This way, I can filter any incoming call_service events by looking at the msg.payload.event.service. If they match the name of the empty script that I have set up, then I know that it should trigger a specific flow. For different audiences and media players you could just set up various scripts to trigger the automation via their respective settings files. This way you can still have lots of different variations on the automation triggered quickly from the frontend.

TTS Trivia (Open Trivia Database API)

I really like this use case – it generates a random trivia question with shuffled answers. It’s fun to do together since it can be set up to send the question to multiple people without spoiling the answer for everyone.

Like my ‘Today in History’ flow, this starts with a template that specifies who the intended audience is (msg.person) and which media player the question should be read out on (msg.entity_id). To generate the trivia, I’ve made use of the Open Trivia Database API. They have thousands of questions and have made them freely accessible under a creative commons license (CC BY-SA 4.0).

This image describes the NodeRED flow used to generate a trivis TTS question.
Trivia NodeRED flow – Generate a random trivia question. Send the question and possible answers to a chosen media player and as a notification to the person who requested the trivia.

This time, I don’t need to change the URL of the HTTP request node since I use the same one each time (generated on the OTD website). The generated data is once again made into a more useable format in a function node. There’s more to do this time to jumble up the answers and have them in a list that is read aloud nicely.

I’ve commented what each part of this function node does but I’ll summarise it here too:

  1. Generate an array of incorrect and correct answers.
  2. Shuffle the list. Otherwise, the correct answer is always the last one.
  3. Add or to the penultimate place in the list and create a comma-separated string that reads as follows: “Answer 1, Answer 2, Answer 3 or Answer 4”. (A space is added after each comma and the comma directly after the or is removed).
  4. This API can generate some unwanted characters when the question contains quotes or apostrophes so I just remove these.
  5. Save all the choices under the shuffled_options variable.
  6. I found that when using TTS, the voice would read this list out very quickly instead of pausing slightly between each possible answer. To fix this, I created a new variable (suffled_options_tts) that adds a question mark to the end of each option. This way the answers list now reads: “Answer 1? Answer 2? Answer 3? or Answer 4?”. When read aloud there is a nice pause between each option.
  7. Then, I also save the question and create arrays of possible TTS starts and endings. I’ve randomised these and include one of each when generating msg.tts_message.
  8. I don’t want to include the randomised starts and ends when the trivia is sent as a notification so I save the question, possible answers and the correct answer to separate flow variables. Now, I can also resend whatever question was last generated to a different person.

Once I’ve formatted and saved the relevant parts of the question in the function node, the formatted question is sent to the chosen media player just like in the ‘Today in History’ flow. When sending the notification, I have added some new functionality. This time, the question and possible answers are sent to the relevant person but the notification has an actionable button. Pressing this will resend the message but with the answer in the place of the ‘Click here to reveal answer’ button. I use an events:all node looking for the event type: ‘mobile_app_notification_action‘ to see when someone requests the answer (this is possibly specific to the official HA Android app, I haven’t checked the iOS one). It’s important to set unique tags for each person so all requests are person-specific. I do this by appending a user’s initials to each tag.

Just like the ‘Today in History’ automation, you can trigger a trivia question from the frontend by linking a button to an empty script that is picked up by an events:all node. Each script can link to a separate settings config that will read the question on a specific media player and send the question to the relevant people. Here, I have also added the functionality to resend the most recently generated trivia question to a specific person. This way the same question can be sent to multiple people at different times. However, if a question is generated, any questions before it are no longer stored in memory.

Play TTS, start automations and send notifications

As I described earlier, including only a single node to play any TTS makes it much easier to see which flows can trigger TTS. I wire in any TTS generating flows (from just the ‘Today in History’ and trivia generators in this case) to this node via a link in node. I also do the same to recognise when any scripts have been run that should lead to a specific type of ‘Today in History’ or trivia generation. Any notifications are also wire to a single call service node for each user via link in nodes and a switch node that routes notifications. These three groups are very simple, using only a few nodes. I typically group them at the top of the page but I’ve left them till last in this explanation so that the steps leading up to this are covered first.

The TTS integration I prefer is the Microsoft one but this works just the same with any other voice, and you only need to change one node. For a different type of notification (these are set up for the official Android app), you would need to change the nodes that configure the messages that are sent and the final node that sends them too.

Image showing the NodeRED nodes that are used to play TTS, start TTS generation automations and send notifications.
Play TTS, start TTS generation automations and send notifications: NodeRED configurations for performing various TTS related actions.

General Use

Since these flows are fairly simple you can easily adapt them to suit your purpose. You can simply check through the nodes and change any instances of ‘p1’ and ‘p2’ (the example user intials) to suit your own needs. Each settings file should contain entity ids of media players that you have set up otherwise the automation won’t have anyhwere to send the generated TTS. I’ve included some comments indicated by a * with a note of what you need to change. There’s also a test node for both flows that you can configure quickly and test by injecting with the timestamp node. If you don’t want either TTS or notifications you could just remove references to whichever you don’t need and the automation should work just fine.

I use these flows alongside room presence detection as part of a morning briefing. Each person’s morning briefing is triggered when they are detected in the Living Room for the first time each day. During the briefing, they are read a quick summary of the weather for the day and also given a random ‘Today in History’ event and a trivia question. I’ve configured it so that the trivia question is the same for everyone in the morning so we can all see if we got it right. There’s a lot more that you could do with this too; it can help improve your general knowledge or the trivia flows could be fleshed out and used as a quiz for children (the trivia API I use also lets you specify certain topics). Anyway, I hope that this has been useful for you and maybe you’ll enjoy some automated trivia too.

You can find other writups I’ve done here.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top