Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • 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. Skripten / Logik
  4. Alexa Shopping List mit Bring synchronisieren

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    918

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    688

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    1.9k

Alexa Shopping List mit Bring synchronisieren

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
175 Beiträge 31 Kommentatoren 36.0k Aufrufe 31 Watching
  • Ä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.
  • M Offline
    M Offline
    MartyBr
    schrieb am zuletzt editiert von
    #166

    @elron
    Kannst du bitte auf das originale Script verlinken? Ich finde es hier leider nicht.
    Danke für die Anpassung.

    Gruß
    Martin


    Intel NUCs mit Proxmox / Iobroker als VM unter Debian
    Raspeberry mit USB Leseköpfen für Smartmeter
    Homematic und Homematic IP

    E 1 Antwort Letzte Antwort
    0
    • S Offline
      S Offline
      Sil4s
      schrieb am zuletzt editiert von
      #167

      Danke an alle für diese tolle Lösung. Ich hatte nur das Problem, dass das sync script alle 2 Minuten Änderungen erkannt hatte, obwohl sich nur das Update Date geändert hatte. Ich habe keine Sachen in Bring oder Alexa hinzugefügt/gelöscht. Daher wollte ich unnötige updates der Listen vermeiden und habe das Skript für mich wie folgt angepasst.

      /******************************************************
       *  Bring ↔ Alexa List Sync (bidirectional) – MASTER VERSION
       *  Author: SiL4S
       ******************************************************/
      
      // List Object IDs
      const bringBaseId = 'bring.0.2c7bf13d-3896-4632-8a4e-c1d5a4993ce5';
      const alexa2BaseId = 'alexa2.1.Lists.SHOP';
      
      // Bring datapoints
      const bringListId = bringBaseId + '.content';
      const bringListCompletedId = bringBaseId + '.recentContent';
      const bringAddToList = bringBaseId + '.saveItem';
      const bringCompleteItem = bringBaseId + '.moveToRecentContent';
      
      // Alexa datapoints
      const alexaAddToList = alexa2BaseId + '.#New';
      const alexaListId = alexa2BaseId + '.json';
      
      // Loop-protection
      let lastAlexaJson = "";
      let lastBringJson = "";
      
      // Debug logging
      const printDebug = true;
      function debug(msg) { if (printDebug) log(msg); }
      
      // Bring Status
      const TodoItemStatus = {
          NeedsAction: 'needs_action',
          Completed: 'completed',
      };
      
      // Normalize item names (trim, collapse spaces, fix casing)
      function normalize(name = '') {
          return name
              .trim()
              .replace(/\s+/g, ' ')
              .toLowerCase()
              .replace(/(^\w|\s\w)/g, m => m.toUpperCase());
      }
      
      // Compare completed-state between Alexa and Bring items
      function compareCompleted(alexaItem, bringItem) {
          return (
              (alexaItem.completed && bringItem.status === TodoItemStatus.Completed) ||
              (!alexaItem.completed && bringItem.status === TodoItemStatus.NeedsAction)
          );
      }
      
      // Remove duplicate Alexa entries
      function eliminateDuplicated() {
          const raw = getState(alexaListId).val;
          if (!raw) return;
          const list = JSON.parse(raw);
          const seen = {};
      
          for (const i of list) {
              const normalized = normalize(i.value);
              if (seen[normalized]) {
                  debug(`Deleting duplicate Alexa item: ${i.value}`);
                  setState(`${alexa2BaseId}.items.${i.id}.#delete`, true);
              } else {
                  seen[normalized] = true;
              }
          }
      }
      
      //-----------------------------------------------
      // Main Sync Function
      //-----------------------------------------------
      function syncLists(alexaList, bringList, bringRecent, timestampBring, source) {
      
          //----------------------------------------------------
          // 1) Step: Process Alexa items (add / complete)
          //----------------------------------------------------
          for (const alexaItem of alexaList) {
              const nameNorm = normalize(alexaItem.value);
      
              let foundInBring = false;
              let foundInRecent = false;
      
              // Bring "active" items
              for (const b of bringList) {
                  if (normalize(b.name) === nameNorm) {
                      foundInBring = true;
      
                      // Completed syncing
                      if (source === 'Alexa' && alexaItem.completed && !compareCompleted(alexaItem, b)) {
                          debug(`→ Alexa COMPLETED → Mark completed in Bring: ${b.name}`);
                          setState(bringCompleteItem, b.name);
                      }
      
                      if (source === 'Bring' && !compareCompleted(alexaItem, b)) {
                          debug(`→ Bring COMPLETED → Mark completed in Alexa: ${alexaItem.value}`);
                          setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, b.status === TodoItemStatus.Completed);
                      }
                  }
              }
      
              // Bring recentContent
              for (const r of bringRecent) {
                  if (normalize(r.name) === nameNorm) {
                      foundInRecent = true;
      
                      if (source === 'Alexa' && !alexaItem.completed) {
                          debug(`→ Alexa ACTIVE → Add item back to Bring: ${r.name}`);
                          setState(bringAddToList, r.name);
                      }
      
                      if (source === 'Bring' && alexaItem.completed === false) {
                          debug(`→ Bring has this item completed → Delete from Alexa: ${alexaItem.value}`);
                          setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                      }
                  }
              }
      
              //----------------------------------------------------------
              // Item exists in Alexa but not in Bring → delete or push
              //----------------------------------------------------------
              if (!foundInBring && !foundInRecent) {
      
                  if (source === 'Alexa') {
                      debug(`→ New Alexa item → Adding to Bring: ${alexaItem.value}`);
                      setState(bringAddToList, nameNorm);
                  }
      
                  if (source === 'Bring') {
                      debug(`→ Bring deleted item → Deleting from Alexa: ${alexaItem.value}`);
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  }
              }
          }
      
          //----------------------------------------------------
          // 2) Step: Push Bring items to Alexa
          //----------------------------------------------------
          if (source === 'Bring') {
      
              const alexaNames = alexaList.map(a => normalize(a.value));
      
              for (const b of bringList) {
                  const bNorm = normalize(b.name);
                  if (!alexaNames.includes(bNorm) && b.status !== TodoItemStatus.Completed) {
                      debug(`→ New Bring item → Adding to Alexa: ${b.name}`);
                      setState(alexaAddToList, b.name);
                  }
              }
          }
      }
      
      //-----------------------------------------------
      // Full Sync Runner
      //-----------------------------------------------
      function doSync(source) {
          debug(`--- SYNC START (${source}) ---`);
      
          eliminateDuplicated();
      
          const rawAlexa = getState(alexaListId).val;
          const rawBring = getState(bringListId).val;
          const rawRecent = getState(bringListCompletedId).val;
      
          if (!rawAlexa || !rawBring || !rawRecent) {
              debug('Missing datapoints!');
              return;
          }
      
          const alexaList = JSON.parse(rawAlexa);
          const bringList = JSON.parse(rawBring);
          const bringRecent = JSON.parse(rawRecent);
          const bringTS = getState(bringListId).ts;
      
          debug('Processing…');
          syncLists(alexaList, bringList, bringRecent, bringTS, source);
          debug(`--- SYNC FINISHED (${source}) ---`);
      }
      
      //-----------------------------------------------
      // Bring Trigger
      //-----------------------------------------------
      on({ id: bringListId, change: "any" }, () => {
          const now = getState(bringListId).val;
          if (now === lastBringJson) {
              debug('Bring: Update ignored (not real change)');
              return;
          }
          lastBringJson = now;
      
          debug('Bring → Real change detected');
          doSync('Bring');
      });
      
      //-----------------------------------------------
      // Alexa Trigger
      //-----------------------------------------------
      on({ id: alexaListId, change: "any" }, () => {
          const now = getState(alexaListId).val;
          if (now === lastAlexaJson) {
              debug('Alexa: Update ignored (polling only)');
              return;
          }
          lastAlexaJson = now;
      
          debug('Alexa → Real change detected');
          doSync('Alexa');
      });
      
      //-----------------------------------------------
      // Initial sync at startup
      //-----------------------------------------------
      doSync('Startup');
      
      
      OreiderO 1 Antwort Letzte Antwort
      1
      • S Sil4s

        Danke an alle für diese tolle Lösung. Ich hatte nur das Problem, dass das sync script alle 2 Minuten Änderungen erkannt hatte, obwohl sich nur das Update Date geändert hatte. Ich habe keine Sachen in Bring oder Alexa hinzugefügt/gelöscht. Daher wollte ich unnötige updates der Listen vermeiden und habe das Skript für mich wie folgt angepasst.

        /******************************************************
         *  Bring ↔ Alexa List Sync (bidirectional) – MASTER VERSION
         *  Author: SiL4S
         ******************************************************/
        
        // List Object IDs
        const bringBaseId = 'bring.0.2c7bf13d-3896-4632-8a4e-c1d5a4993ce5';
        const alexa2BaseId = 'alexa2.1.Lists.SHOP';
        
        // Bring datapoints
        const bringListId = bringBaseId + '.content';
        const bringListCompletedId = bringBaseId + '.recentContent';
        const bringAddToList = bringBaseId + '.saveItem';
        const bringCompleteItem = bringBaseId + '.moveToRecentContent';
        
        // Alexa datapoints
        const alexaAddToList = alexa2BaseId + '.#New';
        const alexaListId = alexa2BaseId + '.json';
        
        // Loop-protection
        let lastAlexaJson = "";
        let lastBringJson = "";
        
        // Debug logging
        const printDebug = true;
        function debug(msg) { if (printDebug) log(msg); }
        
        // Bring Status
        const TodoItemStatus = {
            NeedsAction: 'needs_action',
            Completed: 'completed',
        };
        
        // Normalize item names (trim, collapse spaces, fix casing)
        function normalize(name = '') {
            return name
                .trim()
                .replace(/\s+/g, ' ')
                .toLowerCase()
                .replace(/(^\w|\s\w)/g, m => m.toUpperCase());
        }
        
        // Compare completed-state between Alexa and Bring items
        function compareCompleted(alexaItem, bringItem) {
            return (
                (alexaItem.completed && bringItem.status === TodoItemStatus.Completed) ||
                (!alexaItem.completed && bringItem.status === TodoItemStatus.NeedsAction)
            );
        }
        
        // Remove duplicate Alexa entries
        function eliminateDuplicated() {
            const raw = getState(alexaListId).val;
            if (!raw) return;
            const list = JSON.parse(raw);
            const seen = {};
        
            for (const i of list) {
                const normalized = normalize(i.value);
                if (seen[normalized]) {
                    debug(`Deleting duplicate Alexa item: ${i.value}`);
                    setState(`${alexa2BaseId}.items.${i.id}.#delete`, true);
                } else {
                    seen[normalized] = true;
                }
            }
        }
        
        //-----------------------------------------------
        // Main Sync Function
        //-----------------------------------------------
        function syncLists(alexaList, bringList, bringRecent, timestampBring, source) {
        
            //----------------------------------------------------
            // 1) Step: Process Alexa items (add / complete)
            //----------------------------------------------------
            for (const alexaItem of alexaList) {
                const nameNorm = normalize(alexaItem.value);
        
                let foundInBring = false;
                let foundInRecent = false;
        
                // Bring "active" items
                for (const b of bringList) {
                    if (normalize(b.name) === nameNorm) {
                        foundInBring = true;
        
                        // Completed syncing
                        if (source === 'Alexa' && alexaItem.completed && !compareCompleted(alexaItem, b)) {
                            debug(`→ Alexa COMPLETED → Mark completed in Bring: ${b.name}`);
                            setState(bringCompleteItem, b.name);
                        }
        
                        if (source === 'Bring' && !compareCompleted(alexaItem, b)) {
                            debug(`→ Bring COMPLETED → Mark completed in Alexa: ${alexaItem.value}`);
                            setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, b.status === TodoItemStatus.Completed);
                        }
                    }
                }
        
                // Bring recentContent
                for (const r of bringRecent) {
                    if (normalize(r.name) === nameNorm) {
                        foundInRecent = true;
        
                        if (source === 'Alexa' && !alexaItem.completed) {
                            debug(`→ Alexa ACTIVE → Add item back to Bring: ${r.name}`);
                            setState(bringAddToList, r.name);
                        }
        
                        if (source === 'Bring' && alexaItem.completed === false) {
                            debug(`→ Bring has this item completed → Delete from Alexa: ${alexaItem.value}`);
                            setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                        }
                    }
                }
        
                //----------------------------------------------------------
                // Item exists in Alexa but not in Bring → delete or push
                //----------------------------------------------------------
                if (!foundInBring && !foundInRecent) {
        
                    if (source === 'Alexa') {
                        debug(`→ New Alexa item → Adding to Bring: ${alexaItem.value}`);
                        setState(bringAddToList, nameNorm);
                    }
        
                    if (source === 'Bring') {
                        debug(`→ Bring deleted item → Deleting from Alexa: ${alexaItem.value}`);
                        setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                    }
                }
            }
        
            //----------------------------------------------------
            // 2) Step: Push Bring items to Alexa
            //----------------------------------------------------
            if (source === 'Bring') {
        
                const alexaNames = alexaList.map(a => normalize(a.value));
        
                for (const b of bringList) {
                    const bNorm = normalize(b.name);
                    if (!alexaNames.includes(bNorm) && b.status !== TodoItemStatus.Completed) {
                        debug(`→ New Bring item → Adding to Alexa: ${b.name}`);
                        setState(alexaAddToList, b.name);
                    }
                }
            }
        }
        
        //-----------------------------------------------
        // Full Sync Runner
        //-----------------------------------------------
        function doSync(source) {
            debug(`--- SYNC START (${source}) ---`);
        
            eliminateDuplicated();
        
            const rawAlexa = getState(alexaListId).val;
            const rawBring = getState(bringListId).val;
            const rawRecent = getState(bringListCompletedId).val;
        
            if (!rawAlexa || !rawBring || !rawRecent) {
                debug('Missing datapoints!');
                return;
            }
        
            const alexaList = JSON.parse(rawAlexa);
            const bringList = JSON.parse(rawBring);
            const bringRecent = JSON.parse(rawRecent);
            const bringTS = getState(bringListId).ts;
        
            debug('Processing…');
            syncLists(alexaList, bringList, bringRecent, bringTS, source);
            debug(`--- SYNC FINISHED (${source}) ---`);
        }
        
        //-----------------------------------------------
        // Bring Trigger
        //-----------------------------------------------
        on({ id: bringListId, change: "any" }, () => {
            const now = getState(bringListId).val;
            if (now === lastBringJson) {
                debug('Bring: Update ignored (not real change)');
                return;
            }
            lastBringJson = now;
        
            debug('Bring → Real change detected');
            doSync('Bring');
        });
        
        //-----------------------------------------------
        // Alexa Trigger
        //-----------------------------------------------
        on({ id: alexaListId, change: "any" }, () => {
            const now = getState(alexaListId).val;
            if (now === lastAlexaJson) {
                debug('Alexa: Update ignored (polling only)');
                return;
            }
            lastAlexaJson = now;
        
            debug('Alexa → Real change detected');
            doSync('Alexa');
        });
        
        //-----------------------------------------------
        // Initial sync at startup
        //-----------------------------------------------
        doSync('Startup');
        
        
        OreiderO Offline
        OreiderO Offline
        Oreider
        schrieb am zuletzt editiert von
        #168

        @Sil4s

        Danke, hatte auch die regelmäßigen Aktualisierungen.
        Hab mal auf deine geänderte Version umgestellt. Bisher schaut alles gut aus!

        Danke dafür!

        S 1 Antwort Letzte Antwort
        0
        • OreiderO Oreider

          @Sil4s

          Danke, hatte auch die regelmäßigen Aktualisierungen.
          Hab mal auf deine geänderte Version umgestellt. Bisher schaut alles gut aus!

          Danke dafür!

          S Offline
          S Offline
          Sil4s
          schrieb am zuletzt editiert von
          #169

          @Oreider Super das freut mich, bei mir läuft es auch stabil und meine Frau hat auch noch nicht gemeckert. :)

          1 Antwort Letzte Antwort
          0
          • M MartyBr

            @elron
            Kannst du bitte auf das originale Script verlinken? Ich finde es hier leider nicht.
            Danke für die Anpassung.

            E Offline
            E Offline
            elron
            schrieb am zuletzt editiert von
            #170

            @MartyBr sagte in Alexa Shopping List mit Bring synchronisieren:

            @elron
            Kannst du bitte auf das originale Script verlinken? Ich finde es hier leider nicht.
            Danke für die Anpassung.

            Hi Martin,

            hier bzw. auch im Threadverlauf.

            M 1 Antwort Letzte Antwort
            0
            • E elron

              @MartyBr sagte in Alexa Shopping List mit Bring synchronisieren:

              @elron
              Kannst du bitte auf das originale Script verlinken? Ich finde es hier leider nicht.
              Danke für die Anpassung.

              Hi Martin,

              hier bzw. auch im Threadverlauf.

              M Offline
              M Offline
              MartyBr
              schrieb am zuletzt editiert von
              #171

              @elron
              Der Link funktioniert leider nicht (zumindest bei mir). Ich habe das Script von @sil4s genommen.

              Vielen Dank

              Gruß
              Martin


              Intel NUCs mit Proxmox / Iobroker als VM unter Debian
              Raspeberry mit USB Leseköpfen für Smartmeter
              Homematic und Homematic IP

              E 1 Antwort Letzte Antwort
              0
              • M MartyBr

                @elron
                Der Link funktioniert leider nicht (zumindest bei mir). Ich habe das Script von @sil4s genommen.

                Vielen Dank

                E Offline
                E Offline
                elron
                schrieb am zuletzt editiert von
                #172

                @MartyBr sagte in Alexa Shopping List mit Bring synchronisieren:

                @elron
                Der Link funktioniert leider nicht (zumindest bei mir). Ich habe das Script von @sil4s genommen.

                Vielen Dank

                Okay, komisch, hier nochmal der gesamte Code inkl. der aktuellen Änderung:

                /***********************************************************************************************************************************************************************************
                 * GENERIC INFO:
                 *      Created by Daniel Drießen @ DDProductions
                 * 
                 *      Date of creation:   17.07.2024
                 *      Version:            0.1.0.0    
                 * 
                 * DESCRIPTION:
                 *      This script synchronizes the shopping lists of 'Alexa' and 'Bring'.
                 *      It monitors changes in both shopping lists and ensures that they stay updated with each other.
                 *      The script uses events to detect changes in the shopping lists of both 'Alexa' and 'Bring'.
                 *      When changes are detected, it initiates a synchronization to reconcile any discrepancies between the lists.
                 *      The synchronization process involves comparing the items on both lists and updating each list to reflect the combined items from both sources.
                 * 
                 * DEPENDENCIES:
                 *      - Alexa2 adapter
                 *      - Bring adapter
                 *
                 * LIMITATIONS:
                 *      Due to the nature of the 'Bring' adapter (which does not store an 'added' or 'updated' timestamp for items on the shopping list), a 'real' synchronization is not possible
                 *      because there is no way to detect the order of changes to the shopping lists of 'Alexa' and 'Bring'.
                 * 
                 * TODO & FUTURE GOALS:
                 *      - Add better error handling.
                 *      - Move functions 'getItemsOnAlexaShoppingList' & 'getItemsOnBringShoppingList' into classes 'AlexaShoppingList' & 'BringShoppingList'.
                 *      - Move functions 'addItemToShoppingList', 'removeItemFromShoppingList' into classes 'AlexaShoppingList' & 'BringShoppingList'.
                 *      - Enhance the synchronization logic to minimize potential syncing errors and improve reliability given the above limitations.
                 *      - Maybe add a sync schedule for periodic syncing.
                 * 
                 * CHANGELOG:
                 *      18.07.2024 - Initial version completed.
                 * 
                 ***********************************************************************************************************************************************************************************/
                
                export default this;
                
                
                
                
                
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                +                                                                   SCRIPT SETUP                                                                           +
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                /*---------- OBJECT-ID CONSTANTS ------------------------------------------------------------------------------------------------*/
                const objectID_alexa_shoppingList_folder = 'alexa2.0.Lists.SHOP';
                const objectID_alexa_shoppingList_addItem = 'alexa2.0.Lists.SHOP.#New';
                
                const objectID_bring_shoppingList_sentenceString = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.enumSentence';
                const objectID_bring_shoppingList_addItem = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.saveItem';
                const objectID_bring_shoppingList_removeItem = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.removeItem';
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                
                
                
                
                
                
                
                
                
                
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                +                                                               START OF SCRIPT LOGIC                                                                      +
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                var initComplete = false;
                var syncingInProgress = false;
                var resyncRequests = [];
                startScriptLogic();
                
                
                async function startScriptLogic() {
                    try {
                        await init();
                        initComplete = true;
                    } catch (error) {
                        console.error(error.message);
                        console.debug(`SCRIPT WILL TERMINATE NOW!`);
                        await this.stopScriptAsync();
                    }
                }
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                
                
                
                
                
                /*---------- INIT ---------------------------------------------------------------------------------------------------------------*/
                async function init(): Promise <void> {
                    console.info(`Script initialization...`);
                
                    await synchronizeShoppingLists('init', false);
                
                    console.info(`Script initialization completed successfully!`);
                
                    await checkForResyncRequests();
                }
                
                
                
                /*---------- TRIGGER ------------------------------------------------------------------------------------------------------------*/
                // Alexa
                on({ id: [].concat([objectID_alexa_shoppingList_folder + '.json']), change: 'ne' }, async (obj) => {
                  let value = obj.state.val;
                  let oldValue = obj.oldState.val;
                
                  console.debug(`'Alexa' shopping list changed!`);
                
                  if (initComplete && !syncingInProgress) {
                      await synchronizeShoppingLists('alexa', false);
                      await checkForResyncRequests();
                  } else {
                      resyncRequests.push('alexa');
                  }
                });
                
                // Bring
                on({ id: [].concat([objectID_bring_shoppingList_sentenceString]), change: 'ne' }, async (obj) => {
                  let value = obj.state.val;
                  let oldValue = obj.oldState.val;
                
                  console.debug(`'Bring' shopping list changed!`);
                
                  if (initComplete && !syncingInProgress) {
                      await synchronizeShoppingLists('bring', false);
                      await checkForResyncRequests();
                  } else {
                      resyncRequests.push('bring');
                  }
                });
                
                
                
                /*---------- SYNC ---------------------------------------------------------------------------------------------------------------*/
                async function synchronizeShoppingLists(syncInitiator:string, isResync:boolean) {
                    console.info(`Sync started`);
                    console.debug(`Sync initiator: '${capitalizeFirstLetter(syncInitiator)}'`);
                    console.debug(`Sync is a resync: '${isResync}'`);
                    syncingInProgress = true;
                    
                    var itemsOnAlexaShoppingList = await getItemsOnAlexaShoppingList();
                    var itemsOnBringShoppingList = await getItemsOnBringShoppingList();
                    console.debug(`Items on "Alexa" shopping list (${itemsOnAlexaShoppingList.length}): ${itemsOnAlexaShoppingList.map(item => item.value)}`);
                    console.debug(`Items on "Bring" shopping list (${itemsOnBringShoppingList.length}): ${itemsOnBringShoppingList.map(item => item.value)}`);
                
                    if (syncInitiator.toLowerCase() === 'init') {
                        // If sync initiator is "init"
                        // create a combined item list and add each item missing on each list to each list.
                
                        // Create combined shopping list
                        var itemsOnCombinedShoppingList = [];
                        for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnCombinedShoppingList, itemOnAlexaShoppingList)) {
                                itemsOnCombinedShoppingList.push(itemOnAlexaShoppingList);
                            }
                        }
                        for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnCombinedShoppingList, itemOnBringShoppingList)) {
                                itemsOnCombinedShoppingList.push(itemOnBringShoppingList);
                            }
                        }
                        //console.debug(`Items on "Combined" shopping list: ${itemsOnCombinedShoppingList.map(item => item.value)}`);
                
                        // Add each missing item on each list to each list
                        var itemsToAddToAlexaShoppingList = [];
                        var itemsToAddToBringShoppingList = [];
                
                        for (const itemOnCombinedShoppingList of itemsOnCombinedShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnCombinedShoppingList)) {
                                itemsToAddToAlexaShoppingList.push(itemOnCombinedShoppingList);
                            }
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnCombinedShoppingList)) {
                                itemsToAddToBringShoppingList.push(itemOnCombinedShoppingList);
                            }
                        }
                        if (itemsToAddToAlexaShoppingList.length > 0) {
                            console.debug(`Items to add to "Alexa" shopping list (${itemsToAddToAlexaShoppingList.length}): ${itemsToAddToAlexaShoppingList.map(item => item.value)}`);
                        }
                        if (itemsToAddToBringShoppingList.length > 0) {
                            console.debug(`Items to add to "Bring" shopping list (${itemsToAddToBringShoppingList.length}): ${itemsToAddToBringShoppingList.map(item => item.value)}`);
                        }
                
                        for (const itemToAddToAlexaShoppingList of itemsToAddToAlexaShoppingList) {
                            await AlexaShoppingListItem.addItemToShoppingList(itemToAddToAlexaShoppingList);
                        }
                        for (const itemToAddToBringShoppingList of itemsToAddToBringShoppingList) {
                            await BringShoppingListItem.addItemToShoppingList(itemToAddToBringShoppingList);
                        }
                    } else if (syncInitiator.toLowerCase() === 'alexa') {
                        // If sync initiator is "alexa"
                        // add each item from the alexa shopping list that is missing on the bring shopping list to the bring shopping list.
                        // Then remove each item from the bring shopping list that is not on the alexa shopping list.
                        
                        // Add each item from the alexa shopping list that is missing on the bring shopping list to the bring shopping list.
                        var itemsToAddToBringShoppingList = [];
                
                        for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnAlexaShoppingList)) {
                                itemsToAddToBringShoppingList.push(itemOnAlexaShoppingList);
                            }
                        }
                        if (itemsToAddToBringShoppingList.length > 0) {
                            console.debug(`Items to add to "Bring" shopping list (${itemsToAddToBringShoppingList.length}): ${itemsToAddToBringShoppingList.map(item => item.value)}`);
                        }
                
                        for (const itemToAddToBringShoppingList of itemsToAddToBringShoppingList) {
                            await BringShoppingListItem.addItemToShoppingList(itemToAddToBringShoppingList);
                        }
                
                
                        // Get an update of the bring shopping list
                        itemsOnBringShoppingList = await getItemsOnBringShoppingList();
                
                
                        // Remove each item from the bring shopping list that is not on the alexa shopping list.
                        var itemsToRemoveFromBringShoppingList = [];
                
                        for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnBringShoppingList)) {
                                itemsToRemoveFromBringShoppingList.push(itemOnBringShoppingList);
                            }
                        }
                        if (itemsToRemoveFromBringShoppingList.length > 0) {
                            console.debug(`Items to remove from "Bring" shopping list (${itemsToRemoveFromBringShoppingList.length}): ${itemsToRemoveFromBringShoppingList.map(item => item.value)}`);
                        }
                
                        for (const itemToRemoveFromBringShoppingList of itemsToRemoveFromBringShoppingList) {
                            await BringShoppingListItem.removeItemFromShoppingList(itemToRemoveFromBringShoppingList);
                        }
                    } else if (syncInitiator.toLowerCase() === 'bring') {
                        // If sync initiator is "bring"
                        // add each item from the bring shopping list that is missing on the alexa shopping list to the alexa shopping list.
                        // Then remove each item from the alexa shopping list that is not on the bring shopping list.
                
                        // Add each item from the bring shopping list that is missing on the alexa shopping list to the alexa shopping list.
                        var itemsToAddToAlexaShoppingList = [];
                
                        for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnBringShoppingList)) {
                                itemsToAddToAlexaShoppingList.push(itemOnBringShoppingList);
                            }
                        }
                        if (itemsToAddToAlexaShoppingList.length > 0) {
                            console.debug(`Items to add to "Alexa" shopping list (${itemsToAddToAlexaShoppingList.length}): ${itemsToAddToAlexaShoppingList.map(item => item.value)}`);
                        }
                
                        for (const itemToAddToAlexaShoppingList of itemsToAddToAlexaShoppingList) {
                            await AlexaShoppingListItem.addItemToShoppingList(itemToAddToAlexaShoppingList);
                        }
                
                
                        // Get an update of the alexa shopping list
                        itemsOnAlexaShoppingList = await getItemsOnAlexaShoppingList();
                
                
                        // Remove each item from the alexa shopping list that is not on the bring shopping list.
                        var itemsToRemoveFromAlexaShoppingList = [];
                
                        for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                            if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnAlexaShoppingList)) {
                                itemsToRemoveFromAlexaShoppingList.push(itemOnAlexaShoppingList);
                            }
                        }
                        if (itemsToRemoveFromAlexaShoppingList.length > 0) {
                            console.debug(`Items to remove from "Alexa" shopping list (${itemsToRemoveFromAlexaShoppingList.length}): ${itemsToRemoveFromAlexaShoppingList.map(item => item.value)}`);
                        }
                
                        for (const itemToRemoveFromAlexaShoppingList of itemsToRemoveFromAlexaShoppingList) {
                            await AlexaShoppingListItem.removeItemFromShoppingList(itemToRemoveFromAlexaShoppingList);
                        }
                    }
                
                    console.info(`Sync completed!`);
                    syncingInProgress = false;
                }
                
                
                
                async function checkForResyncRequests() {
                    if (resyncRequests.length > 0) {
                        // Get the first resync request.
                        var firstResyncRequest = resyncRequests[0];
                
                        // Remove the first resync request from the array.
                        resyncRequests.shift();
                
                        // Remove all values from the array that match the firstResyncRequest value
                        resyncRequests = resyncRequests.filter(request => request !== firstResyncRequest);
                
                        // Perform resync
                        await synchronizeShoppingLists(firstResyncRequest, true);
                    }
                }
                
                
                
                /*---------- GET SHOPPING LIST ITEMS --------------------------------------------------------------------------------------------*/
                // Alexa
                async function getItemsOnAlexaShoppingList(): Promise <Array<AlexaShoppingListItem>> {
                    var alexaShoppingListItems = [];
                    var completedAlexaShoppingListItemsToRemove = [];
                
                    var jsonShoppingListString = await getStateAsync(objectID_alexa_shoppingList_folder + '.json');
                    var jsonShoppingList = JSON.parse(jsonShoppingListString.val);
                
                    jsonShoppingList.forEach((item, index) => {
                        var item_id = item.id;
                        var item_listID = item.listId;
                        var item_customerID = item.customerId;
                        var item_shoppingListItem = item.shoppingListItem;
                        var item_value = item.value;
                        var item_completed = item.completed;
                        var item_version = item.version;
                        var item_createdDateTime = item.createdDateTime;
                        var item_updatedDateTime = item.updatedDateTime;
                        var item_idOfFolderObject = objectID_alexa_shoppingList_folder + '.items.' + item.id;
                        var item_idOfDeleteDatapoint = objectID_alexa_shoppingList_folder + '.items.' + item.id + '.#delete';
                        
                        /*
                        console.debug(`item_id: ${item_id}`);
                        console.debug(`item_listID: ${item_listID}`);
                        console.debug(`item_customerID: ${item_customerID}`);
                        console.debug(`item_shoppingListItem: ${item_shoppingListItem}`);
                        console.debug(`item_value: ${item_value}`);
                        console.debug(`item_completed: ${item_completed}`);
                        console.debug(`item_version: ${item_version}`);
                        console.debug(`item_createdDateTime: ${item_createdDateTime}`);
                        console.debug(`item_updatedDateTime: ${item_updatedDateTime}`);
                        console.debug(`item_idOfFolderObject: ${item_idOfFolderObject}`);
                        console.debug(`item_idOfDeleteDatapoint: ${item_idOfDeleteDatapoint}`);
                        */
                
                        try {
                            const newAlexaShoppingListItem = new AlexaShoppingListItem(
                                item_id,
                                item_listID,
                                item_customerID,
                                item_shoppingListItem,
                                item_value,
                                item_completed,
                                item_version,
                                item_createdDateTime,
                                item_updatedDateTime,
                                item_idOfFolderObject,
                                item_idOfDeleteDatapoint);
                                
                                if (!newAlexaShoppingListItem.completed) {
                                    alexaShoppingListItems.push(newAlexaShoppingListItem);
                                } else {
                                    completedAlexaShoppingListItemsToRemove.push(newAlexaShoppingListItem);
                                }
                            } catch (error) {
                                console.error(`Error while creating Alexa Shopping-List Item Object! -  Original Error: ${error.message}`);
                            }
                    });
                
                    if (completedAlexaShoppingListItemsToRemove.length > 0) {
                        for (const completedAlexaShoppingListItemToRemove of completedAlexaShoppingListItemsToRemove) {
                            await AlexaShoppingListItem.removeItemFromShoppingList(completedAlexaShoppingListItemToRemove);
                        }
                    }
                
                    // Sort the array of alexa shopping list items (case insensitive sorting)
                    alexaShoppingListItems.sort((a, b) => a.value.toLowerCase().localeCompare(b.value.toLowerCase()));
                
                    return alexaShoppingListItems;
                }
                
                // Bring
                async function getItemsOnBringShoppingList(): Promise <Array<BringShoppingListItem>> {
                    var bringShoppingListItems = [];
                
                    try {
                        var humanReadableShoppingListObject = await getStateAsync(objectID_bring_shoppingList_sentenceString);
                        var humanReadableShoppingList = humanReadableShoppingListObject.val;
                        if (humanReadableShoppingList !== null && humanReadableShoppingList !== '' && humanReadableShoppingList.length > 0) {
                            humanReadableShoppingList = replaceAllOccurrencesOfASubstringWithinAString(humanReadableShoppingList, ' und ', ', ');
                            humanReadableShoppingList = replaceAllOccurrencesOfASubstringWithinAString(humanReadableShoppingList, ', ', ';');
                            
                            const bringShoppingListItemStrings = splitStringIntoArray(humanReadableShoppingList, ';');
                            
                            for (const bringShoppingListItemString of bringShoppingListItemStrings) {
                                try {
                                    const newBringShoppingListItem = new BringShoppingListItem(bringShoppingListItemString);
                                    bringShoppingListItems.push(newBringShoppingListItem);
                                } catch (error) {
                                    console.error(`Error while creating Alexa Shopping-List Item Object! -  Original Error: ${error.message}`);
                                    continue;
                                }
                            }
                        }
                    } catch (error) {
                        console.error(`Error while getting Bring Shopping-List Items! - Original Error: ${error.message}`);
                    }
                
                    // Sort the array of alexa shopping list items (case insensitive sorting)
                    bringShoppingListItems.sort((a, b) => a.value.toLowerCase().localeCompare(b.value.toLowerCase()));
                
                    return bringShoppingListItems;
                }
                
                
                
                
                
                
                
                
                
                
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                +                                                                     CLASSES                                                                              +
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                class AlexaShoppingListItem {
                    public id: string;
                    public listID: string;
                    public customerID: string;
                    public shoppingListItem: boolean;
                    public value: string;
                    public completed: boolean;
                    public version: number;
                    public createdDateTime: number;
                    public updatedDateTime: number;
                    public idOfFolderObject: string;
                    public idOfDeleteDatapoint: string;
                    
                    constructor(
                        id:string,
                        listID:string,
                        customerID:string,
                        shoppingListItem:boolean,
                        value:string,
                        completed:boolean,
                        version:number,
                        createdDateTime:number,
                        updatedDateTime:number,
                        idOfFolderObject:string,
                        idOfDeleteDatapoint:string) {
                            this.id = id;
                            this.listID = listID;
                            this.customerID = customerID;
                            this.shoppingListItem = shoppingListItem;
                            this.value = value;
                            this.completed = completed;
                            this.version = version;
                            this.createdDateTime = createdDateTime;
                            this.updatedDateTime = updatedDateTime;
                            this.idOfFolderObject = idOfFolderObject;
                            this.idOfDeleteDatapoint = idOfDeleteDatapoint;
                    }
                    
                    /********************
                     * Adds an item to the Alexa shopping list.
                     * 
                     * @param item - The item to save to the Alexa shopping list. Must be either an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.
                     * @return Promise<boolean> - True if the function completed running its code.
                     ********************/
                    static async addItemToShoppingList(item:AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                        // Parameter validation
                        if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                            throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'!");
                        }
                
                        await setStateAsync(objectID_alexa_shoppingList_addItem, capitalizeFirstLetter(item.value), false);
                        return true;
                    }
                
                    /********************
                     * Removes an item from the Alexa shopping list.
                     * 
                     * @param item - The item to remove from the Alexa shopping list. Must be an instance of 'AlexaShoppingListItem'.
                     * @return Promise<boolean> - True if the function completed running its code.
                     ********************/
                     static async removeItemFromShoppingList(item:AlexaShoppingListItem): Promise <boolean> {
                         // Parameter validation
                        if (!(item instanceof AlexaShoppingListItem)) {
                            throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem'!");
                        }
                
                        await setStateAsync(item.idOfDeleteDatapoint, true, false);
                        return true;
                     }
                }
                
                
                
                class BringShoppingListItem {
                    public value: string;
                    
                    constructor(value:string) {
                        this.value = value;
                    }
                
                    /********************
                     * Adds an item to the Bring shopping list.
                     * 
                     * @param item - The item to save to the Bring shopping list. Must be either an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.
                     * @return Promise<boolean> - True if the function completed running its code.
                     ********************/
                    static async addItemToShoppingList(item:AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                        // Parameter validation
                        if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                            throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'!");
                        }
                
                        await setStateAsync(objectID_bring_shoppingList_addItem, capitalizeFirstLetter(item.value), false);
                        return true;
                    }
                
                    /********************
                     * Removes an item from the Bring shopping list.
                     * 
                     * @param item - The item to remove from the Bring shopping list. Must be an instance of 'BringShoppingListItem'.
                     * @return Promise<boolean> - True if the function completed running its code.
                     ********************/
                     static async removeItemFromShoppingList(item:BringShoppingListItem): Promise <boolean> {
                         // Parameter validation
                        if (!(item instanceof BringShoppingListItem)) {
                            throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'BringShoppingListItem'!");
                        }
                
                        await setStateAsync(objectID_bring_shoppingList_removeItem, item.value, false);
                        return true;
                     }
                }
                
                
                
                class ShoppingListUtils {
                    /********************
                     * Checks if a given shopping list array contains a specific shopping list item.
                     * Herefore it compares all items in the given shopping list array with the given shopping list item
                     * (either an 'AlexaShoppingListItem' or a 'BringShoppingListItem')
                     * in a case-insensitive way.
                     * 
                     * @param shoppingListArray - Array of AlexaShoppingListItem or BringShoppingListItem objects to check within.
                     * @param shoppingListItem - The shopping list item to find in the array.
                     * @returns Promise<boolean> - True if the item is found, otherwise false.
                     ********************/
                    static async checkIfShoppingListArrayContainsShoppingListItem(shoppingListArray: Array<AlexaShoppingListItem | BringShoppingListItem>, shoppingListItem: AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                        // Parameter validation
                        if (!Array.isArray(shoppingListArray)) {
                            throw new Error("Invalid parameter: 'shoppingListArray' must be an array.");
                        }
                        if (!(shoppingListItem instanceof AlexaShoppingListItem || shoppingListItem instanceof BringShoppingListItem)) {
                            throw new Error("Invalid parameter: 'shoppingListItem' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.");
                        }
                
                        for (const item of shoppingListArray) {
                            if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                                throw new Error("Invalid parameter: All elements in 'shoppingListArray' must be instances of 'AlexaShoppingListItem' or 'BringShoppingListItem'.");
                            }
                        }
                        
                        // Normalize the value of the shopping list item to lower case for case-insensitive comparison
                        const itemValueToCheck = shoppingListItem.value.toLowerCase();
                
                        // Check if any item in the array matches the shopping list item value
                        for (const item of shoppingListArray) {
                            if (item.value.toLowerCase() === itemValueToCheck) {
                                return true;
                            }
                        }
                
                        return false;
                    }
                }
                /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                
                
                
                
                
                
                
                
                
                
                /*---------- HELPER FUNCTIONS ---------------------------------------------------------------------------------------------------*/
                function capitalizeFirstLetter(input: string): string {
                    if (input.length === 0) {
                        return input; // Return the empty string if input is empty
                    }
                    return input.charAt(0).toUpperCase() + input.slice(1);
                }
                
                function replaceAllOccurrencesOfASubstringWithinAString(originalString: string, searchValue: string, replaceValue: string): string {
                    const regex = new RegExp(searchValue, 'g');
                    return originalString.replace(regex, replaceValue);
                }
                
                function splitStringIntoArray(input: string, delimiter: string): string[] {
                    return input.split(delimiter);
                }
                
                M 1 Antwort Letzte Antwort
                0
                • E elron

                  @MartyBr sagte in Alexa Shopping List mit Bring synchronisieren:

                  @elron
                  Der Link funktioniert leider nicht (zumindest bei mir). Ich habe das Script von @sil4s genommen.

                  Vielen Dank

                  Okay, komisch, hier nochmal der gesamte Code inkl. der aktuellen Änderung:

                  /***********************************************************************************************************************************************************************************
                   * GENERIC INFO:
                   *      Created by Daniel Drießen @ DDProductions
                   * 
                   *      Date of creation:   17.07.2024
                   *      Version:            0.1.0.0    
                   * 
                   * DESCRIPTION:
                   *      This script synchronizes the shopping lists of 'Alexa' and 'Bring'.
                   *      It monitors changes in both shopping lists and ensures that they stay updated with each other.
                   *      The script uses events to detect changes in the shopping lists of both 'Alexa' and 'Bring'.
                   *      When changes are detected, it initiates a synchronization to reconcile any discrepancies between the lists.
                   *      The synchronization process involves comparing the items on both lists and updating each list to reflect the combined items from both sources.
                   * 
                   * DEPENDENCIES:
                   *      - Alexa2 adapter
                   *      - Bring adapter
                   *
                   * LIMITATIONS:
                   *      Due to the nature of the 'Bring' adapter (which does not store an 'added' or 'updated' timestamp for items on the shopping list), a 'real' synchronization is not possible
                   *      because there is no way to detect the order of changes to the shopping lists of 'Alexa' and 'Bring'.
                   * 
                   * TODO & FUTURE GOALS:
                   *      - Add better error handling.
                   *      - Move functions 'getItemsOnAlexaShoppingList' & 'getItemsOnBringShoppingList' into classes 'AlexaShoppingList' & 'BringShoppingList'.
                   *      - Move functions 'addItemToShoppingList', 'removeItemFromShoppingList' into classes 'AlexaShoppingList' & 'BringShoppingList'.
                   *      - Enhance the synchronization logic to minimize potential syncing errors and improve reliability given the above limitations.
                   *      - Maybe add a sync schedule for periodic syncing.
                   * 
                   * CHANGELOG:
                   *      18.07.2024 - Initial version completed.
                   * 
                   ***********************************************************************************************************************************************************************************/
                  
                  export default this;
                  
                  
                  
                  
                  
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  +                                                                   SCRIPT SETUP                                                                           +
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  /*---------- OBJECT-ID CONSTANTS ------------------------------------------------------------------------------------------------*/
                  const objectID_alexa_shoppingList_folder = 'alexa2.0.Lists.SHOP';
                  const objectID_alexa_shoppingList_addItem = 'alexa2.0.Lists.SHOP.#New';
                  
                  const objectID_bring_shoppingList_sentenceString = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.enumSentence';
                  const objectID_bring_shoppingList_addItem = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.saveItem';
                  const objectID_bring_shoppingList_removeItem = 'bring.0.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.removeItem';
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  +                                                               START OF SCRIPT LOGIC                                                                      +
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  var initComplete = false;
                  var syncingInProgress = false;
                  var resyncRequests = [];
                  startScriptLogic();
                  
                  
                  async function startScriptLogic() {
                      try {
                          await init();
                          initComplete = true;
                      } catch (error) {
                          console.error(error.message);
                          console.debug(`SCRIPT WILL TERMINATE NOW!`);
                          await this.stopScriptAsync();
                      }
                  }
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  
                  
                  
                  
                  
                  /*---------- INIT ---------------------------------------------------------------------------------------------------------------*/
                  async function init(): Promise <void> {
                      console.info(`Script initialization...`);
                  
                      await synchronizeShoppingLists('init', false);
                  
                      console.info(`Script initialization completed successfully!`);
                  
                      await checkForResyncRequests();
                  }
                  
                  
                  
                  /*---------- TRIGGER ------------------------------------------------------------------------------------------------------------*/
                  // Alexa
                  on({ id: [].concat([objectID_alexa_shoppingList_folder + '.json']), change: 'ne' }, async (obj) => {
                    let value = obj.state.val;
                    let oldValue = obj.oldState.val;
                  
                    console.debug(`'Alexa' shopping list changed!`);
                  
                    if (initComplete && !syncingInProgress) {
                        await synchronizeShoppingLists('alexa', false);
                        await checkForResyncRequests();
                    } else {
                        resyncRequests.push('alexa');
                    }
                  });
                  
                  // Bring
                  on({ id: [].concat([objectID_bring_shoppingList_sentenceString]), change: 'ne' }, async (obj) => {
                    let value = obj.state.val;
                    let oldValue = obj.oldState.val;
                  
                    console.debug(`'Bring' shopping list changed!`);
                  
                    if (initComplete && !syncingInProgress) {
                        await synchronizeShoppingLists('bring', false);
                        await checkForResyncRequests();
                    } else {
                        resyncRequests.push('bring');
                    }
                  });
                  
                  
                  
                  /*---------- SYNC ---------------------------------------------------------------------------------------------------------------*/
                  async function synchronizeShoppingLists(syncInitiator:string, isResync:boolean) {
                      console.info(`Sync started`);
                      console.debug(`Sync initiator: '${capitalizeFirstLetter(syncInitiator)}'`);
                      console.debug(`Sync is a resync: '${isResync}'`);
                      syncingInProgress = true;
                      
                      var itemsOnAlexaShoppingList = await getItemsOnAlexaShoppingList();
                      var itemsOnBringShoppingList = await getItemsOnBringShoppingList();
                      console.debug(`Items on "Alexa" shopping list (${itemsOnAlexaShoppingList.length}): ${itemsOnAlexaShoppingList.map(item => item.value)}`);
                      console.debug(`Items on "Bring" shopping list (${itemsOnBringShoppingList.length}): ${itemsOnBringShoppingList.map(item => item.value)}`);
                  
                      if (syncInitiator.toLowerCase() === 'init') {
                          // If sync initiator is "init"
                          // create a combined item list and add each item missing on each list to each list.
                  
                          // Create combined shopping list
                          var itemsOnCombinedShoppingList = [];
                          for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnCombinedShoppingList, itemOnAlexaShoppingList)) {
                                  itemsOnCombinedShoppingList.push(itemOnAlexaShoppingList);
                              }
                          }
                          for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnCombinedShoppingList, itemOnBringShoppingList)) {
                                  itemsOnCombinedShoppingList.push(itemOnBringShoppingList);
                              }
                          }
                          //console.debug(`Items on "Combined" shopping list: ${itemsOnCombinedShoppingList.map(item => item.value)}`);
                  
                          // Add each missing item on each list to each list
                          var itemsToAddToAlexaShoppingList = [];
                          var itemsToAddToBringShoppingList = [];
                  
                          for (const itemOnCombinedShoppingList of itemsOnCombinedShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnCombinedShoppingList)) {
                                  itemsToAddToAlexaShoppingList.push(itemOnCombinedShoppingList);
                              }
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnCombinedShoppingList)) {
                                  itemsToAddToBringShoppingList.push(itemOnCombinedShoppingList);
                              }
                          }
                          if (itemsToAddToAlexaShoppingList.length > 0) {
                              console.debug(`Items to add to "Alexa" shopping list (${itemsToAddToAlexaShoppingList.length}): ${itemsToAddToAlexaShoppingList.map(item => item.value)}`);
                          }
                          if (itemsToAddToBringShoppingList.length > 0) {
                              console.debug(`Items to add to "Bring" shopping list (${itemsToAddToBringShoppingList.length}): ${itemsToAddToBringShoppingList.map(item => item.value)}`);
                          }
                  
                          for (const itemToAddToAlexaShoppingList of itemsToAddToAlexaShoppingList) {
                              await AlexaShoppingListItem.addItemToShoppingList(itemToAddToAlexaShoppingList);
                          }
                          for (const itemToAddToBringShoppingList of itemsToAddToBringShoppingList) {
                              await BringShoppingListItem.addItemToShoppingList(itemToAddToBringShoppingList);
                          }
                      } else if (syncInitiator.toLowerCase() === 'alexa') {
                          // If sync initiator is "alexa"
                          // add each item from the alexa shopping list that is missing on the bring shopping list to the bring shopping list.
                          // Then remove each item from the bring shopping list that is not on the alexa shopping list.
                          
                          // Add each item from the alexa shopping list that is missing on the bring shopping list to the bring shopping list.
                          var itemsToAddToBringShoppingList = [];
                  
                          for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnAlexaShoppingList)) {
                                  itemsToAddToBringShoppingList.push(itemOnAlexaShoppingList);
                              }
                          }
                          if (itemsToAddToBringShoppingList.length > 0) {
                              console.debug(`Items to add to "Bring" shopping list (${itemsToAddToBringShoppingList.length}): ${itemsToAddToBringShoppingList.map(item => item.value)}`);
                          }
                  
                          for (const itemToAddToBringShoppingList of itemsToAddToBringShoppingList) {
                              await BringShoppingListItem.addItemToShoppingList(itemToAddToBringShoppingList);
                          }
                  
                  
                          // Get an update of the bring shopping list
                          itemsOnBringShoppingList = await getItemsOnBringShoppingList();
                  
                  
                          // Remove each item from the bring shopping list that is not on the alexa shopping list.
                          var itemsToRemoveFromBringShoppingList = [];
                  
                          for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnBringShoppingList)) {
                                  itemsToRemoveFromBringShoppingList.push(itemOnBringShoppingList);
                              }
                          }
                          if (itemsToRemoveFromBringShoppingList.length > 0) {
                              console.debug(`Items to remove from "Bring" shopping list (${itemsToRemoveFromBringShoppingList.length}): ${itemsToRemoveFromBringShoppingList.map(item => item.value)}`);
                          }
                  
                          for (const itemToRemoveFromBringShoppingList of itemsToRemoveFromBringShoppingList) {
                              await BringShoppingListItem.removeItemFromShoppingList(itemToRemoveFromBringShoppingList);
                          }
                      } else if (syncInitiator.toLowerCase() === 'bring') {
                          // If sync initiator is "bring"
                          // add each item from the bring shopping list that is missing on the alexa shopping list to the alexa shopping list.
                          // Then remove each item from the alexa shopping list that is not on the bring shopping list.
                  
                          // Add each item from the bring shopping list that is missing on the alexa shopping list to the alexa shopping list.
                          var itemsToAddToAlexaShoppingList = [];
                  
                          for (const itemOnBringShoppingList of itemsOnBringShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnAlexaShoppingList, itemOnBringShoppingList)) {
                                  itemsToAddToAlexaShoppingList.push(itemOnBringShoppingList);
                              }
                          }
                          if (itemsToAddToAlexaShoppingList.length > 0) {
                              console.debug(`Items to add to "Alexa" shopping list (${itemsToAddToAlexaShoppingList.length}): ${itemsToAddToAlexaShoppingList.map(item => item.value)}`);
                          }
                  
                          for (const itemToAddToAlexaShoppingList of itemsToAddToAlexaShoppingList) {
                              await AlexaShoppingListItem.addItemToShoppingList(itemToAddToAlexaShoppingList);
                          }
                  
                  
                          // Get an update of the alexa shopping list
                          itemsOnAlexaShoppingList = await getItemsOnAlexaShoppingList();
                  
                  
                          // Remove each item from the alexa shopping list that is not on the bring shopping list.
                          var itemsToRemoveFromAlexaShoppingList = [];
                  
                          for (const itemOnAlexaShoppingList of itemsOnAlexaShoppingList) {
                              if (!await ShoppingListUtils.checkIfShoppingListArrayContainsShoppingListItem(itemsOnBringShoppingList, itemOnAlexaShoppingList)) {
                                  itemsToRemoveFromAlexaShoppingList.push(itemOnAlexaShoppingList);
                              }
                          }
                          if (itemsToRemoveFromAlexaShoppingList.length > 0) {
                              console.debug(`Items to remove from "Alexa" shopping list (${itemsToRemoveFromAlexaShoppingList.length}): ${itemsToRemoveFromAlexaShoppingList.map(item => item.value)}`);
                          }
                  
                          for (const itemToRemoveFromAlexaShoppingList of itemsToRemoveFromAlexaShoppingList) {
                              await AlexaShoppingListItem.removeItemFromShoppingList(itemToRemoveFromAlexaShoppingList);
                          }
                      }
                  
                      console.info(`Sync completed!`);
                      syncingInProgress = false;
                  }
                  
                  
                  
                  async function checkForResyncRequests() {
                      if (resyncRequests.length > 0) {
                          // Get the first resync request.
                          var firstResyncRequest = resyncRequests[0];
                  
                          // Remove the first resync request from the array.
                          resyncRequests.shift();
                  
                          // Remove all values from the array that match the firstResyncRequest value
                          resyncRequests = resyncRequests.filter(request => request !== firstResyncRequest);
                  
                          // Perform resync
                          await synchronizeShoppingLists(firstResyncRequest, true);
                      }
                  }
                  
                  
                  
                  /*---------- GET SHOPPING LIST ITEMS --------------------------------------------------------------------------------------------*/
                  // Alexa
                  async function getItemsOnAlexaShoppingList(): Promise <Array<AlexaShoppingListItem>> {
                      var alexaShoppingListItems = [];
                      var completedAlexaShoppingListItemsToRemove = [];
                  
                      var jsonShoppingListString = await getStateAsync(objectID_alexa_shoppingList_folder + '.json');
                      var jsonShoppingList = JSON.parse(jsonShoppingListString.val);
                  
                      jsonShoppingList.forEach((item, index) => {
                          var item_id = item.id;
                          var item_listID = item.listId;
                          var item_customerID = item.customerId;
                          var item_shoppingListItem = item.shoppingListItem;
                          var item_value = item.value;
                          var item_completed = item.completed;
                          var item_version = item.version;
                          var item_createdDateTime = item.createdDateTime;
                          var item_updatedDateTime = item.updatedDateTime;
                          var item_idOfFolderObject = objectID_alexa_shoppingList_folder + '.items.' + item.id;
                          var item_idOfDeleteDatapoint = objectID_alexa_shoppingList_folder + '.items.' + item.id + '.#delete';
                          
                          /*
                          console.debug(`item_id: ${item_id}`);
                          console.debug(`item_listID: ${item_listID}`);
                          console.debug(`item_customerID: ${item_customerID}`);
                          console.debug(`item_shoppingListItem: ${item_shoppingListItem}`);
                          console.debug(`item_value: ${item_value}`);
                          console.debug(`item_completed: ${item_completed}`);
                          console.debug(`item_version: ${item_version}`);
                          console.debug(`item_createdDateTime: ${item_createdDateTime}`);
                          console.debug(`item_updatedDateTime: ${item_updatedDateTime}`);
                          console.debug(`item_idOfFolderObject: ${item_idOfFolderObject}`);
                          console.debug(`item_idOfDeleteDatapoint: ${item_idOfDeleteDatapoint}`);
                          */
                  
                          try {
                              const newAlexaShoppingListItem = new AlexaShoppingListItem(
                                  item_id,
                                  item_listID,
                                  item_customerID,
                                  item_shoppingListItem,
                                  item_value,
                                  item_completed,
                                  item_version,
                                  item_createdDateTime,
                                  item_updatedDateTime,
                                  item_idOfFolderObject,
                                  item_idOfDeleteDatapoint);
                                  
                                  if (!newAlexaShoppingListItem.completed) {
                                      alexaShoppingListItems.push(newAlexaShoppingListItem);
                                  } else {
                                      completedAlexaShoppingListItemsToRemove.push(newAlexaShoppingListItem);
                                  }
                              } catch (error) {
                                  console.error(`Error while creating Alexa Shopping-List Item Object! -  Original Error: ${error.message}`);
                              }
                      });
                  
                      if (completedAlexaShoppingListItemsToRemove.length > 0) {
                          for (const completedAlexaShoppingListItemToRemove of completedAlexaShoppingListItemsToRemove) {
                              await AlexaShoppingListItem.removeItemFromShoppingList(completedAlexaShoppingListItemToRemove);
                          }
                      }
                  
                      // Sort the array of alexa shopping list items (case insensitive sorting)
                      alexaShoppingListItems.sort((a, b) => a.value.toLowerCase().localeCompare(b.value.toLowerCase()));
                  
                      return alexaShoppingListItems;
                  }
                  
                  // Bring
                  async function getItemsOnBringShoppingList(): Promise <Array<BringShoppingListItem>> {
                      var bringShoppingListItems = [];
                  
                      try {
                          var humanReadableShoppingListObject = await getStateAsync(objectID_bring_shoppingList_sentenceString);
                          var humanReadableShoppingList = humanReadableShoppingListObject.val;
                          if (humanReadableShoppingList !== null && humanReadableShoppingList !== '' && humanReadableShoppingList.length > 0) {
                              humanReadableShoppingList = replaceAllOccurrencesOfASubstringWithinAString(humanReadableShoppingList, ' und ', ', ');
                              humanReadableShoppingList = replaceAllOccurrencesOfASubstringWithinAString(humanReadableShoppingList, ', ', ';');
                              
                              const bringShoppingListItemStrings = splitStringIntoArray(humanReadableShoppingList, ';');
                              
                              for (const bringShoppingListItemString of bringShoppingListItemStrings) {
                                  try {
                                      const newBringShoppingListItem = new BringShoppingListItem(bringShoppingListItemString);
                                      bringShoppingListItems.push(newBringShoppingListItem);
                                  } catch (error) {
                                      console.error(`Error while creating Alexa Shopping-List Item Object! -  Original Error: ${error.message}`);
                                      continue;
                                  }
                              }
                          }
                      } catch (error) {
                          console.error(`Error while getting Bring Shopping-List Items! - Original Error: ${error.message}`);
                      }
                  
                      // Sort the array of alexa shopping list items (case insensitive sorting)
                      bringShoppingListItems.sort((a, b) => a.value.toLowerCase().localeCompare(b.value.toLowerCase()));
                  
                      return bringShoppingListItems;
                  }
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  +                                                                     CLASSES                                                                              +
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  class AlexaShoppingListItem {
                      public id: string;
                      public listID: string;
                      public customerID: string;
                      public shoppingListItem: boolean;
                      public value: string;
                      public completed: boolean;
                      public version: number;
                      public createdDateTime: number;
                      public updatedDateTime: number;
                      public idOfFolderObject: string;
                      public idOfDeleteDatapoint: string;
                      
                      constructor(
                          id:string,
                          listID:string,
                          customerID:string,
                          shoppingListItem:boolean,
                          value:string,
                          completed:boolean,
                          version:number,
                          createdDateTime:number,
                          updatedDateTime:number,
                          idOfFolderObject:string,
                          idOfDeleteDatapoint:string) {
                              this.id = id;
                              this.listID = listID;
                              this.customerID = customerID;
                              this.shoppingListItem = shoppingListItem;
                              this.value = value;
                              this.completed = completed;
                              this.version = version;
                              this.createdDateTime = createdDateTime;
                              this.updatedDateTime = updatedDateTime;
                              this.idOfFolderObject = idOfFolderObject;
                              this.idOfDeleteDatapoint = idOfDeleteDatapoint;
                      }
                      
                      /********************
                       * Adds an item to the Alexa shopping list.
                       * 
                       * @param item - The item to save to the Alexa shopping list. Must be either an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.
                       * @return Promise<boolean> - True if the function completed running its code.
                       ********************/
                      static async addItemToShoppingList(item:AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                          // Parameter validation
                          if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                              throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'!");
                          }
                  
                          await setStateAsync(objectID_alexa_shoppingList_addItem, capitalizeFirstLetter(item.value), false);
                          return true;
                      }
                  
                      /********************
                       * Removes an item from the Alexa shopping list.
                       * 
                       * @param item - The item to remove from the Alexa shopping list. Must be an instance of 'AlexaShoppingListItem'.
                       * @return Promise<boolean> - True if the function completed running its code.
                       ********************/
                       static async removeItemFromShoppingList(item:AlexaShoppingListItem): Promise <boolean> {
                           // Parameter validation
                          if (!(item instanceof AlexaShoppingListItem)) {
                              throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem'!");
                          }
                  
                          await setStateAsync(item.idOfDeleteDatapoint, true, false);
                          return true;
                       }
                  }
                  
                  
                  
                  class BringShoppingListItem {
                      public value: string;
                      
                      constructor(value:string) {
                          this.value = value;
                      }
                  
                      /********************
                       * Adds an item to the Bring shopping list.
                       * 
                       * @param item - The item to save to the Bring shopping list. Must be either an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.
                       * @return Promise<boolean> - True if the function completed running its code.
                       ********************/
                      static async addItemToShoppingList(item:AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                          // Parameter validation
                          if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                              throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'!");
                          }
                  
                          await setStateAsync(objectID_bring_shoppingList_addItem, capitalizeFirstLetter(item.value), false);
                          return true;
                      }
                  
                      /********************
                       * Removes an item from the Bring shopping list.
                       * 
                       * @param item - The item to remove from the Bring shopping list. Must be an instance of 'BringShoppingListItem'.
                       * @return Promise<boolean> - True if the function completed running its code.
                       ********************/
                       static async removeItemFromShoppingList(item:BringShoppingListItem): Promise <boolean> {
                           // Parameter validation
                          if (!(item instanceof BringShoppingListItem)) {
                              throw new Error("Invalid parameter: Parameter 'item' must be an instance of 'BringShoppingListItem'!");
                          }
                  
                          await setStateAsync(objectID_bring_shoppingList_removeItem, item.value, false);
                          return true;
                       }
                  }
                  
                  
                  
                  class ShoppingListUtils {
                      /********************
                       * Checks if a given shopping list array contains a specific shopping list item.
                       * Herefore it compares all items in the given shopping list array with the given shopping list item
                       * (either an 'AlexaShoppingListItem' or a 'BringShoppingListItem')
                       * in a case-insensitive way.
                       * 
                       * @param shoppingListArray - Array of AlexaShoppingListItem or BringShoppingListItem objects to check within.
                       * @param shoppingListItem - The shopping list item to find in the array.
                       * @returns Promise<boolean> - True if the item is found, otherwise false.
                       ********************/
                      static async checkIfShoppingListArrayContainsShoppingListItem(shoppingListArray: Array<AlexaShoppingListItem | BringShoppingListItem>, shoppingListItem: AlexaShoppingListItem | BringShoppingListItem): Promise <boolean> {
                          // Parameter validation
                          if (!Array.isArray(shoppingListArray)) {
                              throw new Error("Invalid parameter: 'shoppingListArray' must be an array.");
                          }
                          if (!(shoppingListItem instanceof AlexaShoppingListItem || shoppingListItem instanceof BringShoppingListItem)) {
                              throw new Error("Invalid parameter: 'shoppingListItem' must be an instance of 'AlexaShoppingListItem' or 'BringShoppingListItem'.");
                          }
                  
                          for (const item of shoppingListArray) {
                              if (!(item instanceof AlexaShoppingListItem || item instanceof BringShoppingListItem)) {
                                  throw new Error("Invalid parameter: All elements in 'shoppingListArray' must be instances of 'AlexaShoppingListItem' or 'BringShoppingListItem'.");
                              }
                          }
                          
                          // Normalize the value of the shopping list item to lower case for case-insensitive comparison
                          const itemValueToCheck = shoppingListItem.value.toLowerCase();
                  
                          // Check if any item in the array matches the shopping list item value
                          for (const item of shoppingListArray) {
                              if (item.value.toLowerCase() === itemValueToCheck) {
                                  return true;
                              }
                          }
                  
                          return false;
                      }
                  }
                  /*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++
                  *++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++*++++++++++++++++++++++++++++++++++++++++++++++++++++*/
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  /*---------- HELPER FUNCTIONS ---------------------------------------------------------------------------------------------------*/
                  function capitalizeFirstLetter(input: string): string {
                      if (input.length === 0) {
                          return input; // Return the empty string if input is empty
                      }
                      return input.charAt(0).toUpperCase() + input.slice(1);
                  }
                  
                  function replaceAllOccurrencesOfASubstringWithinAString(originalString: string, searchValue: string, replaceValue: string): string {
                      const regex = new RegExp(searchValue, 'g');
                      return originalString.replace(regex, replaceValue);
                  }
                  
                  function splitStringIntoArray(input: string, delimiter: string): string[] {
                      return input.split(delimiter);
                  }
                  
                  M Offline
                  M Offline
                  MartyBr
                  schrieb am zuletzt editiert von
                  #173

                  @elron
                  Viele Dank. Ich habe es importiert und die Datenpunkte angepasst. Test erfolgt morgen.

                  Gruß
                  Martin


                  Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                  Raspeberry mit USB Leseköpfen für Smartmeter
                  Homematic und Homematic IP

                  1 Antwort Letzte Antwort
                  0
                  • mcBirneM Offline
                    mcBirneM Offline
                    mcBirne
                    schrieb am zuletzt editiert von mcBirne
                    #174

                    Ich habe die beiden Datenpunkte angepasst. Leider erhalte ich folgende Fehlermeldung:

                    javascript.0	16:24:56.439	error	
                    compile failed at: script.js.Alexas.Bring_Synchronisieren2:36
                    javascript.0	16:24:56.439	error	
                    export default this;
                    javascript.0	16:24:56.439	error	
                    ^^^^^^
                    javascript.0	16:24:56.439	error	
                    SyntaxError: Unexpected token 'export'
                    javascript.0	16:24:56.439	error	
                        at new Script (node:vm:117:7)
                    javascript.0	16:24:56.439	error	
                        at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:2174:25)
                    javascript.0	16:24:56.439	error	
                        at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:2472:44)
                    javascript.0	16:24:56.439	error	
                        at processTicksAndRejections (node:internal/process/task_queues:105:5)
                    javascript.0	16:24:56.439	error	
                        at JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:659:25)
                    

                    Hat das Problem noch jemand? Oder weiß jemand, was ich machen kann?

                    grrfieldG 1 Antwort Letzte Antwort
                    0
                    • mcBirneM mcBirne

                      Ich habe die beiden Datenpunkte angepasst. Leider erhalte ich folgende Fehlermeldung:

                      javascript.0	16:24:56.439	error	
                      compile failed at: script.js.Alexas.Bring_Synchronisieren2:36
                      javascript.0	16:24:56.439	error	
                      export default this;
                      javascript.0	16:24:56.439	error	
                      ^^^^^^
                      javascript.0	16:24:56.439	error	
                      SyntaxError: Unexpected token 'export'
                      javascript.0	16:24:56.439	error	
                          at new Script (node:vm:117:7)
                      javascript.0	16:24:56.439	error	
                          at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:2174:25)
                      javascript.0	16:24:56.439	error	
                          at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:2472:44)
                      javascript.0	16:24:56.439	error	
                          at processTicksAndRejections (node:internal/process/task_queues:105:5)
                      javascript.0	16:24:56.439	error	
                          at JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/src/main.ts:659:25)
                      

                      Hat das Problem noch jemand? Oder weiß jemand, was ich machen kann?

                      grrfieldG Offline
                      grrfieldG Offline
                      grrfield
                      schrieb am zuletzt editiert von
                      #175

                      @mcBirne Es ist zwar schon einige Zeit her, aber hast Du das Skript als TypeScript eingefügt? Die Fehlermeldungen sehen nach JavaScript aus.

                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      913

                      Online

                      32.6k

                      Benutzer

                      82.0k

                      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