I'm struggling trying to find a working example of writing data to the Nest Thermostat API using plain rest. Attempting to write a C# app and cannot use Firebase. The multiple Curl examples posted so far do not work. I have a valid auth_token and can read data without issues. Finding the correct post url is elusive. Can anyone assist?
Examples like
curl -v -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '{"away":"away"}'
don't change any data.
Two things. First, follow redirects with -L. Second, put directly to the away data location, like
curl -v -L -X PUT "https://developer-api.nest.com/structures/g-9y-2xkHpBh1MGkVaqXOGJiKOB9MkoW1hhYyQk2vAunCK8a731jbg/away?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '"away"'
The PUT overwrites all data at a location. The previous command would logically be setting the structure's data to just {"away":"away"}.
user3791884,
Any luck with your C# PUT? Here is C# code that works:
using System.Net.Http;
private async void changeAway()
{
using (HttpClient http = new HttpClient())
{
string url = "https://developer-api.nest.com/structures/" + structure.structure_id + "/?auth=" + AccessToken;
StringContent content = new StringContent("{\"away\":\"home\"}"); // derived from HttpContent
HttpResponseMessage rep = await http.PutAsync(new Uri(url), content);
if (null != rep)
{
Debug.WriteLine("http.PutAsync2=" + rep.ToString());
}
}
}
Debug.WriteLine writes this to the Output window:
"http.PutAsync2=StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: *
Cache-Control: no-cache, max-age=0, private
Content-Length: 15
Content-Type: application/json; charset=UTF-8
}"
These two methods return a valid structure of my data.
1/ command line
curl -v -k -L -X GET "https://developer-api.nest.com/structures/Za6hCZpmt4g6mBTaaA96yuY87lzLtsucYjbxW_b_thAuJJ7oUOelKA/?auth=c.om2...AeiE"
2/ C#
private bool getStructureInfo()
{
bool success = false;
try
{
// Create a new HttpWebRequest Object to the devices URL.
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create("https://developer-api.nest.com/structures/?auth=" + AccessToken);
// Define the request access method.
myHttpWebRequest.Method = "GET";
myHttpWebRequest.MaximumAutomaticRedirections=3;
myHttpWebRequest.AllowAutoRedirect=true;
myHttpWebRequest.Credentials = CredentialCache.DefaultCredentials;
using(HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
if (null != myHttpWebResponse)
{
// Store the response.
Stream sData = myHttpWebResponse.GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader readStream = new StreamReader (sData, Encoding.UTF8);
Debug.WriteLine("Response Structure stream received.");
string data = readStream.ReadToEnd();
Debug.WriteLine(data);
readStream.Close();
success = deserializeStructure(data);
}
}
}
catch (Exception ex)
{
Debug.WriteLine("getStructure Exception=" + ex.ToString());
}
return success;
}
Related
i'm setting up a flask server and i would like to do HTTP POST request with a json content-type from android application.
for my purpose i only need to get json data from different client.
one of these client is an android application and it basically do an http post in the server.
the code of android post request is :
public void SendHttp(View view){
new Thread(new Runnable() {
#Override
public void run() {
StringBuffer stringBuffer = new StringBuffer("");
BufferedReader bufferedReader = null;
final String lte_url="http://192.168.1.8:5000/data_center/lte";
HttpPost httpPost = new HttpPost();
try {
HttpClient httpClient = new DefaultHttpClient();
URI uri = new URI("http://192.168.1.8:5000/data_center/lte");
httpPost.addHeader(new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
httpPost.setURI(uri);
JSONObject send_ = json_lte;
txtSend.setText(""+send_.toString(2));
StringEntity entity = new StringEntity("{"+
"\"date\":"+"\""+send_.getString("Date")+","+
"\"Ping\":"+send_.getString("Ping")+","+
"\"Download\":"+send_.getString("Download")+","+
"\"Upload\":"+send_.getString("Upload")+","+
"\"Latitude\":"+send_.getString("Latitude")+","+
"\"Longitude\":"+send_.getString("Longitude")+","+
"\"Type\":"+send_.getString("Type")+","+
"\"RsRq\":"+send_.getString("RsRq")+","+
"\"RsRp\":"+send_.getString("RsRp")+","+
"\"SINR\":"+send_.getString("SINR")+","+
"\"Bandwidth\":"+send_.getString("Bandwidth")+
"}");
txtSend.setText(entity.toString());
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
} catch (some Exeption...)}
}
}).start();
the only output of the flask server is it
Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.1.237 - - [23/Jul/2019 22:47:58] "POST /data_center/lte HTTP/1.1" 201 -
the code about the server is :
#app.route('/data_center/lte',methods=['POST'])
def post_LTE_data():
try:
data = request.get_json(force=True)
packet = {
'date': data['Date'],
'ping': data['Ping'],
'download': data['Download'],
'upload': data['Upload'],
'latitude': data['Latitude'],
'longitude': data['Longitude'],
'type': data['Type'],
'RsRq': data['RsRq'],
'RsRp': data['RsRp'],
'SINR': data['SINR'],
'bandwidth': data['Bandwidth']
}
lte.append(packet)
return f"OK", 200
except Exception or JsonError as exc:
print(str(exc))
return "some problem"+str(exc), 201
It seems that you have to configure your logging module. You can replace the Python code print(str(exc)) with app.logger.error(str(exc)) to see if it produces some output. You can click here to find some useful code.
By the way, you can take a look at the content received by your Android client because it should receive the response "some problem"+str(exc).
I do not know much about Android code, but it seems that you are dealing with a wrong JSON string. The right format is as below:
{
"foo":"bar",
"good":"bad"
}
In your Android code, you might have to replace
"\"date\":"+"\""+send_.getString("Date")+","
to
"\"date\":"+"\""+send_.getString("Date")+"\","
The above rule should be applied to all lines in the JSON string. Be careful about the symbol "", and you have to make sure that the data during POST is a valid JSON string. Also, I suggest you use another way like utilizing some libraries to build JSON strings to avoid typos.
So, I am using Amazon Alexa Reminders API as shown here.
Here is my method for sending requests to API:
public static void sendReminder(String accessToken, String reminderText, long offsetInSec) {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("https://api.amazonalexa.com/v1/alerts/reminders");
post.addHeader("Authorization", "Bearer " + accessToken);
post.addHeader("Content-Type", "application/json");
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());
String jsonContent = "{ \"requestTime\" : \"" + nowAsISO + "\", \"trigger\": { \"type\" : \"SCHEDULED_RELATIVE\", \"offsetInSeconds\" : \"" + offsetInSec + "\" }, \"alertInfo\": { \"spokenInfo\": { \"content\": [{ \"locale\": \"en-US\", \"text\": \"" + reminderText + "\" }] } }, \"pushNotification\" : { \"status\" : \"ENABLED\" } }";
HttpEntity entity = null;
try {
byte[] bytes = jsonContent.getBytes("UTF-8");
entity = new ByteArrayEntity(bytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
post.setEntity(entity);
try {
CloseableHttpResponse response = client.execute(post);
System.out.println(response);
} catch (IOException e) {
e.printStackTrace();
}
}
And I execute it like this:
RemindersToolkit.sendReminder(session.getUser().getAccessToken(), "text", 1);
Skill also has permission for reminders:
But when the method is executed, I get the following response:
HttpResponseProxy{HTTP/1.1 401 Unauthorized [Content-Type: application/json, Connection: keep-alive, Server: Server, Date: Tue, 22 Jan 2019 00:21:21 GMT, Vary: Accept-Encoding,User-Agent, x-amz-rid: 8YMCM10GKVGTT71JQH3N, X-Cache: Error from cloudfront, Via: 1.1 05a90e634e0872685ad69ee9a4e0eba5.cloudfront.net (CloudFront), X-Amz-Cf-Id: J5CtMnkUTv1hd6p-7-tob7mCb-4DM7y_LxhEiMLt5x3qEqmzhwbx_Q==] org.apache.http.client.entity.DecompressingEntity#6df97b55}
According to Amazon on this page, 401 UNAUTHORIZED means Token is valid but does not have appropriate permissions.
Maybe some of you guys had the same problem or could help me figure out how to solve mine?
Thanks
Got it worked, as pointed out in this answer, granting permission in the skill is not enough, the end user using that skill also has to grant the permission. Ask the user for the permission through permission card when encountered with the unauthorized response.
The issue was that I was using the old Alexa SDK.
I had to download current version of the SDK and there is a different key (not accessToken I've used), which can be obtained directly from the Intent object and can then be used to send requests
I want to add or append my url in interface of retrofit. Code of interface is given below.
public interface PostInterface {
#POST("api/v1/app/user/resetpassword/token")
#Headers({
"Content-Type: application/json"
})
Call<JsonObject> getResult(#Body JsonObject body);
}
In the given url #POST("api/v1/wallet/user/resetpassword/token") i want to append token value.Which is value of a variable of an activity.
and my activity code is given below from where i am call the method.
try {
JsonObject params = new JsonObject();
params.addProperty("email", email);
params.addProperty("signup_mode", "mobile");
PostInterface apiService =TestApiClient.getClient(this).create(PostInterface.class);
Call call = apiService.getResult(params);
call.enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) {
I'm not entirely sure I understood if this should be part of the path or part of the query parameters, so here's both ways.
Part of the path
The way to do this with retrofit is to make it a "variable" in the path and pass it as arguments to the function.
#POST("api/v1/app/user/resetpassword/{token}")
#Headers({
"Content-Type: application/json"
})
Call<JsonObject> getResult(
#Path("token") String token,
#Body JsonObject body);
Notice the curly braces in {token} in the url. This tells retrofit that it should format an argument of your method into the url. To know which argument you use the annotation Path with the same name as the one being formatted. This results in urls like api/v1/app/user/resetpassword/09df7seh98ghs (09df7seh98ghs is my poor representation of a token).
(this assumes your token is a String. Retrofit supports more than that.)
Part of the query parameters
Similar to the way you do this with the #Path annotation you can use the #Query annotation:
#POST("api/v1/app/user/resetpassword/token")
#Headers({
"Content-Type: application/json"
})
Call<JsonObject> getResult(
#Query("token") String token,
#Body JsonObject body);
The difference here is that retrofit will add the given token as a query parameter resulting in urls like api/v1/app/user/resetpassword/token?token=...
Hey i got the answer of my question. Hope if any body is having such problem it can help in future.
Modification in interface:
#POST
#Headers({"Content-Type: application/json"})
Call<JsonObject> getResult(#Url String url, #Body JsonObject body);
Now inside your activity call back please do the following changes
try {
JsonObject params = new JsonObject();
params.addProperty("email", email);
params.addProperty("signup_mode", "mobile");
String url= Constants.BASE_URL+"api/v1/wallet/user/changepassword/"+userIdStr;
PostInterface apiService = TestApiClient.getClient(this).create(PostInterface.class);
Call call = apiService.getChangePassword(url,params);
call.enqueue(new Callback() {
Its working fine.
I use this code in index.php page
function get_model_info($model)
{
$query="select * from mobile where model_name='".$model."' limit 1";
return $query;
}
// $telegram = null;
$query=get_model_info($text);
$telegram->query=$query;
$telegram->runqury();
$result=$telegram->queryresult;
$text=urlencode($result->fetch_object()->info);
$telegram->sendmessage($userid, $text);
and used this code on telegram.php page
public function sendmessage($userid,$text)
{
$url='https://api.telegram.org/bot'.$this->token.'/sendmessage?chat_id='.$userid.'&text='.$text;
file_get_contents($url);
}
but it doesn't work.
sending text messages to telegram chat using php must be like bellow:
$url = "https://api.telegram.org/bot".$botToken."/sendMessage?chat_id=#yourtargetID&text=yourText";
file_get_contents($url);
You must replace sendmessage? with sendMessage? (Capital M)
first time curl user, working on a curl fileupload with http multipart/form-data request with vc++.
After researching I found two ways to make a multipart/form-data request. Either use "CURLOPT_POSTFIELDS" set a value as an array or use formadd and pass the pointer to CURLOPT_POSTFIELDS. I decided to do the second and configure the different fields of the request with "formdata" (two fields, one file (application/sla) the other one origin (text/plain)
I used wireshark to catch the request and saw that CURL returned CURLE_READ_ERROR (26). Then I added CURLFORM_FILECONTENT, "tmp_3DButton.stl" and got CURL_OK but the server I was sending the request to returned "Bad Media Type" and I saw that CURL didnt send my request as multipart..
(win8 64 bit, visual studio 2015, curl, c++
CURL *curl;
CURLcode res;
char error[CURL_ERROR_SIZE];
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
struct curl_slist *headerlist = NULL;
curl_global_init(CURL_GLOBAL_ALL);
// Fill in the file upload field
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_CONTENTTYPE, "application/sla",
CURLFORM_FILECONTENT, "tmp.stl",
CURLFORM_FILE, filePathSTL,
CURLFORM_END);
// Fill in the filename field
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "origin",
CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_FILENAME, "se_1_0",
CURLFORM_END);
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, "Accept: text/plain");
if (curl) {
// URL that receives this POST
curl_easy_setopt(curl, CURLOPT_URL, "http://blabla.com/upload");
//multipart/form-data
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
2);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
error[0] = 0;
// Perform the request, res will get the return code
res = curl_easy_perform(curl);
CString str;
// Check for errors
if (res != CURLE_OK)
{
str.Format("curl_easy_perform return %s [%d]", curl_easy_strerror(res), res);
size_t len = strlen(error);
if (len)
{
_bstr_t bstrt(error);
AfxMessageBox(error);
}
}
curl_easy_cleanup(curl);
filePathSTL is bstrt for example C:\..\..\tmp.stl (with doubled slashes..)
Found an answer, "CURLFORM_FILE" obviously wants a string!