Open jmargel74 opened 2 years ago
I believe it's all graphql even for the activity tracker.
You can MITM your own app traffic and get a decent idea of what is happening here. That analytics
subdomain is for app analytics, it looks like the activity logs are on the main api
subdomain. Interestingly, logs are also submitted to the api
subdomain under /api/log/submit
which makes me think maybe the analytics
subdomain is a 3rd party analytics provider that collects that data and provides insights to Fi.
Here is a sample request for the activity feed:
POST https://api.tryfi.com/graphql HTTP/2.0
content-type: application/json
x-apollo-operation-name: FiFeed
accept: */*
x-session-id: redacted
apollographql-client-version: 3.0.5-0
accept-language: en-US,en;q=0.9
accept-encoding: gzip, deflate, br
x-acting-pet-id: redacted
content-length: redacted
x-apollo-operation-type: query
user-agent: Fi/0 CFNetwork/1402.0.8 Darwin/22.2.0
apollographql-client-name: com.barkinglabs.fi-apollo-ios
cookie: fi_acting_pet_id=redacted; fi_session_id=redacted; fi_partner=1; _fbp=redacted; _uetvid=redacted; ajs_anonymous_id=redacted; ajs_user_id=redacted; _ga=redacted; _hjSessionUser_1228176=redacted; _sp_id.54d7=redacted; _tt_enable_cookie=1; _ttp=redacted; ajs_group_id=null; tatari-session-cookie=redacted; _gcl_au=redacted
x-client: {"osVersion":"16.2","timezone":"America\/New_York","build":"RELEASE","deviceModel":"iPhone15,2","version":"3.0.5","platform":"IOS","deviceId":"redacted"}
{"operationName":"FiFeed","query":"query FiFeed($limit: Int, $pagingInstruction: PagingInstruction, $height: Int!, $width: Int!, $scale: Int) {\n currentUser {\n __typename\n fiFeed(limit: $limit, pagingInstruction: $pagingInstruction) {\n __typename\n ...FiFeedDetails\n }\n }\n}\nfragment FiFeedDetails on FiFeed {\n __typename\n feedItems {\n __typename\n ...FiFeedItemDetails\n }\n pageInfo {\n __typename\n ...PageInfoDetails\n }\n}\nfragment FiFeedItemDetails on FiFeedItem {\n __typename\n id\n timestamp\n ... on FiFeedActivityItem {\n __typename\n activity {\n __typename\n ...ActivityDetails\n ... on Rest {\n __typename\n mapUrl(width: $width, height: $height, scale: $scale)\n }\n ... on Walk {\n __typename\n mapUrl(width: $width, height: $height, scale: $scale)\n }\n ... on Play {\n __typename\n mapUrl(width: $width, height: $height, scale: $scale)\n }\n }\n pet {\n __typename\n ...BasePetInfo\n }\n }\n ... on FiFeedGenericNotificationItem {\n __typename\n title\n body {\n __typename\n ...FormatStringDetails\n }\n hideTimestamp\n }\n ... on FiFeedGoalStreakItem {\n __typename\n numDays\n pet {\n __typename\n ...BasePetInfo\n }\n }\n ... on FiFeedRankingUpdateItem {\n __typename\n pet {\n __typename\n ...BasePetInfo\n breed {\n __typename\n ...BreedDetails\n }\n }\n newBreedRank\n newOverallRank\n newOverallRankPercentile\n }\n ... on FiFeedPhotoAddedItem {\n __typename\n pet {\n __typename\n ...BasePetInfo\n }\n photo {\n __typename\n ...PhotoDetails\n }\n user {\n __typename\n firstName\n }\n }\n ... on FiFeedLikableWalkItem {\n __typename\n followedPet {\n __typename\n ...BasePetInfo\n }\n walk {\n __typename\n ...StrangerWalkDetails\n }\n }\n}\nfragment ActivityDetails on Activity {\n __typename\n id\n start\n end\n areaName\n presentUser {\n __typename\n ...UserDetails\n }\n presentUserString\n totalSteps\n obfuscated\n ... on Walk {\n __typename\n isLikable\n likeCount\n distance\n mapPath {\n __typename\n ... on MapMatchedPath {\n __typename\n path {\n __typename\n ...PositionCoordinates\n }\n }\n ... on UnmatchedPath {\n __typename\n locations {\n __typename\n ...LocationPoint\n }\n }\n }\n }\n ... on Rest {\n __typename\n position {\n __typename\n ...PositionCoordinates\n }\n place {\n __typename\n ...PlaceDetails\n }\n }\n ... on Play {\n __typename\n position {\n __typename\n ...PositionCoordinates\n }\n place {\n __typename\n ...PlaceDetails\n }\n }\n}\nfragment UserDetails on User {\n __typename\n id\n email\n firstName\n lastName\n phoneNumber\n fiNewsNotificationsEnabled\n}\nfragment PositionCoordinates on Position {\n __typename\n latitude\n longitude\n}\nfragment LocationPoint on Location {\n __typename\n date\n errorRadius\n position {\n __typename\n ...PositionCoordinates\n }\n}\nfragment PlaceDetails on Place {\n __typename\n id\n name\n address\n position {\n __typename\n ...PositionCoordinates\n }\n radius\n type\n coordinates {\n __typename\n ...PositionCoordinates\n }\n}\nfragment BasePetInfo on BasePet {\n __typename\n id\n name\n homeCityState\n photos {\n __typename\n first {\n __typename\n image {\n __typename\n ...ImageDetails\n }\n }\n }\n ... on StrangerPet {\n __typename\n followStatus\n }\n ... on Pet {\n __typename\n household {\n __typename\n id\n }\n }\n}\nfragment ImageDetails on Image {\n __typename\n id\n fullSize\n}\nfragment FormatStringDetails on FormatString {\n __typename\n text\n spans {\n __typename\n start\n length\n style\n }\n}\nfragment BreedDetails on Breed {\n __typename\n id\n name\n popularityScore\n}\nfragment PhotoDetails on Photo {\n __typename\n id\n date\n image {\n __typename\n ...ImageDetails\n }\n likeCount\n liked\n caption\n comments {\n __typename\n items {\n __typename\n ...CommentDetails\n }\n totalCount\n }\n pet {\n __typename\n ...BasePetInfo\n }\n poster {\n __typename\n ...PhotoPosterDetails\n }\n}\nfragment CommentDetails on Comment {\n __typename\n id\n comment\n createdAt\n strangerPet {\n __typename\n id\n name\n photos {\n __typename\n first {\n __typename\n image {\n __typename\n fullSize\n }\n }\n }\n }\n}\nfragment PhotoPosterDetails on PhotoPoster {\n __typename\n ... on StrangerUser {\n __typename\n ...StrangerUserDetails\n }\n ... on ExternalUser {\n __typename\n ...ExternalUserDetails\n }\n}\nfragment StrangerUserDetails on StrangerUser {\n __typename\n id\n firstName\n profilePicture {\n __typename\n ...ImageDetails\n }\n}\nfragment ExternalUserDetails on ExternalUser {\n __typename\n id\n name\n profilePicture {\n __typename\n ...ImageDetails\n }\n}\nfragment StrangerWalkDetails on StrangerWalk {\n __typename\n id\n distance\n stepCount\n liked\n likeCount\n}\nfragment PageInfoDetails on PageInfo {\n __typename\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n}","variables":{"height":300,"limit":null,"pagingInstruction":{"cursor":"redacted","direction":"BACKWARD"},"scale":4,"width":373}}
And here is a sample response:
HTTP/2.0 200
date: Wed, 14 Dec 2022 01:42:45 GMT
content-type: application/json; charset=utf-8
content-length: 6675
x-powered-by: Express
vary: Origin
access-control-allow-credentials: true
{"data":{"currentUser":{"__typename":"User","fiFeed":{"__typename":"FiFeed","feedItems":[{"__typename":"FiFeedActivityItem","id":"Activity:2022-08-21T02:54:37.237Z","timestamp":"2022-08-21T02:54:37.237Z","activity":{"__typename":"Walk","id":"redacted","start":"2022-08-21T02:49:18.425Z","end":"2022-08-21T02:59:56.050Z","areaName":"redacted","presentUser":{"__typename":"User","id":"redacted","email":"redacted","firstName":"redacted","lastName":"redacted","phoneNumber":"redacted","fiNewsNotificationsEnabled":false},"presentUserString":"You","totalSteps":1538,"obfuscated":false,"isLikable":false,"likeCount":0,"distance":256.31977063451683,"mapPath":{"__typename":"MapMatchedPath","path":[{"__typename":"Position","latitude":redacted,"longitude":redacted},{"__typename":"Position","latitude":redacted,"longitude":redacted},
"mapUrl":"https://barkinglabs-media.s3.amazonaws.com/maps/redacted.png"},"pet":{"__typename":"Pet","id":"redacted","name":"redacted","homeCityState":"redacted","photos":
I don't know GraphQL at the moment so in the mean time I wrote a quick and dirty script to scrape for activity data: https://github.com/cwille97/fiactivity
I created a .net app (vb.net) with the help of sbabcock23's python code. If you want I can post the code that uses graphql that retrieves the information and the gathers it.
I am an amateur programmer so please be kind when you see this code.. The first part gets the sessionID, the second part gets just some of the basic information from the account. I also have code that dives deeper into it and shows a daily activity of the steps taken. I also use gmap.net to show where the dog is on a map using the GPS coordinates. However what I can't seem to find is the rankings, etc..
Try
Dim logincookie As CookieContainer
Dim postData As String = "password=" & My.Settings.Password & "&email=" & My.Settings.UserName
Dim tempCookies As New CookieContainer
Dim encoding As New UTF8Encoding
Dim byteData As Byte() = encoding.GetBytes(postData)
Dim postReq As HttpWebRequest = DirectCast(System.Net.WebRequest.Create("https://api.tryfi.com/auth/login"), HttpWebRequest)
petStatsTimer.Start()
countdownTimer.Start()
postReq.Method = "POST"
postReq.KeepAlive = True
postReq.CookieContainer = tempCookies
postReq.CookieContainer = CookieJar
postReq.AllowAutoRedirect = False
postReq.ContentType = "application/x-www-form-urlencoded"
postReq.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/4.0 (.NET CLR 3.5.30729)"
postReq.ContentLength = byteData.Length
Dim postreqstream As Stream = postReq.GetRequestStream()
postreqstream.Write(byteData, 0, byteData.Length)
postreqstream.Close()
Dim postresponse As HttpWebResponse
postresponse = DirectCast(postReq.GetResponse(), HttpWebResponse)
Dim postresponseCode = postresponse.StatusCode
tempCookies.Add(postresponse.Cookies)
For Each tempCookie In postresponse.Cookies
CookieJar.Add(tempCookie)
Next
logincookie = tempCookies
Dim postreqreader As New StreamReader(postresponse.GetResponseStream())
Dim thepage As String = postreqreader.ReadToEnd
dict = jss.Deserialize(Of Dictionary(Of String, Object))(thepage)
For Each item In dict
session_id = dict("sessionId").ToString
user_id = dict("userId").ToString
email_id = dict("email").ToString
Next
fiSID = postresponse.Cookies.Item(0).Value 'fi SessionId
Try
' Get Pet Information
Dim restTryFiList As RestClient = New RestClient("https://api.tryfi.com/graphql?query=query " & QUERY_CURRENT_USER_FULL_DETAIL + FRAGMENT_USER_DETAILS + FRAGMENT_USER_FULL_DETAILS + FRAGMENT_PET_PROFILE + FRAGEMENT_BASE_PET_PROFILE + FRAGMENT_BASE_DETAILS + FRAGMENT_POSITION_COORDINATES + FRAGMENT_BREED_DETAILS + FRAGMENT_PHOTO_DETAILS + FRAGMENT_DEVICE_DETAILS + FRAGMENT_LED_DETAILS + FRAGMENT_OPERATIONAL_DETAILS + FRAGMENT_CONNECTION_STATE_DETAILS)
restTryFiList.AddDefaultHeader("Content-Type", "application/json")
Dim requestTryFiList As RestRequest = New RestRequest(Method.POST)
requestTryFiList.AddHeader("Content-Type", "application/json")
requestTryFiList.AddCookie("fi.sid", fiSID)
Dim responseTryFiList As RestResponse = restTryFiList.Execute(requestTryFiList)
TryFiDict = jss.Deserialize(Of Dictionary(Of String, Object))(responseTryFiList.Content)
For Each item In TryFiDict
first_name = TryFiDict.Item("data").Item("currentUser").Item("firstName")
last_name = TryFiDict.Item("data").Item("currentUser").Item("lastName")
pet_id = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("id")
pet_name = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).Item("name")
pet_birth_date = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0)("monthOfBirth") & "/" & TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0)("dayOfBirth") & "/" & TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0)("yearOfBirth")
pet_breed = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("breed").item("name")
pet_image = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("photos").item("first").item("image").item("fullSize")
pet_gender = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("gender")
location_last_updated = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("bases")(0).item("infoLastUpdated")
base_id = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("bases")(0).item("baseId")
network_name = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("bases")(0).item("networkName")
online = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("bases")(0).item("online")
onlineQuality = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("bases")(0).item("onlineQuality")
led_color = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("ledColor").item("name")
led_color_code = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("ledColor").item("ledColorCode")
module_id = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("moduleId")
battery_percentage = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("info").item("batteryPercent")
is_charging = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("info").item("isCharging")
led_enabled = TryFiDict.Item("data").item("currentUser").item("userHouseholds")(0).item("household").item("pets")(0).item("device").item("operationParams").item("ledEnabled")
Next
Catch ex As Exception
MsgBox("Error encounered, please let the developer know of this error:" & ex.ToString)
Exit Sub
End Try
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Constants:
Module modTryFiConst
Public stats_monthly_date_start
Public stats_monthly_date_end
Public stats_monthly_total_steps
Public stats_monthly_total_steps_goal
Public stats_weekly_date_start
Public stats_weekly_date_end
Public stats_weekly_total_steps
Public stats_weekly_total_steps_goal
Public stats_daily_date_start
Public stats_daily_date_end
Public stats_daily_total_steps
Public stats_daily_total_steps_goal
Public TryFiDict As Dictionary(Of String, Object)
Public fiStepsMonthlyDict As Dictionary(Of String, Object)
Public dtMonthly = New DataTable("dtMonthly")
Public dtDaily = New DataTable("dtDaily")
Public Const API_HOST_URL_BASE = "https://api.tryfi.com"
Public Const API_GRAPHQL = "/graphql"
Public Const API_LOGIN = "/auth/login"
Public Const PET_MODE_NORMAL = "NORMAL"
Public Const PET_MODE_LOST = "LOST_DOG"
Public Const PET_ACTIVITY_ONGOINGWALK = "OngoingWalk"
Public Const PET_ACTIVITY_ONGOINGREST = "OngoingRest"
Public Const PET_ACTIVITY_WALK = "Walk"
Public Const PET_ACTIVITY_REST = "Rest"
Public Const VAR_PET_ID = "__PET_ID__"
Public Const QUERY_CURRENT_USER = "query { currentUser { ...UserDetails }}"
Public Const QUERY_CURRENT_USER_FULL_DETAIL = "query { currentUser { ...UserFullDetails }}"
Public Const QUERY_PET_CURRENT_LOCATION = "query { pet (id: \" & VAR_PET_ID & "\) { ongoingActivity(walksVersion: 1) { __typename ...OngoingActivityDetails } }}"
Public QUERY_PET_ACTIVITY = "query { pet (id: " & VAR_PET_ID & ") { dailyStat: currentActivitySummary (period: DAILY) { ...ActivitySummaryDetails } weeklyStat: currentActivitySummary (period: WEEKLY) { ...ActivitySummaryDetails } monthlyStat: currentActivitySummary (period: MONTHLY) { ...ActivitySummaryDetails } }}"
Public Const QUERY_PET_DEVICE_DETAILS = "query { pet (id: \" & VAR_PET_ID & "\"") { __typename ...PetProfile }}"
Public Const FRAGMENT_USER_DETAILS = "fragment UserDetails on User { __typename id email firstName lastName phoneNumber fiNewsNotificationsEnabled chipReseller { __typename id }}"
Public Const FRAGMENT_USER_FULL_DETAILS = "fragment UserFullDetails on User { __typename ...UserDetails userHouseholds { __typename household { __typename pets { __typename ...PetProfile } bases { __typename ...BaseDetails } } }}"
Public Const FRAGEMENT_BASE_PET_PROFILE = "fragment BasePetProfile on BasePet { __typename id name homeCityState yearOfBirth monthOfBirth dayOfBirth gender weight isPurebred breed { __typename ...BreedDetails } photos { __typename first { __typename ...PhotoDetails } items { __typename ...PhotoDetails } } instagramHandle }"
Public Const FRAGMENT_BREED_DETAILS = "fragment BreedDetails on Breed { __typename id name popularityScore}"
Public Const FRAGMENT_PHOTO_DETAILS = "fragment PhotoDetails on Photo { __typename id caption date likeCount liked image { __typename fullSize }}"
Public Const FRAGMENT_PET_PROFILE = "fragment PetProfile on Pet { __typename ...BasePetProfile chip { __typename shortId } device { __typename ...DeviceDetails }}"
Public Const FRAGMENT_DEVICE_DETAILS = "fragment DeviceDetails on Device { __typename id moduleId info subscriptionId hasActiveSubscription hasSubscriptionOverride nextLocationUpdateExpectedBy operationParams { __typename ...OperationParamsDetails } lastConnectionState { __typename ...ConnectionStateDetails } ledColor { __typename ...LedColorDetails } availableLedColors { __typename ...LedColorDetails }}"
Public Const FRAGMENT_LED_DETAILS = "fragment LedColorDetails on LedColor { __typename ledColorCode hexCode name}"
Public Const FRAGMENT_CONNECTION_STATE_DETAILS = "fragment ConnectionStateDetails on ConnectionState { __typename date ... on ConnectedToUser { user { __typename ...UserDetails } } ... on ConnectedToBase { chargingBase { __typename id } } ... on ConnectedToCellular { signalStrengthPercent } ... on UnknownConnectivity { unknownConnectivity }}"
Public Const FRAGMENT_OPERATIONAL_DETAILS = "fragment OperationParamsDetails on OperationParams { __typename mode ledEnabled ledOffAt}"
Public Const FRAGMENT_BASE_DETAILS = "fragment BaseDetails on ChargingBase { __typename baseId name position { __typename ...PositionCoordinates } infoLastUpdated networkName online onlineQuality}"
Public Const FRAGMENT_POSITION_COORDINATES = "fragment PositionCoordinates on Position { __typename latitude longitude}"
Public Const FRAGMENT_ONGOING_ACTIVITY_DETAILS = "fragment OngoingActivityDetails on OngoingActivity { __typename start presentUser { __typename ...UserDetails } areaName lastReportTimestamp obfuscatedReason totalSteps uncertaintyInfo { __typename ...UncertaintyInfoDetails } ... on OngoingWalk { distance positions { __typename ...LocationPoint } path { __typename ...PositionCoordinates } } ... on OngoingRest { position { __typename ...PositionCoordinates } place { __typename ...PlaceDetails } }}"
Public Const FRAGMENT_UNCERTAINTY_DETAILS = "fragment UncertaintyInfoDetails on UncertaintyInfo { __typename areaName updatedAt circle { __typename ...CircleDetails }}"
Public Const FRAGMENT_CIRCLE_DETAILS = "fragment CircleDetails on Circle { __typename radius latitude longitude}"
Public Const FRAGMENT_LOCATION_POINT = "fragment LocationPoint on Location { __typename date errorRadius position { __typename ...PositionCoordinates }}"
Public Const FRAGMENT_PLACE_DETAILS = "fragment PlaceDetails on Place { __typename id name address position { __typename ...PositionCoordinates } radius}"
Public Const FRAGMENT_ACTIVITY_SUMMARY_DETAILS = "fragment ActivitySummaryDetails on ActivitySummary { __typename start end totalSteps stepGoal dailySteps { __typename date totalSteps stepGoal } totalDistance}"
Public Const MUTATION_DEVICE_OPS = "mutation UpdateDeviceOperationParams($input: UpdateDeviceOperationParamsInput!) { updateDeviceOperationParams(input: $input) { __typename ...DeviceDetails }}"
Public Const MUTATION_SET_LED_COLOR = "mutation SetDeviceLed($moduleId: String!, $ledColorCode: Int!) { setDeviceLed(moduleId: $moduleId, ledColorCode: $ledColorCode) { __typename ...DeviceDetails }}"
End Module
This is the code I have for daily statistics. It takes the information and then plots it on a graph.
` Dim restTryFiList As RestClient = New RestClient("https://api.tryfi.com/graphql?query=query query { pet (id: """ & pet_id & """) { dailyStat: currentActivitySummary (period: DAILY) { ...ActivitySummaryDetails } weeklyStat: currentActivitySummary (period: WEEKLY) { ...ActivitySummaryDetails } monthlyStat: currentActivitySummary (period: MONTHLY) { ...ActivitySummaryDetails } }} " + FRAGMENT_ACTIVITY_SUMMARY_DETAILS)
restTryFiList.AddDefaultHeader("Content-Type", "application/json")
Dim requestTryFiList As RestRequest = New RestRequest(Method.POST)
requestTryFiList.AddHeader("Content-Type", "application/json")
requestTryFiList.AddCookie("fi.sid", fiSID)
Dim responseTryFiList As RestResponse = restTryFiList.Execute(requestTryFiList)
TryFiDict.Clear()
TryFiDict = jss.Deserialize(Of Dictionary(Of String, Object))(responseTryFiList.Content)
fiStepsMonthlyDict = jss.Deserialize(Of Dictionary(Of String, Object))(responseTryFiList.Content)
For Each item In TryFiDict
daily_pet_steps = TryFiDict.Item("data").item("pet").item("dailyStat").item("totalSteps")
daily_pet_total_distance = TryFiDict.Item("data").item("pet").item("dailyStat").item("totalDistance")
weekly_pet_steps = TryFiDict.Item("data").item("pet").item("weeklyStat").item("totalSteps")
weekly_pet_total_distance = TryFiDict.Item("data").item("pet").item("weeklyStat").item("totalDistance")
monthly_pet_steps = TryFiDict.Item("data").item("pet").item("monthlyStat").item("totalSteps")
monthly_pet_total_distance = TryFiDict.Item("data").item("pet").item("monthlyStat").item("totalDistance")
stats_monthly_date_start = TryFiDict.Item("data").item("pet").item("monthlyStat").item("start")
stats_monthly_date_end = TryFiDict.Item("data").item("pet").item("monthlyStat").item("end")
stats_monthly_total_steps = TryFiDict.Item("data").item("pet").item("monthlyStat").item("totalSteps")
stats_monthly_total_steps_goal = TryFiDict.Item("data").item("pet").item("monthlyStat").item("stepGoal")
Next
'Monthly Statistics
Dim keyColumn As DataColumn = New DataColumn("Key")
keyColumn.DataType = System.Type.GetType("System.String")
Dim valueColumn As DataColumn = New DataColumn("Value")
valueColumn.DataType = System.Type.GetType("System.String")
dtMonthly.Columns.Add(keyColumn)
dtMonthly.Columns.Add(valueColumn)
For Each item As KeyValuePair(Of String, Object) In fiStepsMonthlyDict.Item("data").item("pet").item("monthlyStat").item("dailySteps")
For i = 0 To 31
Dim iDate As String = fiStepsMonthlyDict.Item("data").item("pet").item("monthlyStat").item("dailySteps")(i).item("date")
Dim oDate As DateTime = Convert.ToDateTime(iDate).ToShortDateString
dtMonthly.rows.add(fiStepsMonthlyDict.Item("data").item("pet").item("monthlyStat").item("dailySteps")(i).item("date"), fiStepsMonthlyDict.Item("data").item("pet").item("monthlyStat").item("dailySteps")(i).item("totalSteps"))
Next
Next`
Hi all, I'm super glad to come across this repo and some of the work being pulled together here. It's been really useful in trying to get my dog's data out of the Fi service.
I'm reasonably familiar with GraphQL and don't need a whole application just to grab this data once (I don't have a need to edit anything at this point)– I've just been using Postman and issuing GraphQL queries directly to api.tryfi.com.
I want a copy of my dog's history (walks, steps, sleep/naps, etc.), but find it hugely disappointing that I have to continue to pay for the service if I want access to these things. Seems pretty horrible that if I want to look back on a fun walk we had years from now, I have to keep the service active.
Since the API isn't documented, I haven't found an obvious way to get the Fi GraphQL schema, so I've been sifting through the code here and at @cwille97's repo.
My question: does anyone have the complete schema anywhere to basically replicate what you can get in the app?
So far I've gotten everything from the Fi app except the historical activity (queries like @jmargel74 's seem to just do the most recent days/month). Can anyone offer cursor or pagination schema to get activity by day all the way back to the first day of my dog's records? I've tried a bunch of things blind, but I'm just guessing here.
To be specific, if you go to the Activity or Sleep screens under the data tab, it looks like it's using a pet({ID}) object with:
{dailyStat/weeklyStat/monthlyStat}: currentActivitySummary (period: {DAILY/WEEKLY/MONTHLY})
For Activity, the above only loads the current period, but the app lets you swipe to go back to previous periods. I'm wondering how to emulate this in GraphQL? I've been able to use limit and cursor parameters in other places, like for the Feed or for Sleep to get more records, but the same approach doesn't work here (GraphQL returns an error that these parameters aren't recognized on currentActivitySummary).
Here's me getting more records for rest/sleep, for example, upping the limit parameter:
query {
pet(id: "{ID}") {
dailyStat: restSummaryFeed(cursor: null, period: DAILY, limit: 1500){
# other return fragments here
}
}
If the schema isn't known, I would really appreciate some suggestions to try for getting historical activity (steps, active time, strain). I'll also organize what I've figured out and will share it here.
Using your query to create a .net application. Thank you for your hard work! As for the activity section I believe that's coming from a site: https://analytics.tryfi.com
It looks like it's on a aws system and having issues getting through. Giving me a {"message":"Missing Authentication Token"}. Tried the session_id but no luck. I don't believe it's a graphql query for the analytics (pet ranking, etc..)