Rhasspy as a service (without Docker)

In the documentation it says you can install Rhasspy in Debian,

Now you can run rhasspy from the command-line:

$ rhasspy --profile en

and access the web interface at http://localhost:12101

This is great for testing, but can Rhasspy be run headless - as a service ? Is this why all examples use Docker, even on a dedicated low powered RasPi Zero ?

Maybe I’m being obsessive here, but on a dedicated low-speed RasPi Zero Rhasspy satellite I don’t see a need for Docker or venv to sandbox applications if there is nothing else running in that machine to protect.

It is possible to run Rhasspy as a service; but there were 3 problems:

  1. shutdown and reboot operations require us to enter our sudo password at the (now non-existent) terminal. Given that this is a dedicated voice assistant satellite and not connected to the interweb, I can probably put up with authorising the user “pi” to have root privileges.
sudo visudo

at end of the file, add

pi ALL = NOPASSWD: ALL

  1. setup the service, by
sudo nano /etc/systemd/system/rhasspy.service

[Unit]
Description=Rhasspy Autostart
After=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/bin/bash -lc ‘/usr/bin/rhasspy --profile en 2>&1 | cat’
StandardOutput=inherit
StandardError=inherit
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

next tell linux to automatically start the service on reboot

sudo systemctl enable rhasspy

and we can start it now

sudo systemctl daemon-reload
sudo systemctl start rhasspy
  1. Linux system services handle stdout differently from command line. If we had used “ExecStart=rhasspy --profile en” above, we would have got “spawnerr: unknown error making dispatchers for ‘microphone’: ENXIO” errors. See Sherlock - Offline Voice Assistant project for a description

And, so far, this seems to be working for me.

Hi there,

imo running any service with root privileges is not recommended, so here’s my rhasspy.service used on a headless debian (x64) machine:

[Unit]
Description=Rhasspy Service
After=syslog.target network.target mosquitto.service

[Service]
Type=simple
# for command, see https://github.com/rhasspy/rhasspy/issues/42#issuecomment-711472505
ExecStart=/bin/bash -c 'rhasspy -p de --user-profiles /opt/rhasspy/profiles 2>&1 | cat'
WorkingDirectory=/opt/rhasspy
User=rhasspy
Group=audio
RestartSec=10
Restart=on-failure
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=rhasspy

[Install]
WantedBy=multi-user.target

User rhasspy and working dir have to be added manually, obviously, and user rhasspy is added in group audio (despite the fact no direct audio hardware is used).
Suggestions to improve it are welcome, as this also is some kind of copy/paste solution…

Agreed !
Unfortunately just pulling the power plug on a RasPi is not recommended either, as it can corrupt the SD card :frowning: But i’m not a unix GOD, so I searched for simple explanation with copy&paste code.

I note you are using syslog for StandardOutput and StandardError … but what about StandardInput ? Does your rhasspy satellite hang when you click the red [Restart] or black power button (Reboot/Shutdown System) ?

Beeing also just an ordinary user, I never missed “StandardInput”… (perhaps I somewhen in time will have to have a look at that?)
Wrt. to Restart: No problem with that, that’s the service itself. And I never tried a “Shutdown” command from within Rhasspy, which is running on my central automation machine. If there’s a need for shutdown, login via ssh is required.
But if needed, just allowing the shutdown command within a sudo environment for user rhasspy should be not to hard to configure, I guess.

@donburch @rejoe2 thanks for sharing your service files! I tried to repeat your steps on my RP where I have rhasspy installed as a deb package, but if I start it as a service it doesn’t see audio input and output:

Feb 09 15:02:32 raspberrypi rhasspy[27323]: [ERROR:2022-02-09 15:02:32,027] rhasspymicrophone_pyaudio_hermes: record
Feb 09 15:02:32 raspberrypi rhasspy[27323]: Traceback (most recent call last):
Feb 09 15:02:32 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/rhasspy-microphone-pyaudio-hermes/rhasspymicrophone_pyaudio_hermes/__init__.py", line 119, in record
Feb 09 15:02:32 raspberrypi rhasspy[27323]:     stream_callback=callback,
Feb 09 15:02:32 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/usr/local/lib/python3.7/site-packages/pyaudio.py", line 750, in open
Feb 09 15:02:32 raspberrypi rhasspy[27323]:     stream = Stream(self, *args, **kwargs)
Feb 09 15:02:32 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/usr/local/lib/python3.7/site-packages/pyaudio.py", line 441, in __init__
Feb 09 15:02:32 raspberrypi rhasspy[27323]:     self._stream = pa.open(**arguments)
Feb 09 15:02:32 raspberrypi rhasspy[27323]: OSError: [Errno -9996] Invalid input device (no default output device)



Feb 09 15:03:06 raspberrypi rhasspy[27323]: [ERROR:2022-02-09 15:03:06,229] rhasspyserver_hermes: Command '['aplay', '-q', '-t', 'wav']' returned non-zero exit status 1.
Feb 09 15:03:06 raspberrypi rhasspy[27323]: Traceback (most recent call last):
Feb 09 15:03:06 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/usr/local/lib/python3.7/site-packages/quart/app.py", line 1821, in full_dispatch_request
Feb 09 15:03:06 raspberrypi rhasspy[27323]:     result = await self.dispatch_request(request_context)
Feb 09 15:03:06 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/usr/local/lib/python3.7/site-packages/quart/app.py", line 1869, in dispatch_request
Feb 09 15:03:06 raspberrypi rhasspy[27323]:     return await handler(**request_.view_args)
Feb 09 15:03:06 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__main__.py", line 1699, in api_text_to_speech
Feb 09 15:03:06 raspberrypi rhasspy[27323]:     results = await asyncio.gather(*aws)
Feb 09 15:03:06 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__main__.py", line 1685, in speak
Feb 09 15:03:06 raspberrypi rhasspy[27323]:     say_chars_per_second=say_chars_per_second,
Feb 09 15:03:06 raspberrypi rhasspy[27323]:   File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__init__.py", line 632, in speak_sentence
Feb 09 15:03:06 raspberrypi rhasspy[27323]:     raise AudioServerException(play_response.error)
Feb 09 15:03:06 raspberrypi rhasspy[27323]: rhasspyserver_hermes.AudioServerException: Command '['aplay', '-q', '-t', 'wav']' returned non-zero exit status 1.

Here is my /etc/systemd/system/rhasspy.service:

[Unit]
Description=Rhasspy Service
After=syslog.target network.target pulseaudio.service

[Service]
Type=simple
ExecStart=/bin/bash -c 'rhasspy --profile en 2>&1 | cat'
WorkingDirectory=/home/pi
User=pi
Group=audio
RestartSec=10
Restart=on-failure
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=rhasspy

[Install]
WantedBy=multi-user.target

What did I miss?
PS: I works fine if I just start it from the shell like rhasspy --profile en

Did you also add the user to the mentionned group?

Additionally, as you are using aplay as command, you may have to make sure, rhasspy as a user is allowed to use this (I’m running headless, as already mentionned).
Perhaps you may try to start rhassy from shell using

sudo -u rhasspy --profile en

This is how I started first prior to elaborating the final service file.

Hi pbelevich, sorry for the delay replying. The short answer is that I’m not all that familiar with Rhasspy, or even linux … so no quick easy answer ;-(

I notice that you are using pyaudio, and the errors show that pyaudio is not working for rhasspy when the error was generated. I can think of a couple of possibe reasons

  1. One of the things I found in my own research is that services do not start and run with everything which is available to the command line. I think rejoe2 is likely correct that the rhasspy service might not have access to the audio device.

  2. Possibly the pyaudio service is not yet running when your Rhasspy service is started ? If so, it may be a simple matter of changing the “After=”" line in your rhasspy.service file from “pulseaudio.service” to “pyaudio.service” (or whatver the correct name is)

  3. I am using arecord (simply because it was easiest to test before installing Rhasspy), so you might like to try changing Rhasspy to use arecord instead of pyaudio. I only suggest this since (if it works for you) it will be easier than researching the other suggestions.