public void GetCharginSessions_OneChargingSession() { // Arrange var timeline = new MessageTimeline(new ICanBusMessage[] { new BatteryPowerMessage(_batteryPower), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Build(), new BatteryInfoMessage(_chargingStarted), new BatteryPowerMessage(_batteryPower), new StateOfChargeMessage(_stateOfCharge), new BatteryPowerMessage(_batteryPower), new BatteryInfoMessage(_chargingStopped), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 1, DateTimeKind.Utc)).Build(), }); // Act var sessions = new ChargingSessionFilter().GetChargingSessions(timeline).ToList(); // Assert sessions.Count.Should().Be(1); sessions[0].Select(m => m.Value.GetType()).Should().BeEquivalentTo( typeof(BatteryInfoMessage), typeof(BatteryPowerMessage), typeof(StateOfChargeMessage), typeof(BatteryPowerMessage)); }
public void GetCharginSessions_NoChargingSession() { // Arrange var timeline = new MessageTimeline(new ICanBusMessage[] { new BatteryPowerMessage(_batteryPower), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Build(), new BatteryPowerMessage(_batteryPower), new StateOfChargeMessage(_stateOfCharge), new BatteryPowerMessage(_batteryPower), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 1, DateTimeKind.Utc)).Build(), }); // Act var sessions = new ChargingSessionFilter().GetChargingSessions(timeline); // Assert sessions.Should().BeEmpty(); }
public void InterpolateTime() { // Arrange var timeline = new MessageTimeline(new ICanBusMessage[] { new BatteryPowerMessage(_batteryPowerPayload), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Build(), new BatteryPowerMessage(_batteryPowerPayload), new BatteryPowerMessage(_batteryPowerPayload), new BatteryPowerMessage(_batteryPowerPayload), new TimestampMessageBuilder(new DateTime(2019, 1, 1, 0, 0, 1, DateTimeKind.Utc)).Build(), }); // Act _timelineInterpolator.InterpolateTime(timeline); // Assert timeline[0].Timestamp.Should().BeNull(); timeline[2].Timestamp.Should().Be(new DateTime(2019, 1, 1, 0, 0, 0, 250, DateTimeKind.Utc)); timeline[3].Timestamp.Should().Be(new DateTime(2019, 1, 1, 0, 0, 0, 500, DateTimeKind.Utc)); timeline[4].Timestamp.Should().Be(new DateTime(2019, 1, 1, 0, 0, 0, 750, DateTimeKind.Utc)); }
public async Task <MessageTimeline> ReadFromCanBusLog(StreamReader reader, bool interpolateTime) { var timeLine = new MessageTimeline(); string line; while ((line = await reader.ReadLineAsync()) != null) { if (string.IsNullOrEmpty(line)) { continue; } var parsedLine = _canBusLogLineParser.TryParseLine(line); if (parsedLine == null) { continue; } var message = _canBusMessageFactory.Create(CarType.Model3, parsedLine.MessageTypeId, parsedLine.Payload); if (message is UnknownMessage) { continue; } var timestamp = TryGetTimestamp(parsedLine, message); timeLine.Add(message, timestamp); } if (interpolateTime) { _timelineInterpolator.InterpolateTime(timeLine); } return(timeLine); }
public void InterpolateTime(MessageTimeline timeline) { if (timeline == null) { throw new ArgumentNullException(nameof(timeline)); } var messages = timeline.ToList(); var histogram = new MessageTypeHistogram(messages.Select(m => m.Value)); var timestampMessagesCount = histogram[TimestampMessage.MessageTypeIdConstant].Count; if (timestampMessagesCount < 2) { return; } var mostFrequentMessageTypes = histogram .Where(mtc => mtc.Count > timestampMessagesCount) .OrderByDescending(mtc => mtc.Count) .Select(mtc => mtc.Key) .ToList(); if (!mostFrequentMessageTypes.Any()) { return; } var messageTypeForInterpolation = mostFrequentMessageTypes.Contains(BatteryPowerMessage.MessageTypeIdConstant) ? BatteryPowerMessage.MessageTypeIdConstant : mostFrequentMessageTypes[0]; var timestampMessages = new CurrentLastValue <ITimestampMessage>(); var timestampIndexes = new CurrentLastValue <int>(); for (var i = 0; i < messages.Count; i++) { var message = messages[i]; if (!(message.Value is ITimestampMessage timestampMessage)) { continue; } timestampMessages.SetCurrent(timestampMessage); timestampIndexes.SetCurrent(i); if (timestampMessages.Last == null) { continue; } var timeDiff = timestampMessage.Timestamp - timestampMessages.Last.Timestamp; if (timeDiff > TimeSpan.FromSeconds(10) || timeDiff == TimeSpan.Zero) { continue; } var rangeHistogram = new MessageTypeHistogram( Enumerable.Range(timestampIndexes.Last + 1, i - timestampIndexes.Last).Select(j => messages[j].Value)); var timeToDivideBy = rangeHistogram[messageTypeForInterpolation].Count + 1; var timeSlice = timeDiff / timeToDivideBy; var interpolatedTime = timestampMessages.Last.Timestamp; for (var j = timestampIndexes.Last + 1; j < i; j++) { var rangeMessage = messages[j]; if (rangeMessage.Value.MessageTypeId != messageTypeForInterpolation) { continue; } interpolatedTime += timeSlice; timeline.SetTime(j, interpolatedTime); } } }
private async Task ProcessTimeline(string destinationPath, MessageTimeline timeline, ChargingSessionTransformationOptions options) { foreach (var chargingSession in new ChargingSessionFilter().GetChargingSessions(timeline)) { if (chargingSession.StartTime == default || chargingSession.EndTime == default) { continue; } if (options.MinimumChargingSessionDuration > TimeSpan.Zero && chargingSession.EndTime - chargingSession.StartTime < options.MinimumChargingSessionDuration) { continue; } var csvFileName = GetChargingSessionCsvFileName(destinationPath, chargingSession); await using var writer = File.CreateText(csvFileName); await _rowWriter.WriteHeader(writer); DateTime lastTimestamp = default; ChargingSessionRow lastRow = null; var row = new ChargingSessionRow(); foreach (var timedMessage in chargingSession.Where(m => !(m.Value is UnknownMessage))) { var timestamp = timedMessage.Timestamp ?? default; var message = timedMessage.Value; ParseMessage(message, row); if (timestamp == default || timestamp == lastTimestamp) { continue; } if (lastTimestamp == default) { lastTimestamp = timestamp; row = new ChargingSessionRow { Timestamp = timestamp }; continue; } EnrichMemoizedValues(row, lastRow); if (row.ShouldWriteRow) { await _rowWriter.WriteLine(writer, row); } lastTimestamp = timestamp; lastRow = row; row = new ChargingSessionRow { Timestamp = timestamp }; } } }
private static string GetChargingSessionCsvFileName(string path, MessageTimeline timeline) { var fileName = $"ChargingSession-{timeline.StartTime:yyyyMMdd-HHmmss}-{timeline.EndTime:yyyyMMdd-HHmmss}.csv"; return(Path.Combine(path, fileName)); }