We were looking for a solution to taking and analysing information posted to Garmin connect for a project. Garmin have not released any sort of web service interface for garmin connect so quite a challenge to get that information. Listed below is the C# code (still a bit rough) that logs in to Garmin and uses the activity-search rest services to receive information:
Login Method:
private CookieContainer LoginGRMN(string loginURL,string userName,string password)
{
CookieContainer cookiJar = new CookieContainer();
string loginResponse = "";
try
{
HttpWebRequest getLogin = (HttpWebRequest)HttpWebRequest.Create(loginURL.Replace("https://", "http://"));
getLogin.Method = "GET";
getLogin.CookieContainer = cookiJar;
getLogin.KeepAlive = true;
var getLoginResp = getLogin.GetResponse();
HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(loginURL);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.CookieContainer = cookiJar;
httpRequest.KeepAlive = true;
string formData = string.Format("login=login&login%3AloginUsernameField={0}&login%3Apassword={1}&login%3AsignInButton= Sign+In&login%3ArememberMe=false&javax.faces.ViewState=j_id1", HttpUtility.UrlEncode(userName), HttpUtility.UrlEncode(password));
byte[] bytedata = Encoding.ASCII.GetBytes(formData);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Flush();
requestStream.Close();
HttpWebResponse logResponse = (HttpWebResponse)httpRequest.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new
StreamReader(logResponse.GetResponseStream(), enc);
loginResponse= loResponseStream.ReadToEnd();
}
catch (Exception exp)
{
throw new Exception("Error connecting to Garmin Connect for login", exp);
}
if (loginResponse.Contains("login:loginUsernameField"))
{
throw new Exception("Error logging in to Garmin Connect");
}
return cookiJar;
}
Search activities method using the JSON response:
public List<Domain.IntegrationActivity> SearchActivities(Domain.ActivitySearchDetails activitySearch)
{
//login to Garmin Connect
var cookiJar= LoginGRMN(activitySearch.LoginURL, activitySearch.Username, activitySearch.Password);
//load activities
string url = activitySearch.ActionURL + "?beginTimestamp>" + activitySearch.FromDate.ToString("s");
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.CookieContainer = cookiJar;
req.Method = "GET";
var grmnResponse = req.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new
StreamReader(grmnResponse.GetResponseStream(), enc);
string grmnXML = loResponseStream.ReadToEnd();
//deserialize the JSON response
var reader = new JsonReader();
dynamic output = reader.Read(grmnXML);
if (!PropertyExists("results",output))
{
throw new Exception("Error on Garmin Json response");
}
//return object
List<Domain.IntegrationActivity> returnAct = new List<Domain.IntegrationActivity>();
foreach (dynamic activity in output.results.activities)
{
DateTime captureDate = DateTime.Parse(activity.activity.uploadDate.display);
Domain.IntegrationActivity retActivity = new Domain.IntegrationActivity()
{
ActivityReference = activity.activity.activityId,
CaptureDate =captureDate,
Calories = PropertyExists("activitySummarySumEnergy", activity.activity) ? int.Parse(activity.activity.activitySummarySumEnergy.display) : 0,
StartTime =PropertyExists("activitySummaryBeginTimestamp", activity.activity)? DateTime.Parse(activity.activity.activitySummaryBeginTimestamp.display): new DateTime(captureDate.Year,captureDate.Month,captureDate.Day,0,0,0),
EndTime = PropertyExists("activitySummaryEndTimestamp", activity.activity) ? DateTime.Parse(activity.activity.activitySummaryEndTimestamp.display) : new DateTime(captureDate.Year, captureDate.Month, captureDate.Day, 0, 0, 0),
Factors = new List<Domain.ActivityFactor>()
};
//ADD other factors
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "ActivityName", Value = PropertyExists("activityName",activity.activity)?activity.activity.activityName.value:"" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "ActivityType", Value = PropertyExists("activityType", activity.activity) ? activity.activity.activityType.display : "" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "Distance", Value = PropertyExists("activitySummarySumDistance", activity.activity) ? activity.activity.activitySummarySumDistance.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "Duration", Value = PropertyExists("activitySummarySumDuration", activity.activity) ? activity.activity.activitySummarySumDuration.minutesSeconds : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "AverageSpeed", Value = PropertyExists("activitySummaryWeightedMeanSpeed", activity.activity) ? activity.activity.activitySummaryWeightedMeanSpeed.withUnitAbbr : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "MaxHeartRate", Value = PropertyExists("activitySummaryMaxHeartRate", activity.activity) ? activity.activity.activitySummaryMaxHeartRate.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "MinHeartRate", Value = PropertyExists("activitySummaryMinHeartRate", activity.activity) ? activity.activity.activitySummaryMinHeartRate.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "AverageHeartRate", Value = PropertyExists("activitySummaryWeightedMeanHeartRate", activity.activity) ? activity.activity.activitySummaryWeightedMeanHeartRate.value : "0" });
returnAct.Add(retActivity);
}
return returnAct;
}
private bool PropertyExists(string name,ExpandoObject obj)
{
return((IDictionary<String, Object>)obj).ContainsKey(name);
}
Hope this helps someone
Sincerely
Martin Naude
Login Method:
private CookieContainer LoginGRMN(string loginURL,string userName,string password)
{
CookieContainer cookiJar = new CookieContainer();
string loginResponse = "";
try
{
HttpWebRequest getLogin = (HttpWebRequest)HttpWebRequest.Create(loginURL.Replace("https://", "http://"));
getLogin.Method = "GET";
getLogin.CookieContainer = cookiJar;
getLogin.KeepAlive = true;
var getLoginResp = getLogin.GetResponse();
HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(loginURL);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.CookieContainer = cookiJar;
httpRequest.KeepAlive = true;
string formData = string.Format("login=login&login%3AloginUsernameField={0}&login%3Apassword={1}&login%3AsignInButton= Sign+In&login%3ArememberMe=false&javax.faces.ViewState=j_id1", HttpUtility.UrlEncode(userName), HttpUtility.UrlEncode(password));
byte[] bytedata = Encoding.ASCII.GetBytes(formData);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Flush();
requestStream.Close();
HttpWebResponse logResponse = (HttpWebResponse)httpRequest.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new
StreamReader(logResponse.GetResponseStream(), enc);
loginResponse= loResponseStream.ReadToEnd();
}
catch (Exception exp)
{
throw new Exception("Error connecting to Garmin Connect for login", exp);
}
if (loginResponse.Contains("login:loginUsernameField"))
{
throw new Exception("Error logging in to Garmin Connect");
}
return cookiJar;
}
Search activities method using the JSON response:
public List<Domain.IntegrationActivity> SearchActivities(Domain.ActivitySearchDetails activitySearch)
{
//login to Garmin Connect
var cookiJar= LoginGRMN(activitySearch.LoginURL, activitySearch.Username, activitySearch.Password);
//load activities
string url = activitySearch.ActionURL + "?beginTimestamp>" + activitySearch.FromDate.ToString("s");
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.CookieContainer = cookiJar;
req.Method = "GET";
var grmnResponse = req.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new
StreamReader(grmnResponse.GetResponseStream(), enc);
string grmnXML = loResponseStream.ReadToEnd();
//deserialize the JSON response
var reader = new JsonReader();
dynamic output = reader.Read(grmnXML);
if (!PropertyExists("results",output))
{
throw new Exception("Error on Garmin Json response");
}
//return object
List<Domain.IntegrationActivity> returnAct = new List<Domain.IntegrationActivity>();
foreach (dynamic activity in output.results.activities)
{
DateTime captureDate = DateTime.Parse(activity.activity.uploadDate.display);
Domain.IntegrationActivity retActivity = new Domain.IntegrationActivity()
{
ActivityReference = activity.activity.activityId,
CaptureDate =captureDate,
Calories = PropertyExists("activitySummarySumEnergy", activity.activity) ? int.Parse(activity.activity.activitySummarySumEnergy.display) : 0,
StartTime =PropertyExists("activitySummaryBeginTimestamp", activity.activity)? DateTime.Parse(activity.activity.activitySummaryBeginTimestamp.display): new DateTime(captureDate.Year,captureDate.Month,captureDate.Day,0,0,0),
EndTime = PropertyExists("activitySummaryEndTimestamp", activity.activity) ? DateTime.Parse(activity.activity.activitySummaryEndTimestamp.display) : new DateTime(captureDate.Year, captureDate.Month, captureDate.Day, 0, 0, 0),
Factors = new List<Domain.ActivityFactor>()
};
//ADD other factors
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "ActivityName", Value = PropertyExists("activityName",activity.activity)?activity.activity.activityName.value:"" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "ActivityType", Value = PropertyExists("activityType", activity.activity) ? activity.activity.activityType.display : "" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "Distance", Value = PropertyExists("activitySummarySumDistance", activity.activity) ? activity.activity.activitySummarySumDistance.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "Duration", Value = PropertyExists("activitySummarySumDuration", activity.activity) ? activity.activity.activitySummarySumDuration.minutesSeconds : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "AverageSpeed", Value = PropertyExists("activitySummaryWeightedMeanSpeed", activity.activity) ? activity.activity.activitySummaryWeightedMeanSpeed.withUnitAbbr : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "MaxHeartRate", Value = PropertyExists("activitySummaryMaxHeartRate", activity.activity) ? activity.activity.activitySummaryMaxHeartRate.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "MinHeartRate", Value = PropertyExists("activitySummaryMinHeartRate", activity.activity) ? activity.activity.activitySummaryMinHeartRate.value : "0" });
retActivity.Factors.Add(new Domain.ActivityFactor() { Name = "AverageHeartRate", Value = PropertyExists("activitySummaryWeightedMeanHeartRate", activity.activity) ? activity.activity.activitySummaryWeightedMeanHeartRate.value : "0" });
returnAct.Add(retActivity);
}
return returnAct;
}
private bool PropertyExists(string name,ExpandoObject obj)
{
return((IDictionary<String, Object>)obj).ContainsKey(name);
}
Hope this helps someone
Sincerely
Martin Naude
Comment