Hauptmenü

Neueste Beiträge

#41
Multimedia / Aw: [Neues Modul] BOSE SoundTo...
Letzter Beitrag von JoWiemann - 21 Februar 2026, 09:30:59
Hallo pah,

sorry, aber keine der Variablen sind im FritzBox Modul vorhanden. Kannst Du feststellen, ab welcher Version des Moduls die Überschneidung auftritt? Ich würde dann ein Diff prüfen. Tritt das Problem auch bei Dir auf?

Grüße Jörg

Btw. Ich stelle das Modul gerade auf Package um. Ist allerdings im Nachhinein echt mit Aufwand verbunden.
#42
Multimedia / Aw: [82_LGTV_WebOS.pm] Modul f...
Letzter Beitrag von CoolTux - 21 Februar 2026, 09:11:03
Zitat von: fireball am 21 Februar 2026, 08:48:02Moin, mein aktueller LG G5 mit Firmware 33.22.95 funzt auch super mit dem lgtv Tool auf der cmdline...

Nach dem Pairing, die Konfig noch um die MAC Adresse erweitert.

Nun funzt lauter, leiser, an und aus, umschalten auf Netflex (aber kein aus, direkt aus Netflix)

root@TestOnly:~/.config/lgtv# lgtv volume set 10
Volume set to 10
root@TestOnly:~/.config/lgtv# lgtv volume set 9
Volume set to 9
root@TestOnly:~/.config/lgtv# lgtv volume set 3
Volume set to 3
root@TestOnly:~/.config/lgtv# lgtv app launch Netflix
Launched: Netflix
root@TestOnly:~/.config/lgtv# lgtv power off
TV powered off
root@TestOnly:~/.config/lgtv# lgtv power on
Sending Wake-on-LAN packet to 00:A1:44:BD:44:BC...
Wake-on-LAN packet sent. TV should power on shortly.
Waiting for TV to respond...
TV is now online and responsive

Wäre cool, wenn man das Modul dahingehend pimpen könnte?!
VG+Danke

Reden wir hier vom FHEM Modul oder von irgend so ein python Teil.
Wenn es sich bei Deiner Anfrage nicht um das FHEM Modul handelt, dann würde ich Dich bitten für Dein Anliegen einen eigenen Thread an zu legen.
#43
Multimedia / Aw: [82_LGTV_WebOS.pm] Modul f...
Letzter Beitrag von CoolTux - 21 Februar 2026, 09:08:42
Zitat von: locodriver am 20 Februar 2026, 17:47:09
Zitat von: CoolTux am 27 Januar 2026, 19:02:05appId":"de.zdf.app.zdfm3

Das ist genau das was ich brauche. Danke Dir Uwe. Ich schau mal das ich die Tage die Anpassungen mache.

Hallo CoolTux, hast du schon Zeit gefunden,die Ergänzung einzubauen?

Dankeschön.

Erledigt. Sollte morgen früh im Update enthalten sein.
#44
FHEM Code changes / Revision 30874: controls_fhem....
Letzter Beitrag von System - 21 Februar 2026, 08:50:09
Revision 30874: controls_fhem.txt: fhemupdate checkin

controls_fhem.txt: fhemupdate checkin

Source: Revision 30874: controls_fhem.txt: fhemupdate checkin
#45
Multimedia / Aw: [82_LGTV_WebOS.pm] Modul f...
Letzter Beitrag von fireball - 21 Februar 2026, 08:48:02
Moin, mein aktueller LG G5 mit Firmware 33.22.95 funzt auch super mit dem lgtv Tool auf der cmdline...

Nach dem Pairing, die Konfig noch um die MAC Adresse erweitert.

Nun funzt lauter, leiser, an und aus, umschalten auf Netflex (aber kein aus, direkt aus Netflix)

root@TestOnly:~/.config/lgtv# lgtv volume set 10
Volume set to 10
root@TestOnly:~/.config/lgtv# lgtv volume set 9
Volume set to 9
root@TestOnly:~/.config/lgtv# lgtv volume set 3
Volume set to 3
root@TestOnly:~/.config/lgtv# lgtv app launch Netflix
Launched: Netflix
root@TestOnly:~/.config/lgtv# lgtv power off
TV powered off
root@TestOnly:~/.config/lgtv# lgtv power on
Sending Wake-on-LAN packet to 00:A1:44:BD:44:BC...
Wake-on-LAN packet sent. TV should power on shortly.
Waiting for TV to respond...
TV is now online and responsive

Wäre cool, wenn man das Modul dahingehend pimpen könnte?!
VG+Danke
#46
FHEM Development / Aw: HttpUtils_NonblockingGet: ...
Letzter Beitrag von Dr. Boris Neubert - 21 Februar 2026, 08:28:34
passibe, der in diesem Board nicht schreiben darf, hat mich noch darauf gebracht, dass ich zum Vergleich das Ergebnis des HttpUtils_NonBlockingGet() zeigen sollte. Hier ist es:

POST /doUpload?dir=%2Fimage%2F HTTP/1.0
Host: dora.intern.gs21.de:9999
User-Agent: fhem
Accept-Encoding: gzip,deflate
Content-Type: multipart/form-data
Content-Length: 8291

����JFIF``��>CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), default quality
��C             





▒▒ $.' ",#(7),01444'9=82<.342��C


▒2!!22222222222222222222222222222222222222222222222222�X "��

���}!1AQa"q2��#B��R��$3br�
▒▒%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz���������������������������������������������������������������������������

���w!1AQaq"2B����       #3R�br�
$4�%�▒▒&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������
                                                                                                                            ?���(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(���

Beide Requests habe ich übrigens eingefangen, indem ich nc -l -p 9999 in einem Terminal habe laufen lassen und localhost:9999 als URL angegeben habe.

Man sieht, dass curl einen Multipart-Request schickt und mit dem Bilddaten noch einen eigenen Header mitsendet. Wie bringt man HttpUtils_NonBlockingGet() dazu?
#47
Automatisierung / Aw: Befehl an Shelly erneut se...
Letzter Beitrag von Starkstrombastler - 21 Februar 2026, 08:20:52
Zitat von: Hadl am 20 Februar 2026, 22:51:59Stimmt, aber im Notify auf "Error" weis ich den Befehl ja leider nichtmehr der fehlgeschlagen ist. Ich müsste erst einen Soll/Ist vergleich machen um den Befehl nochmals zu senden. Das ist relativ hoher Programieraufwand und ich wollte schauen ob es nicht einfacher geht.
Du kannst bei Netzwerkproblemen das Attribut timeout auf einen höheren Wert (Standard: 4 sec) setzen. Es werden dann zusätzliche Readings mit den aktuellen/maximalen Reaktionszeiten und ein Reading mit dem letzten SET Befehl angelegt.
#48
Multimedia / Aw: [82_LGTV_WebOS.pm] Modul f...
Letzter Beitrag von CoolTux - 21 Februar 2026, 06:35:44
Zitat von: locodriver am 20 Februar 2026, 17:47:09
Zitat von: CoolTux am 27 Januar 2026, 19:02:05appId":"de.zdf.app.zdfm3

Das ist genau das was ich brauche. Danke Dir Uwe. Ich schau mal das ich die Tage die Anpassungen mache.

Hallo CoolTux, hast du schon Zeit gefunden,die Ergänzung einzubauen?

Dankeschön.

Leider noch nicht.
#49
Codeschnipsel / Abfrage der Radiosender einer ...
Letzter Beitrag von Prof. Dr. Peter Henning - 21 Februar 2026, 05:27:48
Der nachfolgende Code schreibt das in eine Datei presets.xml für Bose-Boxen um. Kann leicht angepasst werden für andere Zwecke.

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Getopt::Long qw(GetOptions);
use LWP::UserAgent;
use URI;
use XML::LibXML;
use XML::Writer;
use IO::File;

# ---------------- CLI ----------------
my $location    = undef;  # Pflicht, z.B. http://192.168.0.254:49000/MediaServerDevDesc.xml
my $out_file    = "presets.xml";
my $start_id    = 1;
my $max_presets = 99;
my $timeout_s   = 12;
my $debug       = 0;

GetOptions(
  "location=s" => \$location,
  "out=s"      => \$out_file,
  "start=i"    => \$start_id,
  "max=i"      => \$max_presets,
  "timeout=i"  => \$timeout_s,
  "debug!"     => \$debug,
) or die "Usage: $0 --location <URL> [--out presets.xml] [--start 1] [--max 99] [--timeout 12] [--debug]\n";

die "Fehlt: --location (z.B. http://192.168.0.254:49000/MediaServerDevDesc.xml)\n"
  if !$location;

# ---------------- Helpers ----------------
sub norm    { my $s = shift // ""; $s =~ s/^\s+|\s+$//g; return $s; }
sub lc_norm { return lc(norm(shift)); }

# ---------------- HTTP Client ----------------
my $ua = LWP::UserAgent->new(
  agent   => "fritz-favs-to-presets/1.0",
  timeout => $timeout_s,
);
$ua->env_proxy;

# ---------------- 1) Device Description holen ----------------
my $desc_res = $ua->get($location);
die "GET DeviceDesc fehlgeschlagen: " . $desc_res->status_line . "\n"
  if !$desc_res->is_success;

my $desc_xml = $desc_res->decoded_content;
my $desc_doc = XML::LibXML->load_xml(string => $desc_xml);

# Base-URL für relative controlURL
my $loc_uri = URI->new($location);
my $base = $loc_uri->scheme . "://" . $loc_uri->host_port;

# UDN (ohne uuid:)
my ($udn_node) = $desc_doc->findnodes('//*[local-name()="UDN"]');
my $udn = $udn_node ? norm($udn_node->textContent) : "";
$udn =~ s/^uuid://i;
die "Konnte UDN nicht aus DeviceDesc lesen.\n" if !$udn;

# ContentDirectory Service finden -> controlURL
my ($cd_service) = $desc_doc->findnodes(
  '//*[local-name()="service"]/*[local-name()="serviceType" and contains(., "ContentDirectory:1")]/..'
);
die "Kein ContentDirectory:1 Service in DeviceDesc gefunden.\n" if !$cd_service;

my ($control_node) = $cd_service->findnodes('./*[local-name()="controlURL"]');
die "Kein controlURL im ContentDirectory Service.\n" if !$control_node;

my $control_url = norm($control_node->textContent);
$control_url = $base . $control_url if $control_url =~ m{^/};

print "Using FRITZ!Box ContentDirectory controlURL: $control_url\n" if $debug;
print "sourceAccount: $udn/0\n" if $debug;

# ---------------- 2) SOAP Browse ----------------
sub soap_browse {
  my (%p) = @_;
  my $object_id = $p{ObjectID}   // "0";
  my $flag      = $p{BrowseFlag} // "BrowseDirectChildren";

  my $body =
      qq{<?xml version="1.0" encoding="utf-8"?>\n}
    . qq{<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">\n}
    . qq{  <s:Body>\n}
    . qq{    <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">\n}
    . qq{      <ObjectID>$object_id</ObjectID>\n}
    . qq{      <BrowseFlag>$flag</BrowseFlag>\n}
    . qq{      <Filter>*</Filter>\n}
    . qq{      <StartingIndex>0</StartingIndex>\n}
    . qq{      <RequestedCount>0</RequestedCount>\n}
    . qq{      <SortCriteria></SortCriteria>\n}
    . qq{    </u:Browse>\n}
    . qq{  </s:Body>\n}
    . qq{</s:Envelope>\n};

  my $req = HTTP::Request->new(POST => $control_url);
  $req->header('Content-Type' => 'text/xml; charset="utf-8"');
  $req->header('SOAPACTION'   => '"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"');
  $req->content($body);

  my $res = $ua->request($req);
  if (!$res->is_success) {
    die "SOAP Browse fehlgeschlagen (ObjectID=$object_id): " . $res->status_line . "\n"
      . $res->decoded_content . "\n";
  }

  my $soap = XML::LibXML->load_xml(string => $res->decoded_content);

  # <Result> enthält DIDL-Lite als escaped XML
  my ($result_node) = $soap->findnodes('//*[local-name()="Result"]');
  my $result = $result_node ? $result_node->textContent : "";
  $result = norm($result);

  return $result;
}

# ---------------- 3) DIDL-Lite parsen ----------------
sub parse_didl {
  my ($didl_str) = @_;
  return ([], []) if !$didl_str;

  my $didl_doc = XML::LibXML->load_xml(string => $didl_str);

  my @containers;
  for my $c ($didl_doc->findnodes('//*[local-name()="container"]')) {
    my $id = $c->getAttribute("id") // "";
    my ($t) = $c->findnodes('./*[local-name()="title"]');
    my $title = $t ? norm($t->textContent) : "";
    push @containers, { id => norm($id), title => $title };
  }

  my @items;
  for my $it ($didl_doc->findnodes('//*[local-name()="item"]')) {
    my $id = $it->getAttribute("id") // "";
    my ($t) = $it->findnodes('./*[local-name()="title"]');
    my $title = $t ? norm($t->textContent) : "";

    my ($art) = $it->findnodes('.//*[local-name()="albumArtURI"]');
    my $albumart = $art ? norm($art->textContent) : "";

    push @items, { id => norm($id), title => $title, art => $albumart };
  }

  return (\@containers, \@items);
}

# ---------------- 4) Debug: Container/Items auflisten ----------------
sub dump_children_one_level {
  my ($parent_id, $limit_items) = @_;
  $limit_items //= 15;

  my $didl = soap_browse(ObjectID => $parent_id, BrowseFlag => "BrowseDirectChildren");
  my ($containers, $items) = parse_didl($didl);

  print "\n== Children of $parent_id ==\n";
  print "Containers: " . scalar(@$containers) . "\n";
  for my $c (@$containers) {
    printf "  [C] %-45s  id=%s\n", ($c->{title} // ""), ($c->{id} // "");
  }

  print "Items: " . scalar(@$items) . "\n";
  my $max = @$items < $limit_items ? @$items : $limit_items;
  for (my $i=0; $i<$max; $i++) {
    my $it = $items->[$i];
    printf "  [I] %-45s  id=%s\n", ($it->{title} // ""), ($it->{id} // "");
  }
}

# ---------------- 5) BFS: Container per Titel finden ----------------
sub find_container_bfs {
  my (%p) = @_;
  my $root      = $p{root}      // "0";
  my $want_re   = $p{want_re};              # regex auf lowercased title
  my $max_nodes = $p{max_nodes} // 12000;

  my @q = ($root);
  my %seen;
  my $visited = 0;

  while (@q) {
    my $cur = shift @q;
    next if $seen{$cur}++;
    last if ++$visited > $max_nodes;

    my $didl = soap_browse(ObjectID => $cur, BrowseFlag => "BrowseDirectChildren");
    my ($containers, undef) = parse_didl($didl);

    for my $c (@$containers) {
      my $t = lc_norm($c->{title});
      return $c->{id} if defined($want_re) && $t =~ $want_re;
      push @q, $c->{id};
    }
  }
  return undef;
}

# ---------------- 6) Fallback: "beste Senderliste" finden ----------------
# Heuristik: Container mit vielen Items und wenigen Subcontainern
sub find_best_station_list_container {
  my (%p) = @_;
  my $root      = $p{root}      // "0";
  my $max_nodes = $p{max_nodes} // 20000;

  my @q = ($root);
  my %seen;
  my $visited = 0;

  my $best_id    = undef;
  my $best_score = -1;
  my $best_items = 0;
  my $best_conts = 0;

  while (@q) {
    my $cur = shift @q;
    next if $seen{$cur}++;
    last if ++$visited > $max_nodes;

    my $didl = soap_browse(ObjectID => $cur, BrowseFlag => "BrowseDirectChildren");
    my ($containers, $items) = parse_didl($didl);

    my $num_items = scalar(@$items);
    my $num_conts = scalar(@$containers);

    # Favoritenlisten sind oft: viele Items, wenig Untercontainer
    my $score = $num_items * 10 - $num_conts;

    if ($num_items > 0 && $score > $best_score) {
      $best_score = $score;
      $best_id    = $cur;
      $best_items = $num_items;
      $best_conts = $num_conts;
    }

    # weiter runter
    for my $c (@$containers) {
      push @q, $c->{id};
    }
  }

  print "Fallback best container: $best_id (items=$best_items containers=$best_conts score=$best_score)\n"
    if $debug && defined $best_id;

  return $best_id;
}

# ---------------- 7) MAIN: Radio -> Favoriten -> Items ----------------
# 7.1: Radio/Internetradio Container finden (global)
my $radio_id = find_container_bfs(
  root      => "0",
  want_re   => qr/(internet\s*radio|internetradio|radio)/,
  max_nodes => 20000
) or die "Konnte keinen Container 'Internetradio/Radio' finden.\n";

print "Radio container found: $radio_id\n" if $debug;
dump_children_one_level($radio_id) if $debug;

# 7.2: Favoriten darunter finden (per Titel), sonst Fallback (beste Liste)
my $fav_id = find_container_bfs(
  root      => $radio_id,
  want_re   => qr/(favorit|favorite|lieblings|favourites)/,
  max_nodes => 20000
);

if (!$fav_id) {
  print "Kein Favoriten-Container per Titel gefunden – nutze Fallback (Container mit den meisten Sender-Items)...\n"
    if $debug;
  $fav_id = find_best_station_list_container(root => $radio_id, max_nodes => 30000);
}

die "Konnte keine Senderliste unterhalb von '$radio_id' finden.\n" if !$fav_id;

print "Station list container: $fav_id\n" if $debug;
dump_children_one_level($fav_id) if $debug;

# 7.3: Items (Sender) direkt aus Favoritencontainer lesen
my $fav_didl = soap_browse(ObjectID => $fav_id, BrowseFlag => "BrowseDirectChildren");
my (undef, $items) = parse_didl($fav_didl);

die "Keine Sender-Items im Container ($fav_id) gefunden.\n" if !@$items;

# ---------------- 8) presets.xml schreiben ----------------
my $fh = IO::File->new(">$out_file") or die "Kann $out_file nicht schreiben: $!\n";
binmode($fh, ":utf8");
my $w = XML::Writer->new(OUTPUT => $fh, DATA_MODE => 1, DATA_INDENT => 2, ENCODING => "UTF-8");

my $now = time();
$w->xmlDecl("UTF-8");
$w->startTag("presets");

my $pid   = int($start_id);
my $count = 0;

for my $st (@$items) {
  last if $count >= $max_presets;

  my $name = $st->{title} || "Unbenannt";
  my $oid  = $st->{id};
  next if !$oid;

  $w->startTag("preset", id => $pid, createdOn => $now, updatedOn => $now);

  $w->startTag("ContentItem",
    source        => "STORED_MUSIC",
    location      => $oid,
    sourceAccount => $udn . "/0",
    isPresetable  => "true",
  );

  $w->dataElement("itemName", $name);
  $w->dataElement("containerArt", $st->{art}) if $st->{art};

  $w->endTag("ContentItem");
  $w->endTag("preset");

  $pid++;
  $count++;
}

$w->endTag("presets");
$w->end();
$fh->close();

print "OK: $count Sender nach $out_file geschrieben.\n";
exit 0;

#50
Multimedia / Aw: [Neues Modul] BOSE SoundTo...
Letzter Beitrag von Prof. Dr. Peter Henning - 21 Februar 2026, 05:22:33
Zitat von: JoWiemann am 20 Februar 2026, 18:47:11welche Variable soll das denn sein?
Ihr hattet doch etwas geschrieben von $returnListMediaServers, oder $info. Beides wurde im BOSEST-Modul in keiner Weise angerührt, das Modul im FHEM-repository seit ziemlich langer Zeit überhaupt nicht verändert.

Zitat von: JoWiemann am 20 Februar 2026, 18:51:05dass würde mich interessieren. Ggf. kann ich das ja in das FritzBox Modul übernehmen.
Gerne doch => https://forum.fhem.de/index.php?topic=143976.0

LG

pah