def RecordDrink(self, tap_name, ticks, volume_ml=None, username=None, pour_time=None, duration=0, auth_token=None, spilled=False, do_postprocess=True): tap = self._GetTapFromName(tap_name) if not tap: raise BackendError, "Tap unknown" if volume_ml is None: volume_ml = float(ticks) * tap.ml_per_tick user = None if username: user = self._GetUserObjFromUsername(username) if not pour_time: pour_time = datetime.datetime.now() keg = None if tap.current_keg and tap.current_keg.status == 'online': keg = tap.current_keg if spilled: if not keg: self._logger.warning( 'Got spilled pour for tap missing keg; ignoring') return keg.spilled_ml += volume_ml keg.save() return d = models.Drink(ticks=ticks, site=self._site, keg=keg, user=user, volume_ml=volume_ml, starttime=pour_time, duration=duration, auth_token=auth_token) models.DrinkingSession.AssignSessionForDrink(d) d.save() if do_postprocess: d.PostProcess() hook_url = self._site.settings.event_web_hook if hook_url: events = models.SystemEvent.objects.filter(drink=d) if events: event_list = [protolib.ToDict(e) for e in events] tasks.post_webhook_event.delay(hook_url, event_list) return protolib.ToProto(d)
def RecordDrink(self, tap_name, ticks, volume_ml=None, username=None, pour_time=None, duration=0, auth_token=None, spilled=False, shout='', do_postprocess=True): tap = self._GetTapFromName(tap_name) if not tap: raise backend.BackendError("Tap unknown") if volume_ml is None: volume_ml = float(ticks) * tap.ml_per_tick user = None if username: user = self._GetUserObjFromUsername(username) elif self._site.settings.default_user: user = self._site.settings.default_user if not pour_time: pour_time = datetime.datetime.now() keg = None if tap.current_keg and tap.current_keg.status == 'online': keg = tap.current_keg if spilled: if not keg: self._logger.warning('Got spilled pour for tap missing keg; ignoring') return keg.spilled_ml += volume_ml keg.save() return d = models.Drink(ticks=ticks, site=self._site, keg=keg, user=user, volume_ml=volume_ml, time=pour_time, duration=duration, auth_token=auth_token, shout=shout) models.DrinkingSession.AssignSessionForDrink(d) d.save() if do_postprocess: d.PostProcess() event_list = [e for e in models.SystemEvent.objects.filter(drink=d).order_by('id')] if settings.HAVE_CELERY: tasks.handle_new_events.delay(self._site, event_list) return d
def restore(input_fp, kbsite, log_cb=_no_log): def _log(obj): obj_cls = obj.__class__ obj_name = obj_cls.__name__ log_cb(' +++ %s: %s' % (obj_name, obj)) data = kbjson.loads(input_fp.read()) brewer_map = {} for rec in data.get('bdb_brewers', []): try: brewer = bdb_models.Brewer.objects.get(id=rec.id) except bdb_models.Brewer.DoesNotExist: brewer = bdb_models.Brewer(id=rec.id) brewer.name = rec.name brewer.country = rec.get('country') brewer.origin_state = rec.get('origin_state') brewer.origin_city = rec.get('origin_city') brewer.production = rec.production brewer.url = rec.get('url') brewer.description = rec.get('description') brewer.save() _log(brewer) brewer_map[rec.id] = brewer style_map = {} for rec in data.get('bdb_styles', []): try: style = bdb_models.BeerStyle.objects.get(id=rec.id) except bdb_models.BeerStyle.DoesNotExist: style = bdb_models.BeerStyle(id=rec.id) style.name = rec.name style.save() _log(style) style_map[rec.id] = style type_map = {} for rec in data.get('bdb_beertypes', []): try: btype = bdb_models.BeerType.objects.get(id=rec.id) except bdb_models.BeerType.DoesNotExist: btype = bdb_models.BeerType(id=rec.id) btype.name = rec.name btype.brewer = brewer_map[rec.brewer_id] btype.style = style_map[rec.style_id] btype.edition = rec.get('edition') btype.abv = rec.get('abv') btype.calories_oz = rec.get('calories_oz') btype.carbs_oz = rec.get('carbs_oz') btype.save() _log(btype) type_map[rec.id] = btype kbsite.thermosensors.all().delete() for rec in data.get('thermosensors', []): sensor = models.ThermoSensor(site=kbsite, seqn=int(rec.id)) sensor.raw_name = rec.sensor_name sensor.nice_name = rec.nice_name sensor.save() _log(sensor) kbsite.kegs.all().delete() for rec in data['kegs']: keg = models.Keg(site=kbsite, seqn=int(rec.id)) keg.type = type_map[rec.type_id] keg.startdate = rec.started_time keg.enddate = rec.finished_time keg.status = rec.status keg.description = rec.get('description') keg.spilled_ml = rec.spilled_ml size, created = models.KegSize.objects.get_or_create( name=rec.size_name, volume_ml=rec.size_volume_ml) size.save() keg.size = size keg.save() _log(keg) kbsite.taps.all().delete() for rec in data['taps']: tap = models.KegTap(site=kbsite, seqn=int(rec.id)) tap.name = rec.name tap.meter_name = rec.meter_name tap.ml_per_tick = rec.ml_per_tick tap.description = rec.get('description') keg_id = int(rec.get('current_keg_id', 0)) if keg_id: tap.current_keg = models.Keg.objects.get(site=kbsite, seqn=keg_id) thermo_id = int(rec.get('thermo_sensor_id', 0)) if thermo_id: tap.temperature_sensor = models.ThermoSensor.objects.get( site=kbsite, seqn=thermo_id) tap.save() _log(tap) kbsite.sessions.all().delete() for rec in data.get('sessions', []): session = models.DrinkingSession(site=kbsite, seqn=int(rec.id)) session.starttime = rec.start_time session.endtime = rec.end_time session.volume_ml = rec.volume_ml session.name = rec.get('name') session.slug = rec.get('slug') session.save() _log(session) for rec in data.get('thermologs', []): log = models.Thermolog(site=kbsite, seqn=int(rec.id)) log.sensor = models.ThermoSensor.objects.get(site=kbsite, seqn=int(rec.sensor_id)) log.temp = rec.temperature_c log.time = rec.record_time log.save() _log(log) kbsite.thermosummarylogs.all().delete() for rec in data.get('thermosummarylogs', []): log = models.ThermoSummaryLog(site=kbsite, seqn=int(rec.sensor_id)) log.site = kbsite log.seqn = rec.id log.sensor = models.ThermoSensor.objects.get(site=kbsite, seqn=int(rec.sensor_id)) log.date = rec.date log.period = rec.period log.num_readings = rec.num_readings log.min_temp = rec.min_temp log.max_temp = rec.max_temp log.mean_temp = rec.mean_temp log.save() _log(log) user_map = {} for rec in data.get('users', []): user = None # If there's already a user registered with this e-mail address, use it. if rec.email: user_qs = models.User.objects.filter(email=rec.email) if user_qs.count(): user = user_qs[0] user_map[rec.username] = user _log(user) continue # Create a new user, creating a new unique username if necessary. iter = 0 username = rec.username while True: username_qs = models.User.objects.filter(username=username) if not username_qs.count(): break iter += 1 username = '******' % (rec.username[:30], iter) user = models.User(username=username) user.first_name = rec.first_name user.last_name = rec.last_name user.email = rec.email user.password = rec.password user.is_active = rec.is_active user.last_login = rec.last_login user.date_joined = rec.date_joined # XXX non-prod user.is_staff = rec.is_staff user.is_superuser = rec.is_superuser user.save() user_map[rec.username] = user _log(user) for rec in data.get('profiles', []): user = user_map.get(rec.username) if not user: print 'Warning: profile for non-existant user: %s' % rec.username continue profile, created = models.UserProfile.objects.get_or_create(user=user) profile.gender = rec.gender profile.weight = rec.weight profile.save() _log(profile) kbsite.tokens.all().delete() for rec in data.get('tokens', []): token = models.AuthenticationToken(site=kbsite, seqn=int(rec.id)) token.auth_device = rec.auth_device token.token_value = rec.token_value username = rec.get('username') if username: token.user = user_map[username] token.enabled = rec.enabled token.created = rec.created_time token.pin = rec.get('pin') token.save() _log(token) kbsite.drinks.all().delete() for rec in data.get('drinks', []): drink = models.Drink(site=kbsite, seqn=int(rec.id)) drink.ticks = rec.ticks drink.volume_ml = rec.volume_ml drink.session = models.DrinkingSession.objects.get(site=kbsite, seqn=int( rec.session_id)) drink.starttime = rec.pour_time drink.duration = rec.get('duration') drink.status = rec.status keg_id = int(rec.get('keg_id', 0)) if keg_id: drink.keg = models.Keg.objects.get(site=kbsite, seqn=keg_id) username = rec.get('user_id') if username: drink.user = user_map[username] drink.auth_token = rec.get('auth_token') drink.save() _log(drink) log_cb('Regenerating sessions ...') _RegenSessions(kbsite) log_cb('Regenerating stats ...') _RegenStats(kbsite) log_cb('Regenerating events ...') _RegenEvents(kbsite)
def record_drink(self, tap, ticks, volume_ml=None, username=None, pour_time=None, duration=0, shout='', tick_time_series='', photo=None, spilled=False): """Records a new drink against a given tap. The tap must have a Keg assigned to it (KegTap.current_keg), and the keg must be active. Args: tap: A KegTap or matching meter name. ticks: The number of ticks observed by the flow sensor for this drink. volume_ml: The volume, in milliliters, of the pour. If specifed, this value is saved as the Drink's actual value. If not specified, a volume is computed based on `ticks` and the meter's `ticks_per_ml` setting. username: The username with which to associate this Drink, or None for an anonymous Drink. pour_time: The datetime of the drink. If not supplied, the current date and time will be used. duration: Number of seconds it took to pour this Drink. This is optional information not critical to the record. shout: A short comment left by the user about this Drink. Optional. tick_time_series: Vector of flow update data, used for diagnostic purposes. spilled: If drink is recorded as spill, the volume is added to spilled_ml and the "drink" is not saved as an event. Returns: The newly-created Drink instance. """ tap = self._get_tap(tap) if not tap.is_active or not tap.current_keg: raise exceptions.BackendError("No active keg at this tap") keg = tap.current_keg if spilled: keg.spilled_ml += volume_ml keg.save(update_fields=['spilled_ml']) return None if volume_ml is None: meter = tap.current_meter() if not meter: raise exceptions.BackendError("Tap has no meter, can't compute volume") volume_ml = float(ticks) / meter.ticks_per_ml user = None if username: user = self.get_user(username) else: user = models.User.objects.get(username='******') if not pour_time: pour_time = timezone.now() if tick_time_series: try: # Validate the time series by parsing it; canonicalize it by generating # it again. If malformed, just junk it; it's non-essential information. tick_time_series = time_series.to_string(time_series.from_string(tick_time_series)) except ValueError as e: self._logger.warning('Time series invalid, ignoring. Error was: %s' % e) tick_time_series = '' d = models.Drink(ticks=ticks, keg=keg, user=user, volume_ml=volume_ml, time=pour_time, duration=duration, shout=shout, tick_time_series=tick_time_series) models.DrinkingSession.AssignSessionForDrink(d) d.save() keg.served_volume_ml += volume_ml keg.save(update_fields=['served_volume_ml']) if photo: pic = models.Picture.objects.create( image=photo, user=d.user, keg=d.keg, session=d.session ) d.picture = pic d.save() events = models.SystemEvent.build_events_for_drink(d) tasks.schedule_tasks(events) self.build_stats(d.id) signals.drink_recorded.send_robust(sender=self.__class__, drink=d) return d
def gentestdata(): """ default values (contents may change with schema) """ sn = bdb.Brewer(name='Sierra Nevada Brewing Company', country='USA', origin_state='California', origin_city='Chico', production='commercial', url='http://www.sierranevada.com/') sn.save() an = bdb.Brewer(name='Anchor Brewing Company', country='USA', origin_state='California', origin_city='San Francisco', production='commercial', url='http://www.anchorsteam.com/') an.save() # beerstyle defaults pale_ale = bdb.BeerStyle(name='Pale Ale') pale_ale.save() # beertype defaults sn_pa = bdb.BeerType(name="Sierra Nevada Pale Ale", brewer=sn, style=pale_ale, calories_oz=10, carbs_oz=10, abv=5.5) sn_pa.save() as_pa = bdb.BeerType(name="Anchor Liberty Ale", brewer=an, style=pale_ale, calories_oz=10, carbs_oz=10, abv=5.0) as_pa.save() usernames = ['abe', 'bort', 'charlie'] users = [] b = backend.KegbotBackend() for name in usernames: users.append(b.CreateNewUser(name)) half_barrel = models.KegSize(name="half barrel", volume_ml=10000) half_barrel.save() k = models.Keg(type=as_pa, size=half_barrel, status='online', origcost=100) k.save() drink_base = datetime.datetime(2007, 1, 1, 8, 0, 0) drink_interval = datetime.timedelta(seconds=600) drink_num = 0 drink_vols = [] for ml in (2200, 1100, 550, 715, 780): drink_vols.append( units.Quantity(ml, from_units=units.UNITS.KbMeterTick)) # generate some drinks times = (drink_base, drink_base + datetime.timedelta(days=1)) for drink_time in times: for rounds in range(3): for u in users: start = drink_time + drink_num * drink_interval end = start + datetime.timedelta(seconds=10) vol = drink_vols[drink_num % len(drink_vols)] drink = models.Drink(ticks=vol.InKbMeterTicks(), volume_ml=vol.Amount(units.RECORD_UNIT), starttime=start, user=u, keg=k, status='valid') drink.save() drink_num += 1 # fake thermo data thermo_start = datetime.datetime.now() - datetime.timedelta(hours=24) sensor_name = "thermo-0000000000000000" sensor = models.ThermoSensor.objects.create(raw_name=sensor_name, nice_name='Test sensor') for minute in xrange(60 * 24): temp_time = thermo_start + datetime.timedelta(minutes=minute) slot = (minute + 1) / 30.0 var = math.cos(2 * math.pi * slot) temp_value = 5.0 + 2.0 * var record = models.Thermolog(sensor=sensor, temp=temp_value, time=temp_time) record.save()