Navigation

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

    NEWS

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    • Profile
    • Following 0
    • Followers 1
    • Topics 0
    • Posts 8
    • Best 3
    • Groups 1

    icastillo15

    @icastillo15

    Starter

    10
    Reputation
    11
    Profile views
    8
    Posts
    1
    Followers
    0
    Following
    Joined Last Online

    icastillo15 Follow
    Starter

    Best posts made by icastillo15

    • RE: Alexa Shopping List mit Bring synchronisieren

      Hallo zusammen,

      ich habe mein Script nochmal aktualisiert. Es werden in Alexa nun automatisch alle Duplikate sofort wieder gelöscht. Außerdem wird nun erzwungen, dass Artikel mit einem Großbuchstaben beginnen.

      Viel Spaß damit und gerne wieder testen 🙂

      Kleiner Nachtrag: wenn ich über Alexa Dinge hinzufüge und dann in Bring als erledigt markiere, dann werden diese bei mir in Alexa nicht mehr gelöscht. Das muss ich mir nochmal ansehen - könnte an den Zeitstempeln liegen.

      Nachtrag 2: ging doch - mein Adapter war nur offline 😎

      const bringBaseId = 'bring.0.0f0c420c-3298-4911-91f5-7ed0fbbfd36e';
      const alexa2BaseId = 'alexa2.0.Lists.SHOPPING_LIST';
      
      const bringListId = bringBaseId + '.content';
      const bringListCompletedId = bringBaseId + '.recentContent';
      const bringAddToList = bringBaseId + '.saveItem';
      const bringCompleteItem = bringBaseId + '.moveToRecentContent';
      const alexaAddToList = alexa2BaseId + '.#New';
      const alexaListId = alexa2BaseId + '.json';
      
      //switch off to silence:
      const printDebug = true;
      
      function debug(msg) {
          if (printDebug) {
              log(msg)
          }
      }
      
      const TodoItemStatus = {
          NeedsAction: 'needs_action',
          Completed: 'completed',
      };
      
      /**
       * @typedef bringItem
       * @type {object}
       * @property {string} specification
       * @property {string} name
       * @property {string} status
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * @typedef alexaItem
       * @type {object}
       * @property {string} value
       * @property {string} id
       * @property {boolean} completed
       * @property {number} updatedDateTime
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * Compare alexaItem complete and bringItem status -> returns true if same status.
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @returns {boolean} true if same status.
      */
      function compareCompleted(alexaItem, bringItem) {
          if (alexaItem.completed && bringItem.status !== TodoItemStatus.Completed) {
              return false;
          }
          if (!alexaItem.completed && bringItem.status !== TodoItemStatus.NeedsAction) {
              return false;
          }
          return true;
      }
      
      function ListCleaner(Eintrag='') {
          const arr = Eintrag.split(' ');
          for (let i = 0; i < arr.length; i++) {
              arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
          }
          return arr.join(' ');
      }
      
      /**
       * sync lists
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @param {number} timestampBring
       * @param {string} msource
       * @param {Array<bringItem>} recentList
       * @returns {Array<bringItem>} new bring List
       */
      function syncLists(alexaList, list, timestampBring, msource, recentList) {
          const newBringList = [];
          var empty = true;
          for (const alexaItem of alexaList) {
      
              for (const bringItem of list) {
                  empty = false;
      
                  if (bringItem.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItem.found = true;
      
      
                      //found item. Update completed state from 'newer' list: 
                      bringItem.status = TodoItemStatus.NeedsAction;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItem.name || !compareCompleted(alexaItem, bringItem)) {
      
                              if (msource === 'Alexa') {
                                 debug('Updating Bring item: ' + bringItem.name + ' from Alexa');
                                 setState(bringCompleteItem, ListCleaner(bringItem.name));
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItem)) {
                              if (msource === 'Bring') {
                                  bringItem.status = TodoItemStatus.Completed;
                                  debug('Update  Alexa item: ' + alexaItem.value + ' to ' + (bringItem.status === TodoItemStatus.Completed ? 'done' : 'undone') + ' from Bring.');
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItem.status === TodoItemStatus.Completed);
                              } 
                          }
                      }
                  }
              }
      
              for (const bringItemCompleted of recentList) {
                  if (bringItemCompleted.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItemCompleted.found = true;
      
                      //found item. Update completed state from 'newer' list: 
                      bringItemCompleted.status = TodoItemStatus.Completed;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItemCompleted.name || !compareCompleted(alexaItem, bringItemCompleted)) {
      
                              if (msource === 'Alexa') {
                                 debug('Adding Bring item: ' + bringItemCompleted.name + ' from Alexa');
                                 setState(bringAddToList, ListCleaner(bringItemCompleted.name));
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItemCompleted)) {
                              bringItemCompleted.status = TodoItemStatus.Completed;
                              if (msource === 'Bring') {
                                  debug('Delete  Alexa item: ' + alexaItem.value + ' from Bring.');
                                  //setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItemCompleted.status === TodoItemStatus.Completed);
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                              } 
                          }
                      }
                  }
              }
      
      
              if (!alexaItem.found) {
                  //alexa item not found:
                  if (alexaItem.completed) {
                      debug('Delete ' + alexaItem.value + ' because done and not in Bring list.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  } else {
                      if (msource === 'Alexa') {
                          debug('Adding ' + alexaItem.value + ' to Bring list');
                          setState(bringAddToList, ListCleaner(alexaItem.value));
                      }
                  }
              }
      
              if (empty === true) {
                  if (alexaItem.updatedDateTime < timestampBring) {
                      debug('Delete ' + alexaItem.value + ' from Alexa list because Bring list is all done.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  }
              }
          
          }
      
          for (const bringItem of list) {
              if (!bringItem.found) {
                  if (bringItem.status === TodoItemStatus.Completed) {
                      //debug('Remove from bring item:  ' + bringItem.name + ' because done and not on alexa list');
                      //Not executed since I want to keep the recent items inside bring app
                  } else {
                      if (msource === 'Bring') {
                          debug('Adding ' + bringItem.name + ' to Alexa list.');
                          setState(alexaAddToList, ListCleaner(bringItem.name));
                      }
                  }
              }
          }
      
          return newBringList;
      }
      
      
      function doSync(source) {
          eliminateDuplicated();
          const alexaList = JSON.parse(getState(alexaListId).val);
          const state = getState(bringListId);
          const bringList = JSON.parse(state.val);
          const state2 = getState(bringListCompletedId);
          const bringListCompleted = JSON.parse(state2.val);
      
          syncLists(alexaList, bringList, state.ts, source, bringListCompleted);
      }
      
      function eliminateDuplicated() {
          var myAlexaList = JSON.parse(getState(alexaListId).val);
          var arrayWithDuplicates = [];
      
          for(var alexaItem of myAlexaList) {
              var obj = {};
              obj["value"] = ListCleaner(alexaItem.value);
              obj["id"] = alexaItem.id;
              arrayWithDuplicates.push(obj);       
          }
      
          const lookup = arrayWithDuplicates.reduce((a, e) => {
          a[e.value] = ++a[e.value] || 0;
          return a;
          }, {});
      
          const
              getKey = o => keys.map(k => o[k]).join('|'),
              keys = ['value'],
              myarray = arrayWithDuplicates.filter(e => lookup[e.value]),
              hash = Object.create(null),
              duplicates = myarray.filter(o =>
                  (k => (hash[k] = (hash[k] || 0) + 1) > 1)
                  (getKey(o))
              );
      
          for(var item of duplicates) {
              debug('Delete  Alexa item: ' + item.value + ' because duplicated.');
              setState(`${alexa2BaseId}.items.${item.id}.#delete`, true);
          }
      }
      
      on({id: bringListId, change: 'any'}, e => {
          debug('Update triggered from Bring');
          doSync('Bring');
      });
      
      on({id: alexaListId, change: 'any'}, e => {
          debug('Update triggered from Alexa');
          doSync('Alexa');
      });
      
      doSync();
      
      
      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Alexa Shopping List mit Bring synchronisieren

      @iomax @mcBirne

      Hallo zusammen,

      da mich das gleiche Problem betrifft, habe ich mich mal an einem Skript dafür versucht.
      Über den Alexa und Bring Adapter werden jeweils die Listen abgeglichen in beide Richtungen.
      Alles was jeweils in der anderen Liste hinzugefügt wird, wird gesynct. Wenn in der Bring App Dinge als erledigt markiert werden, dann lösche ich diese aus der Alexa Liste komplett raus. Wenn in Alexa Dinge als markiert gesetzt werden, dann wandern die Items in der Bring app unter "zuletetzt verwendet".

      Am wichtigsten war mir aber, dass ich wieder "Alexa füge Birnen auf die Einkaufsliste" sagen kann und die Sachen wieder bei Bring habe 😄

      Im ersten Test lief das Skript bei mir ganz gut - gerne mal selbst testen.

      Einfach in Zeile 1 auf die passende bring Liste bei euch anpassen der rest kann so bleiben

      const bringBaseId = 'bring.0.0f0c420c-3298-4911-91f5-7ed0fbbfd36e';
      const alexa2BaseId = 'alexa2.0.Lists.SHOPPING_LIST';
      
      const bringListId = bringBaseId + '.content';
      const bringListCompletedId = bringBaseId + '.recentContent';
      const bringAddToList = bringBaseId + '.saveItem';
      const bringCompleteItem = bringBaseId + '.moveToRecentContent';
      const alexaAddToList = alexa2BaseId + '.#New';
      const alexaListId = alexa2BaseId + '.json';
      
      //switch off to silence:
      const printDebug = true;
      
      function debug(msg) {
          if (printDebug) {
              log(msg)
          }
      }
      
      const TodoItemStatus = {
          NeedsAction: 'needs_action',
          Completed: 'completed',
      };
      
      /**
       * @typedef bringItem
       * @type {object}
       * @property {string} specification
       * @property {string} name
       * @property {string} status
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * @typedef alexaItem
       * @type {object}
       * @property {string} value
       * @property {string} id
       * @property {boolean} completed
       * @property {number} updatedDateTime
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * Compare alexaItem complete and bringItem status -> returns true if same status.
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @returns {boolean} true if same status.
      */
      function compareCompleted(alexaItem, bringItem) {
          if (alexaItem.completed && bringItem.status !== TodoItemStatus.Completed) {
              return false;
          }
          if (!alexaItem.completed && bringItem.status !== TodoItemStatus.NeedsAction) {
              return false;
          }
          return true;
      }
      
      /**
       * sync lists
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @param {number} timestampBring
       * @param {string} msource
       * @param {Array<bringItem>} recentList
       * @returns {Array<bringItem>} new bring List
       */
      function syncLists(alexaList, list, timestampBring, msource, recentList) {
          const newBringList = [];
          var empty = true;
          for (const alexaItem of alexaList) {
      
              for (const bringItem of list) {
                  empty = false;
      
                  if (bringItem.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItem.found = true;
      
      
                      //found item. Update completed state from 'newer' list: 
                      bringItem.status = TodoItemStatus.NeedsAction;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItem.name || !compareCompleted(alexaItem, bringItem)) {
      
                              if (msource === 'Alexa') {
                                 debug('Updating Bring item: ' + bringItem.name + ' from Alexa');
                                 setState(bringCompleteItem, bringItem.name);
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItem)) {
                              if (msource === 'Bring') {
                                  bringItem.status = TodoItemStatus.Completed;
                                  debug('Update  Alexa item: ' + alexaItem.value + ' to ' + (bringItem.status === TodoItemStatus.Completed ? 'done' : 'undone') + ' from Bring.');
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItem.status === TodoItemStatus.Completed);
                              } 
                          }
                      }
                  }
              }
      
              for (const bringItemCompleted of recentList) {
                  if (bringItemCompleted.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItemCompleted.found = true;
      
                      //found item. Update completed state from 'newer' list: 
                      bringItemCompleted.status = TodoItemStatus.Completed;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItemCompleted.name || !compareCompleted(alexaItem, bringItemCompleted)) {
      
                              if (msource === 'Alexa') {
                                 debug('Adding Bring item: ' + bringItemCompleted.name + ' from Alexa');
                                 setState(bringAddToList, bringItemCompleted.name);
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItemCompleted)) {
                              bringItemCompleted.status = TodoItemStatus.Completed;
                              if (msource === 'Bring') {
                                  debug('Delete  Alexa item: ' + alexaItem.value + ' from Bring.');
                                  //setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItemCompleted.status === TodoItemStatus.Completed);
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                              } 
                          }
                      }
                  }
              }
      
      
              if (!alexaItem.found) {
                  //alexa item not found:
                  if (alexaItem.completed) {
                      debug('Delete ' + alexaItem.value + ' because done and not in Bring list.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  } else {
                      if (msource === 'Alexa') {
                          debug('Adding ' + alexaItem.value + ' to Bring list');
                          setState(bringAddToList, alexaItem.value);
                      }
                  }
              }
      
              if (empty === true) {
                  if (alexaItem.updatedDateTime < timestampBring) {
                      debug('Delete ' + alexaItem.value + ' from Alexa list because Bring list is all done.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  }
              }
          
          }
      
          for (const bringItem of list) {
              if (!bringItem.found) {
                  if (bringItem.status === TodoItemStatus.Completed) {
                      //debug('Remove from bring item:  ' + bringItem.name + ' because done and not on alexa list');
                      //Not executed since I want to keep the recent items inside bring app
                  } else {
                      if (msource === 'Bring') {
                          debug('Adding ' + bringItem.name + ' to Alexa list.');
                          setState(alexaAddToList, bringItem.name);
                      }
                  }
              }
          }
      
          return newBringList;
      }
      
      
      function doSync(source) {
          const alexaList = JSON.parse(getState(alexaListId).val);
          const state = getState(bringListId);
          const bringList = JSON.parse(state.val);
          const state2 = getState(bringListCompletedId);
          const bringListCompleted = JSON.parse(state2.val);
      
          syncLists(alexaList, bringList, state.ts, source, bringListCompleted);
      }
      
      
      on({id: bringListId, change: 'any'}, e => {
          debug('Update triggered from Bring');
          doSync('Bring');
      });
      
      on({id: alexaListId, change: 'any'}, e => {
          debug('Update triggered from Alexa');
          doSync('Alexa');
      });
      
      doSync();
      
      
      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Alexa Shopping List mit Bring synchronisieren

      @fuchsbau

      Danke für die Rückmeldung und das Testen. Mir war das bisher egal, ob Artikel groß oder kleingeschrieben sind aber du hast natürlich Recht. Es schränkt leider etwas Funktionalität ein. Grundsätzlich brauch ich den Sync aber in beide Richtungen, da ich oder meine Freundin gerne auch mal von unterwegs direkt in Bring Sachen hinzufügen und nicht über Alexa. Das sollte dann synchronisiert bleiben.

      Also du nutzt sowohl Alexa Spracheingabe als auch über die Bring App direkt eine Spracheingabe oder meinst du das über den Alexa Bring Skill? Andernfalls wusste ich noch nicht, dass man auch direkt in Bring eine Spracheingabe hat 😀

      Als Erweiterung vom Script könnte ich mir vorstellen, dass ich vorher noch vor jedem Sync ein Cleanup einbaue. Der würde dann über alle Alexa Items rübergehen und die Groß-Kleinschreibung erzwingen. Dabei könnte man auch gleich dupletten entfernen. Dann sollte im anschließenden Sync alles reibungslos klappen.

      Ich schau mir das heute nochmal an wenn ich Zeit finde 🙂 Ansonsten klasse, dass es bei den anderen soweit für ihre Zwecke funktioniert 👍🏻

      posted in Skripten / Logik
      icastillo15
      icastillo15

    Latest posts made by icastillo15

    • RE: Alexa Shopping List mit Bring synchronisieren

      @dicken

      Genau - nach meinem Stand kannst du nur die Kategorien tauschen. Mir reicht das mit der Kachelansicht dann aber völlig als Übersicht. Aber meistens habe ich auch nur kleinere Listen und keine Rieseneinkäufe - wenn nicht gerade Weihnachten ist. Das ist dann wohl sehr individuell 😀

      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Alexa Shopping List mit Bring synchronisieren

      Hallo zusammen,

      ich habe mein Script nochmal aktualisiert. Es werden in Alexa nun automatisch alle Duplikate sofort wieder gelöscht. Außerdem wird nun erzwungen, dass Artikel mit einem Großbuchstaben beginnen.

      Viel Spaß damit und gerne wieder testen 🙂

      Kleiner Nachtrag: wenn ich über Alexa Dinge hinzufüge und dann in Bring als erledigt markiere, dann werden diese bei mir in Alexa nicht mehr gelöscht. Das muss ich mir nochmal ansehen - könnte an den Zeitstempeln liegen.

      Nachtrag 2: ging doch - mein Adapter war nur offline 😎

      const bringBaseId = 'bring.0.0f0c420c-3298-4911-91f5-7ed0fbbfd36e';
      const alexa2BaseId = 'alexa2.0.Lists.SHOPPING_LIST';
      
      const bringListId = bringBaseId + '.content';
      const bringListCompletedId = bringBaseId + '.recentContent';
      const bringAddToList = bringBaseId + '.saveItem';
      const bringCompleteItem = bringBaseId + '.moveToRecentContent';
      const alexaAddToList = alexa2BaseId + '.#New';
      const alexaListId = alexa2BaseId + '.json';
      
      //switch off to silence:
      const printDebug = true;
      
      function debug(msg) {
          if (printDebug) {
              log(msg)
          }
      }
      
      const TodoItemStatus = {
          NeedsAction: 'needs_action',
          Completed: 'completed',
      };
      
      /**
       * @typedef bringItem
       * @type {object}
       * @property {string} specification
       * @property {string} name
       * @property {string} status
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * @typedef alexaItem
       * @type {object}
       * @property {string} value
       * @property {string} id
       * @property {boolean} completed
       * @property {number} updatedDateTime
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * Compare alexaItem complete and bringItem status -> returns true if same status.
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @returns {boolean} true if same status.
      */
      function compareCompleted(alexaItem, bringItem) {
          if (alexaItem.completed && bringItem.status !== TodoItemStatus.Completed) {
              return false;
          }
          if (!alexaItem.completed && bringItem.status !== TodoItemStatus.NeedsAction) {
              return false;
          }
          return true;
      }
      
      function ListCleaner(Eintrag='') {
          const arr = Eintrag.split(' ');
          for (let i = 0; i < arr.length; i++) {
              arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
          }
          return arr.join(' ');
      }
      
      /**
       * sync lists
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @param {number} timestampBring
       * @param {string} msource
       * @param {Array<bringItem>} recentList
       * @returns {Array<bringItem>} new bring List
       */
      function syncLists(alexaList, list, timestampBring, msource, recentList) {
          const newBringList = [];
          var empty = true;
          for (const alexaItem of alexaList) {
      
              for (const bringItem of list) {
                  empty = false;
      
                  if (bringItem.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItem.found = true;
      
      
                      //found item. Update completed state from 'newer' list: 
                      bringItem.status = TodoItemStatus.NeedsAction;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItem.name || !compareCompleted(alexaItem, bringItem)) {
      
                              if (msource === 'Alexa') {
                                 debug('Updating Bring item: ' + bringItem.name + ' from Alexa');
                                 setState(bringCompleteItem, ListCleaner(bringItem.name));
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItem)) {
                              if (msource === 'Bring') {
                                  bringItem.status = TodoItemStatus.Completed;
                                  debug('Update  Alexa item: ' + alexaItem.value + ' to ' + (bringItem.status === TodoItemStatus.Completed ? 'done' : 'undone') + ' from Bring.');
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItem.status === TodoItemStatus.Completed);
                              } 
                          }
                      }
                  }
              }
      
              for (const bringItemCompleted of recentList) {
                  if (bringItemCompleted.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItemCompleted.found = true;
      
                      //found item. Update completed state from 'newer' list: 
                      bringItemCompleted.status = TodoItemStatus.Completed;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItemCompleted.name || !compareCompleted(alexaItem, bringItemCompleted)) {
      
                              if (msource === 'Alexa') {
                                 debug('Adding Bring item: ' + bringItemCompleted.name + ' from Alexa');
                                 setState(bringAddToList, ListCleaner(bringItemCompleted.name));
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItemCompleted)) {
                              bringItemCompleted.status = TodoItemStatus.Completed;
                              if (msource === 'Bring') {
                                  debug('Delete  Alexa item: ' + alexaItem.value + ' from Bring.');
                                  //setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItemCompleted.status === TodoItemStatus.Completed);
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                              } 
                          }
                      }
                  }
              }
      
      
              if (!alexaItem.found) {
                  //alexa item not found:
                  if (alexaItem.completed) {
                      debug('Delete ' + alexaItem.value + ' because done and not in Bring list.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  } else {
                      if (msource === 'Alexa') {
                          debug('Adding ' + alexaItem.value + ' to Bring list');
                          setState(bringAddToList, ListCleaner(alexaItem.value));
                      }
                  }
              }
      
              if (empty === true) {
                  if (alexaItem.updatedDateTime < timestampBring) {
                      debug('Delete ' + alexaItem.value + ' from Alexa list because Bring list is all done.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  }
              }
          
          }
      
          for (const bringItem of list) {
              if (!bringItem.found) {
                  if (bringItem.status === TodoItemStatus.Completed) {
                      //debug('Remove from bring item:  ' + bringItem.name + ' because done and not on alexa list');
                      //Not executed since I want to keep the recent items inside bring app
                  } else {
                      if (msource === 'Bring') {
                          debug('Adding ' + bringItem.name + ' to Alexa list.');
                          setState(alexaAddToList, ListCleaner(bringItem.name));
                      }
                  }
              }
          }
      
          return newBringList;
      }
      
      
      function doSync(source) {
          eliminateDuplicated();
          const alexaList = JSON.parse(getState(alexaListId).val);
          const state = getState(bringListId);
          const bringList = JSON.parse(state.val);
          const state2 = getState(bringListCompletedId);
          const bringListCompleted = JSON.parse(state2.val);
      
          syncLists(alexaList, bringList, state.ts, source, bringListCompleted);
      }
      
      function eliminateDuplicated() {
          var myAlexaList = JSON.parse(getState(alexaListId).val);
          var arrayWithDuplicates = [];
      
          for(var alexaItem of myAlexaList) {
              var obj = {};
              obj["value"] = ListCleaner(alexaItem.value);
              obj["id"] = alexaItem.id;
              arrayWithDuplicates.push(obj);       
          }
      
          const lookup = arrayWithDuplicates.reduce((a, e) => {
          a[e.value] = ++a[e.value] || 0;
          return a;
          }, {});
      
          const
              getKey = o => keys.map(k => o[k]).join('|'),
              keys = ['value'],
              myarray = arrayWithDuplicates.filter(e => lookup[e.value]),
              hash = Object.create(null),
              duplicates = myarray.filter(o =>
                  (k => (hash[k] = (hash[k] || 0) + 1) > 1)
                  (getKey(o))
              );
      
          for(var item of duplicates) {
              debug('Delete  Alexa item: ' + item.value + ' because duplicated.');
              setState(`${alexa2BaseId}.items.${item.id}.#delete`, true);
          }
      }
      
      on({id: bringListId, change: 'any'}, e => {
          debug('Update triggered from Bring');
          doSync('Bring');
      });
      
      on({id: alexaListId, change: 'any'}, e => {
          debug('Update triggered from Alexa');
          doSync('Alexa');
      });
      
      doSync();
      
      
      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Alexa Shopping List mit Bring synchronisieren

      @fuchsbau

      Danke für die Rückmeldung und das Testen. Mir war das bisher egal, ob Artikel groß oder kleingeschrieben sind aber du hast natürlich Recht. Es schränkt leider etwas Funktionalität ein. Grundsätzlich brauch ich den Sync aber in beide Richtungen, da ich oder meine Freundin gerne auch mal von unterwegs direkt in Bring Sachen hinzufügen und nicht über Alexa. Das sollte dann synchronisiert bleiben.

      Also du nutzt sowohl Alexa Spracheingabe als auch über die Bring App direkt eine Spracheingabe oder meinst du das über den Alexa Bring Skill? Andernfalls wusste ich noch nicht, dass man auch direkt in Bring eine Spracheingabe hat 😀

      Als Erweiterung vom Script könnte ich mir vorstellen, dass ich vorher noch vor jedem Sync ein Cleanup einbaue. Der würde dann über alle Alexa Items rübergehen und die Groß-Kleinschreibung erzwingen. Dabei könnte man auch gleich dupletten entfernen. Dann sollte im anschließenden Sync alles reibungslos klappen.

      Ich schau mir das heute nochmal an wenn ich Zeit finde 🙂 Ansonsten klasse, dass es bei den anderen soweit für ihre Zwecke funktioniert 👍🏻

      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Alexa Shopping List mit Bring synchronisieren

      @iomax @mcBirne

      Hallo zusammen,

      da mich das gleiche Problem betrifft, habe ich mich mal an einem Skript dafür versucht.
      Über den Alexa und Bring Adapter werden jeweils die Listen abgeglichen in beide Richtungen.
      Alles was jeweils in der anderen Liste hinzugefügt wird, wird gesynct. Wenn in der Bring App Dinge als erledigt markiert werden, dann lösche ich diese aus der Alexa Liste komplett raus. Wenn in Alexa Dinge als markiert gesetzt werden, dann wandern die Items in der Bring app unter "zuletetzt verwendet".

      Am wichtigsten war mir aber, dass ich wieder "Alexa füge Birnen auf die Einkaufsliste" sagen kann und die Sachen wieder bei Bring habe 😄

      Im ersten Test lief das Skript bei mir ganz gut - gerne mal selbst testen.

      Einfach in Zeile 1 auf die passende bring Liste bei euch anpassen der rest kann so bleiben

      const bringBaseId = 'bring.0.0f0c420c-3298-4911-91f5-7ed0fbbfd36e';
      const alexa2BaseId = 'alexa2.0.Lists.SHOPPING_LIST';
      
      const bringListId = bringBaseId + '.content';
      const bringListCompletedId = bringBaseId + '.recentContent';
      const bringAddToList = bringBaseId + '.saveItem';
      const bringCompleteItem = bringBaseId + '.moveToRecentContent';
      const alexaAddToList = alexa2BaseId + '.#New';
      const alexaListId = alexa2BaseId + '.json';
      
      //switch off to silence:
      const printDebug = true;
      
      function debug(msg) {
          if (printDebug) {
              log(msg)
          }
      }
      
      const TodoItemStatus = {
          NeedsAction: 'needs_action',
          Completed: 'completed',
      };
      
      /**
       * @typedef bringItem
       * @type {object}
       * @property {string} specification
       * @property {string} name
       * @property {string} status
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * @typedef alexaItem
       * @type {object}
       * @property {string} value
       * @property {string} id
       * @property {boolean} completed
       * @property {number} updatedDateTime
       * @property {boolean} [found] - keep track if found or not.
       */
      
      /**
       * Compare alexaItem complete and bringItem status -> returns true if same status.
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @returns {boolean} true if same status.
      */
      function compareCompleted(alexaItem, bringItem) {
          if (alexaItem.completed && bringItem.status !== TodoItemStatus.Completed) {
              return false;
          }
          if (!alexaItem.completed && bringItem.status !== TodoItemStatus.NeedsAction) {
              return false;
          }
          return true;
      }
      
      /**
       * sync lists
       * @param {Array<alexaItem>} alexaList
       * @param {Array<bringItem>} list
       * @param {number} timestampBring
       * @param {string} msource
       * @param {Array<bringItem>} recentList
       * @returns {Array<bringItem>} new bring List
       */
      function syncLists(alexaList, list, timestampBring, msource, recentList) {
          const newBringList = [];
          var empty = true;
          for (const alexaItem of alexaList) {
      
              for (const bringItem of list) {
                  empty = false;
      
                  if (bringItem.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItem.found = true;
      
      
                      //found item. Update completed state from 'newer' list: 
                      bringItem.status = TodoItemStatus.NeedsAction;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItem.name || !compareCompleted(alexaItem, bringItem)) {
      
                              if (msource === 'Alexa') {
                                 debug('Updating Bring item: ' + bringItem.name + ' from Alexa');
                                 setState(bringCompleteItem, bringItem.name);
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItem)) {
                              if (msource === 'Bring') {
                                  bringItem.status = TodoItemStatus.Completed;
                                  debug('Update  Alexa item: ' + alexaItem.value + ' to ' + (bringItem.status === TodoItemStatus.Completed ? 'done' : 'undone') + ' from Bring.');
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItem.status === TodoItemStatus.Completed);
                              } 
                          }
                      }
                  }
              }
      
              for (const bringItemCompleted of recentList) {
                  if (bringItemCompleted.name === alexaItem.value) {
                      alexaItem.found = true;
                      bringItemCompleted.found = true;
      
                      //found item. Update completed state from 'newer' list: 
                      bringItemCompleted.status = TodoItemStatus.Completed;
                      if (alexaItem.updatedDateTime > timestampBring) {
                          if (alexaItem.value !== bringItemCompleted.name || !compareCompleted(alexaItem, bringItemCompleted)) {
      
                              if (msource === 'Alexa') {
                                 debug('Adding Bring item: ' + bringItemCompleted.name + ' from Alexa');
                                 setState(bringAddToList, bringItemCompleted.name);
                              }                   
                          }
                      
                      } else {
                          //keep bring:
      
                          //update alexa:
                          if (!compareCompleted(alexaItem, bringItemCompleted)) {
                              bringItemCompleted.status = TodoItemStatus.Completed;
                              if (msource === 'Bring') {
                                  debug('Delete  Alexa item: ' + alexaItem.value + ' from Bring.');
                                  //setState(`${alexa2BaseId}.items.${alexaItem.id}.completed`, bringItemCompleted.status === TodoItemStatus.Completed);
                                  setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                              } 
                          }
                      }
                  }
              }
      
      
              if (!alexaItem.found) {
                  //alexa item not found:
                  if (alexaItem.completed) {
                      debug('Delete ' + alexaItem.value + ' because done and not in Bring list.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  } else {
                      if (msource === 'Alexa') {
                          debug('Adding ' + alexaItem.value + ' to Bring list');
                          setState(bringAddToList, alexaItem.value);
                      }
                  }
              }
      
              if (empty === true) {
                  if (alexaItem.updatedDateTime < timestampBring) {
                      debug('Delete ' + alexaItem.value + ' from Alexa list because Bring list is all done.');
                      setState(`${alexa2BaseId}.items.${alexaItem.id}.#delete`, true);
                  }
              }
          
          }
      
          for (const bringItem of list) {
              if (!bringItem.found) {
                  if (bringItem.status === TodoItemStatus.Completed) {
                      //debug('Remove from bring item:  ' + bringItem.name + ' because done and not on alexa list');
                      //Not executed since I want to keep the recent items inside bring app
                  } else {
                      if (msource === 'Bring') {
                          debug('Adding ' + bringItem.name + ' to Alexa list.');
                          setState(alexaAddToList, bringItem.name);
                      }
                  }
              }
          }
      
          return newBringList;
      }
      
      
      function doSync(source) {
          const alexaList = JSON.parse(getState(alexaListId).val);
          const state = getState(bringListId);
          const bringList = JSON.parse(state.val);
          const state2 = getState(bringListCompletedId);
          const bringListCompleted = JSON.parse(state2.val);
      
          syncLists(alexaList, bringList, state.ts, source, bringListCompleted);
      }
      
      
      on({id: bringListId, change: 'any'}, e => {
          debug('Update triggered from Bring');
          doSync('Bring');
      });
      
      on({id: alexaListId, change: 'any'}, e => {
          debug('Update triggered from Alexa');
          doSync('Alexa');
      });
      
      doSync();
      
      
      posted in Skripten / Logik
      icastillo15
      icastillo15
    • RE: Einfach mal zeigen will….. :-) - Teil 4

      @k_o_bold Mittlerweile leider schon - der Hersteller hat hier leider sein Lizenz Modell verändert. Als ich mit Neo angefangen habe konnte man die einzelnen Plugins noch einzeln erwerben und das ioBroker Plugin war dabei auch noch kostenlos (damals als Beta).

      Für den Preis heute würde ich es mir auch 2 mal überlegen. Ansonsten die Software selbst überzeugt 🙂 Wer sich nicht sicher ist kann auch alles im Demo Modus im kompletten Umfang testen und für sich entscheiden.

      posted in Praktische Anwendungen (Showcase)
      icastillo15
      icastillo15
    • RE: Einfach mal zeigen will….. :-) - Teil 4

      Hallo zusammen,

      gerne stelle ich euch meine Visualisierung vor. Ich nutze als Programm die AIO Creator NEO weil ich mich damals früh gegen VIS entschieden habe (wirkte mir persönlich zu altbacken). Die Bilder sind alle mit dem Programm Figma bearbeitet und erstellt. Diese basieren auf ein Smart Home Design Konzept, welches ich für mich angepasst habe. Das alles läuft dann als App auf Android/IPad.

      Ich lege vor allem Wert auf leichte Bedienung durch Jedermann und eine übersichtliche Darstellung der einzelnen Funktionen. Des Weiteren möchte ich möglichst alle wichtigen Informationen direkt auf einer Seite dargestellt haben. Ich hab mit der Zeit für mich herausgefunden, dass man in der Regel nicht mehr als einmal auf das Tablet klicken möchte.

      90% der Funktionalität beruht entsprechend auf ioBroker. Folgendes ist eingebunden im NEO:
      -Lichtsteuerung, Temperatureinstellung Heizung, Tankstelle, Abfuhrkalender Solarpanele Leistung (Solax), Wettervorhersage, Youtube, Sendungsverfolgung (Amazon), Speedtest, Temperaturen und Werte Abfahrtsplan für Züge inklusive Verspätungsanzeige, ECOVACS Roboter

      VIS wird bei mir aktuell nur genutzt, um die Dashboards aus Grafana anzuzeigen. Ich binde da aber entsprechend nur VIS in NEO ein über die URL. Für die Zukunft ist noch eine Übersichtsseite geplant für alle Sensoren. Auch mein Rasenmähroboter möchte noch eingebunden werden. In Grafana sollen dann noch weitere Grafiken dazukommen.

      So sieht es auf dem Tablet aus:
      2024-01-17 23_50_26-AIO CREATOR NEO.png

      So werden die Grafiken in FIgma zusammengebaut (ich experimentiere hier gerne etwas rum):
      2024-01-18 00_08_27-Developers – Figma – Opera.png
      Grafana Beispiel:
      2024-01-18 00_11_09-Speedtest - Grafana – Opera.png

      posted in Praktische Anwendungen (Showcase)
      icastillo15
      icastillo15
    • RE: Problem mit dem roadtraffic adapter?

      @mcm57

      Passt, hätte sonst jetzt einen Pull Request gestellt aber sehe du hast es schon übernommen 🙂
      Falls ich weitere Änderungen vornehme stell ich einen neuen PR.

      Ich habe den Fork lediglich aufgemacht, weil es mein erster Adapter war. Ich musste erstmal etwas mit dem Aufbau vertraut werden.

      LG

      posted in ioBroker Allgemein
      icastillo15
      icastillo15
    • RE: Problem mit dem roadtraffic adapter?

      @mcm57

      Hallo zusammen,

      Der alte Adapter funktioniert nicht, da dieser die alte API Version von Here.com verwendet hat, die mittlerweile deprecated ist. Stattdessen wurde die aktuelle Version 8 herausgebracht und es hat sich das Schema verändert. Ich habe diese Änderungen in den Adapter übernommen und dieser funktioniert nun wieder mit der neuen Version.

      Es ist weiterhin ausreichend einen kostenlosen Account auf https://platform.here.com/sign-up zu erstellen. Die neuen generierten API-Keys funktionieren auch nur noch mit der API Version 8. Ich vermute bei den alten Accounts muss ebenfalls ein neuer API-Key angelegt werden.

      posted in ioBroker Allgemein
      icastillo15
      icastillo15
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo