def setup(self): # handle credentials uuid = None uuidlist = None credentials = self._load_credentials_store() if credentials is not None: uuid = credentials['uuid'] uuidlist = credentials['list'] else: login = self.settings.get("login", "") password = self.settings.get("password", "") if login: uuid, uuidlist = BringApi.login(login, password) if uuid is None: self.speak_dialog('bring.error.connect') self.log.warning( "Loading credentials failed, please check your credentials") return self.log.info("Loaded credentials") self._bring = BringApi(uuid, uuidlist) if self._bring is None: self.speak_dialog('bring.error.connect') self.log.warning("API connect failed") self.log.info("API connect succeeded") return
def bring(self): if not self._bring: if not self._uuid or not self._uuidlist: self._uuid, self._uuidlist = BringApi.login( self.getConfig('bringEmail'), self.getConfig('bringPassword')) self.updateConfig('uuid', self._uuid) self.updateConfig('listUuid', self._uuidlist) self._bring = BringApi(self._uuid, self._uuidlist) return self._bring
def getList(self) -> str: uuid = self.skillInstance.getConfig('uuid') uuidList = self.skillInstance.getConfig('listUuid') bringList = BringApi(uuid, uuidList) translation = BringApi.loadTranslations( self.LanguageManager.activeLanguageAndCountryCode) items = bringList.get_items()['purchase'] details = bringList.get_items_detail() itemList = [{ "text": self.translate(item['name'], translation), "image": self.get_image(details, item['name']) } for item in items] return json.dumps(itemList)
def __init__(self, hass, username, password, list_id, name, locale): """Initialize Bring data updater.""" self.list_id = list_id self.locale = locale self.name = name self.api = BringApi(username, password, True) self.purchase = [] self.recently = [] super().__init__( hass, _LOGGER, name=name, update_interval=SCAN_INTERVAL, )
def bring(self): # check if the credentials have changed. if so, get new login. if not self._bring: if not self._uuid or not self._uuidlist: self.logInfo('New Login required using mail and password') self._uuid, self._uuidlist = BringApi.login(self.getConfig('bringEmail'), self.getConfig('bringPassword')) self.updateConfig('uuid', self._uuid) self.updateConfig('listUuid', self._uuidlist) self.logInfo(f'Getting new instance of Bring! with uuid {self._uuid}, default list {self._uuidlist} and custom list {self._overwriteUuidlist}') if self._overwriteUuidlist: self._bring = BringApi(self._uuid, self._overwriteUuidlist) else: self._bring = BringApi(self._uuid, self._uuidlist) itemlist = ", ".join([f'{item["name"]} ({item["listUuid"]})' for item in self._bring.load_lists().json()["lists"]]) self.logInfo(f'Available Bring! lists are {itemlist}. Currently using {self._bring.bringListUUID}') return self._bring
def _addItemInt(self, items) -> Tuple[list, list]: """ internal method to add a list of items to the shopping list :returns: two splitted lists of successful adds and items that already existed. """ bringItems = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] added = list() exist = list() for item in items: if not any(entr['name'].lower() == item.lower() for entr in bringItems): self.bring().purchase_item(BringApi.translateToCH(item, self.LanguageManager.activeLanguageAndCountryCode), "") added.append(item) else: exist.append(item) return added, exist
def getList(self) -> dict: try: bringList = self.skillInstance.bring() translation = BringApi.loadTranslations( self.LanguageManager.activeLanguageAndCountryCode) items = bringList.get_items()['purchase'] details = bringList.get_items_detail() itemList = [{ "text": self.translate(item['name'], translation), "image": self.get_image(details, item['name']) } for item in items] return {'success': True, 'items': itemList} except Exception as e: return {'success': False, 'message': str(e)}
def _deleteItemInt(self, items: list) -> Tuple[list, list]: """ internal method to delete a list of items from the shopping list :returns: two splitted lists of successful deletions and items that were not on the list """ bringItems = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] removed = list() exist = list() for item in items: for entr in bringItems: if entr['name'].lower() == item.lower(): self.bring().recent_item(BringApi.translateToCH(entr['name'], self.LanguageManager.activeLanguageAndCountryCode)) removed.append(item) break else: exist.append(item) return removed, exist
def get_bring(conf): return BringApi(conf['secret']['uuid'], conf['secret']['bringlistuuid'])
class BringShoppingList(AliceSkill): """ Author: philipp2310 Description: maintaines a Bring! shopping list """ def __init__(self): super().__init__() self._uuid = None self._uuidlist = None self._overwriteUuidlist = None self._bring = None def onStart(self): super().onStart() self.reloadConfig() self._connectAccount() def reloadConfig(self, dummy = None): self.logInfo('Bring! config reloading...') self._uuid = self.getConfig('uuid') self._uuidlist = self.getConfig('listUuid') self._overwriteUuidlist = self.getConfig('overwriteListUuid') self._bring = None self.bring() self.logInfo('Bring! config reload done!') return True def bring(self): # check if the credentials have changed. if so, get new login. if not self._bring: if not self._uuid or not self._uuidlist: self.logInfo('New Login required using mail and password') self._uuid, self._uuidlist = BringApi.login(self.getConfig('bringEmail'), self.getConfig('bringPassword')) self.updateConfig('uuid', self._uuid) self.updateConfig('listUuid', self._uuidlist) self.logInfo(f'Getting new instance of Bring! with uuid {self._uuid}, default list {self._uuidlist} and custom list {self._overwriteUuidlist}') if self._overwriteUuidlist: self._bring = BringApi(self._uuid, self._overwriteUuidlist) else: self._bring = BringApi(self._uuid, self._uuidlist) itemlist = ", ".join([f'{item["name"]} ({item["listUuid"]})' for item in self._bring.load_lists().json()["lists"]]) self.logInfo(f'Available Bring! lists are {itemlist}. Currently using {self._bring.bringListUUID}') return self._bring @Online def _connectAccount(self): try: self._bring = self.bring() except BringApi.AuthentificationFailed: raise SkillStartingFailed(skillName=self._name, error='Please check your account login and password') def _deleteCompleteList(self): """ perform the deletion of the complete list -> load all and delete item by item """ items = self.bring().get_items()['purchase'] for item in items: self.bring().recent_item(item['name']) def _addItemInt(self, items) -> Tuple[list, list]: """ internal method to add a list of items to the shopping list :returns: two splitted lists of successful adds and items that already existed. """ bringItems = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] added = list() exist = list() for item in items: if not any(entr['name'].lower() == item.lower() for entr in bringItems): self.bring().purchase_item(BringApi.translateToCH(item, self.LanguageManager.activeLanguageAndCountryCode), "") added.append(item) else: exist.append(item) return added, exist def _deleteItemInt(self, items: list) -> Tuple[list, list]: """ internal method to delete a list of items from the shopping list :returns: two splitted lists of successful deletions and items that were not on the list """ bringItems = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] removed = list() exist = list() for item in items: for entr in bringItems: if entr['name'].lower() == item.lower(): self.bring().recent_item(BringApi.translateToCH(entr['name'], self.LanguageManager.activeLanguageAndCountryCode)) removed.append(item) break else: exist.append(item) return removed, exist def _checkListInt(self, items: list) -> Tuple[list, list]: """ internal method to check if a list of items is on the shopping list :returns: two splitted lists, one with the items on the list, one with the missing ones """ bringItems = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] found = list() missing = list() for item in items: if any(entr['name'].lower() == item.lower() for entr in bringItems): found.append(item) else: missing.append(item) return found, missing def _getShopItems(self, answer: str, session: DialogSession) -> list: """get the values of shopItem as a list of strings""" intent = session.intentName if intent == Intent('SpellWord'): item = ''.join([slot.value['value'] for slot in session.slotsAsObjects['Letters']]) return [item.capitalize()] items = [x.value['value'] for x in session.slotsAsObjects.get('shopItem', list()) if x.value['value'] != 'unknownword'] if not items: self.continueDialog( sessionId=session.sessionId, text=self.randomTalk(f'{answer}_what'), intentFilter=[Intent('Bring_whatItem')], currentDialogState=intent.split(':')[-1].split('/')[-1], slot='buyable', probabilityThreshold=0.1 ) return items ### INTENTS ### @IntentHandler('Bring_deleteList') @Online def delListIntent(self, session: DialogSession): self.continueDialog( sessionId=session.sessionId, text=self.randomTalk('chk_del_all'), intentFilter=[Intent('AnswerYesOrNo')], currentDialogState='confDelList_Bring') @AnyExcept(exceptions=BringApi.AuthentificationFailed, text='authFailed') @Online @IntentHandler('AnswerYesOrNo', requiredState='confDelList_Bring') def confDelIntent(self, session: DialogSession): if self.Commons.isYes(session): self._deleteCompleteList() self.endDialog(session.sessionId, text=self.randomTalk('del_all')) else: self.endDialog(session.sessionId, text=self.randomTalk('nodel_all')) @AnyExcept(exceptions=BringApi.AuthentificationFailed, text='authFailed') @Online @IntentHandler('Bring_addItem') @IntentHandler('Bring_whatItem', requiredState='Bring_addItem') @IntentHandler('SpellWord', requiredState='Bring_addItem') def addItemIntent(self, session: DialogSession): items = self._getShopItems('add', session) if items: added, exist = self._addItemInt(items) self.endDialog(session.sessionId, text=self._combineLists('add', added, exist)) @AnyExcept(exceptions=BringApi.AuthentificationFailed, text='authFailed') @Online @IntentHandler('Bring_deleteItem') @IntentHandler('Bring_whatItem', requiredState='Bring_deleteItem') @IntentHandler('SpellWord', requiredState='Bring_deleteItem') def delItemIntent(self, session: DialogSession): items = self._getShopItems('rem', session) if items: removed, exist = self._deleteItemInt(items) self.endDialog(session.sessionId, text=self._combineLists('rem', removed, exist)) @AnyExcept(exceptions=BringApi.AuthentificationFailed, text='authFailed') @Online @IntentHandler('Bring_checkList') @IntentHandler('Bring_whatItem', requiredState='Bring_checkList') @IntentHandler('SpellWord', requiredState='Bring_checkList') def checkListIntent(self, session: DialogSession): items = self._getShopItems('chk', session) if items: found, missing = self._checkListInt(items) self.endDialog(session.sessionId, text=self._combineLists('chk', found, missing)) @AnyExcept(exceptions=BringApi.AuthentificationFailed, text='authFailed') @Online @IntentHandler('Bring_readList') def readListIntent(self, session: DialogSession): """read the content of the list""" items = self.bring().get_items(self.LanguageManager.activeLanguageAndCountryCode)['purchase'] itemlist = [item['name'] for item in items] self.endDialog(session.sessionId, text=self._getTextForList('read', itemlist)) #### List/Text operations def _combineLists(self, answer: str, first: list, second: list) -> str: firstAnswer = self._getTextForList(answer, first) if first else '' secondAnswer = self._getTextForList(f'{answer}_f', second) if second else '' combinedAnswer = self.randomTalk('state_con', [firstAnswer, secondAnswer]) if first and second else '' return combinedAnswer or firstAnswer or secondAnswer def _getTextForList(self, pref: str, items: list) -> str: """Combine entries of list into wrapper sentence""" if not items: return self.randomTalk(f'{pref}_none') elif len(items) == 1: return self.randomTalk(f'{pref}_one', [items[0]]) value = self.randomTalk(text='gen_list', replace=[', '.join(items[:-1]), items[-1]]) return self.randomTalk(f'{pref}_multi', [value])
class BringDataUpdateCoordinator(DataUpdateCoordinator[int]): """Class to manage fetching shopping list data from endpoint.""" def __init__(self, hass, username, password, list_id, name, locale): """Initialize Bring data updater.""" self.list_id = list_id self.locale = locale self.name = name self.api = BringApi(username, password, True) self.purchase = [] self.recently = [] super().__init__( hass, _LOGGER, name=name, update_interval=SCAN_INTERVAL, ) async def _async_update_data(self) -> Optional[int]: """Fetch new state data for the sensor. This is the only method that should fetch new data for Home Assistant. """ catalog = self.api.loadCatalog(self.locale) details = self.api.get_items_detail() data = self.api.get_items(self.locale) purchase = data["purchase"] recently = data["recently"] self.purchase = self._get_list(purchase, details, catalog) self.recently = self._get_list(recently, details, catalog) return len(purchase) def _get_list(self, source=None, details=None, articles=None): if articles is None: articles = [] items = [] for p in source: found = False for d in details: if p["name"] == d["itemId"]: found = True break item = { "image": p["name"], "name": p["name"], "specification": p["specificitemation"] } if found: item["image"] = d["userIconItemId"] item["key"] = item["image"] if item["name"] in articles: item["name"] = articles[item["name"]] else: if found == 0: item["image"] = item["name"][0] item["image"] = self._purge(item["image"]) if "+" in item["specification"]: specs = item["specification"].split("+") for spec in specs: temp = dict(item.items()) temp["specification"] = spec.strip() items.append(temp) else: items.append(item) return items @staticmethod def _purge(item): return item.lower() \ .replace("é", "e") \ .replace("ä", "ae") \ .replace("-", "_") \ .replace("ö", "oe") \ .replace("ü", "ue") \ .replace(" ", "_")
def _getBring(self) -> BringApi: """get an instance of the BringApi""" return BringApi(self._uuid, self._uuidlist)
class BringlistSkill(MycroftSkill): def __init__(self): MycroftSkill.__init__(self) self._bring = None self._regex = {} def initialize(self): self.settings_change_callback = self.on_websettings_changed self.setup() def on_websettings_changed(self): self.setup() def setup(self): # handle credentials uuid = None uuidlist = None credentials = self._load_credentials_store() if credentials is not None: uuid = credentials['uuid'] uuidlist = credentials['list'] else: login = self.settings.get("login", "") password = self.settings.get("password", "") if login: uuid, uuidlist = BringApi.login(login, password) if uuid is None: self.speak_dialog('bring.error.connect') self.log.warning( "Loading credentials failed, please check your credentials") return self.log.info("Loaded credentials") self._bring = BringApi(uuid, uuidlist) if self._bring is None: self.speak_dialog('bring.error.connect') self.log.warning("API connect failed") self.log.info("API connect succeeded") return @intent_handler( IntentBuilder("AddToBringlist").require("bring.list").require( "bring.add")) def handle_bringlist_add(self, message): self.log.info("Bringlist add") if self._bring is None: self.speak_dialog('bring.error.connect') item, desc = self._get_item(message.data.get('utterance'), 'bring.add.regex') if item is not None: self._bring.purchase_item(item.capitalize(), desc) self.speak_dialog('bring.success.add', data={"Item": item}) return self.speak_dialog('bring.error.add', data={"Item": item}) @intent_handler( IntentBuilder("RemoveFromBringlist").require("bring.list").require( "bring.remove")) def handle_bringlist_remove(self, message): self.log.info("Bringlist remove") if self._bring is None: self.speak_dialog('bring.error.connect') item, desc = self._get_item(message.data.get('utterance'), 'bring.remove.regex') if item: self._bring.recent_item(item.capitalize()) self.speak_dialog('bring.success.remove', data={"Item": item}) return self.speak_dialog('bring.error.remove', data={"Item": item}) @intent_handler( IntentBuilder("ClearBringlist").require("bring.list").require( "bring.clear")) def handle_bringlist_clear(self, message): self.log.info("Bringlist clear") if self._bring is None: self.speak_dialog('bring.error.connect') items = self._bring.get_items()['purchase'] if items: for item in items: self._bring.recent_item(item['name']) self.speak_dialog('bring.success.clear', data={"Count": len(items)}) return self.speak_dialog('bring.error.clear') def _load_credentials_store(self): credentials = None credentials_file = 'credentials.store' if self.file_system.exists(credentials_file): with self.file_system.open(credentials_file, 'rb') as f: credentials = pickle.load(f) return credentials def _get_item(self, text, regfile): match = self._get_regex(regfile).match(text) if match: return match.group('Item'), match.group('Desc') if match.group( 'Desc') is not None else "" else: return None, None def _get_regex(self, regfile): if regfile in self._regex: return self._regex[regfile] with open(self.find_resource(regfile, 'regex')) as f: matcher = f.readline().rstrip('\n') regex = re.compile(matcher) self._regex[regfile] = regex return regex