Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Beowolf

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    B
    • Profile
    • Following 1
    • Followers 0
    • Topics 141
    • Posts 1424
    • Best 80
    • Groups 3

    Beowolf

    @Beowolf

    96
    Reputation
    191
    Profile views
    1424
    Posts
    0
    Followers
    1
    Following
    Joined Last Online

    Beowolf Follow
    Pro Starter Most Active

    Best posts made by Beowolf

    • Wohnungsputzstress an Weihnachten

      An alle die sich einen übertriebenen Wohnungsputz-Weihnachtsstress machen.

      Es kommt das Christkind - nicht das Gesundheitsamt.

      Trotzdem eine frohe Weihnachtszeit und einen guten Rutsch in das neue Jahr.

      🤗 🤗 🤗

      posted in Plauderecke
      B
      Beowolf
    • RE: Wemos d1 mini - http Aufruf geht nur einmal.

      @opensourcenomad

      Echt jetzt? Könnt Ihr den Kleinkrieg an einer anderen Stelle machen?

      Danke

      posted in Microcontroller
      B
      Beowolf
    • RE: E-INK Display OpenEPaperLink - Displayanzeige mit Batterie

      @mcm57

      Displays:
      www.tindie.com/products/electronics-by-nic/5-pcs-29-epaper-tags-for-openepaperlink

      AP:
      www.tindie.com/products/electronics-by-nic/openepaperlink-mini-ap-v3-zigbee-wifi-gateway/

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: Wasserzähler - Version 2 - all-in-device

      @doggie sagte in Wasserzähler - Version 2 - all-in-device:

      Mir scheint das ganze AI on the edge Projekt ist nicht annähernd ausgereift. Sehr, sehr schade. Und enttäuschend.
      Was sagen andere dazu?
      Gibt es eigentlich Systeme die fehlerfrei laufen?
      Als Entwickler des Systems würde mich so ein Fehler nicht schlafen lassen.

      Ein klein wenig Demut wäre nicht schlecht. Hier macht jemand ein Projekt in seiner Freizeit. Alles kostenlos. Letztendlich ist es "Bastelei". Was nicht bedeutet das es sehr, sehr gute Projekte sind.

      Wenn ein 100% zuverlässiges System gesucht wird, sollte man sich event. im Fachhandel umschauen. Ob dort die entsprechenden System und Programme auch kostenlos angeboten werden, kann ich so nicht sagen. Ich glaube aber eher nicht.

      Grüße
      Manfred

      posted in Hardware
      B
      Beowolf
    • RE: Test Adapter iQontrol 2.0.x Vis (Entwicklungs-Thread)

      Vielen Dank. 👍 👍 👍

      Ich liebe dieses Forum und die Leute darin. 😊 😊

      posted in Tester
      B
      Beowolf
    • RE: E-INK Display OpenEPaperLink - Displayanzeige mit Batterie

      @bananajoe sagte in EPS E-INK Display Ansteuerung -> Statusdisplay für 2€:

      @beowolf hast du die selbst geflasht? In der Bucht sind die gerade zu kaufen und ich starre gerade schon eine ganze weile auf das Pinout wo ich denn ran müsste ... (ich bin Tasmota-verwöhnt, da wird immer ein Bild hinterlegt welche Pins man nehmen muss)

      Eines vorab. Das ist nicht auf meinem Mist gewachsen. Ich habe das auch nur mit der Hilfe von Aaron Christophel hin bekommen.

      Vielen, vielen Dank dafür.

      Hier z.B. ein Video von ihm.

      https://www.youtube.com/watch?v=8oQdo9bJ7Rk

      Es geht um diesen TAG

      https://github.com/jjwbruijn/OpenEPaperLink/wiki/2.9″-EL029H3WRA#pinout

      Für den Anschluss und Positionierung der POGO-Pins geht dieses z.B.

      https://github.com/jjwbruijn/OpenEPaperLink/blob/master/Hardware/M3 Newton Jigs by Jelmer/M3-2.9.stl

      Ich habe dieses

      https://github.com/jjwbruijn/OpenEPaperLink/tree/master/Tag_Flasher

      herunter geladen.

      Nun in das Verzeichnis ESP32_Flasher wechseln und dann mit der Hilfe von Visual Studio Code den Flasher auf einen ESP32 S2 aufgespielen.

      Den ESP dann so wie hier mit dem TAG verbinden.

      Anschluss schwarze TAGs.jpg

      Nun ein Verzeichnis höher gehen. Also in den Tag_Flasher Ordner gehen.

      Dann diese Datei herunterladen und in das Verzeichnis ablegen.

      https://github.com/jjwbruijn/OpenEPaperLink/blob/master/binaries/Tag/SOL_M3_Uni_full_26.bin

      Ich habe es mit diesem Befehl gemacht.

      python3 OEPL-Flasher.py -p COM11 -e -n write SOL_M3_Uni_full_26.bin --flash --pt

      COM11 natürlich anpassen.

      Für das Flashen muß auf dem Rechner Python installiert sein.

      Hier die passende Version laden.

      https://www.python.org/

      Bei dem Versuch kamen bei mir ein paar Meldungen das diese oder jenes nicht da ist.

      Ich musste z.b. dieses nachinstallieren: "pip install pyserial". Sollten da noch Meldungen kommen. einfach kurz bei google suchen.

      Danach sollte der Tag mit OPenEPaper geflasht sein.

      Ich hoffe ich habe nichts vergessen.

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • Wasserzähler fertige Platine

      Halloö zusammen,

      event. ist das ja etwas für den ein oder anderen.

      https://www.tindie.com/products/muino/smart-water-meter-reader/

      Grüße

      posted in Hardware
      B
      Beowolf
    • RE: E-INK Display OpenEPaperLink - Displayanzeige mit Batterie

      @bananajoe sagte in EPS E-INK Display Ansteuerung -> Statusdisplay für 2€:

      @beowolf sagte in EPS E-INK Display Ansteuerung -> Statusdisplay für 2€:

      Ich bin ein wenig Ratlos und weiß nicht wo ich anfangen soll.

      Hier mal grob in Schritten zusammengefasst:

      Schritt 1: Eigene VIS für die ePaper Tags
      .........

      Für die schwarzen TAGs muß die Auflösung geändert werden. Sonst gibt es nur Schrott in der Anzeige.

      M3.Newton.2.9-2.jpg

      Also auf 384 x 168 Pixel

      Grüße

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: E-INK Display OpenEPaperLink - Displayanzeige mit Batterie

      @bananajoe

      So, ich habe jetzt das Skript mal ein wenig umgebaut.

      sendTo('puppeteer.0', 'screenshot', { 
          url: urlOfVISView,                     
          path: imageSaveToFilenameWithPath,     
          width: viewWidth,                      
          height: viewHeight,                    
          quality: jpgQuality,                   
      
          waitOption: {
              waitForSelector: waitForSelector,  
              waitForTimeout: 20000              
          },
      
          fullPage: false,                       
      
          clip: {         
              x: cutoutX,                        
              y: cutoutY,                        
              width: cutoutWidth,                
              height: cutoutHeight               
          }
      }, obj => {
          if (obj.error) {
              console.warn("Fehler beim Aufruf der View: " + urlOfVISView + " => " + obj.error.message);
          } else {
              const http = require('http'); 
              const https = require('https');
              const { URL } = require('url');
      
              const boundary = '--------------------------' + Date.now().toString(16);
              const CRLF = '\r\n';
      
              // Payload-Erstellung
              const payload = Buffer.concat([
                  Buffer.from(`--${boundary}${CRLF}Content-Disposition: form-data; name="dither"${CRLF}${CRLF}0${CRLF}`),
                  Buffer.from(`--${boundary}${CRLF}Content-Disposition: form-data; name="mac"${CRLF}${CRLF}${ePaperMAC}${CRLF}`),
                  Buffer.from(`--${boundary}${CRLF}Content-Disposition: form-data; name="image"; filename="screenshot.jpg"${CRLF}Content-Type: image/jpeg${CRLF}${CRLF}`),
                  Buffer.from(obj.result, 'binary'),
                  Buffer.from(`${CRLF}--${boundary}--${CRLF}`)
              ]);
      
              // URL Parsing
              const url = new URL(imageUploadURL);
              const options = {
                  hostname: url.hostname,
                  port: url.port || (url.protocol === 'https:' ? 443 : 80),
                  path: url.pathname + (url.search || ''),
                  method: 'POST',
                  headers: {
                      'Content-Type': 'multipart/form-data; boundary=' + boundary,
                      'Content-Length': payload.length
                  }
              };
      
              // Protokollwahl
              const protocol = url.protocol === 'https:' ? https : http;
      
              // HTTP Request
              const req = protocol.request(options, function(res) {
                  console.log('ImageUploadStatusCode:', res.statusCode);
                  res.on('data', function(chunk) {
                      console.log('Response:', chunk.toString());
                  });
              });
      
              req.on('error', function(e) {
                  console.error('Fehler beim Hochladen:', e.message);
              });
      
              req.write(payload);
              req.end();
          }
      });
      

      Na ja, ich bin jetzt mal ehrlich. Ich habe ChatGPT solange damit gernervt bis ich eine Version hatte die jetzt funktioniert.

      Ich habe keine Ahnung was da wie gemacht wird, aber es läuft. Die TAG werden sehr schnell aktualisiert und alles ohne Fehlermeldungen. 😊

      Grüße
      Manfred

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: E-INK Display OpenEPaperLink - Displayanzeige mit Batterie

      Genau für den Fall, weil "request" nicht mehr geht, hatte ich doch das Skript geändert.

      Hier läuft es ohne Probleme mit der Java-Skriptversion 8.3.1

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf

    Latest posts made by Beowolf

    • RE: ioBroker installation?

      Danke für die schnellen Antorten.

      posted in Installation
      B
      Beowolf
    • ioBroker installation?

      Habe da mal ne Frage.

      Im Netz findet man mehrere Version der Installationsroutine

      1. Hier im Forum
      curl -sSLf https://iobroker.net/install.sh | bash -
      
      1. einmal diese Version
      curl -sL https://iobroker.net/install.sh | bash -
      
      1. und diese Version
      curl -sLf https://iobroker.net/install.sh | bash -
      

      Welche ist denn nun die Richtige, bzw. wo ist der Unterschied?

      Grüße
      Manfred

      posted in Installation
      B
      Beowolf
    • RE: IP-Scanner für das Hausnetz.

      Ok. Danke.

      posted in Off Topic
      B
      Beowolf
    • RE: IP-Scanner für das Hausnetz.

      @arteck
      Mag sein. Mein kleines PRogramm läuft "auserhalb" von ioBroker.

      Und das tolle an meinem Programm ist, es ist vollkommen kostenlos. Es kostet keine 5,95 €.

      😳 😳 😳

      posted in Off Topic
      B
      Beowolf
    • IP-Scanner für das Hausnetz.

      Das ist ein kleiner Webserver-Scanner für das eigene Netzwerk. Das Programm listet dann die gefundenen Adressen auf und durch einen Mausklick kann die entsprechende Adresse direkt aufgerufen werden.

      Der IP-Bereich kann eingestellt werden.

      Ich habe mal versucht eine Anleitung für das Programm zu schreiben.

      1. Entpacke die ZIP-Datei.

      2. Installiere PyInstaller (falls noch nicht geschehen):

        pip install pyinstaller

      3. Starte das Build-Skript build_webscanner.bat per Doppelklick oder über die Eingabeaufforderung:

        build_webscanner.bat

      4. Die fertige EXE-Datei findest du danach im Ordner dist.

      webscanner.zip

      Hier der Inhalt der einzelnen Dateien. Nichts böses drin. 😊

      webscanner.py

      import tkinter as tk
      from tkinter import ttk
      import webbrowser
      import socket
      import threading
      import queue
      from concurrent.futures import ThreadPoolExecutor
      
      START_IP = "192.168.49.1"
      END_IP = "192.168.49.254"
      PORTS = [80]
      
      def ip_to_int(ip):
          parts = list(map(int, ip.split(".")))
          return (parts[0]<<24) + (parts[1]<<16) + (parts[2]<<8) + parts[3]
      
      def int_to_ip(i):
          return f"{(i>>24)&0xFF}.{(i>>16)&0xFF}.{(i>>8)&0xFF}.{i&0xFF}"
      
      def generate_ips(start_ip, end_ip):
          start = ip_to_int(start_ip)
          end = ip_to_int(end_ip)
          for i in range(start, end+1):
              yield int_to_ip(i)
      
      class WebserverScanner:
          def __init__(self, progress_callback=None):
              self.progress_callback = progress_callback
      
          def scan_ip_port(self, ip, port):
              try:
                  with socket.create_connection((ip, port), timeout=0.5):
                      return True
              except:
                  return False
      
          def get_hostname(self, ip):
              try:
                  return socket.gethostbyaddr(ip)[0]
              except:
                  return "Kein Hostname"
      
          def scan_threaded(self, ips, ports):
              results = []
              total = len(ips)*len(ports)
              count_lock = threading.Lock()
              count = [0]
      
              def scan_one(ip_port):
                  ip, port = ip_port
                  if self.scan_ip_port(ip, port):
                      hostname = self.get_hostname(ip)
                      res = {"ip": ip, "hostname": hostname, "port": port}
                  else:
                      res = None
                  with count_lock:
                      count[0] += 1
                      if self.progress_callback:
                          self.progress_callback(count[0], total)
                  return res
      
              ip_ports = [(ip, port) for ip in ips for port in ports]
      
              with ThreadPoolExecutor(max_workers=100) as executor:
                  for r in executor.map(scan_one, ip_ports):
                      if r:
                          results.append(r)
      
              return results
      
      class WebserverViewerApp:
          def __init__(self, root):
              self.root = root
              self.root.title("Webserver Scanner 192.168.49.x")
              self.root.geometry("900x700")
      
              self.entries = []
              self.queue = queue.Queue()
              self.resize_after_id = None
              self.current_columns = None  # Merke letzte Spaltenanzahl
              self.entries_displayed = None
      
              self.header = tk.Label(root, text="Webserver Scanner 192.168.49.1 - 254", font=("Arial", 18))
              self.header.pack(pady=10)
      
              self.progress = ttk.Progressbar(root, orient="horizontal", length=600, mode="determinate")
              self.progress.pack(pady=10)
      
              self.status_label = tk.Label(root, text="Bereit", font=("Arial", 12))
              self.status_label.pack()
      
              self.update_btn = tk.Button(root, text="Jetzt scannen", command=self.start_scan)
              self.update_btn.pack(pady=10)
      
              self.canvas = tk.Canvas(root)
              self.scroll_frame = tk.Frame(self.canvas)
              self.scrollbar = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
              self.canvas.configure(yscrollcommand=self.scrollbar.set)
      
              self.scrollbar.pack(side="right", fill="y")
              self.canvas.pack(fill="both", expand=True)
      
              # Erstelle Fenster-Item für scroll_frame im Canvas
              self.canvas_frame = self.canvas.create_window((0,0), window=self.scroll_frame, anchor="nw")
      
              # Scrollregion aktualisieren bei Größe des scroll_frame
              self.scroll_frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
      
              # Breite des scroll_frame immer an Canvas-Breite anpassen
              self.canvas.bind('<Configure>', self.resize_scroll_frame)
      
              # Debounced Resize-Handler für Fenstergröße
              self.root.bind("<Configure>", self.on_resize)
      
              self.root.after(100, self.check_queue)
      
          def resize_scroll_frame(self, event):
              self.canvas.itemconfig(self.canvas_frame, width=event.width)
      
          def on_resize(self, event):
              # Debounce mit 300ms Delay
              if self.resize_after_id:
                  self.root.after_cancel(self.resize_after_id)
              self.resize_after_id = self.root.after(300, lambda: self.update_display(self.entries))
      
          def start_scan(self):
              self.update_btn.config(state="disabled")
              self.progress['value'] = 0
              self.status_label.config(text="Scan läuft...")
              threading.Thread(target=self.run_scan, daemon=True).start()
      
          def progress_callback(self, count, total):
              percent = int((count / total) * 100)
              self.queue.put(("progress", percent))
      
          def run_scan(self):
              scanner = WebserverScanner(progress_callback=self.progress_callback)
              ips = list(generate_ips(START_IP, END_IP))
              results = scanner.scan_threaded(ips, PORTS)
              self.queue.put(("done", results))
      
          def check_queue(self):
              try:
                  while True:
                      msg, data = self.queue.get_nowait()
                      if msg == "progress":
                          self.progress['value'] = data
                          self.status_label.config(text=f"Scan läuft... {data}%")
                      elif msg == "done":
                          self.entries = data
                          self.update_display(data)
                          self.status_label.config(text=f"Scan abgeschlossen. {len(data)} Server gefunden.")
                          self.update_btn.config(state="normal")
              except queue.Empty:
                  pass
              self.root.after(100, self.check_queue)
      
          def update_display(self, entries):
              # Berechne aktuelle Spaltenanzahl
              frame_width = self.canvas.winfo_width() or 900
              box_min_width = 170
              columns = max(1, frame_width // box_min_width)
      
              # Prüfe, ob Spaltenanzahl oder Einträge sich geändert haben
              if self.current_columns == columns and self.entries_displayed == entries:
                  return
      
              self.current_columns = columns
              self.entries_displayed = entries
      
              # Alte Widgets löschen
              for widget in self.scroll_frame.winfo_children():
                  widget.destroy()
      
              if not entries:
                  tk.Label(self.scroll_frame, text="Keine Webserver gefunden", font=("Arial", 14), fg="red").pack(pady=20)
                  return
      
              box_height = 110
              for index, entry in enumerate(entries):
                  row = index // columns
                  col = index % columns
      
                  container = tk.Frame(self.scroll_frame, bd=1, relief="solid", padx=5, pady=5)
                  container.grid(row=row, column=col, padx=5, pady=5, sticky="nsew")
      
                  ip_label = tk.Label(container, text=entry['ip'], font=("Arial", 12, "bold"))
                  ip_label.pack()
      
                  if entry['hostname']:
                      host_label = tk.Label(container, text=entry['hostname'], font=("Arial", 10), fg="gray")
                      host_label.pack()
      
                  btn_color = "#4CAF50" if entry['port'] == 80 else "#2196F3"
                  open_button = tk.Button(container, text=f"Öffnen (Port {entry['port']})",
                                          bg=btn_color, fg="white",
                                          command=lambda ip=entry['ip'], port=entry['port']: self.open_url(ip, port))
                  open_button.pack(pady=5, fill="x")
      
              # Spalten gleichmäßig verteilen
              for c in range(columns):
                  self.scroll_frame.grid_columnconfigure(c, weight=1)
      
          def open_url(self, ip, port):
              url = f"https://{ip}" if port == 443 else f"http://{ip}"
              webbrowser.open(url)
      
      if __name__ == "__main__":
          root = tk.Tk()
          app = WebserverViewerApp(root)
          root.mainloop()
      
      

      build_webscanner.bat

      @echo off
      echo.
      echo ===============================
      echo   Building webscanner.exe ...
      echo ===============================
      echo.
      
      
      
      pyinstaller webscanner.spec
      
      echo.
      echo Fertig! EXE liegt in /dist/webscanner.exe
      pause
      

      webscanner.spec

      # webscanner.spec
      block_cipher = None
      
      a = Analysis(
          ['webscanner.py'],
          pathex=[],
          binaries=[],
          datas=[],
          hiddenimports=[],
          hookspath=[],
          hooksconfig={},
          runtime_hooks=[],
          excludes=[],
          win_no_prefer_redirects=False,
          win_private_assemblies=False,
          cipher=block_cipher,
          noarchive=False,
      )
      
      pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
      
      exe = EXE(
          pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='webscanner',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False,  # GUI-Anwendung (kein Terminalfenster)
          )
      
      coll = COLLECT(
          exe,
          a.binaries,
          a.zipfiles,
          a.datas,
          strip=False,
          upx=True,
          name='webscanner',
      )
      

      Das Programm kann natürlich auch direkt im cmd-Fenster (Windows) durch python webscanner.py im entsprechenden Verzeichnis gestartet werden.

      Vor dem Start oder der Erstellung der EXE-Datei muß natürlich der IP-Bereich in webscanner.py angepasst werden.

      START_IP = "192.168.49.1"
      END_IP = "192.168.49.254"
      PORTS = [80]
      

      Wenn es läuft, sollte es etwa so aussehen:

      webscanner.jpg

      Viel Spaß damit

      posted in Off Topic
      B
      Beowolf
    • RE: OpenEpaperLink - Script für Tastenabfrage

      Hier ein geändertes Skript für die, die mehrere APs haben.

      //
      // #############################################
      //
      // Dieses Script ermöglicht die Buttonabfrage.
      //
      // In dem Script wird die Socket-Verbindung von Beowolf verwendet (https://forum.iobroker.net/topic/66380/e-ink-display-openepaperlink-displayanzeige-mit-batterie/809?_=1747419968864)
      //
      // Ein erweitertes Skript von Eisbaeeer ist hier (https://forum.iobroker.net/topic/81101/openepaperlink-script-für-tastenabfrage )
      //
      // Die Button-States werden unter dem konfigurierten basePathPrefix erzeugt.
      //
      // #############################################
      
      // #############################################
      //
      // Konfigurierbare Variablen - Hier die Anpassungen vornehmen!
      //
      
      
      const rootPath = '0_userdata.0'; // Bei Bedarf anpassen
      const controlRoot = 'EPaperControl'; // Oberordner für Steuerung
      const buttonRoot = 'Buttons'; // Unterordner für Buttons
      
      const accesspoints = [
          { location: 'Erdgeschoss', ip: '192.168.49.185' }, // Accesspoint IP Adresse
          { location: 'Obergeschoss', ip: '192.168.49.186' }, // Accesspoint IP Adresse
          { location: 'Dachgeschoss', ip: '192.168.49.187' }, // Accesspoint IP Adresse
          { location: 'Hühnerhaus', ip: '192.168.49.139' } // Accesspoint IP Adresse
      ];
      
      //
      // ENDE Anpassungen! Ab hier nichts mehr ändern!
      // #############################################
      //
      
      // Automatisch generierte Pfade für jeden Accesspoint
      accesspoints.forEach(ap => {
          ap.name = `${ap.location}-AP`;
          ap.controlState = `${rootPath}.${controlRoot}.${ap.location}.Start`;
          ap.buttonPathPrefix = `${rootPath}.${controlRoot}.${ap.location}.${buttonRoot}`;
      });
      
      const WebSocket = require('ws');
      
      let wsConnections = {};
      let pingIntervals = {};
      let scriptStatus = {};
      
      // Initialisierung der Steuerobjekte
      accesspoints.forEach(ap => {
          scriptStatus[ap.name] = false;
      
          setObject(ap.controlState, {
              type: 'state',
              common: {
                  name: `Start/Stop ${ap.name}`,
                  type: 'boolean',
                  role: 'switch',
                  read: true,
                  write: true,
                  def: false
              },
              native: {}
          });
      
          on({ id: ap.controlState, change: 'ne' }, (obj) => {
              if (obj.state.val === true) {
                  scriptStatus[ap.name] = true;
                  connectWebSocket(ap.name, ap.ip);
              } else {
                  scriptStatus[ap.name] = false;
                  disconnectWebSocket(ap.name);
              }
          });
      
          getState(ap.controlState, (err, state) => {
              if (!err && state && state.val === true) {
                  scriptStatus[ap.name] = true;
                  connectWebSocket(ap.name, ap.ip);
              }
          });
      });
      
      function connectWebSocket(name, ip) {
          if (wsConnections[name]) return;
      
          const url = `ws://${ip}/ws`;
          const ws = new WebSocket(url);
          wsConnections[name] = ws;
      
          ws.on('open', () => {
              console.log(`WebSocket ${name} verbunden (${ip})`);
              pingIntervals[name] = setInterval(() => {
                  if (ws.readyState === WebSocket.OPEN) {
                      ws.ping();
                  }
              }, 10000);
          });
      
          ws.on('message', (data) => {
              try {
                  const parsed = JSON.parse(data);
                  handleData(name, parsed);
              } catch {
                  // Parsing-Fehler ignorieren
              }
          });
      
          ws.on('close', () => {
              clearInterval(pingIntervals[name]);
              delete wsConnections[name];
              if (scriptStatus[name]) {
                  setTimeout(() => connectWebSocket(name, ip), 5000);
              }
          });
      
          ws.on('error', () => {
              // Fehler ignorieren
          });
      }
      
      function disconnectWebSocket(name) {
          if (wsConnections[name]) {
              wsConnections[name].close();
              clearInterval(pingIntervals[name]);
              delete wsConnections[name];
              delete pingIntervals[name];
          }
      }
      
      function handleData(apName, parsedData) {
          const ap = accesspoints.find(a => a.name === apName);
          if (!ap || !scriptStatus[ap.name]) return;
      
          if (!parsedData.tags || !Array.isArray(parsedData.tags) || parsedData.tags.length === 0) return;
      
          parsedData.tags.forEach(tag => {
              if (!tag.mac) return;
      
              const macClean = tag.mac.replace(/:/g, '');
              const basePath = `${ap.buttonPathPrefix}.${macClean}`;
      
              ensureChannelExists(basePath, tag.alias || tag.name || 'Unbenannt', () => {
                  if ('wakeupReason' in tag) {
                      const statePath = `${basePath}.wakeupReason`;
                      updateStateIfChanged(statePath, tag.wakeupReason);
                  }
              });
          });
      }
      
      function ensureChannelExists(id, name, callback) {
          getObject(id, (err, obj) => {
              if (!obj) {
                  setObject(id, {
                      type: 'channel',
                      common: { name: name },
                      native: {}
                  }, callback);
              } else {
                  callback();
              }
          });
      }
      
      function updateStateIfChanged(id, value) {
          if (value === null || value === undefined) return;
      
          const isPrimitive = val => ['string', 'number', 'boolean'].includes(typeof val);
      
          let storedValue = value;
          let valueType = typeof value;
      
          if (!isPrimitive(value)) {
              try {
                  storedValue = JSON.stringify(value);
                  valueType = 'string';
              } catch {
                  return;
              }
          }
      
          getState(id, (err, state) => {
              if (err || !state) {
                  setObject(id, {
                      type: 'state',
                      common: {
                          name: id.split('.').pop(),
                          type: valueType,
                          role: 'value',
                          read: true,
                          write: false
                      },
                      native: {}
                  }, () => setState(id, storedValue, true));
              } else if (state.val !== storedValue) {
                  setState(id, storedValue, true);
              }
          });
      }
      
      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: OpenEpaperLink - Script für Tastenabfrage

      Habe das Skript mal NUR für die Button geändert. Es wird kein Inhalt an die TAGs gesendet.

      //
      // #############################################
      //
      // Dieses Script ermöglicht die Buttonabfrage.
      //
      // In dem Script wird die Socket-Verbindung von Beowolf verwendet (https://forum.iobroker.net/topic/66380/e-ink-display-openepaperlink-displayanzeige-mit-batterie/809?_=1747419968864)
      //
      // Ein erweitertes Skript von Eisbaeeer ist hier (https://forum.iobroker.net/topic/81101/openepaperlink-script-für-tastenabfrage )
      //
      // Die Button-States werden unter dem konfigurierten basePathPrefix erzeugt.
      //
      // #############################################
      
      // #############################################
      //
      // Konfigurierbare Variablen - Hier die Anpassungen vornehmen!
      //
      
      const controlStatePath = '0_userdata.0.Buttons-DG-TAGs';   // Basis für controlState und basePath
      const controlState = `${controlStatePath}.Start`;          // Skript starten oder beenden
      const basePathPrefix = `${controlStatePath}.Tag_Buttons`;  // Basis-Pfad für Button-States
      const accesspointIP = '192.168.49.187';                    // Accesspoint IP Adresse
      
      //
      // ENDE Anpassungen! Ab hier nichts mehr ändern!
      // #############################################
      
      
      
      
      
      const wsUrl = `ws://${accesspointIP}/ws`;
      const WebSocket = require('ws');
      
      let ws;
      let pingInterval;
      let scriptStopping = false;
      
      function connectWebSocket() {
          if (scriptStopping) return;
          ws = new WebSocket(wsUrl);
      
          ws.on('open', () => {
              console.log('WebSocket verbunden');
              startHeartbeat();
          });
      
          ws.on('message', (data) => {
              try {
                  const parsed = JSON.parse(data);
                  handleData(parsed);
              } catch (err) {
                  // Parsing-Fehler ignorieren
              }
          });
      
          ws.on('close', () => {
              clearInterval(pingInterval);
              if (!scriptStopping) setTimeout(connectWebSocket, 5000);
          });
      
          ws.on('error', () => {
              // WebSocket-Fehler ignorieren
          });
      }
      
      function startHeartbeat() {
          pingInterval = setInterval(() => {
              if (ws.readyState === WebSocket.OPEN) {
                  ws.ping();
              }
          }, 10000);
      }
      
      function handleData(parsedData) {
          if (!parsedData.tags || !Array.isArray(parsedData.tags) || parsedData.tags.length === 0) {
              return;
          }
      
          parsedData.tags.forEach(tag => {
              if (!tag.mac) return;
      
              const macClean = tag.mac.replace(/:/g, '');
              const basePath = `${basePathPrefix}.${macClean}`;
      
              ensureChannelExists(basePath, tag.alias || tag.name || 'Unbenannt', () => {
                  if ('wakeupReason' in tag) {
                      const statePath = `${basePath}.wakeupReason`;
                      updateStateIfChanged(statePath, tag.wakeupReason);
                  }
              });
          });
      }
      
      function ensureChannelExists(id, name, callback) {
          getObject(id, (err, obj) => {
              if (!obj) {
                  setObject(id, {
                      type: 'channel',
                      common: {
                          name: name
                      },
                      native: {}
                  }, callback);
              } else {
                  callback();
              }
          });
      }
      
      function updateStateIfChanged(id, value) {
          if (value === null || value === undefined) return;
      
          const isPrimitive = val => ['string', 'number', 'boolean'].includes(typeof val);
      
          let storedValue = value;
          let valueType = typeof value;
      
          if (!isPrimitive(value)) {
              try {
                  storedValue = JSON.stringify(value);
                  valueType = 'string';
              } catch {
                  return;
              }
          }
      
          getState(id, (err, state) => {
              if (err || !state) {
                  setObject(id, {
                      type: 'state',
                      common: {
                          name: id.split('.').pop(),
                          type: valueType,
                          role: 'value',
                          read: true,
                          write: false
                      },
                      native: {}
                  }, () => setState(id, storedValue, true));
              } else if (state.val !== storedValue) {
                  setState(id, storedValue, true);
              }
          });
      }
      
      function disconnectWebSocket() {
          if (ws) {
              ws.close();
              ws = null;
          }
          clearInterval(pingInterval);
      }
      
      function setupControl() {
          setObject(controlState, {
              type: 'state',
              common: {
                  name: 'EPaper Script Control',
                  type: 'boolean',
                  role: 'switch',
                  read: true,
                  write: true,
                  def: true
              },
              native: {}
          });
      
          on({ id: controlState, change: 'ne' }, (obj) => {
              if (obj.state.val === true) {
                  scriptStopping = false;
                  connectWebSocket();
              } else {
                  scriptStopping = true;
                  disconnectWebSocket();
              }
          });
      
          getState(controlState, (err, state) => {
              if (!err && state && state.val === true) {
                  connectWebSocket();
              }
          });
      }
      
      setupControl();
      

      Hier wird jetzt nur der Datenpunkt "wakeupReason" angelegt.

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: OpenEpaperLink - Script für Tastenabfrage

      @eisbaeeer

      Fein, fein. Danke dafür.

      Ich habe das Skript jetzt noch nicht probiert.

      Besteht mit dem Skript auch die Möglichkeit, das ich mit den Tasten auch eine z.B. Lampe über ioBroker schalten kann?

      posted in Praktische Anwendungen (Showcase)
      B
      Beowolf
    • RE: Shelly Pro3EM ohne Shelly Adapter?

      @mcm1957 sagte in Shelly Pro3EM ohne Shelly Adapter?:

      Allerdings musst du dich dann selbst um alles kümmern

      Ok, das ist natürlich ein guter Grund für den Adapter. Danke für die Erklärungen.

      Grüße

      posted in Einbindung von Geräten
      B
      Beowolf
    • Shelly Pro3EM ohne Shelly Adapter?

      Hallo zusammen,

      ich hatte schon gesucht, aber nicht wirklich was gefunden bei dem ich sicher bin das es passt.

      Deshalb hier die Frage: Kann ich einen Shelly Pro3EM ohne Shelly Adapter mit ioBroker verbinden?

      Ich hatte, weiß leider nicht mehr wo gelesen, das der Shelly nur sein "eigenen mqtt-Broker" anspricht und nicht den mqtt-Adapter den ich unter ioBroker schon habe.

      Stimmt das?

      Grüße
      Manfred

      posted in Einbindung von Geräten
      B
      Beowolf
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo