Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. ...nicht in offiziellem Repo
  5. Life360 NextGeneration

NEWS

  • Neuer ioBroker-Blog online: Monatsrückblick März/April 2026
    BluefoxB
    Bluefox
    7
    1
    288

  • Verwendung von KI bitte immer deutlich kennzeichnen
    HomoranH
    Homoran
    9
    1
    269

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    18
    1
    913

Life360 NextGeneration

Geplant Angeheftet Gesperrt Verschoben ...nicht in offiziellem Repo
copilotstandortgeo locationmap
146 Beiträge 15 Kommentatoren 1.7k Aufrufe 17 Beobachtet
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • D Daniel81

    Super Arbeit, danke! Ich bin froh, dass der Adapter wieder funktioniert.

    Weiß jemand, ob sich der Token irgendwann ändert und ich dann wieder aktiv werden muss?
    Aber wie gesagt: Ich bin jetzt erstmal happy, dass ich wieder damit arbeiten kann und meine own Tracks vom Handy schmeißen kann.

    Vielen Dank und bitte dran bleiben – ich hoffe, der Adapter schafft es auch bald ins offizielle ioBroker Repository.

    skvarelS Online
    skvarelS Online
    skvarel
    Developer
    schrieb am zuletzt editiert von skvarel
    #115

    @Daniel81 sagte:

    Vielen Dank und bitte dran bleiben – ich hoffe, der Adapter schafft es auch bald ins offizielle ioBroker Repository.

    Danke. Ja, ich werde dranbleiben. Dieser Adapter ist eine Herzensangelegenheit ;)

    Eine Aufnahme ins ioBroker Repository ist bereits beantragt. @mcm1957 hat bereits einen ersten Blick drüber geworfen .... an dieser Stelle, vielen Dank an mcm für seinen Support!

    #TeamInventwo
    Unsere Adapter:
    Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

    Wer uns mit einem Kaffee unterstützen möchte: PayPal

    1 Antwort Letzte Antwort
    1
    • D Daniel81

      Super Arbeit, danke! Ich bin froh, dass der Adapter wieder funktioniert.

      Weiß jemand, ob sich der Token irgendwann ändert und ich dann wieder aktiv werden muss?
      Aber wie gesagt: Ich bin jetzt erstmal happy, dass ich wieder damit arbeiten kann und meine own Tracks vom Handy schmeißen kann.

      Vielen Dank und bitte dran bleiben – ich hoffe, der Adapter schafft es auch bald ins offizielle ioBroker Repository.

      BananaJoeB Online
      BananaJoeB Online
      BananaJoe
      Most Active
      schrieb am zuletzt editiert von
      #116

      @Daniel81 sagte:

      Weiß jemand, ob sich der Token irgendwann ändert und ich dann wieder aktiv werden muss?

      Ich setze das unter Home Assistant schon seit März 2025 ein und musste etwa vor 3 Wochen zum ersten mal das Token erneuern, hat also ein Jahr gehalten

      ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 10 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV APC 750W kaskadiert || Creality CR-10 SE 3D-Drucker

      1 Antwort Letzte Antwort
      1
      • skvarelS Online
        skvarelS Online
        skvarel
        Developer
        schrieb am zuletzt editiert von
        #117

        Ich werde noch eine bessere Meldung über den Log ausgeben lassen, wenn der Token abgelaufen ist. So muss man nicht unnötig nach Fehlern suchen, wenn die Instanz rot sein sollte.

        #TeamInventwo
        Unsere Adapter:
        Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

        Wer uns mit einem Kaffee unterstützen möchte: PayPal

        1 Antwort Letzte Antwort
        0
        • stefu87_CHS Online
          stefu87_CHS Online
          stefu87_CH
          schrieb am zuletzt editiert von
          #118

          Kannst du dir das erklären @skvarel das nur bei der Tochter der Batteriewert auf -1 geht? Wenn ich aber den Adapter neu starte, habe ich ca 2 min den aktuellen Wert und dann wieder -1.

          339b127f-b565-4d7c-a8f0-ac2cc143a23f-image.jpeg

          Model : AMD Ryzen 7 8745HS w/ Radeon 780M Graphics
          Cores: 1 × 8 = 8 cores
          Threads: 16
          mit Proxmox
          LXC Container mit Iobroker

          skvarelS 1 Antwort Letzte Antwort
          0
          • stefu87_CHS stefu87_CH

            Kannst du dir das erklären @skvarel das nur bei der Tochter der Batteriewert auf -1 geht? Wenn ich aber den Adapter neu starte, habe ich ca 2 min den aktuellen Wert und dann wieder -1.

            339b127f-b565-4d7c-a8f0-ac2cc143a23f-image.jpeg

            skvarelS Online
            skvarelS Online
            skvarel
            Developer
            schrieb am zuletzt editiert von
            #119

            @stefu87_CH .. Ich tippe auf Einstellungen in der App oder generell im Handy. Irgendein Sleep-Mode ?!

            Ich habe die Möglichkeiten alle vom Ursprungs-Adapter übernommen und nur den Login geändert und die Karte für den iFrame hinzugefügt.

            Vielen Dank an @migoller an dieser Stelle!

            #TeamInventwo
            Unsere Adapter:
            Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

            Wer uns mit einem Kaffee unterstützen möchte: PayPal

            stefu87_CHS 1 Antwort Letzte Antwort
            0
            • skvarelS skvarel

              @stefu87_CH .. Ich tippe auf Einstellungen in der App oder generell im Handy. Irgendein Sleep-Mode ?!

              Ich habe die Möglichkeiten alle vom Ursprungs-Adapter übernommen und nur den Login geändert und die Karte für den iFrame hinzugefügt.

              Vielen Dank an @migoller an dieser Stelle!

              stefu87_CHS Online
              stefu87_CHS Online
              stefu87_CH
              schrieb am zuletzt editiert von
              #120

              @skvarel sagte:

              Ich tippe auf Einstellungen in der App oder generell im Handy. Irgendein Sleep-Mode ?!

              Aber was mir dann spanisch vorkommt, das in der APP auf dem Handy immer der aktuelle Wert angezeigt wird. Werde das aber mal beobachten ob das einfach gerade Zufall ist, oder ob es sporadisch vorkommt.

              Model : AMD Ryzen 7 8745HS w/ Radeon 780M Graphics
              Cores: 1 × 8 = 8 cores
              Threads: 16
              mit Proxmox
              LXC Container mit Iobroker

              skvarelS 1 Antwort Letzte Antwort
              1
              • stefu87_CHS stefu87_CH

                @skvarel sagte:

                Ich tippe auf Einstellungen in der App oder generell im Handy. Irgendein Sleep-Mode ?!

                Aber was mir dann spanisch vorkommt, das in der APP auf dem Handy immer der aktuelle Wert angezeigt wird. Werde das aber mal beobachten ob das einfach gerade Zufall ist, oder ob es sporadisch vorkommt.

                skvarelS Online
                skvarelS Online
                skvarel
                Developer
                schrieb am zuletzt editiert von skvarel
                #121

                @stefu87_CH .. ich werde das hier auch mal beobachten. Ich habe nie auf die Werte geachtet, weil mir der Akku anderer Familienmitglieder nicht so wichtig ist.

                #TeamInventwo
                Unsere Adapter:
                Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                Wer uns mit einem Kaffee unterstützen möchte: PayPal

                V 1 Antwort Letzte Antwort
                0
                • skvarelS skvarel

                  @stefu87_CH .. ich werde das hier auch mal beobachten. Ich habe nie auf die Werte geachtet, weil mir der Akku anderer Familienmitglieder nicht so wichtig ist.

                  V Offline
                  V Offline
                  Verblizz
                  schrieb am zuletzt editiert von
                  #122

                  @skvarel , @stefu87_ch :
                  Ich kann dazu berichten, dass meine Tochter grundsätzlich den Akkusparmodus eingeschaltet hat, aber der Battariestand wird bei mir trotzdem in den neuen Adapter übertragen... In der App auf dem Handy ist der natürlich auch sichtbar...

                  1 Antwort Letzte Antwort
                  1
                  • skvarelS Online
                    skvarelS Online
                    skvarel
                    Developer
                    schrieb am zuletzt editiert von
                    #123

                    Mal eine Spielerei mit dem vis-maps Widget

                    Beide Marker in einer Karte, Die Bilder der Personen kommen aus der App und liegen als URL in den Adapterobjekten.

                    fa5d2ad8-46ee-430a-9e8e-299dfaa68916-image.jpeg

                    #TeamInventwo
                    Unsere Adapter:
                    Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                    Wer uns mit einem Kaffee unterstützen möchte: PayPal

                    Merlin123M 1 Antwort Letzte Antwort
                    0
                    • skvarelS skvarel

                      Mal eine Spielerei mit dem vis-maps Widget

                      Beide Marker in einer Karte, Die Bilder der Personen kommen aus der App und liegen als URL in den Adapterobjekten.

                      fa5d2ad8-46ee-430a-9e8e-299dfaa68916-image.jpeg

                      Merlin123M Offline
                      Merlin123M Offline
                      Merlin123
                      schrieb am zuletzt editiert von
                      #124

                      @skvarel Ist ja nett.... Skaliert die Map dann automatisch, je nach Abstand?

                      Beta-Tester

                      skvarelS 1 Antwort Letzte Antwort
                      0
                      • Merlin123M Merlin123

                        @skvarel Ist ja nett.... Skaliert die Map dann automatisch, je nach Abstand?

                        skvarelS Online
                        skvarelS Online
                        skvarel
                        Developer
                        schrieb am zuletzt editiert von
                        #125

                        @Merlin123 .. jepp

                        #TeamInventwo
                        Unsere Adapter:
                        Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                        Wer uns mit einem Kaffee unterstützen möchte: PayPal

                        1 Antwort Letzte Antwort
                        0
                        • skvarelS Online
                          skvarelS Online
                          skvarel
                          Developer
                          schrieb am zuletzt editiert von
                          #126

                          So gefällt es mir noch besser.

                          Für einen schnellen Überblick:

                          5db62443-f21a-433f-97b8-ec10c709ee95-image.jpeg

                          Wenn ich dann oben rechts auf das Icon klicke, gibt es mehr Details:

                          4448a8f4-9fff-4216-86ca-c467d704f85e-image.jpeg

                          #TeamInventwo
                          Unsere Adapter:
                          Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                          Wer uns mit einem Kaffee unterstützen möchte: PayPal

                          1 Antwort Letzte Antwort
                          0
                          • Merlin123M Offline
                            Merlin123M Offline
                            Merlin123
                            schrieb am zuletzt editiert von
                            #127

                            @skvarel Wie hast Du die Übersicht gemacht? Kannst Du das als Export teilen?

                            Beta-Tester

                            skvarelS 1 Antwort Letzte Antwort
                            0
                            • Merlin123M Merlin123

                              @skvarel Wie hast Du die Übersicht gemacht? Kannst Du das als Export teilen?

                              skvarelS Online
                              skvarelS Online
                              skvarel
                              Developer
                              schrieb am zuletzt editiert von skvarel
                              #128

                              @Merlin123

                              Hier mit zwei Markern:

                              [
                                {
                                  "tpl": "tplOsm",
                                  "data": {
                                    "bindings": [
                                      "markersImage1",
                                      "markersImage2"
                                    ],
                                    "mCount": 2,
                                    "g_common": true,
                                    "maxZoom": 20,
                                    "markersLon-oid1": "life360ng.0.people.xxx.longitude",
                                    "markersLat-oid1": "life360ng.0.people.xxx.latitude",
                                    "markersSwap1": false,
                                    "markersImage1": "http://192.168.130.130:8082/vis-2.0/main/blue.png",
                                    "markersWidth1": 50,
                                    "markersHeight1": 50,
                                    "markersOffsetX1": 0,
                                    "markersOffsetY1": 0,
                                    "markersOpacity1": 1,
                                    "markersView1": null,
                                    "markersUrl1": null,
                                    "g_markers-1": true,
                                    "markersLon-oid2": "life360ng.0.people.xxx.longitude",
                                    "markersLat-oid2": "life360ng.0.people.xxx.latitude",
                                    "markersSwap2": null,
                                    "markersImage2": "http://192.168.130.130:8082/vis-2.0/main/red.png",
                                    "markersWidth2": 50,
                                    "markersHeight2": 50,
                                    "markersOffsetX2": 0,
                                    "markersOffsetY2": 0,
                                    "markersOpacity2": 1,
                                    "markersView2": null,
                                    "markersUrl2": null,
                                    "g_markers-2": true,
                                    "g_css_border": true,
                                    "g_css_shadow_padding": true
                                  },
                                  "style": {
                                    "bindings": [
                                      "border-radius"
                                    ],
                                    "left": "10px",
                                    "top": "10px",
                                    "width": "1157px",
                                    "height": "659px",
                                    "z-index": "10",
                                    "border-radius": "{alias.0.VIS_Customizer.Radius_Ecken}px",
                                    "padding": null,
                                    "padding-left": null,
                                    "padding-top": null,
                                    "padding-right": null,
                                    "padding-bottom": null,
                                    "box-shadow": "3px 3px 5px #000000CC",
                                    "margin-left": null,
                                    "margin-top": null,
                                    "margin-right": null,
                                    "margin-bottom": null,
                                    "border-width": "",
                                    "border-color": "",
                                    "border-style": ""
                                  },
                                  "widgetSet": "map",
                                  "_id": "i000001"
                                }
                              ]
                              

                              #TeamInventwo
                              Unsere Adapter:
                              Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                              Wer uns mit einem Kaffee unterstützen möchte: PayPal

                              Merlin123M 1 Antwort Letzte Antwort
                              0
                              • skvarelS skvarel

                                @Merlin123

                                Hier mit zwei Markern:

                                [
                                  {
                                    "tpl": "tplOsm",
                                    "data": {
                                      "bindings": [
                                        "markersImage1",
                                        "markersImage2"
                                      ],
                                      "mCount": 2,
                                      "g_common": true,
                                      "maxZoom": 20,
                                      "markersLon-oid1": "life360ng.0.people.xxx.longitude",
                                      "markersLat-oid1": "life360ng.0.people.xxx.latitude",
                                      "markersSwap1": false,
                                      "markersImage1": "http://192.168.130.130:8082/vis-2.0/main/blue.png",
                                      "markersWidth1": 50,
                                      "markersHeight1": 50,
                                      "markersOffsetX1": 0,
                                      "markersOffsetY1": 0,
                                      "markersOpacity1": 1,
                                      "markersView1": null,
                                      "markersUrl1": null,
                                      "g_markers-1": true,
                                      "markersLon-oid2": "life360ng.0.people.xxx.longitude",
                                      "markersLat-oid2": "life360ng.0.people.xxx.latitude",
                                      "markersSwap2": null,
                                      "markersImage2": "http://192.168.130.130:8082/vis-2.0/main/red.png",
                                      "markersWidth2": 50,
                                      "markersHeight2": 50,
                                      "markersOffsetX2": 0,
                                      "markersOffsetY2": 0,
                                      "markersOpacity2": 1,
                                      "markersView2": null,
                                      "markersUrl2": null,
                                      "g_markers-2": true,
                                      "g_css_border": true,
                                      "g_css_shadow_padding": true
                                    },
                                    "style": {
                                      "bindings": [
                                        "border-radius"
                                      ],
                                      "left": "10px",
                                      "top": "10px",
                                      "width": "1157px",
                                      "height": "659px",
                                      "z-index": "10",
                                      "border-radius": "{alias.0.VIS_Customizer.Radius_Ecken}px",
                                      "padding": null,
                                      "padding-left": null,
                                      "padding-top": null,
                                      "padding-right": null,
                                      "padding-bottom": null,
                                      "box-shadow": "3px 3px 5px #000000CC",
                                      "margin-left": null,
                                      "margin-top": null,
                                      "margin-right": null,
                                      "margin-bottom": null,
                                      "border-width": "",
                                      "border-color": "",
                                      "border-style": ""
                                    },
                                    "widgetSet": "map",
                                    "_id": "i000001"
                                  }
                                ]
                                
                                Merlin123M Offline
                                Merlin123M Offline
                                Merlin123
                                schrieb am zuletzt editiert von
                                #129

                                @skvarel Nutzt du da den vis-map für die vis1? Wird ja anscheinend nicht mehr weiter entwickelt.

                                Beta-Tester

                                skvarelS BananaJoeB 2 Antworten Letzte Antwort
                                0
                                • Merlin123M Merlin123

                                  @skvarel Nutzt du da den vis-map für die vis1? Wird ja anscheinend nicht mehr weiter entwickelt.

                                  skvarelS Online
                                  skvarelS Online
                                  skvarel
                                  Developer
                                  schrieb am zuletzt editiert von
                                  #130

                                  @Merlin123 .. das Widget funktioniert auch in VIS 2

                                  #TeamInventwo
                                  Unsere Adapter:
                                  Autodarts, FoxESS, Enpal, Life360ng, Tidy, vis-inventwo, vis-2-widgets-inventwo, vis-icontwo, vis-2-widgets-icontwo

                                  Wer uns mit einem Kaffee unterstützen möchte: PayPal

                                  Merlin123M 1 Antwort Letzte Antwort
                                  0
                                  • Merlin123M Merlin123

                                    @skvarel Nutzt du da den vis-map für die vis1? Wird ja anscheinend nicht mehr weiter entwickelt.

                                    BananaJoeB Online
                                    BananaJoeB Online
                                    BananaJoe
                                    Most Active
                                    schrieb am zuletzt editiert von BananaJoe
                                    #131

                                    @Merlin123 sagte:

                                    @skvarel Nutzt du da den vis-map für die vis1? Wird ja anscheinend nicht mehr weiter entwickelt.

                                    Wenn es einen Grund gibt, an den Widgets was zu ändern wird da dann wohl auch was gemacht. Da Google und OpenStreetMap aber wohl kaum was an ihren Aufrufen ändern werden, muss auch nichts angepasst werden.
                                    Bluefox hat da ja scheinbar persönlich ein Auge drauf.

                                    Bloß weil an einem Adapter länger was nichts passiert, heißt das nicht gleich das der "Tod" ist

                                    ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 10 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV APC 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                                    Merlin123M 1 Antwort Letzte Antwort
                                    1
                                    • BananaJoeB BananaJoe

                                      @Merlin123 sagte:

                                      @skvarel Nutzt du da den vis-map für die vis1? Wird ja anscheinend nicht mehr weiter entwickelt.

                                      Wenn es einen Grund gibt, an den Widgets was zu ändern wird da dann wohl auch was gemacht. Da Google und OpenStreetMap aber wohl kaum was an ihren Aufrufen ändern werden, muss auch nichts angepasst werden.
                                      Bluefox hat da ja scheinbar persönlich ein Auge drauf.

                                      Bloß weil an einem Adapter länger was nichts passiert, heißt das nicht gleich das der "Tod" ist

                                      Merlin123M Offline
                                      Merlin123M Offline
                                      Merlin123
                                      schrieb am zuletzt editiert von
                                      #132

                                      @BananaJoe eher wegen den nicht bearbeiteten Issues... Da würde ich schon denken, dass jemand die prüft.
                                      Bildschirmfoto_20260419_091546.png

                                      Beta-Tester

                                      1 Antwort Letzte Antwort
                                      0
                                      • skvarelS skvarel

                                        @Merlin123 .. das Widget funktioniert auch in VIS 2

                                        Merlin123M Offline
                                        Merlin123M Offline
                                        Merlin123
                                        schrieb am zuletzt editiert von
                                        #133

                                        @skvarel hab es auch mal eingebaut. Nett :)

                                        Beta-Tester

                                        BananaJoeB 1 Antwort Letzte Antwort
                                        1
                                        • Merlin123M Offline
                                          Merlin123M Offline
                                          Merlin123
                                          schrieb am zuletzt editiert von
                                          #134

                                          Hier mal die aktuelle Version meines "Adresse und POI" Suchscriptes. die POIs werden leider nicht immer gefunden. Hängt anscheinend mit der Größe des Gebäudes und dem ermittelten Standorts zusammen. Wenn man den Radius um den Standort zu groß macht, findet er teilweise falsche Sachen, macht man ihn zu klein findet man nichts.
                                          Weiteres Problem:
                                          Wenn man zu viele Anfragen an die Openmap API schickt, blockiert die erstmal.
                                          Im Script sind deswegen (vor allem beim Start) Verzögerungen drin. Trotzdem kann es mal zu Problemen kommen und das Script liefert dann keine Werte.
                                          Was auch drin ist: Er ändert nur die alten Werte, wenn die neuen in nem gewissen Maße abweichen. Soll Probleme verhindern, wenn der aktuelle Standort mal leicht variiert. Hatte das zu Hause, dass er erst die richtige Adresse angezeigt hat, und als ich im Garten nahe bei den Nachbarn war ist er bei der Adresse umgesprungen. Passiert jetzt nicht.
                                          Halt mit dem Nachteil, das unter Umständen die alte Adresse bleibt, auch wenn man beim NAchbar ist. Abhängig halt von den Abständen....

                                          Ist aktuell für 3 Personen ausgelegt. Wenn man die Daten für eine Person leer läß werden nur 2 bearbeitet usw.

                                          /************************************************************
                                           * Mehrpersonen-Standortscript für ioBroker + Life360
                                           *
                                           * Konfiguration:
                                           * Nur Name + Life360-ID eintragen.
                                           * Alles andere wird automatisch erzeugt.
                                           ************************************************************/
                                          
                                          /* ---------------------------------------------------------
                                           * PERSONENKONFIGURATION
                                           * --------------------------------------------------------- */
                                          const PERSON1_NAME = 'Oliver';
                                          const PERSON1_ID   = 'b9fxxxxa7e';
                                          
                                          const PERSON2_NAME = 'Hannah';
                                          const PERSON2_ID   = 'f7fxxxx8e9d';
                                          
                                          const PERSON3_NAME = 'Marleen';
                                          const PERSON3_ID   = '880xxxaea';
                                          
                                          /* ---------------------------------------------------------
                                           * ALLGEMEINE EINSTELLUNGEN
                                           * --------------------------------------------------------- */
                                          const MIN_INTERVAL_MS                 = 60 * 1000;
                                          const MIN_DISTANCE_M                  = 40;
                                          const DEBOUNCE_MS                     = 5000;
                                          
                                          const POI_RADIUS_M                    = 25;
                                          const SECOND_TRY_RADIUS               = 80;
                                          
                                          const GAP_BETWEEN_CALLS               = 2500;
                                          const STARTUP_PERSON_DELAY_MS         = 8000;
                                          const OVERPASS_RETRY_DELAY_MS         = 3000;
                                          
                                          const ADDRESS_STABLE_DISTANCE_M       = 20;
                                          const POI_STABLE_DISTANCE_M           = 120;
                                          const KEEP_POI_IF_OVERPASS_FAILS_M    = 150;
                                          
                                          const USER_AGENT = 'ioBroker-Standortscript/1.0 (Kontakt: oliver@voelker123.de)';
                                          
                                          // Debug
                                          const DEBUG_LOG_POI_CANDIDATES = true;
                                          const DEBUG_LOG_REJECTED_POIS  = true;
                                          
                                          /* ---------------------------------------------------------
                                           * PERSONENLISTE AUTOMATISCH ERZEUGEN
                                           * --------------------------------------------------------- */
                                          const PERSON_CONFIGS = [
                                              { name: PERSON1_NAME, id: PERSON1_ID },
                                              { name: PERSON2_NAME, id: PERSON2_ID },
                                              { name: PERSON3_NAME, id: PERSON3_ID }
                                          ];
                                          
                                          const PERSONS = PERSON_CONFIGS
                                              .filter(p => String(p.name || '').trim() && String(p.id || '').trim())
                                              .map(p => {
                                                  const cleanName = String(p.name).trim();
                                                  const cleanId = String(p.id).trim();
                                          
                                                  return {
                                                      key: cleanName,
                                                      id: cleanId,
                                                      latState: `life360ng.0.people.${cleanId}.latitude`,
                                                      lonState: `life360ng.0.people.${cleanId}.longitude`,
                                                      targetState: `0_userdata.0.VIS.Position.Standort_${cleanName}`,
                                                      baseState: `0_userdata.0.VIS.Position.${cleanName}`
                                                  };
                                              });
                                          
                                          if (!PERSONS.length) {
                                              throw new Error('Keine Personen konfiguriert. Bitte mindestens NAME und ID für eine Person eintragen.');
                                          }
                                          
                                          // Laufzeitstatus pro Person
                                          const runtime = {};
                                          
                                          /* ---------------------------------------------------------
                                           * Initialisierung
                                           * --------------------------------------------------------- */
                                          for (const person of PERSONS) {
                                              person.addressState  = `${person.baseState}.Standort_${person.key}_Adresse`;
                                              person.poiState      = `${person.baseState}.Standort_${person.key}_POI`;
                                              person.lastLatState  = `${person.baseState}.Standort_${person.key}_LastLat`;
                                              person.lastLonState  = `${person.baseState}.Standort_${person.key}_LastLon`;
                                              person.lastTsState   = `${person.baseState}.Standort_${person.key}_LastLookupTs`;
                                              person.poiTypeState  = `${person.baseState}.Standort_${person.key}_POI_Type`;
                                              person.poiDistState  = `${person.baseState}.Standort_${person.key}_POI_Distance`;
                                              person.poiLatState   = `${person.baseState}.Standort_${person.key}_POI_Lat`;
                                              person.poiLonState   = `${person.baseState}.Standort_${person.key}_POI_Lon`;
                                          
                                              runtime[person.key] = {
                                                  debounceTimer: null,
                                                  lookupRunning: false
                                              };
                                          
                                              createStateIfMissing(person.targetState, '', 'string', `${person.key} Standort`);
                                              createStateIfMissing(person.addressState, '', 'string', `${person.key} Adresse`);
                                              createStateIfMissing(person.poiState, '', 'string', `${person.key} POI`);
                                              createStateIfMissing(person.lastLatState, 0, 'number', `${person.key} letzte Lookup-Latitude`);
                                              createStateIfMissing(person.lastLonState, 0, 'number', `${person.key} letzte Lookup-Longitude`);
                                              createStateIfMissing(person.lastTsState, 0, 'number', `${person.key} letzter Lookup-Zeitstempel`);
                                              createStateIfMissing(person.poiTypeState, '', 'string', `${person.key} POI Typ`);
                                              createStateIfMissing(person.poiDistState, 0, 'number', `${person.key} POI Distanz`);
                                              createStateIfMissing(person.poiLatState, 0, 'number', `${person.key} POI Latitude`);
                                              createStateIfMissing(person.poiLonState, 0, 'number', `${person.key} POI Longitude`);
                                          
                                              on({ id: person.latState, change: 'ne' }, () => scheduleLookup(person, false));
                                              on({ id: person.lonState, change: 'ne' }, () => scheduleLookup(person, false));
                                          }
                                          
                                          /* ---------------------------------------------------------
                                           * Initial-Refresh beim Start: immer erzwingen, aber gestaffelt
                                           * --------------------------------------------------------- */
                                          setTimeout(() => {
                                              PERSONS.forEach((person, index) => {
                                                  setTimeout(() => {
                                                      scheduleLookup(person, true);
                                                  }, index * STARTUP_PERSON_DELAY_MS);
                                              });
                                          }, 2000);
                                          
                                          /* ---------------------------------------------------------
                                           * Hauptlogik
                                           * --------------------------------------------------------- */
                                          function scheduleLookup(person, force) {
                                              const rt = runtime[person.key];
                                          
                                              if (rt.debounceTimer) clearTimeout(rt.debounceTimer);
                                          
                                              rt.debounceTimer = setTimeout(() => {
                                                  runLookup(person, !!force).catch(err => log(`${person.key}: Standortscript Fehler: ${err}`, 'error'));
                                              }, force ? 500 : DEBOUNCE_MS);
                                          }
                                          
                                          async function runLookup(person, force) {
                                              const rt = runtime[person.key];
                                          
                                              if (rt.lookupRunning) {
                                                  log(`${person.key}: Lookup läuft bereits, überspringe parallelen Aufruf.`, 'debug');
                                                  return;
                                              }
                                          
                                              const lat = parseFloat(getState(person.latState).val);
                                              const lon = parseFloat(getState(person.lonState).val);
                                          
                                              if (!isFinite(lat) || !isFinite(lon)) {
                                                  log(`${person.key}: Ungültige Koordinaten, Lookup abgebrochen.`, 'warn');
                                                  return;
                                              }
                                          
                                              const previousLat = parseFloat(getState(person.lastLatState).val);
                                              const previousLon = parseFloat(getState(person.lastLonState).val);
                                              const moveDistance = (isFinite(previousLat) && isFinite(previousLon) && !(previousLat === 0 && previousLon === 0))
                                                  ? distanceMeters(previousLat, previousLon, lat, lon)
                                                  : 999999;
                                          
                                              if (!force && !shouldLookup(person, lat, lon)) {
                                                  log(`${person.key}: Lookup übersprungen (Cooldown oder Bewegung zu gering).`, 'debug');
                                                  return;
                                              }
                                          
                                              rt.lookupRunning = true;
                                          
                                              try {
                                                  log(`${person.key}: Starte Lookup für ${lat}, ${lon}${force ? ' (forced)' : ''}`, 'info');
                                          
                                                  const oldAddress = String(getState(person.addressState).val || '').trim();
                                                  const oldPoi = String(getState(person.poiState).val || '').trim();
                                                  const oldPoiType = String(getState(person.poiTypeState).val || '').trim();
                                                  const oldPoiLat = parseFloat(getState(person.poiLatState).val);
                                                  const oldPoiLon = parseFloat(getState(person.poiLonState).val);
                                          
                                                  const addressInfo = await getAddressFromNominatim(lat, lon);
                                                  const rawAddressText = buildAddressText(addressInfo);
                                                  const addressText = stabilizeAddress(oldAddress, rawAddressText, moveDistance);
                                          
                                                  setState(person.addressState, addressText || '', true);
                                                  setState(person.targetState, addressText || 'Unbekannter Standort', true);
                                          
                                                  setState(person.lastLatState, lat, true);
                                                  setState(person.lastLonState, lon, true);
                                                  setState(person.lastTsState, Date.now(), true);
                                          
                                                  await sleep(GAP_BETWEEN_CALLS);
                                          
                                                  let poi = null;
                                                  let finalText = addressText || 'Unbekannter Standort';
                                                  let overpassFailed = false;
                                          
                                                  try {
                                                      const firstPoiResult = await getNearbyNamedPoi(person, lat, lon, POI_RADIUS_M, addressText);
                                                      poi = firstPoiResult.poi;
                                                      overpassFailed = firstPoiResult.overpassFailed === true;
                                          
                                                      const mayRetryWithLargerRadius =
                                                          SECOND_TRY_RADIUS > POI_RADIUS_M &&
                                                          !overpassFailed &&
                                                          (
                                                              firstPoiResult.hadCandidates ||
                                                              addressLooksLikeBusiness(addressText)
                                                          );
                                          
                                                      if (!poi && mayRetryWithLargerRadius) {
                                                          await sleep(OVERPASS_RETRY_DELAY_MS);
                                                          const secondPoiResult = await getNearbyNamedPoi(person, lat, lon, SECOND_TRY_RADIUS, addressText);
                                                          poi = secondPoiResult.poi;
                                                          overpassFailed = secondPoiResult.overpassFailed === true;
                                                      }
                                                  } catch (poiErr) {
                                                      overpassFailed = true;
                                                      log(`${person.key}: POI-Suche fehlgeschlagen (${poiErr}). Verwende Adresse bzw. alten POI.`, 'warn');
                                                  }
                                          
                                                  if (!poi && oldPoi && isFinite(oldPoiLat) && isFinite(oldPoiLon) && !(oldPoiLat === 0 && oldPoiLon === 0)) {
                                                      const distToOldPoi = distanceMeters(lat, lon, oldPoiLat, oldPoiLon);
                                                      const allowedKeepDistance = overpassFailed ? KEEP_POI_IF_OVERPASS_FAILS_M : POI_STABLE_DISTANCE_M;
                                          
                                                      if (isStablePoiType(oldPoiType) && distToOldPoi <= allowedKeepDistance) {
                                                          poi = {
                                                              name: oldPoi,
                                                              typeLabel: oldPoiType || 'remembered',
                                                              dist: distToOldPoi,
                                                              lat: oldPoiLat,
                                                              lon: oldPoiLon,
                                                              remembered: true
                                                          };
                                                          log(
                                                              `${person.key}: Behalte bisherigen POI '${oldPoi}' bei (Distanz ${distToOldPoi.toFixed(1)} m, OverpassFailed=${overpassFailed}).`,
                                                              'info'
                                                          );
                                                      }
                                                  }
                                          
                                                  if (poi && poi.name) {
                                                      setState(person.poiState, poi.name, true);
                                                      setState(person.poiTypeState, poi.typeLabel || '', true);
                                                      setState(person.poiDistState, round1(poi.dist || 0), true);
                                                      setState(person.poiLatState, poi.lat || 0, true);
                                                      setState(person.poiLonState, poi.lon || 0, true);
                                          
                                                      if (addressText && !addressText.toLowerCase().includes(poi.name.toLowerCase())) {
                                                          finalText = poi.name + ', ' + addressText;
                                                      } else {
                                                          finalText = poi.name;
                                                      }
                                                  } else {
                                                      setState(person.poiState, '', true);
                                                      setState(person.poiTypeState, '', true);
                                                      setState(person.poiDistState, 0, true);
                                                      setState(person.poiLatState, 0, true);
                                                      setState(person.poiLonState, 0, true);
                                                  }
                                          
                                                  setState(person.targetState, finalText, true);
                                                  log(`${person.key}: Standort aktualisiert: ${finalText}`, 'info');
                                          
                                              } catch (err) {
                                                  log(`${person.key}: Fehler beim Standort-Lookup: ${err}`, 'error');
                                              } finally {
                                                  rt.lookupRunning = false;
                                              }
                                          }
                                          
                                          function shouldLookup(person, lat, lon) {
                                              const lastTsRaw  = getState(person.lastTsState).val;
                                              const lastLatRaw = getState(person.lastLatState).val;
                                              const lastLonRaw = getState(person.lastLonState).val;
                                          
                                              const lastTs  = Number(lastTsRaw || 0);
                                              const lastLat = parseFloat(lastLatRaw);
                                              const lastLon = parseFloat(lastLonRaw);
                                          
                                              const now = Date.now();
                                          
                                              if (lastTs > 0 && (now - lastTs) < MIN_INTERVAL_MS) {
                                                  return false;
                                              }
                                          
                                              if (isFinite(lastLat) && isFinite(lastLon) && !(lastLat === 0 && lastLon === 0)) {
                                                  const dist = distanceMeters(lastLat, lastLon, lat, lon);
                                                  if (dist < MIN_DISTANCE_M) {
                                                      return false;
                                                  }
                                              }
                                          
                                              return true;
                                          }
                                          
                                          async function getAddressFromNominatim(lat, lon) {
                                              const url =
                                                  'https://nominatim.openstreetmap.org/reverse' +
                                                  '?format=jsonv2' +
                                                  '&lat=' + encodeURIComponent(lat) +
                                                  '&lon=' + encodeURIComponent(lon) +
                                                  '&addressdetails=1' +
                                                  '&zoom=18';
                                          
                                              const response = await httpGetAsync(url, {
                                                  'User-Agent': USER_AGENT,
                                                  'Accept': 'application/json'
                                              });
                                          
                                              if (response.statusCode < 200 || response.statusCode >= 300) {
                                                  throw new Error('Nominatim HTTP ' + response.statusCode);
                                              }
                                          
                                              let data;
                                              try {
                                                  data = JSON.parse(response.data);
                                              } catch (e) {
                                                  throw new Error('Nominatim JSON konnte nicht geparst werden');
                                              }
                                          
                                              return data;
                                          }
                                          
                                          function buildAddressText(data) {
                                              if (!data) return '';
                                          
                                              const a = data.address || {};
                                          
                                              const road =
                                                  a.road ||
                                                  a.pedestrian ||
                                                  a.footway ||
                                                  a.path ||
                                                  a.cycleway ||
                                                  '';
                                          
                                              const houseNumber = a.house_number || '';
                                              const postcode = a.postcode || '';
                                              const city =
                                                  a.city ||
                                                  a.town ||
                                                  a.village ||
                                                  a.hamlet ||
                                                  a.municipality ||
                                                  '';
                                          
                                              let result = '';
                                          
                                              if (road) {
                                                  result += road;
                                                  if (houseNumber) result += ' ' + houseNumber;
                                              }
                                          
                                              if (postcode || city) {
                                                  if (result) result += ', ';
                                                  result += [postcode, city].filter(Boolean).join(' ');
                                              }
                                          
                                              if (!result && data.display_name) {
                                                  result = data.display_name;
                                              }
                                          
                                              return cleanText(result);
                                          }
                                          
                                          function stabilizeAddress(oldAddress, newAddress, moveDistance) {
                                              const oldA = String(oldAddress || '').trim();
                                              const newA = String(newAddress || '').trim();
                                          
                                              if (!newA) return oldA;
                                              if (!oldA) return newA;
                                              if (oldA === newA) return newA;
                                          
                                              if (moveDistance <= ADDRESS_STABLE_DISTANCE_M) {
                                                  log(`Adress-Stabilisierung aktiv: Behalte '${oldA}' statt neu '${newA}' bei (Bewegung ${moveDistance.toFixed(1)} m).`, 'info');
                                                  return oldA;
                                              }
                                          
                                              return newA;
                                          }
                                          
                                          function addressLooksLikeBusiness(addressText) {
                                              const a = String(addressText || '').toLowerCase();
                                          
                                              return (
                                                  a.includes('luisenring') ||
                                                  a.includes('mannheim') ||
                                                  a.includes('industrie') ||
                                                  a.includes('gewerbe') ||
                                                  a.includes('business') ||
                                                  a.includes('park')
                                              );
                                          }
                                          
                                          function buildGeneralPoiQuery(lat, lon, radius) {
                                              return `
                                          [out:json][timeout:10];
                                          (
                                            nwr(around:${radius},${lat},${lon})["name"]["shop"];
                                            nwr(around:${radius},${lat},${lon})["name"]["amenity"];
                                            nwr(around:${radius},${lat},${lon})["name"]["tourism"];
                                            nwr(around:${radius},${lat},${lon})["name"]["leisure"];
                                            nwr(around:${radius},${lat},${lon})["name"]["office"];
                                          );
                                          out center tags;
                                          `;
                                          }
                                          
                                          function buildBusinessPoiQuery(lat, lon, radius) {
                                              return `
                                          [out:json][timeout:6];
                                          (
                                            nwr(around:${radius},${lat},${lon})["name"]["office"];
                                            nwr(around:${radius},${lat},${lon})["name"]["office"="company"];
                                            nwr(around:${radius},${lat},${lon})["name"]["office"="energy_supplier"];
                                            nwr(around:${radius},${lat},${lon})["name"]["building"="office"];
                                          );
                                          out center tags;
                                          `;
                                          }
                                          
                                          async function getNearbyNamedPoi(person, lat, lon, radius, addressText) {
                                              const isBusinessAddress = addressLooksLikeBusiness(addressText);
                                              const query = isBusinessAddress
                                                  ? buildBusinessPoiQuery(lat, lon, radius)
                                                  : buildGeneralPoiQuery(lat, lon, radius);
                                          
                                              log(`${person.key}: Verwende ${isBusinessAddress ? 'Business' : 'General'}-POI-Query im Radius ${radius} m.`, 'info');
                                          
                                              const response = await httpPostAsync(
                                                  'https://overpass-api.de/api/interpreter',
                                                  query,
                                                  {
                                                      'User-Agent': USER_AGENT,
                                                      'Content-Type': 'text/plain; charset=utf-8',
                                                      'Accept': 'application/json'
                                                  }
                                              );
                                          
                                              if (response.statusCode === 504 || response.statusCode === 502 || response.statusCode === 429) {
                                                  log(`${person.key}: Overpass HTTP ${response.statusCode}, verwende keinen neuen POI.`, 'warn');
                                                  return { poi: null, hadCandidates: false, overpassFailed: true };
                                              }
                                          
                                              if (response.statusCode < 200 || response.statusCode >= 300) {
                                                  throw new Error('Overpass HTTP ' + response.statusCode);
                                              }
                                          
                                              let data;
                                              try {
                                                  data = JSON.parse(response.data);
                                              } catch (e) {
                                                  throw new Error('Overpass JSON konnte nicht geparst werden');
                                              }
                                          
                                              if (!data.elements || !data.elements.length) {
                                                  log(`${person.key}: Keine POI-Kandidaten im Radius ${radius} m gefunden.`, 'info');
                                                  return { poi: null, hadCandidates: false, overpassFailed: false };
                                              }
                                          
                                              const candidates = data.elements
                                                  .map(el => {
                                                      const cLat = el.lat || (el.center && el.center.lat);
                                                      const cLon = el.lon || (el.center && el.center.lon);
                                                      const rawName = el.tags && el.tags.name ? String(el.tags.name).trim() : '';
                                                      const name = cleanText(rawName);
                                                      const tags = el.tags || {};
                                                      const dist = (isFinite(cLat) && isFinite(cLon))
                                                          ? distanceMeters(lat, lon, cLat, cLon)
                                                          : 999999;
                                          
                                                      return {
                                                          name: name,
                                                          tags: tags,
                                                          dist: dist,
                                                          lat: cLat || 0,
                                                          lon: cLon || 0,
                                                          priority: poiPriority(tags, name),
                                                          maxDistance: getPoiMaxDistance(tags, name, addressText),
                                                          typeLabel: getPoiTypeLabel(tags)
                                                      };
                                                  })
                                                  .filter(x => x.name);
                                          
                                              if (!candidates.length) {
                                                  log(`${person.key}: Overpass lieferte Objekte, aber keinen benannten Kandidaten.`, 'info');
                                                  return { poi: null, hadCandidates: false, overpassFailed: false };
                                              }
                                          
                                              candidates.sort((a, b) => {
                                                  if (a.priority !== b.priority) return a.priority - b.priority;
                                                  return a.dist - b.dist;
                                              });
                                          
                                              if (DEBUG_LOG_POI_CANDIDATES) {
                                                  log(`${person.key}: POI-Kandidaten Radius ${radius} m: ${JSON.stringify(candidates)}`, 'info');
                                              }
                                          
                                              for (const candidate of candidates) {
                                                  if (candidate.dist <= candidate.maxDistance) {
                                                      log(
                                                          `${person.key}: POI akzeptiert: ${candidate.name} (${candidate.typeLabel}, Distanz ${candidate.dist.toFixed(1)} m, erlaubt ${candidate.maxDistance} m)`,
                                                          'info'
                                                      );
                                                      return { poi: candidate, hadCandidates: true, overpassFailed: false };
                                                  } else if (DEBUG_LOG_REJECTED_POIS) {
                                                      log(
                                                          `${person.key}: POI verworfen: ${candidate.name} (${candidate.typeLabel}, Distanz ${candidate.dist.toFixed(1)} m, erlaubt ${candidate.maxDistance} m)`,
                                                          'info'
                                                      );
                                                  }
                                              }
                                          
                                              log(`${person.key}: Kein POI bestand die Distanz-/Prioritätsprüfung im Radius ${radius} m.`, 'info');
                                              return { poi: null, hadCandidates: true, overpassFailed: false };
                                          }
                                          
                                          function poiPriority(tags, name) {
                                              const poiName = String(name || '').toLowerCase();
                                          
                                              if (tags.amenity === 'fire_station') return 1;
                                              if (tags.amenity === 'school') return 1;
                                              if (tags.amenity === 'kindergarten') return 1;
                                              if (tags.amenity === 'hospital') return 1;
                                              if (tags.amenity === 'clinic') return 1;
                                              if (tags.shop === 'supermarket') return 1;
                                          
                                              if (
                                                  poiName.includes('schule') ||
                                                  poiName.includes('grundschule') ||
                                                  poiName.includes('realschule') ||
                                                  poiName.includes('gymnasium')
                                              ) return 1;
                                          
                                              if (tags.office === 'energy_supplier') return 2;
                                              if (tags.office === 'company') return 3;
                                              if (tags.building === 'office') return 4;
                                          
                                              if (tags.shop === 'bakery') return 8;
                                              if (tags.shop === 'kiosk') return 8;
                                              if (tags.shop === 'convenience') return 7;
                                          
                                              if (tags.shop) return 2;
                                              if (tags.amenity) return 3;
                                              if (tags.tourism) return 4;
                                              if (tags.leisure) return 5;
                                              if (tags.office) return 6;
                                          
                                              return 99;
                                          }
                                          
                                          function getPoiMaxDistance(tags, name, addressText) {
                                              const poiName = String(name || '').toLowerCase();
                                              const addr = String(addressText || '').toLowerCase();
                                          
                                              if (tags.amenity === 'hospital') return 90;
                                              if (tags.amenity === 'fire_station') return 70;
                                          
                                              if (tags.amenity === 'school') {
                                                  let dist = 60;
                                          
                                                  if (
                                                      poiName.includes('schule') ||
                                                      poiName.includes('realschule') ||
                                                      poiName.includes('grundschule') ||
                                                      poiName.includes('gymnasium')
                                                  ) {
                                                      dist = 90;
                                                  }
                                          
                                                  if (
                                                      addr.includes('schulstraße') ||
                                                      addr.includes('schule') ||
                                                      addr.includes('bobenheim-roxheim')
                                                  ) {
                                                      dist = 130;
                                                  }
                                          
                                                  return dist;
                                              }
                                          
                                              if (tags.amenity === 'kindergarten') return 60;
                                              if (tags.amenity === 'clinic') return 50;
                                              if (tags.shop === 'supermarket') return 40;
                                          
                                              if (tags.office === 'energy_supplier') return 40;
                                              if (tags.office === 'company') return 35;
                                              if (tags.building === 'office') return 30;
                                          
                                              if (tags.shop === 'bakery') return 15;
                                              if (tags.shop === 'kiosk') return 15;
                                              if (tags.shop === 'convenience') return 20;
                                          
                                              if (tags.shop) return 25;
                                              if (tags.amenity) return 30;
                                              if (tags.tourism) return 30;
                                              if (tags.leisure) return 25;
                                              if (tags.office) return 25;
                                          
                                              return 20;
                                          }
                                          
                                          function getPoiTypeLabel(tags) {
                                              if (tags.amenity) return `amenity=${tags.amenity}`;
                                              if (tags.shop) return `shop=${tags.shop}`;
                                              if (tags.tourism) return `tourism=${tags.tourism}`;
                                              if (tags.leisure) return `leisure=${tags.leisure}`;
                                              if (tags.office) return `office=${tags.office}`;
                                              if (tags.building) return `building=${tags.building}`;
                                              return 'unknown';
                                          }
                                          
                                          function isStablePoiType(typeLabel) {
                                              const t = String(typeLabel || '').toLowerCase();
                                              return (
                                                  t.includes('amenity=school') ||
                                                  t.includes('amenity=fire_station') ||
                                                  t.includes('amenity=hospital') ||
                                                  t.includes('amenity=clinic') ||
                                                  t.includes('amenity=kindergarten') ||
                                                  t.includes('shop=supermarket') ||
                                                  t.includes('office=company') ||
                                                  t.includes('office=energy_supplier') ||
                                                  t.includes('building=office')
                                              );
                                          }
                                          
                                          function httpGetAsync(url, headers) {
                                              return new Promise((resolve, reject) => {
                                                  httpGet(url, { headers: headers, timeout: 15000 }, (err, response) => {
                                                      if (err) return reject(err);
                                                      resolve(response);
                                                  });
                                              });
                                          }
                                          
                                          function httpPostAsync(url, body, headers) {
                                              return new Promise((resolve, reject) => {
                                                  httpPost(url, body, { headers: headers, timeout: 20000 }, (err, response) => {
                                                      if (err) return reject(err);
                                                      resolve(response);
                                                  });
                                              });
                                          }
                                          
                                          function sleep(ms) {
                                              return new Promise(resolve => setTimeout(resolve, ms));
                                          }
                                          
                                          function distanceMeters(lat1, lon1, lat2, lon2) {
                                              const R = 6371000;
                                              const toRad = deg => deg * Math.PI / 180;
                                          
                                              const dLat = toRad(lat2 - lat1);
                                              const dLon = toRad(lon2 - lon1);
                                          
                                              const a =
                                                  Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                                                  Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
                                                  Math.sin(dLon / 2) * Math.sin(dLon / 2);
                                          
                                              return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
                                          }
                                          
                                          function round1(v) {
                                              return Math.round(Number(v || 0) * 10) / 10;
                                          }
                                          
                                          function cleanText(str) {
                                              return String(str || '')
                                                  .replace(/\s+/g, ' ')
                                                  .replace(/\s+,/g, ',')
                                                  .trim();
                                          }
                                          
                                          function createStateIfMissing(id, def, type, name) {
                                              if (!existsState(id)) {
                                                  createState(id, def, {
                                                      name: name,
                                                      type: type,
                                                      role: type === 'number' ? 'value' : 'text',
                                                      read: true,
                                                      write: true
                                                  });
                                              }
                                          }
                                          

                                          Beta-Tester

                                          1 Antwort Letzte Antwort
                                          1

                                          Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

                                          Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

                                          Mit deinem Input könnte dieser Beitrag noch besser werden 💗

                                          Registrieren Anmelden
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          613

                                          Online

                                          32.8k

                                          Benutzer

                                          82.8k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe