Kreyenborg.koeln https://www.kreyenborg.koeln/ ... die Welt von Smart-Home leicht erklärt Fri, 10 Feb 2023 09:57:43 +0000 de hourly 1 https://wordpress.org/?v=6.8 https://www.kreyenborg.koeln/wp-content/uploads/2020/05/cropped-logo_kreyenborg_transparent-32x32.png Kreyenborg.koeln https://www.kreyenborg.koeln/ 32 32 ioBroker Jarvis von Extern via Reverse-Proxy erreichbar machen https://www.kreyenborg.koeln/iobroker-jarvis-von-extern-via-reverse-proxy-erreichbar-machen/ https://www.kreyenborg.koeln/iobroker-jarvis-von-extern-via-reverse-proxy-erreichbar-machen/#respond Fri, 10 Feb 2023 09:57:14 +0000 https://www.kreyenborg.koeln/?p=3161 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 MinutenIn diesem Beitrag zeige ich Dir, wie Du von extern Zugriff auf Jarvis erhalten kannst.

Der Beitrag ioBroker Jarvis von Extern via Reverse-Proxy erreichbar machen erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 Minuten

Natürlich gibt es – wie immer – mehrere Herangehensweisen, um Jarvis von Extern zu erreichen. Ich selbst benutze sowohl die Variante per VPN (Wireguard) als auch die Variante mit einem Reverse-Proxy, der bei mir allerhand Aufgaben übernimmt.

Eins vorab: Eine Jarvis-Installation „einfach so“ freizugeben ist fahrlässig und kann im schlimmsten Falle bedeuten, das jemand von außerhalb die Kontrolle über Dein Smart-Home übernimmt!

Installation des Apache2 Reverse-Proxy

Zuvor bringen wir das System auf den aktuellen Stand:

apt update && apt upgrade -y

Danach installieren wir Apache2

sudo apt install -y apache2

Sobald Apache installiert wurde, bitte einige Anpassungen vornehmen:

Module aktivieren

sudo -s
a2enmod rewrite headers env dir mime

Modul anpassen

nano /etc/apache2/mods-available/http2.conf

und diesen Text vor dem Inhalt einfügen

# mod_http2 doesn't work with mpm_prefork
<IfModule !mpm_prefork>
Protocols h2 h2c http/1.1
H2Direct on
H2StreamMaxMemSize 5120000000
[...]

Neustart von Apache2

systemctl restart apache2.service

Standardseite von Apache kopieren und deaktivieren

cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-jarvis.conf
a2dissite 000-default.conf

vHost anpassen

nano /etc/apache2/sites-available/001-jarvis.conf

Datei öffnen, folgenden Inhalt anlegen und die hervorgehobenen Zeilen anpassen

<VirtualHost *:80>
    ServerName jarvis.domain.de
    ServerAlias jarvis.domain.de
    ServerAdmin jarvis@domain.de

    ErrorLog /var/log/apache2/jarvis_error.log
    CustomLog /var/log/apache2/jarvis_access.log combined
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =jarvis.domain.de
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

vHost aktivieren

a2ensite 001-jarvis.conf && systemctl restart apache2.service

Certbot installieren und Let’s Encrypt Zertifikate beantragen

Bevor Du den nächsten Schritt ausführst, solltest Du sicherstellen, das der Port 80 und 443 von deinem Router auf den Server durchgereicht werden, da der Certbot von Let’s Encrypt eine live Prüfung vornimmt und den Apache-Server erreichen muss.

apt install -y certbot python3-certbot-apache
certbot --apache

Nachdem das Zertifikat erstellt wurde, kannst du die Datei anpassen, damit sie für Jarvis funktioniert.

Zuerst legen wir eine Sicherheitskopie für den Fall der Fälle an.

mv /etc/apache2/sites-available/001-jarvis-le-ssl.conf /etc/apache2/sites-available/001-jarvis-le-ssl.conf.bak

Jarvis vHost mit SSL und Passwort Schutz

Datei öffnen, folgenden Inhalt anlegen und die hervorgehobenen Zeilen anpassen.

nano /etc/apache2/sites-available/001-jarvis-le-ssl.conf
<IfModule mod_ssl.c>
   SSLUseStapling on
   SSLStaplingCache shmcb:/var/run/ocsp(128000)
   <VirtualHost *:443>
      SSLCACertificateFile /etc/letsencrypt/live/jarvis.domain.de/fullchain.pem
      SSLCertificateFile /etc/letsencrypt/live/jarvis.domain.de/fullchain.pem
      SSLCertificateKeyFile /etc/letsencrypt/live/jarvis.domain.de/privkey.pem

      #######################################################################
      # For self-signed-certificates only!
      # SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
      # SSLCACertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
      # SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
      #######################################################################

      Protocols h2 h2c http/1.1
      Header add Strict-Transport-Security: "max-age=15552000;includeSubdomains"
      ServerAdmin jarvis@domain.de
      ServerName jarvis.domain.de
      ServerAlias jarvis.domain.de

      SSLEngine on
      SSLCompression off
      SSLOptions +StrictRequire
      SSLProtocol -all +TLSv1.3 +TLSv1.2
      SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
      SSLHonorCipherOrder off
      SSLSessionTickets off
      ServerSignature off
      SSLStaplingResponderTimeout 5
      SSLStaplingReturnResponderErrors off
      SSLOpenSSLConfCmd Curves X448:secp521r1:secp384r1:prime256v1
      SSLOpenSSLConfCmd ECDHParameters secp384r1
      LogLevel warn

      ErrorLog /var/log/apache2/jarvis_error.log
      CustomLog /var/log/apache2/jarvis_access.log combined

      ProxyPassMatch (.*)(\/jarvis-socket)$ "ws://10.0.0.1:8400/$1$2"
      ProxyPass / http://10.0.0.1:8400/
      ProxyPassReverse / http://10.0.0.1:8400/

      <Proxy *>
         Order deny,allow
         Allow from all
         AuthType Basic
         AuthName "Password Required"
         AuthUserFile /etc/apache2/.htpasswd
         Require valid-user
      </Proxy>
   </VirtualHost>
</IfModule>

In den Zeilen 39, 40 und 41 gibst Du die IP Deines Jarvis an, inklusive des Ports von 8400 – dies ist der direkte Port von Jarvis und umgeht den Verkehr über den Webserver des ioBroker.

In Zeile 39 wird der sogenannte WebSocket von Jarvis angesprochen. Dies ist eine „Standleitung“, die nicht abbricht – so werden alle Informationen (Status-Änderungen usw) bi-direktional ausgetauscht. Hier kannst Du auch gerne wss (WebSocketSecure) verwenden, welches aber nicht nötig ist, da der Reverse-Proxy innerhalb deines Netzwerk auch prima ohne SSL oder WSS auskommt. Der Browser wirft zwar einen Fehler, das er nicht zu wss:// verbinden kann – dies kann aber getrost ignoriert werden.

Benutzer für Jarvis im Apache anlegen

sudo htpasswd -c /etc/apache2/.htpasswd <Benutzer>

Hier wirst Du nach einem Passwort und der Wiederholung des Passworts gefragt.

Für jeden weiteren Benutzer, bitte nicht das Argument -c angeben, um die Datei nicht zu überschreiben:

sudo htpasswd /etc/apache2/.htpasswd <AndererBenutzer>

Sicherheit erhöhen und aktivieren

Hiermit erstellen wird einen 4096 Bit langen Schlüssel. Es kann bei einem Raspberry Pi in etwa 6 – 10 Minuten in Anspruch nehmen. Bei schnelleren System geht dies natürlich binnen Minuten. Auch hier bitte wieder die hervorgehobenen Zeilen anpassen.

openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
cat /etc/ssl/certs/dhparam.pem >> /etc/letsencrypt/live/jarvis.domain.de/fullchain.pem

Nun kann der Apache neu gestartet werden.

systemctl restart apache2.service

Jarvis über https aufrufen

Nachdem Du nun alle Einstellungen getätigt hast, kannst natürlich auch Jarvis von extern erreichen. Dies geschieht mit:

https://jarvis.domain.de

Nach dem Eingeben von Benutzername und Passwort wird – wenn alles richtig eingestellt und konfiguriert wurde – Jarvis geladen und Du kannst es genauso bedienen, wie in deinem Heimnetz.

Der Beitrag ioBroker Jarvis von Extern via Reverse-Proxy erreichbar machen erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/iobroker-jarvis-von-extern-via-reverse-proxy-erreichbar-machen/feed/ 0
Grafikkarte an virtuelle Maschine durchreichen https://www.kreyenborg.koeln/grafikkarte-an-virtuelle-maschine-durchreichen/ https://www.kreyenborg.koeln/grafikkarte-an-virtuelle-maschine-durchreichen/#respond Thu, 22 Dec 2022 12:48:19 +0000 https://www.kreyenborg.koeln/?p=3048 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 4 MinutenIn diesem Beitrag zeige dich Dir, wie Du in TrueNAS eine Grafikkarte an eine virtuelle Maschine durchreichen kannst.

Der Beitrag Grafikkarte an virtuelle Maschine durchreichen erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 4 Minuten

In TrueNAS hat man inzwischen die Möglichkeit, eine Grafikkarte zu einer virtuellen Maschine durchzureichen. Nach einigen Versuchen, dies zu bewerkstelligen, erschien es auf den „ersten Blick“ gar nicht so einfach, das richtige Setup zu finden, da TrueNAS selbst auch noch eine Grafikkarte für eigene Funktionen benötigt.

Somit hatte ich zu Beginn immer das Problem, das die externe Grafikkarte, welche ich gerne an eine VM durchreichen wollte, von TrueNAS belegt wurde und die interne Grafikkarte zur Verwendung in einer VM zur Verfügung stand – dies sollte genau anders herum sein.

Damit Du nun dieses Problem sehr schnell und einfach lösen kannst, folge einfach den kurzen Schritten unterhalb und schon kannst Du die externe Grafikkarte in deiner VM verwenden.

BIOS Einstellungen

Damit die externe Grafikkarte in TrueNAS durchgereicht werden kann, sind 2 BIOS-Einstellungen notwendig.

  1. Advanced -> CPU Config -> SVM Module -> enable
  2. Advanced -> AMD CBS -> IOMMU -> enable

Erkannte Grafikkarten des Systems identifizieren

Nachdem Du die BIOS-Einstellungen getätigt hast, kannst Du nach einem Neustart die installierten und erkannten Grafikkarten anzeigen lassen. Dies geschieht mit folgendem Befehl innerhalb der TrueNAS CLI:

midclt call device.get_gpus | jq

Als Ausgabe erhälst Du eine Liste, die in etwa so aussieht:

[
  {
    "addr": {
      "pci_slot": "0000:07:00.0",
      "domain": "0000",
      "bus": "07",
      "slot": "00"
    },
    "description": "NVIDIA Corporation GK106 [GeForce GTX 660]",
    "devices": [
      {
        "pci_id": "10DE:11C0",
        "pci_slot": "0000:07:00.0",
        "vm_pci_slot": "pci_0000_07_00_0"
      },
      {
        "pci_id": "10DE:0E0B",
        "pci_slot": "0000:07:00.1",
        "vm_pci_slot": "pci_0000_07_00_1"
      }
    ],
    "vendor": "NVIDIA",
    "uses_system_critical_devices": false,
    "available_to_host": false
  },
  {
    "addr": {
      "pci_slot": "0000:09:00.0",
      "domain": "0000",
      "bus": "09",
      "slot": "00"
    },
    "description": "Advanced Micro Devices, Inc. [AMD/ATI] Renoir",
    "devices": [
      {
        "pci_id": "1002:1636",
        "pci_slot": "0000:09:00.0",
        "vm_pci_slot": "pci_0000_09_00_0"
      },
      {
        "pci_id": "1002:1637",
        "pci_slot": "0000:09:00.1",
        "vm_pci_slot": "pci_0000_09_00_1"
      },
      {
        "pci_id": "1022:15DF",
        "pci_slot": "0000:09:00.2",
        "vm_pci_slot": "pci_0000_09_00_2"
      },
      {
        "pci_id": "1022:1639",
        "pci_slot": "0000:09:00.3",
        "vm_pci_slot": "pci_0000_09_00_3"
      },
      {
        "pci_id": "1022:1639",
        "pci_slot": "0000:09:00.4",
        "vm_pci_slot": "pci_0000_09_00_4"
      },
      {
        "pci_id": "1022:15E3",
        "pci_slot": "0000:09:00.6",
        "vm_pci_slot": "pci_0000_09_00_6"
      }
    ],
    "vendor": "AMD",
    "uses_system_critical_devices": false,
    "available_to_host": true
  }
]

An der Ausgabe kannst Du nun erkennen, das TrueNAS 2 Grafikkarten gefunden hat. Einmal eine NVIDIA und eine AMD. Unterhalb jeder Grafikkarte gibt es den Hinweis "available_to_host": true/false. Dies besagt, das die Grafikkarte für den Host (also TrueNAS selbst) zur Verfügung steht (true) oder nicht (false). Bei meinem System war dies kontinuierlich so, das die AMD Karte für den Host zur Verfügung stand. Dies wollte ich, wie oben bereits erwähnt, nicht. Also musste ich die Karten wechseln. Dies geht, sobald TrueNAS in die GUI gestartet hat leider nicht mehr über das Web-Interface (zumindest bei mir nicht).

Korrekte Grafikkarte durchrreichen

In der Ausgabe oberhalb habe ich 4 Zeilen (4, 13, 28 und 37) markiert – diese Zeilen beinhalten die sogenannten PCI-ID’s, die nun durch das oben aktivierte IOMMU vom BIOS kommen. Wichtig ist, die ID’s zu nutzen, die auf .0 enden! Diese werden genutzt, um TrueNAS mitzuteilen, welche ID der Grafikkarte isoliert werden soll – also die Karte, die an die VM durchgereicht werden soll. Bei mir ist dies die ID: 0000:07:00.0. Diese ID teilst Du nun dem folgenden Kommando mit:

midclt call system.advanced.update '{"isolated_gpu_pci_ids": ["0000:07:00.0"]}' | jq

Ausgabe des oberen Befehls:

{
  "id": 1,
  "consolemenu": true,
  "serialconsole": true,
  "serialport": "ttyS0",
  "serialspeed": "9600",
  "powerdaemon": false,
  "swapondrive": 2,
  "overprovision": null,
  "traceback": true,
  "advancedmode": false,
  "autotune": false,
  "debugkernel": false,
  "uploadcrash": true,
  "anonstats": true,
  "anonstats_token": "",
  "motd": "Welcome to TrueNAS",
  "boot_scrub": 7,
  "fqdn_syslog": false,
  "sed_user": "USER",
  "sysloglevel": "F_INFO",
  "syslogserver": "",
  "syslog_transport": "UDP",
  "kdump_enabled": false,
  "isolated_gpu_pci_ids": [
    "0000:07:00.0"
  ],
  "kernel_extra_options": "",
  "syslog_tls_certificate": null,
  "syslog_tls_certificate_authority": null,
  "consolemsg": false
}

Hier bestätigt TrueNAS in Zeile 26, das die GPU erfolgreich isoliert wurde. Führe hiernach bitte einen Neustart durch, damit der integrierte NVIDIA Treiber (oder andere) die Grafikkarte nicht einbindet.

Neustart und virtuelle Maschine einrichten

Nachdem Du nun das System neu gestartet hast, kannst Du dich in der Web-Oberfläche des TrueNAS anmelden, auf Virtualisierung gehen und dort zu der passenden virtuellen Maschine, die externe Grafikkarte auswählen. Dies richtest Du unter Geräte -> Hinzufügen ein. Hier ist abermals wichtig, die richtige ID zu wählen. Statt mit einem Doppelpunkt, sind die Geräte nun mit einem Unterstrich getrennt.

Richtiges PCI Gerät auswählen
Richtiges PCI Gerät auswählen

Virtuelle Maschine starten und testen

Wenn Du nun deine virtuelle Maschine startest, kann es sein, das der NVIDIA Treiber direkt zur Verfügung steht und die Grafikkarte schon erkannt wurde. Sollte der Befehl nvidia-smi nicht gefunden werden, so installierst Du zuerst den NVIDIA-Detector, der prüft, ob überhaupt eine Grafikkarte gefunden wurde.

sudo apt install nvidia-detect

Mit einem Aufruf von nvidia-detect bekommst Du als Ausgabe, welche Karte gefunden wurde und welcher Treiber am Besten geeignet ist.

user@server:~$ nvidia-detect
Detected NVIDIA GPUs:
00:06.0 VGA compatible controller [0300]: NVIDIA Corporation GK106 [GeForce GTX 660] [10de:11c0] (rev a1)

Checking card:  NVIDIA Corporation GK106 [GeForce GTX 660] (rev a1)
Your card is supported by all driver versions.
Your card is also supported by the Tesla 470 drivers series.
Your card is also supported by the Tesla 450 drivers series.
Your card is also supported by the Tesla 418 drivers series.
It is recommended to install the
    nvidia-driver
package.

Das System empfiehlt also, den nvidia-driver als Paket zu installieren, da er mit fast allen Karten kompatibel ist. Wir installieren direkt das NVIDIA-SMI Paket mit, da dies ein nützliches Tool zur Statusabfrage der Grafikkarte ist.

sudo apt install nvidia-driver && sudo apt install nvidia-smi

Nach der Installation des Treibers und SMI, kannst Du mit nvidia-smi Informationen zu deiner Grafikkarte anzeigen lassen. Auch teilt das Tool Dir mit, ob gerade GPU-Prozesse laufen oder nicht (Dies kann, wenn die GPU benutzt wird, aus einer anderen Shell ggf. besser abgefragt werden).

Ausgabe von nvidia-smi
Ausgabe von nvidia-smi

Der Beitrag Grafikkarte an virtuelle Maschine durchreichen erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/grafikkarte-an-virtuelle-maschine-durchreichen/feed/ 0
Virtuelle Maschine erreicht das Host-System nicht https://www.kreyenborg.koeln/virtuelle-maschine-erreicht-das-host-system-nicht/ https://www.kreyenborg.koeln/virtuelle-maschine-erreicht-das-host-system-nicht/#respond Wed, 21 Dec 2022 14:33:37 +0000 https://www.kreyenborg.koeln/?p=3009 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 MinutenIn diesem Beitrag zeige dich Dir, wie Du FreeNAS/TrueNAS einrichtest, damit Du mit der virtuellen Maschine den Host erreichen kannst.

Der Beitrag Virtuelle Maschine erreicht das Host-System nicht erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 Minuten

In diesem Beitrag zeige dich Dir, wie Du FreeNAS/TrueNAS einrichtest, damit Du mit der virtuellen Maschine den Host erreichen kannst, damit z.B. eine NFS-Freigabe eingebunden werden kann.

Da die virtuellen Maschinen über den sogenannten Bridge-Adapter (bro) mit dem Host kommunizieren, muss dieser zuerst richtig eingestellt werden.

Dies kannst Du entweder über die grafische Oberfläche Deines TruenAS/FreeNAS erledigen oder über die Kommando-Zeile – ich empfehle aber grundsätzlich die Eingaben über die Kommando-Zeile des Host Systems, da man hier vor dem Gerät sitzt, im Falle eines Netzwerk-Verlustes.

Konfiguration über die Konsole

br0 Adapter über das Menü einrichten

TrueNAS/FreeNAS Hauptmenü
TrueNAS/FreeNAS Hauptmenü

Hier wählst Du 1 für das Netzwerk aus. Im Nachfolgenden erscheint Deine bisherige Konfiguration. Das heisst, in dem meisten Fällen ist hier nur die Netzwerkkarte mit einer IP belegt und der Brdige-Adapter fehlt. Um dies richtig einzustellen, notiere Dir bitte die aktuelle IP Adresse der Netzwerkkarte.

Bestehende Konfiguration löschen

Als nächstes musst Du die aktuelle Konfiguration Deiner Netzwerkkarte löschen. Dies geschieht durch markieren der passenden Zeile und drücken der Taste d (delete).

Bestehende Konfiguration löschen

br0 Adapter erstellen (Bridge)

Danach erstellst Du mit n (new) ein neues Netzwerk mit dem Namen br0. Dies wird später die Netzwerk-Bridge, unter welche alle virtuellen Maschinen mit dem Host kommunizieren können.

Als Typ wählst Du Bridge und als bridge_members Deine Netzwerkkarte(n) aus. Hierüber wird dann der Netzwerk-Verkehr geleitet.

Du kannst als aliases (ipv4_dhcp auf No) Deine oben notierte IP für die Bridge eingeben oder eine IP per DHCP beziehen (ipv4_dhcp auf Yes). Ich empfehle natürlich die Verwendung der statischen IP. Bitte beachte die Subnetz-Synatx, die hier direkt mit angegeben werden muss. Beispiel: 192.168.1.100/24

br0 mit zugewiesener IP
Netzwerk Einstellungen übernehmen

Mit diesen Schritten haben wir die feste IP von Deiner Netzwerkkarte gelöst und dem Bridge-Adapter, der nun softwaregesteuert arbeitet, zugewiesen. Dies ist nötig, damit die virtuellen Maschinen auch diesen Adapter verwenden und unter eigener IP laufen können. Damit die Änderungen im System bleiben, musst Du die Eingaben in dem Fenster noch mit a (Apply) und ggf. p (persitent) bestätigen.

br0 mit richtig eingestellter IP-Adresse

Nun kannst Du sicherheitshalber das System einmal neu starten, damit sich auch die Firewall (neuere TrueNAS Scale Versionen) mit der neuen Netzwerk-Konfiguration zurechtfindet. Dies passiert im CLI Menü mit der 8.

Eingerichteten br0 Adapter der virtuellen Maschine zuweisen

Nach einem Neustart kannst Du nun via Browser Dein TrueNAS/FreeNAS erreichen und in der virtuellen Maschine als Netzwerk-Anbindung den br0 Adapter auswählen und wirst nach einem Start der Maschine feststellen, das sich eine NFS-Freigabe problemlos mounten lässt.

br0 als Auswahl der Netzwerkkarte

Konfiguration über das Web-Interface

… wird derzeit erstellt. Bitte etwas Geduld 🙂

Der Beitrag Virtuelle Maschine erreicht das Host-System nicht erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/virtuelle-maschine-erreicht-das-host-system-nicht/feed/ 0
Virtuelle Maschine bootet nur bis UEFI/startet nicht https://www.kreyenborg.koeln/virtuelle-maschine-bootet-nur-bis-uefi-startet-nicht/ https://www.kreyenborg.koeln/virtuelle-maschine-bootet-nur-bis-uefi-startet-nicht/#comments Wed, 21 Dec 2022 13:51:43 +0000 https://www.kreyenborg.koeln/?p=2993 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 2 MinutenIn diesem Beitrag zeige dich Dir, wie Du eine virtuelle Maschine, die Du unter TrueNAS installiert hast, trotzdem booten kannst.

Der Beitrag Virtuelle Maschine bootet nur bis UEFI/startet nicht erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 2 Minuten

In diesem Beitrag zeige dich Dir, wie Du eine virtuelle Maschine, die Du unter TrueNAS installiert hast, trotzdem booten kannst.

Dieser Fehler tritt eigentlich auf, weil TrueNAS das UEFI nicht ganz unterstützt und somit die passende Boot-Datei nicht findet.

Dies ist zwar lästig, aber in wenigen Minuten behoben. Versprochen 🙂

Zu aller erst bekommt Du das oben gezeigte Bild von der virtuellen Maschine präsentiert, welches Dir mitteilt, das etwas nicht stimmt.

  1. Dieses Fenster bestätigst du erstmal mit der Eingabe von exit.
    Dies bringt Dich in das „BIOS“ der virtuellen Maschine, wo Du mit den Pfeil-Tasten auf der Tastatur navigieren kannst.
  2. Wähle Boot Maintenance Manager aus
  3. Wähle Boot from File aus
  4. Wähle im nachfolgenden Fenster die Festplatte aus (meist ist nur eine verfügbar)
  5. Wähle EFI aus
  6. Wähle den Namen des Betriebssystems aus. In dem Falle hier debian
  7. Als letztes wählst Du grubx64.efi aus. Dies ist die eigentliche Bootdatei. Ab diesem Zeitpunkt sollte die virtuelle Maschine starten und Dich zur Shell bringen.

Damit diese Eingaben nicht bei jedem Start erneut eingegeben werden müssen, kopieren wir die Boot-Dateien an eine andere Stelle, damit der Bootloader diese selbst findet.

Hierzu loggst Du dich in der Shell der virtuellen Maschine ein und setzt folgende Kommandos ab. Diese müssen als root oder mit einem sudo berechtigten Benutzer erfolgen, da wir einen Ordner erstellen, der in einem schreibgeschützten Ordner liegt.

mkdir -p /boot/efi/EFI/BOOT
cp /boot/efi/EFI/debian/grubx64.efi /boot/efi/EFI/BOOT/bootx64.efi

Achte hier besonders auf den geänderten Dateinamen am Ende!

Hiernach kannst Du einen Neustart mittels reboot durchführen. So kannst Du direkt sehen, ob das Kopieren der Datei deine virtuelle Maschine starten lässt.

Bitte beachte, sollte das System aktualisiert werden ist es nötig, die oben genannten Schritte erneut durchzuführen!

Der Beitrag Virtuelle Maschine bootet nur bis UEFI/startet nicht erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/virtuelle-maschine-bootet-nur-bis-uefi-startet-nicht/feed/ 2
Virtuelle Maschine von TrueNAS auf anderen Server umziehen https://www.kreyenborg.koeln/virtuelle-maschine-von-truenas-auf-anderen-server-umziehen/ https://www.kreyenborg.koeln/virtuelle-maschine-von-truenas-auf-anderen-server-umziehen/#respond Tue, 20 Dec 2022 14:55:54 +0000 https://www.kreyenborg.koeln/?p=2822 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 4 MinutenIn diesem Beitrag zeige dich Dir, wie Du eine Festplatte der virtuellen Maschine sichern kannst.

Der Beitrag Virtuelle Maschine von TrueNAS auf anderen Server umziehen erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 4 Minuten

In diesem Beitrag zeige dich Dir, wie Du eine Festplatte der virtuellen Maschine sichern kannst, damit Du sie entweder als vollständiges Backup hast, oder eben auf einen anderen Server kopieren und dort weiter benutzen kannst. Letzteres war mein Vorhaben aus aktuellem Server-Neukauf 😉 Da das ZFS-Dateisystem keinen direkten Kopiervorgang erlaubt, behelfen wir uns einer kleinen Hilfe. Ich benutze in dieser Anleitung die Version Scale und nicht Core. Die Schritte sollten aber ähnlich sein.

Herausfinden, wo die Festplatte der VM liegt

Hierzu öffnest Du deine TrueNAS Instanz, wählst Virtualisierung, klappst die Maschine auf und klickst auf Geräte.

Virtuelle Maschine öffnen

Dort wählst Du bei Disk die 3 Punkte aus und wählst erneut Bearbeiten aus.

Festplattenspeicherort herausfinden

Danach erscheint der Pool, auf welchem die virtuelle Festplatte liegt.

Pool der virtuellen Festplatte

Nachdem Du nun den Speicherpfad der Festplatte herausgefunden hast, musst Du die virtuelle Maschine ausschalten. Dazu wählst Du im Fenster vorher Ausschalten.

Speicherpunkt der virtuellen Festplatte aktivieren

Damit die Festplatte nun gesichert werden kann, habe ich bei mir alle vorherigen Sicherungspunkte gelöscht und einen einzigen neu angelegt. Dies geschieht über Datasets, Pool-Name, Festplatte.

Virtuelle Festplatte bereinigen und Speicherpunkt anlegen

Auf der rechten Seite wählst Du Snapshots verwalten aus. Dann erscheint eine Liste, mit den ggf. automatisch angelegten Snapshots.

Diese bitte alle löschen, da sonst das Backup später einen veralteten Stand hat, da immer der älteste Snapshot genommen wird.

Vorhandene Snapshots löschen

Nun gehen wir abermals auf Datasets, Pool-Name, Festplatte. Hier wählst Du Snapshot erstellen aus. Die Einstellungen im nachfolgenden Fenster lässt Du wie sie sind und klickst zusätzlich Rekursiv an. Damit werden alle Daten der Festplatte gesichert. Die Absicherung dauert nur einen kurzen Moment. Dies kann abermals mit einem Klick auf Snapshots verwalten kontrolliert werden.

Erstellung des Snapshots kontrollieren

Festplatten-Abbild in ein ZIP-Archiv kopieren

Damit die virtuelle Festplatte portabel wird, muss Sie in ein ZIP-Archiv kopiert werden. Der Speicherplatz des ZIP-Archivs kann frei gewählt werden und sollte ausreichen Kapazität für die virtuelle Festplatte bereithalten.

Nachdem Du dich nun auf deinem TrueNAS per SSH oder lokal angemeldet hast, gibst Du folgenden Befehl ein. Der linke Teil ist die Quelle, also die virtuelle Festplatte im Dateisystem und der rechte Teil das Ziel, also das ZIP-Archiv und der Pfad, wo es gespeichert werden soll. Der Pfad /mnt/Data/snapshot_app.gz sollte also von Dir anzupassen sein. Der Parameter -R besagt, das rekursiv gesichert wird – also alles unterhalb der Festplatte selbst.

zfs send -R -v Virtual_Machines/app-server@manual-2022-12-20_14-57 | gzip > /mnt/Data/snapshot_app.gz

Hierbei ist zu beachten, das nach der Festplatte ein @ Symbol kommt, welches auf das soeben angelegte Snapshot-Abbild zeigt. Der Parameter -v gibt die Rückmeldungen des Einlese- und Packvorgangs aus. Wie Du sehen kannst, dauert dies eine kleine Weile, bis das Abbild eingelesen und gepackt wurde.

Einlesen und Packen der virtuellen Festplatte

Sobald der Vorgang abgeschlossen wurde, ist die virtuelle Festplatte „portabel“ und kann nun per FTP heruntergeladen, auf eine andere Festplatte kopiert oder verschoben werden. Bei mir dauerte der Vorgang zum Sichern von 27.1GB in etwa 14 Minuten. Die Datei, die die „27 GB“ dann enthält, ist um die 11GB groß, je nachdem, wie viele Daten auf der virtuellen Festplatte vorhanden sind.

Festplatten-Abbild entpacken

Sobald Du nun das Festplatten Archiv auf einen neuen Server kopiert hast oder die Datei nach einem Ausfall zurück kopieren möchtest, muss dieses erst einmal entpackt werden,

Dies geschieht mit:

gunzip snapshot_app.gz

Das Entpacken des Archivs geht in der Regel relativ schnell. Bitte beachte, dass das Archiv beim Entpacken gelöscht wird. Solltest Du dies nicht wünschen, so ist der Parameter (-k -> Keep (behalten)) für Dich sinnvoll und der Befehl lautet:

Mit dem Parameter -v gibt GUNZIP ggf. auch Fehlermeldungen aus, warum die Datei nicht entpackt werden kann.

gunzip -k -v snapshot_app.gz

Festplatte in das ZFS Datei System wiederherstellen

Um die Festplatte nun aus der entpackten Datei in das ZFS Dateisystem zu bekommen, gibst Du folgenden Befehl ein:

zfs receive -F -v Virtual_Machines/neue_festplatte < snapshot_app

Auch gilt wieder der Parameter -v für die Ausgabe und -F für ein volles Empfangen der Daten. Das Zurücksichern in das ZFS-Dateisystem geht relativ schnell von Statten. Danach kann die Quelldatei gelöscht werden und die zurück gesicherte Festplatte einer virtuellen Maschine zugewiesen werden.

Virtuelle Festplatte in das ZFS-Dateisystem zurück sichern

Der Beitrag Virtuelle Maschine von TrueNAS auf anderen Server umziehen erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/virtuelle-maschine-von-truenas-auf-anderen-server-umziehen/feed/ 0
iRobot Steuerung in ioBroker https://www.kreyenborg.koeln/irobot-steuerung-in-iobroker/ https://www.kreyenborg.koeln/irobot-steuerung-in-iobroker/#comments Fri, 08 Oct 2021 11:02:39 +0000 https://www.kreyenborg.koeln/?p=2526 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 10 MinutenIn diesem Beitrag zeige ich Dir, wie Du deinen iRobot Roboter anhand der Räume komfortabel steuern und mehr Informationen abrufen kannst.

Der Beitrag iRobot Steuerung in ioBroker erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 10 Minuten

In diesem Beitrag zeige ich Dir, wie du deinen iRobot Roboter bequem anhand der Räume steuern kannst. Die Steuerung über die iRobot App bietet inzwischen die Möglichkeit, den jeweiligen Roboter mit einem Fingerzeig in den jeweiligen Raum fahren zu lassen. Über ioBroker ist dies bisher leider nur über Umwege möglich. Hier setzt mein Skript an und bietet Dir komfortabel die Möglichkeit, den Roboter in verschiedene Räume und sogar Zonen zu senden.

Des Weiteren zeigt das Skript folgende Daten an:

  • die gereinigte Fläche des Durchgangs
  • welches Wischtuch z.B. beim Braava installiert ist
  • ob der Wassertank des Braava gefüllt ist oder nicht

Damit das Skript ordnungsgemäß arbeiten kann, ist der Roomba Adapter in ioBroker notwendig. Des Weiteren sind ein paar Vorbereitungen notwendig – die aber relativ schnell, einfach und einmalig erledigt werden können.

Vorbereitungen

Installiere bitte den Roomba Adapter in ioBroker und richte den Adapter ein. Wie dies funktioniert, ist hier beschrieben.

Erstelle Dir ein neues Skript im common Bereich mit dem Namen „iRobot-Control“. In das leere Skript kopierst Du Dir den nachfolgenden Inhalt. Startest das Skript aber noch nicht, da noch 2 Zeilen anzupassen sind – Zeile 32 und 33.

Skript

/*
 * @copyright 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur erweiterten Steuerung der iRobot Roboter.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 * 
 * Ansprüche gegenüber Dritten bestehen nicht. 
 * 
 * Skript Name:		iRobot-Control
 * Skript Version:	1.2
 * Erstell-Datum:	14. Oktober 2021
 * 
 */

// Datenpunkte neu erstellen
var ueberschreiben = false;

// Hauptdatenpunkt unterhalb javascript
var datenpunkt = "iRobot."; // Abschließender Punkt !!! WICHTIG !!!

// Instanzen der Geräte
var datenpunkt_instanz = "roomba."; // Abschließender Punkt | !!! BITTE NICHT ÄNDERN !!!
var instanz_geraet = [0, 1]; // Installierte Instanz | Bsp: 0 für Roomba, 1 für Braava
var instanz_name = ["Roomba", "Braava"]; // Keine Leerzeichen | Namen der Geräte ohne Leerzeichen

function abonniere_datenpunkte() {
    for (let i = 0; i < instanz_geraet.length; i++) {
        // Abonniere Datenpunkt zu Details des Roboters
        on({ id: datenpunkt_instanz + instanz_geraet[i] + ".device._rawData", change: "any" }, function (obj) {
            // Hole Datenpunkt
            var j = JSON.parse(obj.state.val);

            // Aktualisiere alle Datenpunkte
            var tmp_id = obj.id.split(".");
            var id = tmp_id[1];
            aktualisiere_datenpunkte(id, j);
        });
        // Abonniere eigene Datenpunkte zur Steuerung
        on({ id: "javascript.0." + datenpunkt + instanz_name[i] + ".Steuerung", change: "any" }, function (obj) {
            if (obj.state.val != "" || obj.state.val != null) {
                var tmp_id = obj.id.split(".");
                robot_steuerung(instanz_name.indexOf(tmp_id[tmp_id.length - 2]), obj.state.val, "Skript-Control");
            }
        });
        // Abonniere eigene Datenpunkte für geplante Bereiche
        on({ id: "javascript.0." + datenpunkt + instanz_name[i] + ".Geplante_Bereiche", change: "any" }, function (obj) {
            if (obj.state.val != "" || obj.state.val != null) {
                var tmp_id = obj.id.split(".");
                robot_auftrag(instanz_name.indexOf(tmp_id[tmp_id.length - 2]), obj.state.val);
            }
        });
    }
    log("iRobot-Control: Benötigte Datenpunkte wurden erstellt und abonniert. Skript ist einsatzbereit!");
}

// Reinigungsauftrag
function robot_auftrag(idRoboter, bereiche) {
    // Basis JSON Objekt
    let j_kommando = {
        command: "start",
        ordered: 1,
        pmap_id: null,
        regions: [],
        user_pmapv_id: null
    };
    // Sortiere Bereiche in Array ein
    var array_bereiche = bereiche.split(",");

    // Gefundene Bereiche
    var gefundene_bereiche = new Array();

    // Lese alle vorhandenen Räume ein
    var vorhandene_bereiche = $('state[id=javascript.0.' + datenpunkt + instanz_name[idRoboter] + '.*.*.name]');
    
    // Prüfe, ob mindestens ein Raum im Datenpunkt existiert
    if (vorhandene_bereiche[0] != undefined) {
        // Trenne den Datenpunkt
        var tmp_id = vorhandene_bereiche[0].split(".");
        // Karte
        var karte = getState(datenpunkt + instanz_name[idRoboter] + ".Bereiche." + tmp_id[tmp_id.length - 4] + ".pmap_id").val;
        j_kommando.pmap_id = karte;
        // Version der Karte
        var version = getState(datenpunkt + instanz_name[idRoboter] + ".Bereiche." + tmp_id[tmp_id.length - 4] + ".user_pmapv_id").val;
        j_kommando.user_pmapv_id = version;
        // Suche die passende ID zum Raum
        for (let i = 0; i < array_bereiche.length; i++) {
            vorhandene_bereiche.each(function (id, n) {
                // Trenne den Datenpunkt
                var tmp_dp = id.split(".");
                // ID des Bereichs (Raum oder Zone)
                var bereich_id = tmp_dp[tmp_id.length - 2];
                // Typ -> Zone oder Raum
                var typ = tmp_dp[tmp_id.length - 3];
                // lesbarer Name des Bereichs
                var bereich_name = getState(id).val;
                // Sortiere die Räume und Zonen ein
                if (bereich_name.toLowerCase() == array_bereiche[i].trim().toLowerCase()) {
                    if (typ == "Raeume") {
                        let tmp = { region_id: bereich_id.toString(), type: "rid" };
                        j_kommando.regions.push(tmp);
                        gefundene_bereiche.push(bereich_name + " (ID: " + bereich_id + ")");
                    }
                    if (typ == "Zonen") {
                        let tmp = { region_id: bereich_id.toString(), type: "zid" };
                        j_kommando.regions.push(tmp);
                        gefundene_bereiche.push(bereich_name + " (ID: " + bereich_id + ")");
                    }
                }
            });
        }
        let kommando = JSON.stringify(j_kommando);
        log("iRobot-Control: Starte Reinigung mit " + instanz_name[idRoboter] + " für: " + gefundene_bereiche.join(", "));
        setState(datenpunkt_instanz + idRoboter + ".commands._runCommand", kommando);
    } else {
        log("iRobot-Control: Noch keine Bereiche vorhanden. Auftrag kann nicht gestartet werden!");
    }
}

// Roboter Steuerung
function robot_steuerung(id, kommando, app) {
    let j_command = { command: kommando, time: Date.now() / 1000 | 0, initiator: app };
    let command = JSON.stringify(j_command);

    // Prüfe, von wem das Kommando kam
    if (app == "Skript-Control") {
        setState("roomba." + id + ".commands._runCommand", command);
    } else {
        setState(datenpunkt + instanz_name[id] + ".Steuerung", kommando, true);
    }
}

// Lege neuen Raum an
function neuer_raum(geraet, pmap_id, region_id, region_type, user_pmapv_id) {
    // Bereiche
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id, '', { name: 'ID der Karte', type: 'string', role: 'state' }, function () { });
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".pmap_id", pmap_id, { name: "ID der Karte", type: 'string', role: 'value' }, function () { });
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, { name: "Version der Karte", type: 'string', role: 'value' }, function () { });

    // Raum
    if (region_type == "rid") {
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id, '', { name: 'ID des Raumes', type: 'string', role: 'state' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.region_id', region_id, { name: 'ID Des Raumes', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.name', '', { name: 'Eigener Name des Raumes', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.erstellt', hole_datum(), { name: 'Datum des Hinzufügens', type: 'string', role: 'value' }, function () { });
        log("iRobot-Control: Neuer Raum für " + geraet + " gefunden und angelegt! ID: " + region_id);
    }

    // Schmutzzone
    if (region_type == "zid") {
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Zonen.' + region_id, '', { name: 'ID der Zone', type: 'string', role: 'state' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".Zonen." + region_id + '.region_id', region_id, { name: 'ID der Zone', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".Zonen." + region_id + '.name', '', { name: 'Eigener Name der Zone', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Zonen.' + region_id + '.erstellt', hole_datum(), { name: 'Datum des Hinzufügens', type: 'string', role: 'value' }, function () { });
        log("iRobot-Control: Neue Zone für " + geraet + " gefunden und angelegt! ID: " + region_id);
    }
}

// Aktualisiere alle Datenpunkte
function aktualisiere_datenpunkte(id, j) {
    // Generelle Datenpunkte
    // Gereinigte Quadratmeter
    setState(datenpunkt + instanz_name[id] + ".Quadratmeter", parseFloat((j.bbrun.sqft / 10.764).toFixed(2)), true);
    // Prüfe Wassertank des Braava
    if (j.cleanMissionStatus.notReady === 31) {
        setState(datenpunkt + instanz_name[id] + ".Wassertank", true, true);
    } else {
        setState(datenpunkt + instanz_name[id] + ".Wassertank", false, true);
    }
    // Wischtuch des Braava
    if (j.detectedPad != null) {
        setState(datenpunkt + instanz_name[id] + ".Wischtuch", j.detectedPad, true);
    }

    // Aktuelle Räume im Auftrag
    setState(datenpunkt + instanz_name[id] + ".Durchgang_Raeume", generiere_raumliste(id, j.lastCommand.pmap_id, j.lastCommand.regions), true);

    // Prüfe, ob kein Training stattfindet
    if (j.lastCommand.regions != null) {
        var region_id = j.lastCommand.regions[0].region_id;
        var region_type = j.lastCommand.regions[0].type;
        var pmap_id = j.lastCommand.pmap_id;
        var user_pmapv_id = j.lastCommand.user_pmapv_id;

        // Region Räume
        if (region_type == "rid") {
            // Prüfe, ob Raum existiert
            if (!existsState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".Raeume." + region_id + ".region_id")) {
                // Raum existiert nicht. Raum anlegen
                neuer_raum(instanz_name[id], pmap_id, region_id, region_type, user_pmapv_id);
            } else {
                if (user_pmapv_id != null) {
                    setState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, true);
                }
            }
        }
        // Region Zonen
        if (region_type == "zid") {
            // Prüfe, ob Raum existiert
            if (!existsState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".Zonen." + region_id + ".region_id")) {
                // Raum existiert nicht. Raum anlegen
                neuer_raum(instanz_name[id], pmap_id, region_id, region_type, user_pmapv_id);
            } else {
                if (user_pmapv_id != null) {
                    setState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, true);
                }
            }
        }
    }
}

// Generiere Raumliste
function generiere_raumliste(id, karte, raeume) {
    if (raeume == null) {
        return "Keine Räume im Auftrag";
    } else {
        // Lege Array an
        var raumliste_name = new Array();
        // Irritiere über die übermittelten Räume
        for (let i = 0; i < raeume.length; i++) {
            var name = "";
            if (raeume[i].type == "rid") {
                if (existsState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Raeume." + raeume[i].region_id + ".name")) {
                    name = getState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Raeume." + raeume[i].region_id + ".name").val;
                    if (name == "" || name == null) {
                        name = "Namenloser Raum mit der ID: " + raeume[i].region_id;
                    }
                } else {
                    // Raum noch nicht vorhanden
                    name = "Nicht definierter Raum (ID: " + raeume[i].region_id + ")";
                }
            }
            if (raeume[i].type == "zid") {
                if (existsState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Zonen." + raeume[i].region_id + ".name")) {
                    name = getState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Zonen." + raeume[i].region_id + ".name").val;
                    if (name == "" || name == null) {
                        name = "Namenlose Zone mit der ID: " + raeume[i].region_id;
                    }
                } else {
                    // Raum noch nicht vorhanden
                    name = "Nicht definierte Zone (ID: " + raeume[i].region_id + ")";
                }
            }
            if (name != "") {
                raumliste_name.push(name);
            }
        }
        // Gebe Raumliste zurück
        if (raumliste_name.length === 0) {
            return "Keine Räume im Autrag!";
        } else {
            return raumliste_name.join(", ");
        }
    }
}

// Datum 
function hole_datum() {
    let datum = new Date();
    let tag = '0' + datum.getDate();
    let monat = '0' + (datum.getMonth() + 1);
    let jahr = datum.getFullYear();
    let stunde = '0' + datum.getHours();
    let minute = '0' + datum.getMinutes();
    let sekunde = '0' + datum.getSeconds();
    return tag.substr(-2) + '.' + monat.substr(-2) + '.' + jahr + ' ' + stunde.substr(-2) + ':' + minute.substr(-2) + ':' + sekunde.substr(-2);
}

// Werte für die Datenpunkte
// iRobot Objekte
var objekt = [
    "Steuerung",
    "Quadratmeter",
    "Wassertank",
    "Wischtuch",
    "Durchgang_Raeume",
    "Geplante_Bereiche"
];

// Beschreibung der Objekte
var beschreibung = [
    "Steuerung des Roboters",
    "Gereinigte Quadratmeter",
    "Wassertank des Braava",
    "Montiertes Wischtuch des Braava",
    "Räume des aktuellen Durchgangs",
    "Geplante Bereiche für den Durchgang"
];

// Einheiten der Objekte
var einheiten = [
    "",
    "qm²",
    "",
    "",
    "",
    ""
    ,];

// Typen der Objekte
var typen = [
    "string",
    "number",
    "boolean",
    "string",
    "string"
];

// Rollen der Objekte
var rolle = [
    "action",
    "value",
    "inidcator",
    "value",
    "value",
    "string"
];

// Erstelle die benötigten Datenpunkte
function datenpunkte_erstellen() {
    for (let g = 0; g < instanz_geraet.length; g++) {
        for (let i = 0; i < objekt.length; i++) {
            createState(datenpunkt + instanz_name[g] + "." + objekt[i], null, ueberschreiben, {
                name: beschreibung[i],
                desc: beschreibung[i],
                type: typen[i],
                role: rolle[i],
                unit: einheiten[i]
            });
        }
    }
    log("iRobot-Control: Datenpunkte werden im Hintergrund erstellt. Dies dauert 30 Sekunden. Bitte warten!");
    setTimeout(abonniere_datenpunkte, 30000);
}

function irobot_erster_start() {
    log("iRobot-Control: Erster Start des Skriptes! Datenpunkte werden erstellt!");
    // Datenpunkte werden erstellt
    if (existsState(datenpunkt_instanz + "0.device._rawData")) {
        datenpunkte_erstellen();
    } else {
        stopScript("");
        log("iRobot-Control: Fehler: Roomba Adapter scheint nicht installiert zu sein!", "error");
    }
}

// Erster Start und Initialisierung
irobot_erster_start();

Änderungen

1.2 (14. Oktober 2021)

  • Änderung der Priorisierung der Räume
  • Raumfindung angepasst
  • Start-Limit angepasst

1.0 (07. Oktober 2021)

  • erste Version

Konfiguration

Damit nun das Skript weiss, welche iRobot Geräte (bei mehr als 2 Instanzen) bei Dir vorhanden sind, musst Du Zeile 32 und 33 wie folgt anpassen.

Zeile 32: Hier sind die Instanzen des Roomba Adapters gemeint. Bei einem Gerät ist es die 0. Bei mehr als einer Instanz sind diese mit Komma getrennt anzugeben.

Zeile 33: Hier gibst Du die Namen der Geräte an, damit Du sie leichter zuordnen kannst.

Ab hier kannst Du das Skript starten und es werden einige Datenpunkte unterhalb javascript.0.iRobot erzeugt. Pro Gerät, welches Du angegeben hast, wie folgt:

DatenpunktBezeichnung
Bereiche (Ordner)Beinhaltet die Bereiche, die gefunden wurden (s.u.)
Duchgang_RaeumeRäume des aktuellen Durchgangs
Geplante_BereicheGeplante Bereiche für den Durchgang
QuadratmeterGereinigte Quadratmeter
SteuerungSteuerung des Roboters (mehr Befehle möglich)
WassertankWassertank des Braava (sonst „null“)
WischtuchWischtuch des Braava (sonst „null“)

Räume dem Skript hinzufügen

Da das Skript nun gestartet ist und die einzelnen Datenpunkte oberhalb bereits erstellt worden sind, kannst Du beginnen, die einzelnen Räume dem Skript zuzuweisen.

Starte mit der Roomba App auf dem Smartphone einen Reinigungsauftrag für ein Gerät (beim Roomba ohne Nachwischen). Sobald der Roboter losgefahren ist (maximal 60 Sekunden später), kannst Du im Log von ioBroker erkennen, dass das Skript eine ID und einen Bereich (Zone oder Raum) ausgibt.

Robot-Control: Neuer Raum für Roomba gefunden und angelegt! ID: 4

Hieran kannst Du erkennen, das es sich um einen neuen Raum handelt, den das Skript noch nicht kennt.

Der Roboter kann in der Zwischenzeit zur Basis zurückkehren.

Nun begibst Du Dich in den Objekt-Browser von ioBroker und navigierst zu:

javascript.0.iRobot.<Name-des-Roboters>.Bereiche.<Karte-ID>.<Bereich>.<ID des Raumes> (Bereich: Raeume oder Zone; ID des Raumes: ID aus dem Log)

Hier solltest du ein Layout wie folgt sehen:

Objekte des Skriptes
Objekte des Skriptes

Dort gibt es nun den Ordner mit der gefundenen ID – hier 4. Diesen Ordner kannst Du nun der Übersicht halber einem Raum aus der ioBroker Liste zuweisen (nur für die Optik). Viel wichtiger ist hier der Datenpunkt „name„. Das ist später der eigentliche Name, den das Skript verwendet. Anklicken, Namen festlegen, Wert setzen, Fertig. Der erste Raum ist nun angelegt.
Tipp: Am Besten verwendest Du die gleichen Namen, wie in der App.

Nun solltest Du (innerhalb von 60 Sekunden) sehen, das der Datenpunkt „Durchgang_Raeume“ auch den von dir festgelegten Raum darstellt.

Datenpunkt des aktuellen Durchgangs
Datenpunkt des aktuellen Durchgangs

Diesen Schritt kannst Du nun für jeden Raum wiederholen. Bitte bedenke, dass das Skript während der Einrichtung immer nur einen Raum identifiziert. Dies macht es Dir leichter, die einzelnen Räume zu benennen, da man bei mehreren ID’s wahrscheinlich durcheinander kommt 😉

Anwendung des Skripts – Räume und Zonen steuern

Nachdem Du nun alle Räume und Zonen dem Skript mitgeteilt hast, kann es an die eigentliche Verwendung gehen – das Steuern des Roboters über die Raumnamen.

Hier ist der jeweilige Datenpunkt javascript.0.iRobot.<Name-des-Roboters>.Geplante_Bereiche wichtig, denn hier kannst du – jeweils durch ein Komma getrennt, deine Räume und Zonen zur gleichen Zeit eintragen und der Roboter beginnt mit der Reinigung. Auch die Priorisierung ist möglich. Der Raum oder die Zone, die zuerst angegeben ist, wird zuerst gereinigt. Einfach, oder?

Beispiel:

Du möchtest Küche, Couchtisch und Esszimmer reinigen. So schreibst Du diesen Wert (String) einfach in den Datenpunkt. Dies kann natürlich auch über ein kleines Skript erfolgen, welches in etwa so aussieht:

// Reinigung von Küche, Couchtisch und Esszimmer jeden Tag zur goldenen Abendstunde
schedule({ astro: "goldenHour" }, function () {
    setState("javascript.0.iRobot.Roomba.Geplante_Bereiche", "Küche, Couchtisch, Esszimmer", true);
});

Weitere Zeiten zum Thema „Astro“ findest Du hier.

Natürlich lassen sich alle Datenpunkte auch in VIS oder JarVIS steuern und anzeigen.

Hier ein Beispiel für JarVIS und den Roomba i7:

Roomba i7 in JarVIS
Roomba i7 in JarVIS

Anwendung des Skripts – iRobot steuern

Wie eingangs erwähnt, bietet mein Skript noch einige Steuerbefehle mehr. Diese laufen über den Datenpunkt javascript.0.iRobot.<Name-des-Roboters>.Steuerung

Dieser Wert wird immer mit dem des Roomba Adapter abgeglichen – heisst, wenn der Adapter „stop“ meldet, aktualisiert sich dieser Datenpunkt auch. Wir können diesen Datenpunkt aber auch selber nutzen, um den iRobot zu steuern. Dies funktioniert mit folgenden Befehlen, die der Roomba Adapter zwar unterstützt aber nicht selbst anbietet:

WertBezeichnung
startStarten des iRobot
stopStoppen des iRobot
pausePausieren des iRobot
resumeFortsetzen des iRobot
dockiRobot zur Aufladestation senden
trainiRobot auf einen Kartierungslauf schicken
findiRobot suchen – ein Ton ertönt
evaciRobot an der Absaugstation absaugen lassen (nur für Modelle mit Absaugstation)
Mögliche Steuerbefehle

Anwendung des Skript – erweiterte Datenpunkte

Der Roomba Adapter bietet zwar die Ausgabe der erledigten Quadratmeter – dies funktioniert aber leider inzwischen – oder bei neueren Modellen – nicht mehr. Mein Skript zeigt Dir folgende Werte an:

DatenpunktBeschreibung
QuadratmeterGereinigte Quadratmeter des Durchlaufs
Wassertankfalse bei vollem Behälter – true bei leerem Behälter
WischtuchInstalliertes Wischtuch der Braava Modelle
Erweiterte Datenpunkte

Der Beitrag iRobot Steuerung in ioBroker erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/irobot-steuerung-in-iobroker/feed/ 25
Proscenic Roboter in ioBroker integrieren https://www.kreyenborg.koeln/proscenic-roboter-in-iobroker-integrieren/ https://www.kreyenborg.koeln/proscenic-roboter-in-iobroker-integrieren/#comments Fri, 24 Sep 2021 14:16:10 +0000 https://www.kreyenborg.koeln/?p=2479 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 MinutenIn diesem Beitrag zeige ich Dir, wie du mit Hilfe von einem Skript deinen Proscenic Roboter in ioBroker steuern kannst.

Der Beitrag Proscenic Roboter in ioBroker integrieren erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 Minuten

Leider lässt sich der Roboter nicht komplett in ioBroker integrieren und zeigt somit leider keine Karte bzw. den Status/Batterie-Stand an. Ich forsche aktuell danach, ob es sich nicht doch noch realisieren lässt.

Mit dem u.g. Skript ist es immerhin möglich, den Roboter via VIS oder Jarvis zu steuern.

Es werden 2 Datenpunkte angelegt: Modus und Steuerung.

In der Steuerung hat man die Auswahl zwischen Start, Stop und Aufladen

Der Modus-Datenpunkt steuert die Reinigung des Roboters: Auto, Bereich, Rand

Skript

Nun erstellen wir in ioBroker ein neues Skript im common Bereich. Es bekommt den Namen “Proscenic-Remote”.

/*
 * @copyright 2021 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2021 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur Steuerung des Proscenic.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 *
 * Ansprüche gegenüber Dritten bestehen nicht.
 *
 * Skript Name:     Proscenic-Remote
 * Skript Version:  1.0
 * Erstell-Datum:   24. September 2021
 *
 */
 
// Datenpunkte neu erstellen
var ueberschreiben = true;
 
// Hauptdatenpunkt unterhalb javascript
var datenpunkt = "Proscenic.";
 
// IP des Proscenic
const robot_ip = "192.168.5.100";
 
// Port des Proscenic
const robot_port = 10684;
 
// Aktion für den Staubsauger (Stop, Start, Aufladen)
const robot_aktion = ['',
    'BERkRFMjA5MDYwMDAxMDAwMzAwMDAwMDAw',
    'BERkRFMjA5MDYwMDAxMDAwMjAwMDAwMDAx',
    'BGRkRFMjA5MDYwMDAxMDAwMTAwMDAwMDAw'];
 
// Text für Aktion
const robot_aktion_text = ['', 'Stop', 'Start', 'Aufladen'];
 
// Reinigungsmodus (Auto, Bereich, Rand)
const rein_modus = ['',
    'A5RkRFMjA5MDYwMDAxMDAwMjA1MDAwMDAw',
    'BBRkRFMjA5MDYwMDAxMDAwMjA0MDAwMDAw',
    'BCRkRFMjA5MDYwMDAxMDAwMjAzMDAwMDAw'];
 
// Text für Reinigungsmodus
const rein_modus_text = ['', 'Auto-Modus', 'Bereich-Reinigung', 'Rand-Reinigung']
 
// Aktion | 0 = Steuerung, 1 = Reinigungsmodus
function robot_steuerung(aktion = 0, funktion = 0) {
    let befehl = "";
    let nachricht = "";
    if (aktion == 0) {
        befehl = robot_aktion[funktion];
        nachricht = 'Proscenic: Steuerung: ' + robot_aktion_text[funktion] + ' an Roboter gesendet!';
    }
 
    if (aktion == 1) {
        befehl = rein_modus[funktion];
        // Robotor stoppen, damit neuer Modus angenommen wird
        robot_steuerung(0, 1);
        nachricht = 'Proscenic: Reinigungs-Modus: ' + rein_modus_text[funktion] + ' an Roboter gesendet!';
    }
 
    // Befehl ausführen
    let kommando = '<MESSAGE Version="1.0"><HEADER MsgType="MSG_TRANSIT_SHAS_REQ" MsgSeq="1" From="02000000000000000" To="01801930aea421f164" Keep="0"/>'
    kommando = kommando + '<BODY>PFRSQU5TSVRfSU5GTz48Q09NTUFORD5ST0JPVF9DTUQ8L0NPTU1BTkQ+PFJUVT5BQTU1QTU1QT'
    kommando = kommando + befehl;
    kommando = kommando + 'MDA8L1JUVT48L1RSQU5TSVRfSU5GTz4K</BODY></MESSAGE>\r\n\r\n';
    if (funktion != undefined && funktion != 0) {
        var dgram = require('dgram');
        var client = dgram.createSocket('udp4');
        var message = Buffer.from(kommando);
        client.send(message, 0, message.length, robot_port, robot_ip, function (err, bytes) {
            if (err) throw err;
            client.close();
            log(nachricht);
        });
    }
}
 
// Erstelle die benötigten Datenpunkte
function datenpunkte_erstellen() {
    createState(datenpunkt + "Steuerung", "", ueberschreiben, {
        name: "Steuerung des Roboters",
        desc: "Steuerung des Roboters",
        type: "number",
        role: "value",
        min: 0,
        max: 3,
        "states": {
            "0": "Nichts",
            "1": "Stop",
            "2": "Start",
            "3": "Aufladen"
        }
    });
    createState(datenpunkt + "Modus", "", ueberschreiben, {
        name: "Reinigungsmodus des Roboters",
        desc: "Reinigungsmodus des Roboters",
        type: "number",
        role: "value",
        min: 0,
        max: 3,
        "states": {
            "0": "Nichts",
            "1": "Auto",
            "2": "Bereich",
            "3": "Rand"
        }
    });
}
 
function proscenic_erster_start() {
    log("Proscenic: Erster Start des Skriptes! Datenpunkte werden erstellt!");
    // Datenpunkte werden erstellt
    datenpunkte_erstellen();
}
 
// Erster Start und Initialisierung
proscenic_erster_start();
 
// Abonniere Datenpunkt zur Steuerung
on({ id: "javascript.0.Proscenic.Steuerung", change: "any" }, function (obj) {
    robot_steuerung(0, obj.state.val);
});
on({ id: "javascript.0.Proscenic.Modus", change: "any" }, function (obj) {
    robot_steuerung(1, obj.state.val);
});

Anwendung

In Zeile 31 musst Du zunächst die IP des Roboters anpassen.

Das Skript erstellt 2 Datenpunkte unterhalb javascript.0.Proscenic und lauscht im Hintergrund auf Änderung.
Die Datenpunkte kannst Du nun via Skript, VIS oder Auswahlliste auf die jeweiligen Werte einstellen.
Folgende Werte sind möglich:

Steuerung:

WertFunktion
0Standard
1Stop
2Start
3Aufladen

Modus:

WertFunktion
0Standard
1Auto
2Bereich
3Rand

Unterstützte Geräte

Roboter-ModellUnterstützt?
790TJa
M8Nein (laut Feedback)

Der Beitrag Proscenic Roboter in ioBroker integrieren erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/proscenic-roboter-in-iobroker-integrieren/feed/ 11
Shelly Firmware Update per Skript https://www.kreyenborg.koeln/shelly-firmware-update-per-skript/ https://www.kreyenborg.koeln/shelly-firmware-update-per-skript/#comments Mon, 07 Jun 2021 09:17:46 +0000 https://www.kreyenborg.koeln/?p=1938 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: < 1 MinuteIn diesem Beitrag zeige ich Dir, wie du mit Hilfe von JavaScript alle deine Shelly updaten kannst.

Der Beitrag Shelly Firmware Update per Skript erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: < 1 Minute

Shelly bringt in regelmäßigen Abständen neue Updates für die Module heraus. Über die Smartphone App lassen sich die Updates natürlich auf alle Shelly aufspielen – jedoch innerhalb von ioBroker gibt es nur die Möglichkeit, das Update via der Shelly Instanz zu installieren. Hier behelfen wir uns eines Skriptes, welches manuell den Update-Prozess auf den Shelly auslösen kann. Es wird auch nur das Update ausgelöst, wenn tatsächlich eines zur Verfügung steht.

Skript

Nun erstellen wir in ioBroker ein neues Skript im common Bereich. Es bekommt den Namen “Shelly-Firmware”.

/*
 * @copyright 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur Verbrauchserfassung der Shelly Geräte.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 *
 * Ansprüche gegenüber Dritten bestehen nicht.
 *
 * Skript Name:     Shelly-Firmware
 * Skript Version:  1.0
 * Erstell-Datum:   07. Juni 2021
 *
 */
 
// Datenpunkt der Shelly (Standard: shelly.0)
var shelly_dp = "shelly.0";
 
// Datenpunkte der Shelly (!!! Bitte nicht ändern !!!)
var shellyDps = $('state[id=' + shelly_dp + '.*.firmware]');
 
let anzahl_shelly = 0;
let anzahl_shelly_update = 0;
 
// Starte Reboot
shellyDps.each(function (id, i) {
    if (getState(id).val == true) {
        setState(id + "update", true);
        anzahl_shelly_update++;
    }
    anzahl_shelly++;
});
stopScript("");
log("Shelly-Firmware: Der Update-Befehl wurde an " + anzahl_shelly_update + " von " + anzahl_shelly + " Shelly gesendet!");

Der Beitrag Shelly Firmware Update per Skript erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/shelly-firmware-update-per-skript/feed/ 6
Shelly Reboot per Skript https://www.kreyenborg.koeln/shelly-reboot-per-skript/ https://www.kreyenborg.koeln/shelly-reboot-per-skript/#comments Mon, 07 Jun 2021 08:54:34 +0000 https://www.kreyenborg.koeln/?p=1934 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: < 1 MinuteIn diesem Beitrag zeige ich Dir, wie du mit Hilfe von JavaScript alle deine Shelly rebooten kannst.

Der Beitrag Shelly Reboot per Skript erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: < 1 Minute

Normalerweise sollten die Shelly eigentlich wie gut geschmiertes Getriebe durchlaufen. Manchmal kann aber auch ein Reboot helfen, einen Shelly wieder zur besseren Performance zu verhelfen. Aber, jeden Shelly einzeln zu rebooten, ist ab einer bestimmten Anzahl lästig, oder? Somit stelle ich Dir heute ein Skript vor, welches dies übernimmt.

Skript

Nun erstellen wir in ioBroker ein neues Skript im common Bereich. Es bekommt den Namen “Shelly-Reboot”.

/*
 * @copyright 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur Steuerung der Shelly Geräte.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 *
 * Ansprüche gegenüber Dritten bestehen nicht.
 *
 * Skript Name:     Shelly-Reboot
 * Skript Version:  1.0
 * Erstell-Datum:   07. Juni 2021
 *
 */
 
// Datenpunkt der Shelly (Standard: shelly.0)
var shelly_dp = "shelly.0";
 
// Datenpunkte der Shelly (!!! Bitte nicht ändern !!!)
const shellyDps = $('state[id=' + shelly_dp + '.*.reboot]');
 
let anzahl_shelly = 0;
 
// Starte Reboot
shellyDps.each(function (id, i) {
    setState(id, true);
    anzahl_shelly++;
});
stopScript("");
log("Shelly-Reboot: Der Reboot-Befehl wurde an " + anzahl_shelly + " Shelly gesendet!");

Nach dem Aufruf werden alle gefundenen Shelly neugestartet und das Skript selbst beendet sich wieder.

Der Beitrag Shelly Reboot per Skript erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/shelly-reboot-per-skript/feed/ 1
Batterie Status der ZigBee Geräte abfragen und per WhatsApp zuschicken lassen https://www.kreyenborg.koeln/batterie-status-der-zigbee-geraete-abfragen-und-per-whatsapp-zuschicken-lassen/ https://www.kreyenborg.koeln/batterie-status-der-zigbee-geraete-abfragen-und-per-whatsapp-zuschicken-lassen/#comments Mon, 19 Apr 2021 11:31:05 +0000 https://www.kreyenborg.koeln/?p=1912 Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 MinutenIn diesem Beitrag zeige ich Dir, wie du den Batteriestatus Deiner ZigBee Geräte abfragen und Dir per WhatsApp zuschicken lassen kannst.

Der Beitrag Batterie Status der ZigBee Geräte abfragen und per WhatsApp zuschicken lassen erschien zuerst auf Kreyenborg.koeln.

]]>
Kreyenborg.koeln
Kreyenborg.koeln - ... die Welt von Smart-Home leicht erklärt

Lesedauer: 3 Minuten

Dieses Skript dient der Abfrage des Batteriestandes Deiner ZigBee Geräte. Es läuft in Standardeinstellung nachts um 1 Uhr und stellt alle wesentlichen Informationen wie Gerätename, Raum und Batteriestand (in Volt und Prozent) bereit und schickt sie Dir per WhatsApp zu.

Vorbereitung

Damit dieses Skript zuverlässig funktioniert, benötigst Du mein Skript für den WhatsAppBot. Nebenbei erwähnt kannst Du das Skript auch verwenden, um die Mitteilungen per E-Mail zu versenden. Dazu sind ein paar Anpassungen notwendig.

Skript

Zuerst erstellst du ein neues Javascript im Bereich common.

/*
 * @copyright 2021 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2021 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur Status-Abfrage der ZigBee Geräte.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 * 
 * Ansprüche gegenüber Dritten bestehen nicht. 
 * 
 * Skript Name:		ZigBee Batterie Status
 * Skript Version:	1.2
 * Erstell-Datum:	15. Oktober 2021
 * 
 */

// Datenpunkt der ZigBee Geräte (Standard: zigbee.0)
var zigbee_dp = "zigbee.0";

// Datenpunkte der ZigBee (!!! Bitte nicht ändern !!!)
const zigbeeDpsBattery = $('state[id=' + zigbee_dp + '.*.battery]');

function zigbeeBatterieStatus() {
    // Anzahl gefundene ZigBee Geräte
    var gefundene_geraete = new Array();

    // Namen der ZigBee Geräte
    var geraete_namen = new Array();

    // Batteriestand der ZigBee Geräte
    var batterie_stand = new Array();

    // Batteriestand in Volt der ZigBee Geräte
    var batterie_volt = new Array();

    // Räume der ZigBee Geräte - falls angegeben
    var raeume = new Array();

    // Batterie Status des ZigBee Gerät
    var status = new Array();
    log("ZigBee Batterie Status: Batterie Status wird abgefragt!");
    zigbeeDpsBattery.each(function (id) {
        let tmp_id = id.split(".");
        var tmp_id_g = tmp_id[0] + "." + tmp_id[1] + "." + tmp_id[2];
        gefundene_geraete.push(tmp_id_g);
        // Speichere Namen ab
        var name = getObject(tmp_id_g).common.name;
        if (name != "") {
            geraete_namen.push(name);
        } else {
            geraete_namen.push("");
        }

        // Hole Batteriestand
        var tmp_batterie_stand = getState(tmp_id_g + ".battery").val;
        if (tmp_batterie_stand != null) {
            batterie_stand.push(tmp_batterie_stand + "%");

            // Status der Batterie
            if (tmp_batterie_stand > 75) {
                status.push("voll");
            }
            if (tmp_batterie_stand <= 50) {
                status.push("ok");
            }
            if (tmp_batterie_stand <= 25) {
                status.push("fast leer");
            }
            if (tmp_batterie_stand < 25) {
                status.push("kritisch");
            }
        } else {
            batterie_stand.push("-%");
            status.push("keine Information");
        }

        // Hole Batterie %
        var tmp_batterie_volt = getState(tmp_id_g + ".voltage").val;
        if (tmp_batterie_volt != null) {
            batterie_volt.push(tmp_batterie_volt + "V");
        } else {
            batterie_volt.push("-V");
        }

        // Hole Raum
        var tmp_raum = getObject(tmp_id_g, 'rooms').enumNames[0];
        if (tmp_raum != undefined) {
            if (tmp_raum.de != undefined) {
                raeume.push(tmp_raum.de);
            } else {
                raeume.push(tmp_raum);
            }
        } else {
            raeume.push("kein Raum");
        }
    });
    // Generiere String
    var text = '*ZigBee Batteriestatus von ' + gefundene_geraete.length;
    if (gefundene_geraete.length > 1) {
        text += ' Geräten*<br><br>';
    } else {
        text += ' Gerät*<br><br>';
    }
    for (let i = 0; i < gefundene_geraete.length; i++) {
        text += "*" + geraete_namen[i] + ":* " + status[i] + "<br>Raum: " + raeume[i] + " | Batterie: " + batterie_stand[i] + " | Volt: " + batterie_volt[i] + "<br><br>";
    }

    log("ZigBee Batterie Status: Batterie Status abgefragt!");
    // Sende Nachricht
    WhatsAppBot(0, text);
    //log(text);
}
zigbeeBatterieStatus();

// Nachts um 1 Uhr den Batteriestand abfragen
schedule('0 1 * * *', zigbeeBatterieStatus);

Skript anpassen

In Zeile 117 musst du den Namen des WhatsAppBot Skriptes anpassen, wenn dieses von Dir anders benannt wurde, als in der Anleitung angegeben. Außerdem wird der jeweilige Empfänger benötigt – aber dies ist ja schon in der Anleitung zum WhatsAppBot erwähnt 😉

Solltest Du das Skript verwenden wollen, um die Nachrichten per E-Mail zu erhalten, so musst Du in Zeile 117 das „WhatsAppBot“ gegen „sendTo“ austauschen und ggf. den Text etwas anpassen, da dieser für die Verwendung in WhatsApp formatiert ist (* für Fettschrift).

Status Mitteilung per WhatsApp empfangen

Die Statusmitteilung erscheint wie folgt auf Deinem Mobiltelefon.

ZigBee Batterie Status in WhatsApp

Der Beitrag Batterie Status der ZigBee Geräte abfragen und per WhatsApp zuschicken lassen erschien zuerst auf Kreyenborg.koeln.

]]>
https://www.kreyenborg.koeln/batterie-status-der-zigbee-geraete-abfragen-und-per-whatsapp-zuschicken-lassen/feed/ 14
Powered by atecplugins.com