Da ich inzwischen dazu übergegangen bin, möglichst viele Anwendungen auf meinem Heimserver als Docker-Container laufen zu lassen, musste ich einen Weg finden, den Signal Messenger auch für Home Assistant, das mittlerweile ebenfalls in einem Docker-Container läuft, nutzen zu können. Die Installation ist im Prinzip vergleichbar mit der normalen Installation von signal-cli, jedoch weicht die Installation von Java, das für signal-cli benötigt wird, in diesem Falle ein wenig ab.
Signal Messenger auf Host System installieren
Zunächst muss man die
aktuelle Version
von signal-cli herausfinden, die sich im GitHub-Repository findet. Hat man die aktuelle Versionsnummer, gibt man den folgenden Befehl im Terminal ein, wobei "0.6.2"
durch die aktuelle Versionsnummer ersetzt werden muss (die Anführungszeichen bleiben bestehen).
$ export VERSION="0.6.2"
Anschließend lässt sich signal-cli mit den folgenden Befehlen herunterladen und installieren. ${VERSION}
wird dabei automatisch durch die oben festgelegte Versionsnummer ersetzt.
$ wget https://github.com/AsamK/signal-cli/releases/download/v"${VERSION}"/signal-cli-"${VERSION}".tar.gz
$ sudo tar xf signal-cli-"${VERSION}".tar.gz -C /opt
$ sudo ln -sf /opt/signal-cli-"${VERSION}"/bin/signal-cli /usr/local/bin/
Java installieren und einrichten
Da ich auf dem Host-System eigentlich kein Java benötige und es meiner Erfahrung nach die spätere Einbindung in den Docker-Container von Home Assistant vereinfacht, benutze ich die OpenJDK-Version von AdoptOpenJDK . Die heruntergeladene Datei muss in einem Wunschverzeichnis entpackt werden
$ tar -xf OpenJDK11U-jdk_x64_linux_hotspot_11.0.3_7.tar.gz
Anschließend muss die Java-Version noch im System registriert werden
$ export PATH=$PWD/jdk-11.0.3+7-jre/bin:$PATH
(Alternativ nur export JAVA_HOME="$PWD/jdk-11.0.3+7-jre"
(richtigen Pfad angeben))
Zuletzt kann man überprüfen, ob die Installation erfolgreich gewesen ist.
$ java -version
Signal registrieren
Zuletzt wird die Rufnummer, die für signal-cli genutzt werden soll, mit dem folgenden Befehl registriert, wobei PHONENUMBER
durch die entsprechende Rufnummer im internationalen Format (z. B. +491701234567) ersetzt werden muss. Es muss sich um eine Rufnummer handeln, auf der man Sprachanrufe oder SMS empfangen kann, da man einen Verifizierungscode empfangen können muss. Bei dem folgenden Befehl erhält man den Verifizierungscode per Sprachanruf.
$ signal-cli -u PHONENUMBER register --voice
Nach wenigen Sekunden erhält man einen Anruf auf der angegebenen Rufnummer und eine Computerstimme teilt einem den Verifizierungscode mit, den man mit dem folgenden Befehl zur Verifizierung der Rufnummer nutzt.
$ signal-cli -u PHONENUMBER verify CODE
Nun kann man mit dem folgenden Befehl testen, ob man Nachrichten verschicken kann, wobei RECIPIENT
durch die Rufnummer des Empfängers (ebenfalls im internationalen Format) ersetzt werden muss. Selbstverständlich muss es sich um eine Nummer handelt, die bereits bei Signal registriert ist.
$ signal-cli -u PHONENUMBER send -m "This is a test message" RECIPIENT
Signal in Home Assistant nutzen
Um das auf dem Host-System installierte signal-cli nun auch in einem Home Assistant Docker-Container nutzen zu können, müssen die Pfade, in denen sich signal-cli, die Konfigurationsdateien und Java befinden, in den Docker-Container von Home Assistant eingebunden werden. Bei Nutzung von docker-compose sieht das z. B. so aus:
homeassistant:
container_name: Home-Assistant
image: homeassistant/home-assistant:stable
volumes:
- /srv/docker-persist/Home Assistant:/config
- /etc/localtime:/etc/localtime:ro
- /opt/signal-cli/signal-cli-0.6.2:/opt/signalmessenger/signal-cli
- ~/.local/share/signal-cli/data:/opt/signalmessenger/data
- /srv/OpenJDK/jdk-11.0.3+7-jre:/opt/OpenJDK
restart: always
ports:
- "8123:8123"
environment:
- JAVA_HOME=/opt/OpenJDK
depends_on:
- docker-mqtt
- docker-db
Unter dem Punkt volumes
werden neben dem Verzeichnis, in dem sich Konfigurationsdateien von Home Assistant befinden (im obigen Beispiel /srv/docker-persist/Home Assistant
), drei Verzeichnisse für die Nutzung von signal-cli eingebunden:
- In dem Verzeichnis
/opt/signal-cli/signal-cli-0.6.2
befindet sich signal-cli auf dem Host. Dieses wird in meinem Fall in das Verzeichnis/opt/signalmessenger/signal-cli
im Docker-Container eingebunden. - In dem Verzeichnis
~/.local/share/signal-cli/data
befinden sich die Konfigurationsdateien von signal-cli auf dem Host System, die ich in das Verzeichnis/opt/signalmessenger/data
im Docker-Container eingebunden habe. - Java habe ich in das Verzeichnis
/srv/OpenJDK/jdk-11.0.3+7-jre
installiert und binde es in das Verzeichnis/opt/OpenJDK
im Docker-Container ein.
Zusätzlich muss Java noch innerhalb des Docker-Containers registriert werden, damit das (Docker-)System weiß, wo sich Java befindet. Dies erfolgt im Punkt environment
im obigen docker-compose.yaml.
signalmessenger custom component
Nachdem signal-cli im Docker-Container verfügbar ist, muss - sofern noch nicht geschehen - signalmessenger als custom component registriert werden. Dazu wird im Konfigurationsverzeichnis von Home Assistant im Ordner custom_components
ein neuer Ordner namens signalmessenger
angelegt. Darin wiederum werden die folgenden beiden Dateien angelegt:
__init__.py
mit dem Inhalt
"""Signal Messenger integration using signal-cli.
Place this in `<confdir>/custom_components/signalmessenger/__init__.py`
"""
def setup(hass, config):
return True
notify.py
mit dem Inhalt
"""
Signal Messenger for notify component.
Place this in `homeassistant/components/signalmessenger/notify.py`
"""
from os import path
import subprocess
import logging
import voluptuous as vol
from homeassistant.components.notify import (
ATTR_DATA, ATTR_TITLE, ATTR_TITLE_DEFAULT, PLATFORM_SCHEMA,
BaseNotificationService)
from homeassistant.const import CONF_API_KEY
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = []
_LOGGER = logging.getLogger("signalmessenger")
CONF_SENDER_NR = 'sender_nr'
CONF_RECP_NR = 'recp_nr'
CONF_GROUP = 'group'
CONF_SIGNAL_CLI_PATH = 'signal_cli_path'
CONF_SIGNAL_CONF_PATH = 'signal_conf_path'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_SENDER_NR): cv.string,
vol.Optional(CONF_RECP_NR): cv.string,
vol.Optional(CONF_GROUP): cv.string,
vol.Optional(CONF_SIGNAL_CLI_PATH): cv.string,
vol.Optional(CONF_SIGNAL_CONF_PATH): cv.string,
})
def get_service(hass, config, discovery_info=None):
"""Get the Join notification service."""
sender_nr = config.get(CONF_SENDER_NR)
recp_nr = config.get(CONF_RECP_NR)
group = config.get(CONF_GROUP)
signal_cli_path = config.get(CONF_SIGNAL_CLI_PATH)
signal_conf_path = config.get(CONF_SIGNAL_CONF_PATH)
if sender_nr is None or signal_cli_path is None:
_LOGGER.error("Please specify sender_nr and signal_cli_path")
return False
if not ((recp_nr is None) ^ (group is None)):
_LOGGER.error("Either recp_nr or group is required")
return False
return SignalNotificationService(sender_nr, recp_nr, group,
signal_cli_path, signal_conf_path)
class SignalNotificationService(BaseNotificationService):
"""Implement the notification service for Join."""
def __init__(self, sender_nr, recp_nr, group, signal_cli_path, signal_conf_path):
"""Initialize the service."""
self.sender_nr = sender_nr
self.recp_nr = recp_nr
self.group = group
self.signal_cli_path = path.join(signal_cli_path, "signal-cli")
self.signal_conf_path = signal_conf_path
def send_message(self, message="", **kwargs):
"""Send a message to a user."""
# Establish default command line arguments
mainargs = [self.signal_cli_path]
if self.signal_conf_path is not None:
mainargs.extend(['--config', self.signal_conf_path])
mainargs.extend(["-u", self.sender_nr, "send"])
if self.group is not None:
mainargs.extend(["-g", self.group])
else:
mainargs.extend([self.recp_nr])
mainargs.extend(["-m", message])
# Add any "data":{"attachments":<value>} values as attachments to send.
# Supports list to send multiple attachments at once.
if kwargs is not None:
data = kwargs.get('data',None)
if data and data.get('attachments',False):
attachments = kwargs['data']['attachments']
mainargs.append('-a')
if isinstance(attachments,str):
mainargs.append(attachments)
else:
mainargs.extend(attachments)
# Raise an Exception if something goes wrong
p = subprocess.Popen(mainargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Wait for completion
p.wait()
output, err = p.communicate()
ret = p.returncode
if ret != 0:
raise Exception("Signal Error %d: '%s'" % (ret, err))
signalmessenger notify
-Komponente in Home Assistant einrichten
Nun kann in der configuration.yaml
von Home Assistant die neue signalmessenger notify-Komponente genutzt werden. Diese hat das folgende Muster:
notify:
- name: signal_me
platform: signalmessenger
sender_nr: "+491234567890"
recp_nr: "+499876543210"
signal_cli_path: /opt/signalmessenger/signal-cli/bin
signal_conf_path: /opt/signalmessenger
- name: signal_significant_other
platform: signalmessenger
sender_nr: "+491234567890"
recp_nr: "+496789012345"
signal_cli_path: /opt/signalmessenger/signal-cli/bin
signal_conf_path: /opt/signalmessenger
name
ist der Name, der für dieentity_id
dernotify
-Komponente genutzt wird, also z. B.notify.signal_me
- die
sender_nr
ist die Nummer, auf die signal-cli im Host-System registriert wurde - pro Empfängernummer (
recp_nr
) muss ein eigenernotify
-Eintrag angelegt werden signal_cli_path
undsignal_conf_path
enthält die Angabe der Pfade, unter denen signal-cli bzw. die Konfigurationsdateien von signal-cli in den Docker-Container eingebunden wurden (siehedocker-compose.yaml
weiter oben)
Nachrichten über den Signal Messenger von Home Assistant aus versenden
Damit Home Assistant die neu eingerichtete notify
-Komponente nutzen kann, muss Home Assistant einmal neu gestartet werden. Anschließend steht die neue notify
-Komponente zur Verfügung.
Neben reinem Text ist es auch möglich, einen Anhang zu verschicken. Der Code hat dieses Muster:
- service: notify.signal_me
data:
message: >-
Hello World!
data:
attachments:
- '/path/to/image.jpg'