def tell_weather(self, ignored): '''Tell the current weather and a short forecast''' LOG.debug('telling weather') units = self.nest.scale.lower() def new_forecast(title, info): tcond = info['condition'].capitalize() thi = info['temp_high_' + units] tlo = info['temp_low_' + units] item = Item(u'%s: %s' % (title, tcond), subtitle=u'High: {0:.1f}°{1}, ' u'Low: {2:.1f}°{1}'.format( thi, units.upper(), tlo)) return item data = self.nest.structure.weather conditions = data['current']['condition'].capitalize() temp = data['current']['temp_' + units] humidity = data['current']['humidity'] items = [] item = Item(u'Now: %s' % conditions) item.subtitle = u'{0:.1f}°{1}, {2:.0f}% humidity'.format( temp, units.upper(), humidity) items.append(item) items.append(new_forecast('Today', data['forecast']['daily'][0])) items.append(new_forecast('Tomorrow', data['forecast']['daily'][1])) return items
def tell_target(self, temp): '''Tell the target temperature''' LOG.debug('telling target temperature') target = self.nest.target_temperature temp = temp.strip() temp = temp.strip('"') temp = temp.strip("'") units = self.nest.scale.upper() if temp: if self.nest.mode == 'range': temps = temp.split() if len(temps) != 2: return [Item('Waiting for valid input...')] for t in temps: if len(t) == 1 or len(t) > 2: return [Item('Waiting for valid input...')] return [Item(u'Set temperature range to %.1f°%s - %.1f°%s' % ( float(temps[0]), units, float(temps[1]), units), arg=temp, valid=True)] else: return [Item(u'Set temperature to %.1f°%s' % (float(temp), units), arg=temp, valid=True)] else: if self.nest.mode == 'range': item = Item( u'Target temperature range is %.1f°%s - ' u'%.1f°%s' % (target[0], units, target[1], units)) else: item = Item( u'Target temperature: %.1f°%s' % (target, units)) if self.nest.mode == 'range': item.subtitle = (u'Enter a temperature range in °%s to update; ' u'use format "low high"' % units) else: item.subtitle = u'Enter a temperature in °%s to update' % units return [item]
def _show_alert_information(self, weather): items = [] if 'alerts' in weather: for alert in weather['alerts']: item = Item(alert['description'], icon='error.png') if alert['expires']: item.subtitle = 'Expires at {}'.format( alert['expires'].strftime(self.config['time_format'])) if 'uri' in alert: item.arg = clean_str(alert['uri']) item.valid = True items.append(item) return items
def _show_alert_information(self, weather): items = [] if 'alerts' in weather: for alert in weather['alerts']: item = Item(alert['description'], icon='error.png') if alert['expires']: item.subtitle = 'Expires at {}'.format(alert['expires'].strftime( self.config['time_format'])) if 'uri' in alert: item.arg = clean_str(alert['uri']) item.valid = True items.append(item) return items
def tell_icons(self, ignored): items = [] sets = [f for f in os.listdir('icons') if not f.startswith('.')] for iset in sets: uid = 'icons-{}'.format(iset) icon = 'icons/{}/{}.png'.format(iset, EXAMPLE_ICON) title = iset.capitalize() item = Item(title, uid=uid, icon=icon, arg=u'icons|' + iset, valid=True) info_file = os.path.join('icons', iset, 'info.json') if os.path.exists(info_file): with open(info_file, 'rt') as ifile: info = json.load(ifile) if 'description' in info: item.subtitle = info['description'] items.append(item) return items
def tell_icons(self, ignored, prefix=None): items = [] sets = [f for f in os.listdir('icons') if not f.startswith('.')] for iset in sets: uid = 'icons-{}'.format(iset) icon = 'icons/{}/{}.png'.format(iset, EXAMPLE_ICON) title = iset.capitalize() item = Item(title, uid=uid, icon=icon, arg=u'icons|' + iset, valid=True) info_file = os.path.join('icons', iset, 'info.json') if os.path.exists(info_file): with open(info_file, 'rt') as ifile: info = json.load(ifile) if 'description' in info: item.subtitle = info['description'] items.append(item) return items
def tell_status(self, ignore): '''Tell the Nest's overall status''' LOG.debug('telling status') temp = self.nest.temperature target = self.nest.target_temperature humidity = self.nest.humidity away = 'yes' if self.nest.structure.away else 'no' fan = self.nest.fan units = self.nest.scale.upper() item = Item(u'Temperature: %.1f°%s' % (temp, units)) if self.nest.mode == 'range': target = u'Heat/cool to %.1f°%s - %.1f°%s' % ( target[0], units, target[1], units) elif self.nest.mode == 'heat': target = u'Heating to %.1f°%s' % (target, units) else: target = u'Cooling to %.1f°%s' % (target, units) item.subtitle = u'%s Humidity: %.1f%% Fan: %s Away: %s' % ( target, humidity, fan, away) return [item]
def tell_query(self, query, start=None, end=None): '''List entries that match a query. Note that an end time without a start time will be ignored.''' LOG.info('tell_query("{0}", start={1}, end={2})'.format( query, start, end)) if not start: end = None needs_refresh = False query = query.strip() if self.cache.get('disable_cache', False): LOG.debug('cache is disabled') needs_refresh = True elif self.cache.get('time') and self.cache.get('time_entries'): last_load_time = self.cache.get('time') LOG.debug('last load was %s', last_load_time) import time now = int(time.time()) if now - last_load_time > CACHE_LIFETIME: LOG.debug('automatic refresh') needs_refresh = True else: LOG.debug('cache is missing timestamp or data') needs_refresh = True if needs_refresh: LOG.debug('refreshing cache') try: all_entries = toggl.TimeEntry.all() except Exception: LOG.exception('Error getting time entries') raise Exception('Problem talking to toggl.com') import time self.cache['time'] = int(time.time()) self.cache['time_entries'] = serialize_entries(all_entries) else: LOG.debug('using cached data') all_entries = deserialize_entries(self.cache['time_entries']) LOG.debug('%d entries', len(all_entries)) if start: LOG.debug('filtering on start time %s', start) if end: LOG.debug('filtering on end time %s', end) all_entries = [ e for e in all_entries if e.start_time < end and e.stop_time > start ] else: all_entries = [e for e in all_entries if e.stop_time > start] LOG.debug('filtered to %d entries', len(all_entries)) efforts = {} # group entries with the same description into efforts (so as not to be # confused with Toggl tasks for entry in all_entries: if entry.description not in efforts: efforts[entry.description] = Effort(entry.description, start, end) efforts[entry.description].add(entry) efforts = efforts.values() efforts = sorted(efforts, reverse=True, key=lambda e: e.newest_entry.start_time) items = [] if start: if len(efforts) > 0: seconds = sum(e.seconds for e in efforts) LOG.debug('total seconds: %s', seconds) total_time = to_hours_str(seconds) if end: item = Item('{0} hours on {1}'.format( total_time, start.date().strftime(DATE_FORMAT)), subtitle=Item.LINE) else: item = Item('{0} hours from {1}'.format( total_time, start.date().strftime(DATE_FORMAT)), subtitle=Item.LINE) else: item = Item('Nothing to report') items.append(item) show_suffix = start or end for effort in efforts: item = Item(effort.description, valid=True) now = LOCALTZ.localize(datetime.datetime.now()) newest_entry = effort.newest_entry if newest_entry.is_running: item.icon = 'running.png' started = newest_entry.start_time delta = to_approximate_time(now - started) seconds = effort.seconds total = '' if seconds > 0: hours = to_hours_str(seconds, show_suffix=show_suffix) total = ' ({0} hours total)'.format(hours) item.subtitle = 'Running for {0}{1}'.format(delta, total) item.arg = 'stop|{0}|{1}'.format(newest_entry.id, effort.description) else: seconds = effort.seconds hours = to_hours_str(datetime.timedelta(seconds=seconds), show_suffix=show_suffix) if start: item.subtitle = ('{0} hours'.format(hours)) else: stop = newest_entry.stop_time if stop: delta = to_approximate_time(now - stop, ago=True) else: delta = 'recently' oldest = effort.oldest_entry since = oldest.start_time since = since.strftime('%m/%d') item.subtitle = ('{0} hours since {1}, ' 'stopped {2}'.format(hours, since, delta)) item.arg = 'continue|{0}|{1}'.format(newest_entry.id, effort.description) items.append(item) if len(query.strip()) > 1: # there's a filter test = query[1:].strip() items = self.fuzzy_match_list(test, items, key=lambda t: t.title) if len(items) == 0: items.append(Item("Nothing found")) return items
def tell_query(self, query, start=None, end=None): '''List entries that match a query. Note that an end time without a start time will be ignored.''' LOG.info('tell_query("{0}", start={1}, end={2})'.format( query, start, end)) if not start: end = None needs_refresh = False query = query.strip() if self.cache.get('disable_cache', False): LOG.debug('cache is disabled') needs_refresh = True elif self.cache.get('time') and self.cache.get('time_entries'): last_load_time = self.cache.get('time') LOG.debug('last load was %s', last_load_time) import time now = int(time.time()) if now - last_load_time > CACHE_LIFETIME: LOG.debug('automatic refresh') needs_refresh = True else: LOG.debug('cache is missing timestamp or data') needs_refresh = True if needs_refresh: LOG.debug('refreshing cache') try: all_entries = toggl.TimeEntry.all() except Exception: LOG.exception('Error getting time entries') raise Exception('Problem talking to toggl.com') import time self.cache['time'] = int(time.time()) self.cache['time_entries'] = serialize_entries(all_entries) else: LOG.debug('using cached data') all_entries = deserialize_entries(self.cache['time_entries']) LOG.debug('%d entries', len(all_entries)) if start: LOG.debug('filtering on start time %s', start) if end: LOG.debug('filtering on end time %s', end) all_entries = [e for e in all_entries if e.start_time < end and e.stop_time > start] else: all_entries = [e for e in all_entries if e.stop_time > start] LOG.debug('filtered to %d entries', len(all_entries)) efforts = {} # group entries with the same description into efforts (so as not to be # confused with Toggl tasks for entry in all_entries: if entry.description not in efforts: efforts[entry.description] = Effort(entry.description, start, end) efforts[entry.description].add(entry) efforts = efforts.values() efforts = sorted(efforts, reverse=True, key=lambda e: e.newest_entry.start_time) items = [] if start: if len(efforts) > 0: seconds = sum(e.seconds for e in efforts) LOG.debug('total seconds: %s', seconds) total_time = to_hours_str(seconds) if end: item = Item('{0} hours on {1}'.format( total_time, start.date().strftime(DATE_FORMAT)), subtitle=Item.LINE) else: item = Item('{0} hours from {1}'.format( total_time, start.date().strftime(DATE_FORMAT)), subtitle=Item.LINE) else: item = Item('Nothing to report') items.append(item) show_suffix = start or end for effort in efforts: item = Item(effort.description, valid=True) now = LOCALTZ.localize(datetime.datetime.now()) newest_entry = effort.newest_entry if newest_entry.is_running: item.icon = 'running.png' started = newest_entry.start_time delta = to_approximate_time(now - started) seconds = effort.seconds total = '' if seconds > 0: hours = to_hours_str(seconds, show_suffix=show_suffix) total = ' ({0} hours total)'.format(hours) item.subtitle = 'Running for {0}{1}'.format(delta, total) item.arg = 'stop|{0}|{1}'.format(newest_entry.id, effort.description) else: seconds = effort.seconds hours = to_hours_str(datetime.timedelta(seconds=seconds), show_suffix=show_suffix) if start: item.subtitle = ('{0} hours'.format(hours)) else: stop = newest_entry.stop_time if stop: delta = to_approximate_time(now - stop, ago=True) else: delta = 'recently' oldest = effort.oldest_entry since = oldest.start_time since = since.strftime('%m/%d') item.subtitle = ('{0} hours since {1}, ' 'stopped {2}'.format(hours, since, delta)) item.arg = 'continue|{0}|{1}'.format(newest_entry.id, effort.description) items.append(item) if len(query.strip()) > 1: # there's a filter test = query[1:].strip() items = self.fuzzy_match_list(test, items, key=lambda t: t.title) if len(items) == 0: items.append(Item("Nothing found")) return items