def _calculate_lap_total(laps: List[LapStatus]) -> LapStatus: start_lap = laps[0] end_lap = laps[-1] total_status = LapStatus(id=f"{start_lap.id} - {end_lap.id}", startTimePit=start_lap.startTimePit, endTimePit=start_lap.endTimePit, startTime=start_lap.startTime, endTime=end_lap.endTime, startOdo=start_lap.startOdo, endOdo=end_lap.endOdo, insideTemp=end_lap.insideTemp, outsideTemp=end_lap.outsideTemp, startSOC=start_lap.startSOC, endSOC=end_lap.endSOC, startRangeIdeal=start_lap.startRangeIdeal, endRangeIdeal=end_lap.endRangeIdeal, startRangeEst=start_lap.startRangeEst, endRangeEst=end_lap.endRangeEst, startRangeRated=start_lap.startRangeRated, endRangeRated=end_lap.endRangeRated, consumptionRated=start_lap.consumptionRated, finished=False) # TODO calculate energy as sum energy = 0 chargeSocAdded = 0 chargeEnergyAdded = 0 chargeRangeAdded = 0 now = pendulum.now(tz='utc') duration = pendulum.Period(now, now) pit_duration = pendulum.Period(now, now) chargeDuration = pendulum.Period(now, now) for lap in laps: energy += lap.energy duration += lap.duration pit_duration += lap.pitDuration chargeSocAdded += lap.chargeSocAdded if lap.chargeSocAdded else 0 chargeEnergyAdded += lap.chargeEnergyAdded if lap.chargeEnergyAdded else 0 chargeRangeAdded += lap.chargeRangeRatedAdded if lap.chargeRangeRatedAdded else 0 chargeDuration += lap.chargeDuration if lap.chargeDuration else pendulum.Period( now, now) total_status.energy = energy total_status.duration = duration total_status.pitDuration = pit_duration total_status.chargeSocAdded = chargeSocAdded total_status.chargeEnergyAdded = chargeEnergyAdded total_status.chargeRangeRatedAdded = chargeEnergyAdded total_status.chargeDuration = chargeDuration return total_status
def get_graph_charging_lap_data(): lap_id = request.args.get('lap') field = request.args.get('field') laps = data_processor.get_laps_raw() lap = laps[int(lap_id) if lap_id else -1] lap_data = lap['lap_data'] lap_chargings = data_processor.get_car_chargings(int(lap_id)) charges = lap_chargings[0]['charges'] graph_periods = [ pendulum.Period(charges[0]['date'], charge['date']) for charge in charges ] graph_labels = [ f"{raw_value.hours:02d}:{raw_value.minutes:02d}:{raw_value.remaining_seconds:02d}" for raw_value in graph_periods ] graph_data = [ float(charge[field]) if charge[field] is not None else None for charge in charges ] return _jsonify({ "labels": graph_labels, "values": graph_data, 'raw': lap_chargings })
def test_split_job(self, mocker, api, edge_class, next_edge_class, id_field): """Test that split will correctly downsize edge_object""" interval = pendulum.Period(pendulum.Date(2010, 1, 1), pendulum.Date(2010, 1, 10)) params = {"time_increment": 1, "breakdowns": []} job = InsightAsyncJob(api=api, edge_object=edge_class(1), interval=interval, params=params) mocker.patch.object(edge_class, "get_insights", return_value=[{ id_field: 1 }, { id_field: 2 }, { id_field: 3 }]) small_jobs = job.split_job() edge_class.get_insights.assert_called_once() assert len(small_jobs) == 3 assert all(j.interval == job.interval for j in small_jobs) for i, small_job in enumerate(small_jobs, start=1): assert str( small_job ) == f"InsightAsyncJob(id=<None>, {next_edge_class(i)}, time_range={job.interval}, breakdowns={[]})"
def test_read_records_all(self, mocker, api): """1. yield all from mock 2. if read slice 2, 3 state not changed if read slice 2, 3, 1 state changed to 3 """ job = mocker.Mock(spec=InsightAsyncJob) job.get_result.return_value = [ mocker.Mock(), mocker.Mock(), mocker.Mock() ] job.interval = pendulum.Period(pendulum.date(2010, 1, 1), pendulum.date(2010, 1, 1)) stream = AdsInsights( api=api, start_date=datetime(2010, 1, 1), end_date=datetime(2011, 1, 1), insights_lookback_window=28, ) records = list( stream.read_records( sync_mode=SyncMode.incremental, stream_slice={"insight_job": job}, )) assert len(records) == 3
def test_expiry_delta(self, dummy_user: auth.User): expiry_delta = timedelta(hours=1) token = auth.AuthToken.create(dummy_user, expiry_delta=expiry_delta) payload = auth.AuthToken.verify(token) iat = pendulum.from_timestamp(payload['iat']) exp = pendulum.from_timestamp(payload['exp']) assert pendulum.Period(start=iat, end=exp).as_timedelta() == expiry_delta
def should_turn_on(self): if self.start_at is None or self.ends_at is None: return True date_start = pendulum.now().replace(hour=self.start_at.hour, minute=self.start_at.minute) date_end = pendulum.now().replace(hour=self.ends_at.hour, minute=self.ends_at.minute) period = pendulum.Period(date_start, date_end) return now() in period
def _table_header(self): """Generate header for COUNTER table for report, as list of cells.""" header_cells = list(HEADER_FIELDS[self.report_type]) start_month_first_day = datetime.date( self.period[0].year, self.period[0].month, 1 ) for d_obj in pendulum.Period(start_month_first_day, self.period[1]).range( "months" ): header_cells.append(d_obj.strftime("%b-%Y")) return header_cells
def test_slice_gen(): start_date = TEST_DATE generator = AdjustableSliceGenerator(start_date) dates = [] for i in generator: dates.append(i) generator.adjust_range( pendulum.Period(start=start_date, end=start_date)) assert dates days = [(slice.end_date - slice.start_date).total_days() for slice in dates] assert days[1] == AdjustableSliceGenerator.DEFAULT_RANGE_DAYS
def test_str(self, api, account): interval = pendulum.Period(pendulum.Date(2010, 1, 1), pendulum.Date(2011, 1, 1)) job = InsightAsyncJob( edge_object=account, api=api, params={"breakdowns": [10, 20]}, interval=interval, ) assert str( job ) == f"InsightAsyncJob(id=<None>, {account}, time_range=<Period [2010-01-01 -> 2011-01-01]>, breakdowns=[10, 20])"
def test_between(self): times = [time(12, 00), time(23, 00)] timedeltas = [ timedelta(hours=1), timedelta(days=1), timedelta(days=2), timedelta(days=3), timedelta(days=6), ] for t in times: for weekday in WEEKDAYS: day = weekday[0] for delta in timedeltas: openingperiod = OpeningPeriod.objects.create( store=self.store, day=day, time=t, duration=delta) period = openingperiod.period( OpeningPeriod.weekday_as_datetime(weekday=day, time=t, store=self.store)) period_before = pendulum.Period( start=period.start - timedelta(seconds=2), end=period.start - timedelta(seconds=1), ) period_over_start = pendulum.Period( start=period_before.start, end=period.start + timedelta(seconds=1)) period_in = pendulum.Period( start=period.start + timedelta(seconds=1), end=period.end - timedelta(seconds=1), ) period_over_end = pendulum.Period( start=period.end - timedelta(seconds=1), end=period.end + timedelta(seconds=1), ) period_after = pendulum.Period( start=period.end + timedelta(seconds=1), end=period.end + timedelta(seconds=2), ) period_over = pendulum.Period( start=period.start - timedelta(seconds=1), end=period.end + timedelta(seconds=1), ) for p in [period_before, period_after]: periods = OpeningPeriod.objects.between(period=p) self.assertEqual(len(periods), 0) for p in [ period_over_start, period_in, period_over_end, period_over ]: periods = OpeningPeriod.objects.between(period=p) self.assertEqual(len(periods), 1) openingperiod.delete()
def _fill_months(self): """Ensure each month in period represented and zero fill if not.""" start_month_first_day = datetime.date( self.period[0].year, self.period[0].month, 1 ) start, end = start_month_first_day, self.period[1] try: for d_obj in pendulum.Period(start, end).range("months"): if d_obj not in (x[0] for x in self._full_data): self._full_data.append((d_obj, 0)) except IndexError: # pragma: nocover pass else: self._full_data.sort()
def test_split_job_smallest(self, mocker, api): """Test that split will correctly downsize edge_object""" interval = pendulum.Period(pendulum.Date(2010, 1, 1), pendulum.Date(2010, 1, 10)) params = {"time_increment": 1, "breakdowns": []} job = InsightAsyncJob(api=api, edge_object=Ad(1), interval=interval, params=params) with pytest.raises( ValueError, match="The job is already splitted to the smallest size."): job.split_job()
def weekdays(self): now = pendulum.now().at(hour=self.time.hour, minute=self.time.minute, second=self.time.second, microsecond=self.time.microsecond) start = now.subtract(days=now.isoweekday()).add(days=self.day) period = pendulum.Period(start=start, end=start + self.duration) result = set() for day in period.xrange('days'): weekday = day.isoweekday() if weekday in result: break result.add(weekday) return result
def job_fixture(api, account): params = { "level": "ad", "action_breakdowns": [], "breakdowns": [], "fields": ["field1", "field2"], "time_increment": 1, "action_attribution_windows": [], } interval = pendulum.Period(pendulum.Date(2019, 1, 1), pendulum.Date(2019, 1, 1)) return InsightAsyncJob(edge_object=account, api=api, interval=interval, params=params)
def _generate_async_jobs(self, params: Mapping) -> Iterator[AsyncJob]: """Generator of async jobs :param params: :return: """ for ts_start in self._date_intervals(): if ts_start in self._completed_slices: continue ts_end = ts_start + pendulum.duration(days=self.time_increment - 1) interval = pendulum.Period(ts_start, ts_end) yield InsightAsyncJob(api=self._api.api, edge_object=self._api.account, interval=interval, params=params)
def convertPendulum(request, template, resource): ''' Converts request.from request.to and template.period in pendulum :param resource: a resource class :param request: a request class :param template: a template class :return: 3 pendulum from from_date,to_date and period ''' expirationtime = None print(type(request.from_date)) startime = pendulum.parse(request.from_date) endtime = pendulum.parse(request.to_date) if resource.to_date != None: expirationtime = pendulum.parse(resource.to_date) period = pendulum.Period(startime, startime.add(weeks=template.period)) return startime, endtime, period, expirationtime
def get_graph_data_lap(): lap_id = request.args.get('lap') field = request.args.get('field') laps = data_processor.get_laps_raw() lap = laps[int(lap_id) if lap_id else -1] lap_data = lap['lap_data'] graph_periods = [ pendulum.Period(lap_data[0]['date'], item['date']) for item in lap_data ] graph_labels = [ f"{raw_value.hours:02d}:{raw_value.minutes:02d}:{raw_value.remaining_seconds:02d}" for raw_value in graph_periods ] graph_data = [ float(item[field]) if item[field] is not None else None for item in lap_data ] return _jsonify({"labels": graph_labels, "values": graph_data})
def _totals_line(self, metric): """Generate Totals for a given metric.""" total_cells = [TOTAL_TEXT[self.report_type]] publishers = {resource.publisher for resource in self.pubs} if len(publishers) == 1: total_cells.append(publishers.pop()) else: total_cells.append("") platforms = {resource.platform for resource in self.pubs} if len(platforms) == 1: total_cells.append(platforms.pop()) else: total_cells.append("") if self.report_type in ("JR1", "BR1", "BR2", "JR2", "BR3"): total_cells.extend([""] * 4) if self.report_type in ("DB2", "JR2", "BR3"): total_cells.append(metric) total_usage = 0 pdf_usage = 0 html_usage = 0 start_month_first_day = datetime.date( self.period[0].year, self.period[0].month, 1 ) months = list( pendulum.Period(start_month_first_day, self.period[1]).range("months") ) month_data = [0] * len(months) for pub in self.pubs: if pub.metric != metric: continue if self.report_type == "JR1": pdf_usage += pub.pdf_total # pytype: disable=attribute-error html_usage += pub.html_total # pytype: disable=attribute-error for data in pub: total_usage += data[2] month_data[months.index(data[0])] += data[2] total_cells.append(str(total_usage)) if self.report_type == "JR1": total_cells.append(str(html_usage)) total_cells.append(str(pdf_usage)) total_cells.extend(str(d) for d in month_data) return total_cells
def period(self): period = pendulum.Period(start=self.start, end=self.end) period.closed = self.closed return period
def schedulePPendulum(request, resource, template, aged): errors = {} u = generateXMLDoc(aged) r = generateXMLDoc(resource) c = None # per ora non usato template.message_structure templateInfo = {} templateInfo['tags'] = template.message_structure #todo il tone e' da aggiungere come parametro alla classe template--> template.tone #templateInfo['tone'] = template.tone templateInfo['tone'] = "Neutral" if type(request.from_date) is not Pendulum: times = convertPendulum(request, template, resource) startime = times[0] endtime = times[1] period = times[2] expirationtime = times[3] else: startime = request.from_date endtime = request.to_date period = pendulum.Period(startime, startime.add(weeks=template.period)) expirationtime = resource.to_date if expirationtime == None: expirationtime = endtime valid_interval = endtime - startime if valid_interval > period: valid_interval = period if template.nmsgmin != template.nmsgmax: nmsg = rnd.randrange(template.nmsgmin, template.nmsgmax + 1) else: nmsg = template.nmsgmax miniplan = [Message(count, aged.aged_id, intervention_session_id=1) for count in xrange(nmsg)] miniplanID = uuid.uuid4() channels = getChannelsAvailable(template, aged) with open('csv/prova_import_messages.csv') as csvmessages: messages = csv.DictReader(csvmessages) msgs_tosend = getListMessages(messages, nmsg, resource, channels) er = checkForErrors(errors, endtime, expirationtime, startime, miniplan, nmsg, len(msgs_tosend)) errors = er[0] miniplan = er[1] if er[2]: endtime = er[3] else: return errors, miniplan day_of_event = mapDay(resource.on_day) if day_of_event == None: errors['ErrorNoDay'] = 'Error no day specified for periodic messages' miniplan = [] return errors, miniplan # length of the loop depending on the msgs found if len(msgs_tosend) < nmsg: lenloop = len(msgs_tosend) else: lenloop = nmsg c = 0 i = 0 for dt in valid_interval.range("days"): if dt.day_of_week == day_of_event: if c % int(resource.every) == 0: if i > lenloop: break miniplan[i].miniplan_id = miniplanID miniplan[i].date = dt.date() miniplan[i].time_1 = dt.date() miniplan[i].time_2 = dt.subtract(days=1).date() miniplan[i].time = scheduleHour(aged, None) miniplan[i].attached_audio = msgs_tosend[i]['Audio'] miniplan[i].attached_media = msgs_tosend[i]['Media'] miniplan[i].URL = msgs_tosend[i]['URL'] miniplan[i].channel = msgs_tosend[i]['Channel'] #miniplan[i].message_text = generate_message_text(aged, msgs_tosend[i]['Text'],msgs_tosend[i]['URL']) message_body = msgs_tosend[i]['Text'] m = createMessageJson(message_body, templateInfo) miniplan[i].message_text = composeMessage(u, r, c, m) miniplan[i].intervention_session_id = request.intervention_session_id miniplan[i].pilot_id = request.pilot_id i += 1 c += 1 miniplan = checkMsgsOneDay(miniplan, endtime) return errors, miniplan
def schedule(request, resource, template, aged): print "_______________SCHEDULE_______________" errors = {} if type(request.from_date) is not Pendulum: times = convertPendulum(request, template, resource) startime = times[0] endtime = times[1] period = times[2] expirationtime = times[3] else: startime = request.from_date endtime = request.to_date period = pendulum.Period(startime, startime.add(weeks=template.period)) expirationtime = resource.to_date if expirationtime == None: expirationtime = endtime if template.nmsgmin != template.nmsgmax and template.nmsgmax > template.nmsgmin: nmsg = rnd.randrange(template.nmsgmin, template.nmsgmax + 1) else: nmsg = template.nmsgmax # creates miniplan that is a list of messages miniplan = [Message(count, aged.aged_id, intervention_session_id=1) for count in xrange(nmsg)] channels = getChannelsAvailable(template, aged) ''' with open('csv/prova_import_messages.csv') as csvmessages: messages = csv.DictReader(csvmessages) msgs_tosend = getListMessages(messages, nmsg, resource, channels) ''' messages = getResourceMessages(resource.resource_id) msgs_tosend = selectMessages(messages, nmsg, channels) er = checkForErrors(errors, endtime, None, startime, miniplan, nmsg, len(msgs_tosend)) errors = er[0] miniplan = er[1] if er[2]: endtime = er[3] else: return errors, miniplan # length of the loop depending on the msgs found if len(msgs_tosend) < nmsg: lenloop = len(msgs_tosend) else: lenloop = nmsg for i in range(0, lenloop): miniplan[i].message_text = generate_message_text(aged, msgs_tosend[i]['Text'], msgs_tosend[i]['URL']) miniplan[i].attached_audio = msgs_tosend[i]['Audio'] miniplan[i].attached_media = msgs_tosend[i]['Media'] miniplan[i].URL = msgs_tosend[i]['URL'] miniplan[i].channel = msgs_tosend[i]['Channel'] miniplan = ED(miniplan, lenloop, startime, endtime, period, aged) miniplan = checkMsgsOneDay(miniplan, endtime) return errors, miniplan
def scheduleLPendulum(request, resource, template, aged): print "_______________SCHEDULEPENDULUM_______________" ''' Returns the miniplan scheduled with more frequency at the end of the interval It divides the interval for every msg with logaritmic growth:1 1/2 1/3 1/4 Check on period(valid weeks): if request interval is larger that period then user period as interval Last message always sent the day before the event With Pendulum :param request: a request class :param template: a template class :param aged: a user class :return: a miniplan that is a list of messages class with all the fields completed ''' errors = {} miniplanID = uuid.uuid4() u = generateXMLDoc(aged) r = generateXMLDoc(resource) c = None # per ora non usato # todo: tenuta provvisoria per la demo, bisogna stabilire una struttura standard templateInfo = {} templateInfo['tags'] = template.message_structure templateInfo['tone'] = "Neutral" if type(request.from_date) is not Pendulum: times = convertPendulum(request, template, resource) startime = times[0] endtime = times[1] period = times[2] expirationtime = times[3] else: startime = request.from_date endtime = request.to_date period = pendulum.Period(startime, startime.add(weeks=template.period)) expirationtime = resource.to_date if expirationtime == None: expirationtime = endtime if template.nmsgmin != template.nmsgmax: nmsg = rnd.randrange(template.nmsgmin, template.nmsgmax + 1) else: nmsg = template.nmsgmax miniplan = [Message(count, aged.aged_id, intervention_session_id=1) for count in xrange(nmsg)] valid_interval = endtime - startime if valid_interval > period: errors['Interval changed'] = 'Duration of the template(' + str( period) + ') less than interval set by the care giver' valid_interval = period channels = getChannelsAvailable(template, aged) messages = getResourceMessages(resource.resource_id) if messages is None: errors = {'Error': 'Messages not found'} miniplan = {} return errors, miniplan msgs_tosend = selectMessages(messages, nmsg, channels) ''' with open('csv/prova_import_messages.csv') as csvmessages: messages = csv.DictReader(csvmessages) msgs_tosend = getListMessages(messages, nmsg, resource, channels) ''' er = checkForErrors(errors, endtime, expirationtime, startime, miniplan, nmsg, len(msgs_tosend)) errors = er[0] miniplan = er[1] if er[2]: endtime = er[3] else: return errors, miniplan # length of the loop depending on the msgs found if len(msgs_tosend) < nmsg: lenloop = len(msgs_tosend) else: lenloop = nmsg for i in range(0, lenloop): date = endtime - valid_interval miniplan[i].miniplan_id = miniplanID miniplan[i].date = date.date() miniplan[i].time_1 = date.date() miniplan[i].time_2 = date.add(days=1).date() miniplan[i].time = scheduleHourFromDate(aged, date).time() # miniplan[i].message_text = buildMessage(aged, msgs_tosend[i]) message_body = msgs_tosend[i]['Text'] m = createMessageJson(message_body, templateInfo) miniplan[i].message_text = composeMessage(u, r, c, m) miniplan[i].attached_audio = msgs_tosend[i].audio miniplan[i].attached_media = msgs_tosend[i].media miniplan[i].URL = msgs_tosend[i].url miniplan[i].message_id = msgs_tosend[i].message_id miniplan[i].channel = msgs_tosend[i].channels[0]['channel_name'] miniplan[i].intervention_session_id = request.intervention_session_id miniplan[i].pilot_id = request.pilot_id valid_interval = valid_interval / (i + 2) miniplan = checkMsgsOneDayPendulum(miniplan, endtime) return errors, miniplan
def scheduleEDPPendulum(request, resource, template, aged): print "_______________SCHEDULEEDPPENDULUM_______________" ''' Returns the miniplan with the temporal interval between the msgs divided equally with Pendulum :param request: a request class :param template: a template class :param aged: a user class :return: a miniplan that is a list of messages class with all the fields completed ''' errors = {} miniplanID = uuid.uuid4() u = generateXMLDoc(aged) r = generateXMLDoc(resource) c = None # per ora non usato #todo: tenuta provvisoria per la demo, bisogna stabilire una struttura standard templateInfo = {} templateInfo['tags'] = template.message_structure templateInfo['tone'] = "Neutral" if type(request.from_date) is not Pendulum: times = convertPendulum(request, template, resource) startime = times[0] endtime = times[1] period = times[2] else: startime = request.from_date endtime = request.to_date period = pendulum.Period(startime, startime.add(weeks=template.period)) valid_interval = endtime - startime if valid_interval > period: errors['Interval changed'] = 'Duration of the template(' + str( period) + ') less than interval set by the care giver' valid_interval = period if template.nmsgmin != template.nmsgmax and template.nmsgmax > template.nmsgmin: nmsg = rnd.randrange(template.nmsgmin, template.nmsgmax + 1) else: nmsg = template.nmsgmax # creates miniplan that is a list of messages miniplan = [Message(count, aged.aged_id, intervention_session_id=1) for count in xrange(nmsg)] channels = getChannelsAvailable(template, aged) messages = getResourceMessages(resource.resource_id) if messages is None: errors = {'Error': 'Messages not found'} miniplan = {} return errors, miniplan msgs_tosend = selectMessages(messages, nmsg, channels) er = checkForErrors(errors, endtime, None, startime, miniplan, nmsg, len(msgs_tosend)) errors = er[0] miniplan = er[1] if er[2]: endtime = er[3] else: return errors, miniplan # length of the loop depending on the msgs found if len(msgs_tosend) < nmsg: lenloop = len(msgs_tosend) else: lenloop = nmsg step_send_msg = valid_interval / lenloop date = startime + (step_send_msg / 2) for i in range(0, lenloop): miniplan[i].miniplan_id = miniplanID miniplan[i].date = date.date() miniplan[i].time = scheduleHour(aged, None) miniplan[i].message_text = buildMessage(aged, msgs_tosend[i]) message_body = msgs_tosend[i]['Text'] m = createMessageJson(message_body, templateInfo) miniplan[i].message_text = composeMessage(u, r, c, m) miniplan[i].attached_audio = msgs_tosend[i].audio miniplan[i].attached_media = msgs_tosend[i].media miniplan[i].URL = msgs_tosend[i].url miniplan[i].channel = msgs_tosend[i].channels[0]['channel_name'] miniplan[i].time_1 = date.date() miniplan[i].time_2 = date.add(days=1).date() miniplan[i].intervention_session_id = request.intervention_session_id miniplan[i].pilot_id = request.pilot_id date += step_send_msg miniplan = checkMsgsOneDay(miniplan, endtime) return errors, miniplan
def _update_car_laps(): global _car_laps_list global _car_laps_formatted global _get_configuration_func global _car_charging_processes logger.debug("updating car laps") configuration = _get_configuration_func() positions = _data_source.get_car_positions(configuration) _car_laps_list = lap_analyzer.find_laps(configuration, positions, configuration.startRadius, 0, 0) _car_charging_processes = _data_source.get_charging_processes( configuration) # load driver names dates = [l.startTime for l in _car_laps_list] if dates: driver_map = _data_source.get_driver_changes(configuration, dates) for l in _car_laps_list: if l.startTime in driver_map: l.driver_name = driver_map[l.startTime].name # fill charging data for l in _car_laps_list: for charging in _car_charging_processes: if not charging.end_date: continue # incomplete records - they are visible in the db from time to time charging.start_date = charging.start_date.replace( tzinfo=timezone.utc) charging.end_date = charging.end_date.replace(tzinfo=timezone.utc) if l.startTimePit <= charging.start_date and ( not l.endTimePit or l.endTimePit > charging.start_date): # set the value l.chargeStartTime = pendulum.from_timestamp( charging.start_date.timestamp()) l.chargeEndTime = pendulum.from_timestamp( charging.end_date.timestamp()) l.chargeEnergyAdded = charging.charge_energy_added l.chargeStartSoc = charging.start_battery_level l.chargeEndSoc = charging.end_battery_level l.chargeStartRangeRated = charging.start_rated_range_km l.chargeEndRangeRated = charging.end_rated_range_km l.chargeRangeRatedAdded = charging.end_rated_range_km - charging.start_rated_range_km # the validator doesn't fill it for some reason l.chargeSocAdded = charging.end_battery_level - charging.start_battery_level # the validator doesn't fill it for some reason l.chargeDuration = pendulum.Period(charging.start_date, charging.end_date) break # load only one charging total_lap = _calculate_lap_total( _car_laps_list) if _car_laps_list else None recent_lap = _car_laps_list[-1] if _car_laps_list else None prev_lap_list = _car_laps_list[-configuration.previousLaps - 1:-1] if len(_car_laps_list) > 0 else [] prev_lap_list.reverse() # to have newest on top total_formatted = generate_labels(_get_configuration_func().lapLabelsTotal, total_lap.dict()) previous_formatted = [ generate_labels(_get_configuration_func().lapLabelsPrevious, lap.dict()) for lap in prev_lap_list ] recent_formatted = generate_labels( _get_configuration_func().lapLabelsRecent, recent_lap.dict()) _car_laps_formatted = JsonLapsResponse(total=total_formatted, previous=previous_formatted, recent=recent_formatted) logger.debug("updating car laps done")
def scheduleEDPPendulum(request, resource, template, aged): ''' Returns the miniplan with the temporal interval between the msgs divided equally with Pendulum :param request: a request class :param template: a template class :param aged: a user class :return: a miniplan that is a list of messages class with all the fields completed ''' errors = {} miniplanID = uuid.uuid4() if type(request.from_date) is not Pendulum: times = convertPendulum(request, template, resource) startime = times[0] endtime = times[1] period = times[2] else: startime = request.from_date endtime = request.to_date period = pendulum.Period(startime, startime.add(weeks=template.period)) valid_interval = endtime - startime if valid_interval > period: errors['Interval changed'] = 'Duration of the template(' + str( period) + ') less than interval set by the care giver' valid_interval = period if template.nmsgmin != template.nmsgmax and template.nmsgmax > template.nmsgmin: nmsg = rnd.randrange(template.nmsgmin, template.nmsgmax + 1) else: nmsg = template.nmsgmax # creates miniplan that is a list of messages miniplan = [ Message(count, aged.aged_id, intervention_session_id=1) for count in xrange(nmsg) ] channels = getChannelsAvailable(template, aged) ''' with open('csv/prova_import_messages.csv') as csvmessages: messages = csv.DictReader(csvmessages) msgs_tosend = getListMessages(messages, nmsg, resource, channels) ''' messages = getResourceMessages(resource.resource_id) if messages is None: errors = {'Error': 'Messages not found'} miniplan = {} return errors, miniplan msgs_tosend = selectMessages(messages, nmsg, channels) er = checkForErrors(errors, endtime, None, startime, miniplan, nmsg, len(msgs_tosend)) errors = er[0] miniplan = er[1] if er[2]: endtime = er[3] else: return errors, miniplan # length of the loop depending on the msgs found if len(msgs_tosend) < nmsg: lenloop = len(msgs_tosend) else: lenloop = nmsg step_send_msg = valid_interval / lenloop date = startime + (step_send_msg / 2) for i in range(0, lenloop): miniplan[i].miniplan_id = miniplanID miniplan[i].date = date.date() miniplan[i].time = scheduleHour(aged, None) miniplan[i].message_text = buildMessage(aged, msgs_tosend[i]) miniplan[i].attached_audio = msgs_tosend[i].audio miniplan[i].attached_media = msgs_tosend[i].media miniplan[i].URL = msgs_tosend[i].url miniplan[i].channel = msgs_tosend[i].channels[0]['channel_name'] miniplan[i].time_1 = date.date() miniplan[i].time_2 = date.add(days=1).date() miniplan[i].intervention_session_id = request.intervention_session_id miniplan[i].pilot_id = request.pilot_id date += step_send_msg miniplan = checkMsgsOneDay(miniplan, endtime) return errors, miniplan
def set_charge_energy_added(cls, v, values) -> pendulum.Duration: return values['chargeEndTime'] - values['chargeStartTime'] if values[ 'chargeEndTime'] and values['chargeStartTime'] else pendulum.Period( pendulum.now(), pendulum.now())
def parent_job_fixture(api, grouped_jobs): interval = pendulum.Period(pendulum.Date(2019, 1, 1), pendulum.Date(2019, 1, 1)) return ParentAsyncJob(api=api, jobs=grouped_jobs, interval=interval)
def add_calculated_fields(*, current_item: Dict[str, Any], initial_status, current_status, position_list, lap_list, total, charging_process_list, forecast, configuration: Configuration, current_item_index: Optional[int], now_dt: pendulum.DateTime): """ Add hardcoded calculated fields into current_item Note the prototype is the same for all calculated functions even if all inputs are not used :param current_item: :param initial_status: :param current_status: :param position_list: :param lap_list: :param total: :param charging_process_list: :param forecast: :param configuration: :param current_item_index: :param now_dt: time to calculate data for. :return: """ if not lap_list: return logger.info(f"{len(lap_list)} laps on forecast input") unfinished_lap = lap_list[ -1] if lap_list and not lap_list[-1]['finished'] else None logger.debug(f"unfinished lap: {unfinished_lap is not None}") car_laps = lap_list[:-1] if not car_laps: return None logger.info(f"{len(car_laps)} laps to analyze") start_time = configuration.start_time end_time = configuration.start_time.add(hours=configuration.hours) time_since_start = now_dt - start_time if now_dt > start_time else pendulum.period( now_dt, now_dt) time_to_end = end_time - now_dt if now_dt < end_time else pendulum.period( now_dt, now_dt) distance_since_start = \ current_status['distance'] if current_status and 'distance' in current_status and current_status['distance'] is not None else 0.0 # print(f"from start: {time_since_start.in_hours()}, to end: {time_to_end.in_hours()}, dist: {distance_since_start}") avg_lap_time = pendulum.Period(now_dt, now_dt) avg_pit_time = pendulum.Period(now_dt, now_dt) avg_lap_distance = 0 for lap in car_laps: avg_lap_time += lap['lap_duration'] avg_pit_time += lap['pit_duration'] avg_lap_distance += lap['distance'] logger.info( f"sum lap time {avg_lap_time}, sum lap distance {avg_lap_distance}") avg_lap_time /= len(car_laps) avg_pit_time /= len(car_laps) avg_lap_distance /= len(car_laps) # print(f"avg lap time {avgLapTime}, avg pit time: {avgPitTime}, avg lap distance {avgLapDistance}") # print(f"avg lap time {avgLapTime}, avg lap distance {avgLapDistance}") unfinished_lap_remaining_time = pendulum.Period(now_dt, now_dt) unfinished_lap_remaining_distance = 0 # calculate time and dist for the unfinished lap # print(f"unfinished lap duration {unfinished_lap.duration} vs avg {avgLapTime}") if unfinished_lap and unfinished_lap['lap_duration'] < avg_lap_time: unfinished_lap_remaining_time = avg_lap_time - unfinished_lap[ 'lap_duration'] # print(f"unfinished lap time remaining time: {unfinished_lap_remaining_time}") if unfinished_lap and unfinished_lap['distance'] < avg_lap_distance: unfinished_lap_remaining_distance = avg_lap_distance - unfinished_lap[ 'distance'] # print(f"unfinished lap time remaining distance: {unfinished_lap_remaining_time}") time_to_forecast = time_to_end if unfinished_lap_remaining_time: time_to_forecast -= unfinished_lap_remaining_time # print(f"time to forecast: {timeToForecast.in_hours()}") full_laps_remaining = int(time_to_forecast / (avg_lap_time + avg_pit_time)) # print(f"laps to go: {fullLapsRemaining}") remaining_last_lap_time = time_to_forecast - full_laps_remaining * ( avg_lap_time + avg_pit_time) # time left after max possible full laps # print(f"last lap time: {remaining_last_lap_time}") coef = remaining_last_lap_time / (avg_lap_time + avg_pit_time) # print(f"coef: {coef}") last_lap_duration = avg_lap_time * coef # print(f"last lap duration: {last_lap_duration}") last_pit_duration = avg_pit_time * coef # print(f"last pit duration : {last_pit_duration}") last_lap_distance = avg_lap_distance * coef # print(f"last lap distance: {last_lap_distance}") total_estimated_distance = distance_since_start + unfinished_lap_remaining_distance + full_laps_remaining * avg_lap_distance + last_lap_distance # print(f"total estimated distance: {total_estimated_distance}") current_item['avg_lap_duration'] = avg_lap_time current_item['avg_pit_duration'] = avg_pit_time current_item['avg_full_duration'] = avg_lap_time + avg_pit_time current_item['avg_lap_distance'] = avg_lap_distance current_item[ 'unfinished_lap_remaining_time'] = unfinished_lap_remaining_time current_item[ 'unfinished_lap_remaining_distance'] = unfinished_lap_remaining_distance current_item['full_laps_remaining'] = full_laps_remaining current_item['last_lap_duration'] = last_lap_duration current_item['last_pit_duration'] = last_pit_duration current_item['last_full_duration'] = last_lap_duration + last_pit_duration current_item['last_lap_distance'] = last_lap_distance current_item['total_estimated_distance'] = total_estimated_distance # add best lap metric (best full avg speed best_lap_id = None best_avg_speed = 0 best_full_duration = time_since_start best_lap_distance = 0 for lap in car_laps: if 'full_avg_speed' in lap and lap['full_avg_speed'] > best_avg_speed: best_avg_speed = lap['full_avg_speed'] best_lap_id = lap['lap_id'] best_full_duration = lap['full_duration'] best_lap_distance = lap['distance'] current_item['best_lap'] = best_lap_id best_full_laps_remaining = int(time_to_forecast / best_full_duration) # print(f"laps to go: {fullLapsRemaining}") best_remaining_last_lap_time = time_to_forecast - best_full_laps_remaining * best_full_duration # time left after max possible full laps # print(f"last lap time: {remaining_last_lap_time}") best_coef = best_remaining_last_lap_time / best_full_duration # print(f"coef: {coef}") best_last_lap_distance = best_lap_distance * best_coef # print(f"last lap distance: {last_lap_distance}") best_estimated_distance = distance_since_start + unfinished_lap_remaining_distance + best_full_laps_remaining * best_lap_distance + best_last_lap_distance current_item['best_estimated_distance'] = best_estimated_distance
def period(self, day): return pendulum.Period(start=self.start(day), end=self.end(day))