Signal Messenger mit Home Assistant Docker nutzen

signal-cli so installieren und konfigurieren, dass es von einem Home Assistant Docker-Container genutzt werden kann

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 die entity_id der notify-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 eigener notify-Eintrag angelegt werden
  • signal_cli_path und signal_conf_path enthält die Angabe der Pfade, unter denen signal-cli bzw. die Konfigurationsdateien von signal-cli in den Docker-Container eingebunden wurden (siehe docker-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.

/img/home_assistant/notify_signal.png

Signal-Nachricht über Home Assistant verschicken

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'

Die folgenden Beiträge könnten Dich auch interessieren: