Google Home SYNC and ReportState "online" values don't seem to be read by iOS client but Android is OK - ios

Problem
When fulfilling SYNC requests, QUERY requests and ReportState calls, I'm reporting all devices as "online": true. I can see this value being correctly read by Google, in that the values appear set on the ReportState Dashboard test tool. Android works fine, showing the device online ("Linked to you") after a brief query ("Connecting..."). Converesly, when using the iOS mobile client, as the user goes into the page for a device, it queries only to then report the device as being offline. Both the dashboard and JSON responses to calls all show "online": true. If the user tries interacting with the device, for example turning it on, it works.
QUERY Response
{
"requestId": "ARequestId",
"payload": {
"devices": [{
"id": "ADeviceId",
"online": true,
"status": "SUCCESS"
}]
}
}
Notes
This could be a bug in the iOS client, but it seems much more likely it's a bug in my code or misunderstanding on my part as this is my first Smart Home Action.
I've tried including "online": true all over the place, e.g. in SYNC, QUERY and ReportState calls. This has at least given the dashboard awareness of the initial online state, but not helped the iOS client.
In general, ReportState seems to work fine, in that my changes are reflected in the dashboard.
Screenshots
Note the contradiction between the test tool's state and the iOS client's indication.
ReportState Dashboard showing online=true
iOS Google Home Client showing same device as offline

I came back to this issue after around a year away from this project. It turns out that this is actually due to misreading the response structure of the QUERY Intent. The SYNC Intent expects an array of objects with "id" fields. The QUERY Intent expects a dictionary keyed by the id.
Bizarrely, even though this is back-end to back-end, and no error is thrown by the Google side, an Android client seems to handle this fine, but the iOS client doesn't.
Essentially, yes there is a bug there somewhere with iOS in as much as it ought to behave the same as Android, and similarly there ought to be a 400 error for the bad request format, but the error was essentially in my response structure.
A Correct SYNC Intent Response
[
{
"id": "DeviceId1",
"online": true,
"status": "SUCCESS"
},
{
"id": "DeviceId2",
"online": true,
"status": "SUCCESS"
}
]
My Erroneous QUERY Intent Response (Same as correct SYNC)
[
{
"id": "DeviceId1",
"online": true,
"status": "SUCCESS"
},
{
"id": "DeviceId2",
"online": true,
"status": "SUCCESS"
}
]
A Correct QUERY Intent Response (a keyed dictionary, rather than an array)
{
"DeviceId1" :
{
"online": true,
"status": "SUCCESS"
},
"DeviceId2" :
{
"online": true,
"status": "SUCCESS"
}
}
So even though the emergent behaviour was different in iOS and Android, it was me all along. It was a very easy to miss slip. Hope this helps someone, as the lack of errors coming back meant this one was infuriating.

Related

iOS fetch healthkit data combining multiple devices

I have an application that collects healthkit data from iOS.
It sends the data to my application like this:
{
"header": {
"id": "18018B64-850A-4F3A-9D21-4FF0C99762D6",
"creation_date_time": "2020-01-15T14:15:00.000+01:00",
"schema_id": {
"namespace": "omh",
"name": "step-count",
"version": "1.0"
}
},
"source": {
"operating_system_version": "13.3.0",
"bundle_identifier": "com.garmin.connect.mobile",
"product_type": "iPhone10,4",
"name": "Connect",
"version": "20"
},
"device": null,
"body": {
"step_count": 888,
"effective_time_frame": {
"time_interval": {
"start_date_time": "2020-01-15T14:15:00.000+01:00",
"end_date_time": "2020-01-15T14:29:59.000+01:00"
}
}
}
},
I want the separate data, because my app shows its own aggregations (day, month, today, etc) and I want to do this as I wish on server side, so I don't have access to the users phone. The users phone sends new measurements to the server as they are available in the background.
But, the issue is that I also receive measurements that are from iPhone iteself, or another device collecting stepcounts.
I could filter the incoming data for one device, but that means that if we turn off the watch, we miss data. Healthkit does collect iPhone data, so in the Health app you do see stepcounts.
I actually want to see the data that is in the healthkit app, so I get updated constantly.
Short question: I don't want to have to think about the device, I just want the HK value as it changes. Is this possible?
The way to reproduce the aggregates shown in Health on iOS is to use HKStatisticsCollectionQuery rather than uploading individual samples and then attempting to compute the values for charts yourself. It's unlikely that you will be able to reproduce the logic that HKStatisticsCollectionQuery uses to combine overlapping data, so it is much more straightforward to use the query directly.

Using filter on /me/joinedTeams not working

I'm implementing a search for a user's joined Teams unsing Microsoft Graph. The idea is to make a call to /beta/me/joinedTeams and use a ?$filter=startswith(description,'searchterm') filter.
So for example when I try the request https://graph.microsoft.com/beta/me/joinedTeams?$filter=startswith(description,'Business') in the Microsoft Graph Explorer it ignores the filter and I get these results:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#groups",
"value": [
{
"id": "02bd9fd6-8f93-4758-87c3-1fb73740a315",
"displayName": "HR Taskforce",
"description": "Welcome to the HR Taskforce team.",
"isArchived": false
},
{
"id": "13be6971-79db-4f33-9d41-b25589ca25af",
"displayName": "Business Development",
"description": "Welcome to the BizDev team.",
"isArchived": false
},
{
"id": "8090c93e-ba7c-433e-9f39-08c7ba07c0b3",
"displayName": "X1050 Launch Team",
"description": "Welcome to the team that we've assembled to launch our product.",
"isArchived": false
}
]
}
Am I doing something wrong with my request?
Your request is right, but the joinedTeams does not support filtering or ordering results. So although we pass the filter/orderby parameter, when Microsoft Graph sees a query parameter it doesn't expect, it simply ignores the unknown filter/orderby parameter and returns an unfiltered/default-sorted result.
I have tried the api with odata query parameters for trial O365 account and real account.
https://developer.microsoft.com/en-us/graph/docs/concepts/query_parameters
Not all parameters are supported across all Microsoft Graph APIs, and
support might differ significantly between the v1.0 and beta
endpoints.
The only suggestion for you is to vote up the existing feature request in User Voice or submit a new one.
Thanks for pointing this out. As Seiya points out, /me/joinedTeams does not support the OData query parameters. The documentation suggested otherwise, I've made a doc fix that should propagate in the next day or two.

How to send a device management request using NodeRed or any REST client

I am trying to sent a DM firmware update command from a NodeRed Flow.
Function node:
msg.payload = {"MgmtInitiationRequest": {
"action":"firmware/update",
"devices": [{
"typeId": "myType",
"deviceId": "myDevice"
}]
}}
msg.headers={"Content-Type":"application/json"}
return msg;
I send it to a http request node with a POST to
https://orgid.internetofthings.ibmcloud.com/api/v0002/mgmt/requests
Basic Authentication with api keys. I based it of Initiate a device management request
I get back a 403 which the docs have as:
One or more of the devices does not support the requested action
Anyone see what I'm missing? It works fine from the IoT Platform UI to the same devicetype/deviceid.
EDIT: Same 403 if I use a Rest client like Postman.
The swagger API documentation is a little bit misleading in that the 'body' parameter is given a name.
But, like the other POST APIs, that name isn't actually included anywhere as part of the payload.
The payload should just look like this:
{
"action": "firmware/update",
"devices": [
{
"typeId": "string",
"deviceId": "string"
}
]
}
This page in the documentation provides more detail:
https://console.ng.bluemix.net/docs/services/IoT/devices/device_mgmt/requests.html#firmware-actions-update
Has your appliance published the set of supported commands it supports when it announced itself as a managed device?
A device connects to the Watson IoT Platform and uses the managed devices operation to become a managed device.
Which looks something like this
Topic: iotdevice-1/mgmt/manage
{
...
"supports": {
"deviceActions": true,
"firmwareActions": boolean
},
...
},
...
}
https://console.ng.bluemix.net/docs/services/IoT/devices/device_mgmt/index.html

Get Recommendation from LinkedIn API returns empty map [:] as response

I have created a web application from which I am trying to get recommendations of a user from his/her LinkedIn Profile using URL
String url="https://api.linkedin.com/v1/people/~:(recommendations-received:(id,recommendation-type,recommendation-text,recommender))?format=json"
When I am using this URL in the
Api Explorer it works fine. And gives output:-
{ "recommendationsReceived": {
"_total": 2,
"values": [
{
"id": 558598601,
"recommendationText": "xxx is among the best team players I ever worked with. He has handled client effectively with smooth operations. I had always seen him as person with solution mindset and always look for solution rather than thinking about the problem. ",
"recommendationType": {
"code": "colleague"
},
"recommender": {
"firstName": "XXX",
"id": "YYYY",
"lastName": "XXX"
}
},
{
"id": ZZZZ,
"recommendationText": "XXX is one of the most dedicated person at work.I always him with a flexible attitude and ready to adapt himself in all situation.I have seen him work all night to catch up all the deadlines and deliver on time ."
"recommendationType": {
"code": "colleague"
},
"recommender": {
"firstName": "XXX",
"id": "YYYY",
"lastName": "XXXX"
}
}
] } }
The problem comes, when I am using this URL in my Developer app.It doesn't give any error just simple return an empty map [:] as output in response
Irrespective of these recommendation fields, I successfully get the user basic profile data such as email, id, image,firstName,lastName.Means my code is working for other fields well but not for these recommendation fields*
To find the solution, I did some internet surfing and find a link of Linked API docs
Linked API Docs
As per Docs following selection of profile fields are only available
to applications that have applied and been approved for the Apply with
LinkedIn program:
Recommendation Fields
I already created a LinkedIn Developer account to get key & Secret
So how do I apply and get approval for Apply with LinkedIn Recommendation Fields.
I already have seen the LinkedIn support but can't find the way to ask question to the Linked Developer help support
Please suggest me the right way.
After a long internet surfing,I have found something fruitful that, I have to fill up a form to get these fields.Here is the form
along with its procedural details
You can use just recommendations-received keyword. Try the following link. I am getting all recommendations details with this link.
https://api.linkedin.com/v1/people/~:(recommendations-received)?format=json

Restkit: How to get and map data from multiple source

I'm currently working on iOS Application with RestKit 0.20 to access data from Tastypie API.
And I am trying to get feeds data from URL like this
/api/v2/feed/?format=json
Then I will get array of feeds as below.
{
"meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 2
},
"objects": [
{
"id": 1,
"info": "This is my first post",
"pub_date": "2013-02-03T15:59:33.311000",
"user": "/api/v2/user/1/",
"resource_uri": "/api/v2/feed/1/"
},
{
"id": 2,
"info": "second post, yeah",
"pub_date": "2013-02-03T16:00:09.350000",
"user": "/api/v2/user/1/",
"resource_uri": "/api/v2/feed/2/"
}
]
}
if I want to fetch more data about user which Tastypie send it as url like a foreign key "user": "/api/v2/user/1/", do I have to nested call objectRequestOperation.
I'm confusing because I'm using block to callback when data is successful loaded. So is there any better way than requesting user data again for each feed after requesting feed complete.
Thank you very much :)
You have to define in the Feed resource :
user = fields.ToOneField(UserResource, full=True)
More info in the tastypie doc http://django-tastypie.readthedocs.org/en/latest/resources.html
Why Resource URIs?
Resource URIs play a heavy role in how Tastypie delivers data. This can seem very different from other solutions which simply inline related data. Though Tastypie can inline data like that (using full=True on the field with the relation), the default is to provide URIs.
URIs are useful because it results in smaller payloads, letting you fetch only the data that is important to you. You can imagine an instance where an object has thousands of related items that you may not be interested in.
URIs are also very cache-able, because the data at each endpoint is less likely to frequently change.
And URIs encourage proper use of each endpoint to display the data that endpoint covers.
Ideology aside, you should use whatever suits you. If you prefer fewer requests & fewer endpoints, use of full=True is available, but be aware of the consequences of each approach.

Resources