Text-to-Speech in openHAB

Posted by ads' corner on Sunday, 2020-08-16
Posted in [Ansible][Linux][Openhab]

In my ongoing endeavor to improve our home, a while ago I added a notification when the washing machine and the dryer are finished. The notification is send to a Telegram channel. Over the summer vacation I added a number new ChromeCast Audio devices (Google no longer offers the Audio CC, if you need one get one now). One is placed in the kitchen. Not only can I listen to music while eating breakfast, I can also output notifications, by using the CC as an audio sink in openHAB.

To make that useful, I decided to use a Text-to-Speech system. openHAB offers a couple different TTS systems, however most of them need a cloud integration, and therefore a working Internet connection. The “Pico TTS” works standalone, and was my favorite choice for this implementation.

Installation

The default Debian installation in Raspbian does not have Pico TTS available, it’s in the non-free repository. So I had to install that first. The Ansible Playbook:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
- name: add Debian non-free signing key
  apt_key:
    url: https://ftp-master.debian.org/keys/release-10.asc
    keyring: /etc/apt/trusted.gpg.d/debian-10.gpg
    state: present

- name: add Debian non-free repository
  apt_repository:
    repo: "deb http://deb.debian.org/debian {{ ansible_distribution_release }} non-free"
    filename: "non-free"
    state: present
    update_cache: yes
  register: non_free_repository

Then install the Pico TTS package:

1
2
3
4
5
- name: Install TTS packages
  apt:
    name:
      - libttspico-utils
    state: present

And configure it in openHAB:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
- name: Set TTS settings
  lineinfile:
    dest: /etc/openhab2/services/runtime.cfg
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    state: "{{ item.state }}"
  loop:
    - { regexp: '^#? ?org.eclipse.smarthome.voice:defaultTTS=', line: 'org.eclipse.smarthome.voice:defaultTTS=PicoTTS', state: present }
    - { regexp: '^#? ?org.eclipse.smarthome.voice:defaultVoice=', line: 'org.eclipse.smarthome.voice:defaultVoice=picotts:enUS', state: present }
  notify:
    - restart openhab2

Rules

In my rules file for the washing machine and the dryer I expanded the notification a bit:

1
2
3
4
5
6
7
8
if (now.isAfter(now.withTimeAtStartOfDay.plusHours(6).plusMinutes(0)) && now.isBefore(now.withTimeAtStartOfDay.plusHours(23).plusMinutes(0))) {
    if ({{ CC_Kitchen_Audio|replace(':','_') }}_volume.state != 50) {
        {{ CC_Kitchen_Audio|replace(':','_') }}_volume.sendCommand(50)
    }
    playSound("{{ CC_Kitchen_Audio }}", "computerbeep_55.mp3")
    Thread::sleep(500)
    say("Washing machine is finished", "picotts:enUS", "{{ CC_Kitchen_Audio }}")
}

The {{ CC_Kitchen_Audio }} is replaced by Ansible with the actual details of the ChromeCast. I described the details in this blog posting.

The say() command accepts 3 parameters:

  • The text
  • The language (US english here)
  • The audio sink (the ChromeCast)

Before the text is spoken, I also output a short beep, to raise attention and activate the ChromeCast. And I set the volume to 50 percent if that is not yet the case.

Finally all of this only happens if the time is between 6 in the morning and 11 in the evening. Don’t want the system to talk in the middle of the night, if someone might sleep in the next room.


Categories: [Ansible] [Linux] [Openhab]