Say a fortune - Help get kids to bed :)

Hello,

My kids love their nightly “surprise”. Once they are in bed, we press the “Night Button” (Sonoff button) and it does a few things:

  • it sets the lights (RGB but that’s not what the kids are about)
  • it speaks a little sentence in the language selected for the day (Global String Item) such as “It is now time to go to bed”

I would love to extend the system using some kinda fortune files so they don’t get bored and get a different funny quote evey day.

Sure I could write a rule and pack all of the text in there but I would rather have the quotes sourced from a text file.

Did anyone already do something that that or something in that direction ?

It is basically about fetching a random string into the “right” file. The right file being the one matching topic / language etc…

Once we have the string, the rule is trivial.

Not to be overly pedantic, but a rule is a text file.

But I know what you mean.

Probably not this specifically but how I would implement this would depend on the rules language being used. Some make it easier to read and parse text files than others. Once loaded, parsing can be as simple as splitting the String on newlines.

A fairly simple way to load a text file into a rule is to use executeCommandLine to cat the file. In JS Scripting is could be as simple as:

var rawFortunes = actions.Exec.executeCommandLine(time.Duration.ofSeconds(1), 'cat', '/path/to/fortunes/file.txt');
var fortunes = rawFortunes.split('\n');

Then you can generate a random integer between 0 and fortunes.length to select the fortune, or get fancier as needed.

Another approach could be to put everything into a .map file under transformations or creating a Map transformation in the UI. Use just an integer count for the left side of the map and your text to the right.

0=Phrase 1
1=Phrase 2
2=Phrase 3

Then your rule can generate a random number and use the Map transformation to pull the phrase to send on.

ok, that gives me a solution. If I can make a shell call, I would rather avoid loading a ton of text to keep a single line in the end. I can do some bash wizardry that will directly provide the line.
Not sure if I want to install fortune just for that but that also just what it does with a few bells and whistles.

Thanks for the pointer, I need to test that.

That works awesome ! I ended up using fortune… it is THE tool for the job…
Thanks for the hint @rlkoshak

Setup

in a shell:

sudo apt install fortune

Create a file somewhere (/usr/share/games/fortunes/ may be a good idea but you don’t have to…):

touch /etc/openhab/rules/myquotes

Add quotes in there in the format (You need a % between each quote, a newline does not cut it since fortunes MAY be multilines):

quote 1
still quote 1
%
quote2 
foo bar 
bla
%
yet another quote

then run

strfile /etc/openhab/rules/myquotes

Quick test in the shell

You can now run:

fortune /etc/openhab/rules/myquotes

It should show you a quote.

In a rule

in a .items file, add:

Switch                TestTrigger                                           "TEST"

Now in a .rules file:

rule "Fortune"
when
    Item TestTrigger changed to ON
then
    var fortune_file = "/etc/openhab/rules/myquotes"
    var fortune = executeCommandLine(Duration.ofSeconds(1), "/usr/games/fortune", fortune_file);
    logInfo("Fortune", "{}", fortune)

    TestTrigger.sendCommand(OFF)
end

Some comments

The nice thing with the solution is that you now (almost) only need to edit your fortune file.
The run of strfile /etc/openhab/rules/myquotes could be done using a file watcher or a system cron, which reeduce the need to access the console.

I want to point something out in case you were not aware and for future readers of the thread.

In OH 3+ you can manually run rules, even if they are file based rules.

  • On the karaf console openhab:script <name of .rules file>-<rule number in file>. For example if the file is named “foo.rules” and the rule to run is the third defined rule in the file openhab:script foo-3 will run the rule.

  • In MainUI navigate to Settings → Rules → Fortune and click/tap the triangular play icon at the top.

  • Through the REST API at the /rules/{ruleUID}/runnow API endpoint.

  • Many rules languages (including Blockly and basic UI Rules) have a run rule Action that can be used to run another rule.

  • In MainUI from the developer sidebar you can create/access a special Script called “-Scratchpad-”. As the name implies, this is intended to be a quick way to experiment with some rules code to figure out how to do something, interact with your system, test your rules, etc. It’s a great place to experiment for something like this.

Given all the ways there are to trigger a rule, there really is no need to create a Test Item to trigger a rule to experiment with.

I am sure this will be controversial but do you really want to have the last thought(voice) your kids hear as they go to sleep be some computer generated voice?
I would consider you or your better half recording those fortunes and play them back so much nicer for the kids to hear a parent’s voices as the thing they subconsciously puzzle over as they drift off to sleep.

Yeah I am coming from OH2 and there are still stuff I do like I used to.
That’s a handy trick, I can get rid of that test Switch :slight_smile:

TTS is not meant to be a replacement !
I would not even record our voices, we are here with the real ones !

The fortunes come when the time comes to go to bed. The kids calm down as they want to hear what comes since they guess the language and want to hear the “fortune”.

Then comes the goodnight story and that has nothing to do with OH :slight_smile: