What am I doing wrong?
I've got error when inserting data to GoogleFit (last line).
I know that C# API doesn't include detailed error information but I don't know how to send it through google console website.
Google.GoogleApiException HResult=0x80131500
Message=Google.Apis.Requests.RequestError Bad Request [400] Errors
[Message[Bad Request] Location[ - ] Reason[invalidArgument]
Domain[global]]
using Google.Apis.Auth.OAuth2;
using Google.Apis.Fitness.v1;
using Google.Apis.Fitness.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.Threading;
namespace GoogleFitImport
{
class Program
{
static void Main(string[] args)
{
GoogleFitImport.InsertToGoogleFit();
}
}
public class GoogleFitImport
{
private static readonly DateTime zero = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long ToJavaMiliseconds(DateTime dt)
{
return (long)(dt - zero).TotalMilliseconds;
}
public static long ToJavaNanoseconds(DateTime dt)
{
return (long)(dt - zero).TotalMilliseconds * 10 ^ 6;
}
public static DateTime FromJavaNanoseconds(long? nanoseconds)
{
if (nanoseconds == null)
nanoseconds = 0;
return FromJavaMiliseconds((nanoseconds.Value / (10 ^ 6)));
}
public static DateTime FromJavaMiliseconds(long mili)
{
return zero.AddMilliseconds((double)mili);
}
public static void InsertToGoogleFit()
{
string UserId = "me";
List<KeyValuePair<DateTime, float>> measures = new List<KeyValuePair<DateTime, float>>();
measures.Add(new KeyValuePair<DateTime, float>(new DateTime(2000, 01, 01, 12, 0, 0, DateTimeKind.Utc), 10.1f));
measures.Add(new KeyValuePair<DateTime, float>(new DateTime(2000, 01, 02, 12, 0, 0, DateTimeKind.Utc), 10.2f));
measures.Add(new KeyValuePair<DateTime, float>(new DateTime(2000, 01, 03, 12, 0, 0, DateTimeKind.Utc), 10.3f));
// https://www.googleapis.com/auth/fitness.body.write
var clientId = "000000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com"; // From https://console.developers.google.com
var clientSecret = "XXXXXXXXXXXXXXXXXXXXXXXX"; // From https://console.developers.google.com
//Scopes for use with the Google Drive API
string[] scopes = new string[]
{
FitnessService.Scope.FitnessBodyWrite,
FitnessService.Scope.FitnessBodyRead,
};
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync
(
new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
},
scopes,
Environment.UserName,
CancellationToken.None,
new FileDataStore("Google.Fitness.Auth", false)
).Result;
FitnessService fitnessService = new FitnessService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "FromLibraCsvToGoogleFit" //Assembly.GetExecutingAssembly().GetName().Name,
});
DataSource dataSource = new DataSource()
{
Type = "raw", //""derived",
Application = new Google.Apis.Fitness.v1.Data.Application()
{
Name = "maweightimport"
},
DataType = new DataType()
{
Name = "com.google.weight",
Field = new List<DataTypeField>()
{
new DataTypeField() {Name = "weight", Format = "floatPoint"}
}
},
Device = new Device()
{
Type = "scale",
Manufacturer = "unknown",
Model = "unknown",
Uid = "maweightimport",
Version = "1.0"
}
};
//string dataSourceId = "derived:com.google.weight:{clientId}:unknown:unknown:maweightimport"
string dataSourceId =
$"{dataSource.Type}:{dataSource.DataType.Name}:{clientId.Split('-')[0]}:{dataSource.Device.Manufacturer}:{dataSource.Device.Model}:{dataSource.Device.Uid}";
try
{
DataSource googleDataSource = fitnessService.Users.DataSources.Get(UserId, dataSourceId).Execute();
}
catch (Exception ex) //create if not exists
{
Console.WriteLine(ex);
DataSource googleDataSource = fitnessService.Users.DataSources.Create(dataSource, UserId).Execute();
}
Google.Apis.Fitness.v1.Data.Dataset weightsDataSource = new Google.Apis.Fitness.v1.Data.Dataset()
{
DataSourceId = dataSourceId,
Point = new List<DataPoint>()
};
DateTime minDateTime = DateTime.MaxValue;
DateTime maxDateTime = DateTime.MinValue;
foreach (var weight in measures)
{
long ts = ToJavaNanoseconds(weight.Key);
weightsDataSource.Point.Add
(
new DataPoint()
{
DataTypeName = "com.google.weight",
StartTimeNanos = ts,
EndTimeNanos = ts,
Value = new List<Value>()
{
new Value()
{
FpVal = weight.Value
}
}
}
);
if (minDateTime > weight.Key)
minDateTime = weight.Key;
if (maxDateTime < weight.Key)
maxDateTime = weight.Key;
}
weightsDataSource.MinStartTimeNs = ToJavaNanoseconds(minDateTime);
weightsDataSource.MaxEndTimeNs = ToJavaNanoseconds(maxDateTime);
string dataSetId = "2000.01.01-2000.01.03";
var save = fitnessService.Users.DataSources.Datasets.Patch(weightsDataSource, UserId, dataSourceId, dataSetId).Execute(); //ERROR HERE !
//var read = fitnessService.Users.DataSources.Datasets.Get(UserId, dataSourceId, dataSetId).Execute();
}
}
}
string dataSetId = "2000.01.01-2000.01.03";
Has to be in Nanos.
Related
I've written some code to add an event to Google Calander:
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "ID",
ClientSecret = "Secret",
},
new[] { CalendarService.Scope.Calendar },
Account.Text,
CancellationToken.None).Result;
var service = new CalendarService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "Custom CRM",
});
var myEvent = new Event
{
Summary = Title.Text,
Location = AppointmentLocation.Text,
ColorId = Convert.ToString(AppointmentColourInt),
Description = Description.Text,
Start = new EventDateTime()
{
DateTime = new DateTime(StartDate.Value.Year, StartDate.Value.Month, StartDate.Value.Day, Convert.ToInt32(StartTime.Text.Substring(0, 2)), Convert.ToInt32(StartTime.Text.Substring(StartTime.Text.Length - 2)), 00),
TimeZone = "Europe/London"
},
End = new EventDateTime()
{
DateTime = new DateTime(EndDate.Value.Year, EndDate.Value.Month, EndDate.Value.Day, Convert.ToInt32(EndTime.Text.Substring(0, 2)), Convert.ToInt32(EndTime.Text.Substring(EndTime.Text.Length - 2)), 00),
TimeZone = "Europe/London"
},
};
var recurringEvent = service.Events.Insert(myEvent, CalendarID);
recurringEvent.SendNotifications = true;
recurringEvent.Execute();
Is there a way I could get the ID of the event once it has been created so that I can save it to my database for future reference?
Thanks.
var recurringEvent = service.Events.Insert(myEvent, CalendarID);
recurringEvent.SendNotifications = true;
var results = recurringEvent.Execute();
Execute will return to you the object it inserted. The Id should be in there.
I can create an event but I can't create an event with a conference.
I tried all these types: "eventHangout" "eventNamedHangout" "hangoutsMeet" but still getting Invalid conference type value
Google.GoogleApiException: 'Google.Apis.Requests.RequestError
Invalid conference type value. [400]
Errors [
Message[Invalid conference type value.] Location[ - ] Reason[invalid] Domain[global]
]
Here's the code that creates and executes an event:
CalendarService service = GetCalendarService();
EventDateTime start = new EventDateTime();
start.DateTime = new DateTime(2021, 02, 19, 18, 47, 0);
EventDateTime end = new EventDateTime();
end.DateTime = new DateTime(2021, 02, 19, 18, 50, 0);
Event newEvent = new Event();
newEvent.Start = start;
newEvent.End = end;
newEvent.Summary = "New event";
newEvent.Description = "description";
newEvent.ConferenceData = CreateConferenceData();
EventsResource.InsertRequest request = service.Events.Insert(newEvent, calendarId);
request.ConferenceDataVersion = 1;
Event createdEvent = request.Execute();
Here's the code of CreateConferenceData() method:
ConferenceData conferenceData = new ConferenceData()
{
CreateRequest = new CreateConferenceRequest()
{
RequestId = Guid.NewGuid().ToString(),
ConferenceSolutionKey = new ConferenceSolutionKey()
{
Type = "hangoutsMeet" // Change according to your preferences
};
}
};
return conferenceData;
this is my service and worked perfect conference event
_calenarService = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = GenerateCredentials(),
ApplicationName = this._applicationName
});
var myEvent = new Event
{
Summary = "Google Calendar API Testing ",
Location = "Islamabad, Punjab, Pakistan",
Start = new EventDateTime()
{
DateTime = new DateTime(2021, 4, 5, 14, 0, 0),
TimeZone = "Asia/Karachi"
},
End = new EventDateTime()
{
DateTime = new DateTime(2021, 9, 10, 15, 0, 0),
TimeZone = "Asia/Karachi"
},
Recurrence = new String[] { "RRULE:FREQ=WEEKLY;BYDAY=MO" },
//If you want to add attendee
//Attendees = new List<EventAttendee>()
//{
// new EventAttendee { Email = "......com" },
// new EventAttendee { Email = "......." }
//},
ConferenceData = new ConferenceData
{
ConferenceSolution = new ConferenceSolution
{
Key = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
}
},
CreateRequest = new CreateConferenceRequest
{
RequestId = "qwerfsdiob",
ConferenceSolutionKey = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
},
},
EntryPoints = new List<EntryPoint> ()
{
new EntryPoint { EntryPointType = "video" },
}
}
};
var recurringEvent = _calenarService.Events.Insert(myEvent, "primary");
recurringEvent.SendNotifications = true;
recurringEvent.ConferenceDataVersion = 1;
Event eventData = recurringEvent.Execute();
I have 3 methods that do same stuff. One difference, they work with different models.
Here is the methods code:
public IEnumerable<PropertyImportDto> ImportStandardCsv(string fileData)
{
List<PropertyImportDto> data;
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(fileData.Substring(fileData.IndexOf(',') + 1))))
{
using (var streamWriter = new StreamReader(memoryStream))
using (var csvReader = new CsvReader(streamWriter))
{
var records = csvReader.GetRecords<PropertyImportDto>();
data = records.ToList();
}
}
return data;
}
public IEnumerable<ArthurPropertiesImportDto> ImportArthurCsv(string fileData)
{
List<ArthurPropertiesImportDto> data;
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(fileData.Substring(fileData.IndexOf(',') + 1))))
{
using (var streamWriter = new StreamReader(memoryStream))
using (var csvReader = new CsvReader(streamWriter))
{
var records = csvReader.GetRecords<ArthurPropertiesImportDto>();
data = records.ToList();
}
}
return data;
}
public IEnumerable<LandlordVisionImportDto> ImportLandlordVision(string fileData)
{
List<LandlordVisionImportDto> data;
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(fileData.Substring(fileData.IndexOf(',') + 1))))
{
using (var streamWriter = new StreamReader(memoryStream))
using (var csvReader = new CsvReader(streamWriter))
{
var records = csvReader.GetRecords<LandlordVisionImportDto>();
data = records.ToList();
}
}
return data;
}
And I call it like this
public async Task ImportProperties(PM101ImportDto input)
{
switch (input.fileTypeId)
{
case 1:
{
var properties = _csvAppService.ImportStandardCsv(input.FileBase64);
foreach (var item in properties)
{
var property = new Property
{
PropertyTypeId = 1,
BuildingTypeId = 12,
PhoneNumber = item.PhoneNumber,
PropertyTitleId = 1,
AccountManagerId = AbpSession.TenantId,
Addresses = new List<PropertyAddress>
{
new PropertyAddress
{
Line1 = item.Line1,
Line2 = item.Line2,
Line3 = item.Line3,
PostCode = item.PostalCode,
PostTown = item.Town,
Country = item.Country,
County = item.County,
Latitude = item.Latitude,
Longitude = item.Longitude
},
},
Sites = new List<Site>
{
new Site
{
NumberOfWindows = 0,
NumberOfBedRooms = 0,
ApproximateYearBuilt = 1970,
PropertyAge = 50,
FuelTypeId = 1,
ParkingTypeId = 1,
FurnishingTypeId = 1
}
},
MarketingInformation = new List<PropertyMarketingInformation>
{
new PropertyMarketingInformation
{
MarketingDescription = "", IsBillsIncluded = false
}
}
};
await _propertyRepository.InsertAsync(property);
}
break;
}
case 2:
{
var properties = _csvAppService.ImportLandlordVision(input.FileBase64);
foreach (var item in properties)
{
var property = new Property
{
PropertyTypeId = 1,
BuildingTypeId = 12,
PropertyTitleId = 1,
AccountManagerId = AbpSession.TenantId,
Addresses = new List<PropertyAddress>
{
new PropertyAddress
{
Line1 = item.Line1,
Line2 = item.Line2,
PostCode = item.PostCode,
PostTown = item.Town,
County = item.County
}
},
Sites = new List<Site>
{
new Site
{
NumberOfWindows = 0,
NumberOfBedRooms = 0,
ApproximateYearBuilt = 1970,
PropertyAge = 50,
FuelTypeId = 1,
ParkingTypeId = 1,
FurnishingTypeId = 1
}
},
MarketingInformation = new List<PropertyMarketingInformation>
{
new PropertyMarketingInformation
{
MarketingDescription = "", IsBillsIncluded = false
}
}
};
await _propertyRepository.InsertAsync(property);
}
break;
}
case 3:
{
var properties = _csvAppService.ImportArthurCsv(input.FileBase64);
foreach (var item in properties)
{
var property = new Property
{
PropertyTypeId = 1,
BuildingTypeId = 12,
PropertyTitleId = 1,
AccountManagerId = AbpSession.TenantId,
Addresses = new List<PropertyAddress>
{
new PropertyAddress
{
Line1 = item.Line1,
Line2 = item.Line2,
Line3 = item.Line3,
PostCode = item.PostCode,
PostTown = item.City,
County = item.County,
Country = item.Country,
Latitude = item.Latitude,
Longitude = item.Longitude
}
},
Sites = new List<Site>
{
new Site
{
NumberOfWindows = 0,
NumberOfBedRooms = 0,
ApproximateYearBuilt = 1970,
PropertyAge = 50,
FuelTypeId = 1,
ParkingTypeId = 1,
FurnishingTypeId = 1
}
},
MarketingInformation = new List<PropertyMarketingInformation>
{
new PropertyMarketingInformation
{
MarketingDescription = "", IsBillsIncluded = false
}
}
};
await _propertyRepository.InsertAsync(property);
}
}
break;
}
}
How I can rewrite those 3 methods to one gneric method?
Typical use case for generic type parameters
public IEnumerable<T> ImportStandardCsv<T>(string fileData)
{
var bytes = Convert.FromBase64String(fileData.Substring(fileData.IndexOf(',') + 1));
using (var memoryStream = new MemoryStream(bytes))
using (var streamReader = new StreamReader(memoryStream))
using (var csvReader = new CsvReader(streamReader))
return csvReader.GetRecords<T>();
}
call
IEnumerable<PropertyImportDto> result = ImportStandardCsv<PropertyImportDto>(input.FileBase64);
I just started working on csvhelper library today and new help with how to add entries in the next column. Say I have three datasets composed of (ABC Office, Sarah's office and Brian's office) These are Building names...For each building I have TaskName, PointName, DataName and then Local and Value data of rows.
Each building will have 2 columns, There can be 10 or 20 buildings (Dynamic)
and each building can be 1000's of data rows below local and Value row.
I have the following code
using (var writer = new StreamWriter(filePath))
using (var csv1 = new CsvWriter(writer))
{
foreach (var point in this.Points)
{
csv1.WriteField(point.BuildingName);
csv1.WriteField(" ");
csv1.NextRecord();
csv1.WriteField(point.TaskName);
csv1.WriteField(" ");
csv1.NextRecord();
csv1.WriteField(point.PointName);
csv1.WriteField(" ");
csv1.NextRecord();
csv1.WriteField(point.DataName);
csv1.WriteField(" ");
csv1.NextRecord();
}
}
The problem is that it puts all the points information in first column and then ' ' in the second field.
What I need is something like this eventually.
After the point information added, I want to be able to append a data set of Local and Value column under each point.
Is this formatting in CSV possible using CSVHelper?
Update:
So far I have gotten this far.. Using String builder added first 5 rows of data.
Now I need to be able to append a dataset of columns Local and Value under each Office. Is there a way in CSVHeper library that I can specify where to append the dataset. First 5 rows I am getting like this.
var row1 = new StringBuilder();
var row2 = new StringBuilder();
var row3 = new StringBuilder();
var row4 = new StringBuilder();
foreach (var point in this.Points)
{
row1.Append($"{ point.BuildingName},,");
row2.Append($"{point.TaskName},,");
row3.Append($"{ point.PointName},,");
row4.Append($"{ point.DataName},,");
}
//StreamWriter sw = new StreamWriter("filePath", true);
using (StreamWriter sw = new StreamWriter(filePath1))
{
sw.Write(row1.ToString());
sw.WriteLine();
sw.Write(row2.ToString());
sw.WriteLine();
sw.Write(row3.ToString());
sw.WriteLine();
sw.Write(row4.ToString());
sw.WriteLine();
sw.Close();
}
What you are trying create is not the standard CSV file that CsvHelper was built to create. A CSV file has one row of headers followed by rows of data. You appear to be creating an Excel report using comma separated values. CsvHelper can help you write the fields, but you are going to have to supply the logic for writing the report format. The following is one way that you could do it.
public static void Main(string[] args)
{
var points = new List<Point>
{
new Point
{
BuildingName = "ABC Office",
TaskName = "Temperature",
PointName = "14",
DataName = "Temperature: Degrees F",
Results = new List<Result> {
new Result { Local = new DateTime(2019, 1,1), Value = 2},
new Result { Local = new DateTime(2019, 1, 2), Value = 23}
}
},
new Point
{
BuildingName = "Sarah's Office",
TaskName = "Fan",
PointName = "33",
DataName = "0=Stop;1=Run",
Results = new List<Result> {
new Result { Local = new DateTime(2019, 1,1), Value = 2},
new Result { Local = new DateTime(2019, 1, 2), Value = 23},
new Result { Local = new DateTime(2019, 1, 3), Value = 45},
new Result { Local = new DateTime(2019, 1, 4), Value = 34},
new Result { Local = new DateTime(2019, 1, 5), Value = 36}
}
},
new Point
{
BuildingName = "Brian's Office",
TaskName = "Fan",
PointName = "35",
DataName = "Humidity",
Results = new List<Result> {
new Result { Local = new DateTime(2019, 1,1), Value = 2},
new Result { Local = new DateTime(2019, 1, 2), Value = 23},
new Result { Local = new DateTime(2019, 1, 3), Value = 45},
new Result { Local = new DateTime(2019, 1, 4), Value = 34},
new Result { Local = new DateTime(2019, 1, 5), Value = 36},
new Result { Local = new DateTime(2019, 1, 6), Value = 56},
new Result { Local = new DateTime(2019, 1, 7), Value = 92}
}
},
};
using (var writer = new StreamWriter(filePath))
using (var csv = new CsvWriter(writer))
{
// Print buildings
foreach (var point in points)
{
csv.WriteField(point.BuildingName);
csv.WriteField("");
}
csv.NextRecord();
// Print Tasks
foreach (var point in points)
{
csv.WriteField(point.TaskName);
csv.WriteField("");
}
csv.NextRecord();
// Print Points
foreach (var point in points)
{
csv.WriteField(point.PointName);
csv.WriteField("");
}
csv.NextRecord();
// Print DataNames
foreach (var point in points)
{
csv.WriteField(point.DataName);
csv.WriteField("");
}
csv.NextRecord();
// Print value titles
foreach (var point in points)
{
csv.WriteField("Local");
csv.WriteField("Value");
}
csv.NextRecord();
var endReached = false;
var pointIndex = 0;
// Print values
while (!endReached)
{
endReached = true;
foreach (var point in points)
{
if (point.Results.Count > pointIndex)
{
csv.WriteField(point.Results[pointIndex].Local);
csv.WriteField(point.Results[pointIndex].Value);
if (point.Results.Count > pointIndex + 1)
{
endReached = false;
}
}
else
{
csv.WriteField("");
csv.WriteField("");
}
}
csv.NextRecord();
pointIndex += 1;
}
}
}
public class Point
{
public string BuildingName { get; set; }
public string TaskName { get; set; }
public string PointName { get; set; }
public string DataName { get; set; }
public List<Result> Results { get; set; }
}
public class Result
{
public DateTime Local { get; set; }
public int Value { get; set; }
}
I'm using the following code:
DynamoDBContextConfig config = new DynamoDBContextConfig()
{
ConsistentRead = false,
Conversion = DynamoDBEntryConversion.V2
};
using (DynamoDBContext context = new DynamoDBContext(config))
{
long unixTimestamp = (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
QTrackStatus qTrackStatus = new QTrackStatus()
{
Key = "m#m.com",
EventCode = "CC",
EventDateTime = "2019-09-09 14:00:30",
EventLocation = "BFS",
EventLastUpdate = unixTimestamp
};
DynamoDBOperationConfig dynamoDBOperationConfig = new DynamoDBOperationConfig()
{
QueryFilter = new List<ScanCondition>()
{
{ new ScanCondition("EventCode", ScanOperator.NotEqual, "CC") }
},
ConditionalOperator = ConditionalOperatorValues.And
};
await context.SaveAsync(qTrackStatus, dynamoDBOperationConfig);
}
What I'm trying to do is only save the record if the EventCode is not CC. Currently it's always saving. I could retrieve the record first, do a check and then call SaveAsync if required - however I'd like to do it all in the SaveAsync call. Is this possible?
Unless I've missed something, it doesn't look like this is possible with the higher level api. I ended up re-factoring to the following:
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
{
TableName = "QTrackStatus",
ReturnValues = ReturnValue.ALL_NEW,
ConditionExpression = "EventCode <> :ec",
UpdateExpression = "SET EventCode = :ec, EventDateTime = :edt, EventLocation = :el, EventLastUpdate = :elu",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{ ":ec", new AttributeValue("CC") },
{ ":edt", new AttributeValue("2019-09-09 14:00:30") },
{ ":el", new AttributeValue("BFS") },
{ ":elu", new AttributeValue() { N = ((long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString() } }
},
Key = new Dictionary<string, AttributeValue>()
{
{ "Key", new AttributeValue("m#m.com") }
}
};
try
{
UpdateItemResponse updateItemResponse = await client.UpdateItemAsync(updateItemRequest);
}
catch(ConditionalCheckFailedException e)
{
}
This allows me to achieve my goal.