Webhooks and Ubidots

Don’t worry about it, we’re here to help you! :slight_smile:

Answering your questions:

  1. As I said before, for testing purpose I used the sample code provided by Particle once you created the Webhook, but you can set the delay required for your application and you shouldn’t get any issue.

  1. The status code response 400 means Bad Request – Error due to an invalid body in your request. Please verify if it’s a valid JSON string and that the fields are the ones expected by the endpoint (string, object or float).

See the REST API Reference for any doubt with it!

Best Regards,
Maria C.

@mariahernandez,

OK, sounds like a good step. How can I see the JSON string that is being sent? I don’t see it in the Particle Console.

Also, can you verify that the screen shots I attached to this post look correct?

Thanks,

Chip

@chipmc,

Unfortunately I’m not sure about that… Because the particle packages goes encrypted. For that reason I recommend you start with the sample code which works properly, and then you can add in small fragments your routine to the base example in order to verify where can be the error.

Maria C.

Send you hook to https://requestb.in/ or simailr and that way you can see exactly what you are sending

1 Like

@Viscacha

Thank you for the suggestion.

OK, I gave up on the “Table” integration after seeing others had done the same. I am using the custom JSON approach and was able to send multiple data points in one publish. Great news!

However, I wanted to add “context” to one of the values and I am stuck.

After reading the Ubidots API reference, I think the format I need to add “context” to the Watering variable looks like this in my Webhook:

{
  "Moisture": "{{Moisture}}",
  "Watering": {
    "value": "{{Watering}}",
    "context": "{{status}}"
  },
  "SoilTemp": "{{SoilTemp}}"
}
  

I put together a string that I think fits the bill with this line of code:

String status = "Oops";
String data = String::format("{\"Moisture\":%i, \"Watering\": { \"value\": %i, \"context\":\"" + status + " \"}, \"SoilTemp\":%i}",capValue, wateringMinutes, soilTemp);
Particle.publish("AquaMaster", data, PRIVATE);

In the console, I see the web hook go out and it looks OK:

{"data":"{\"Moisture\":517, \"Watering\": { \"value\": 0, \"context\":\"Oops \"}, \"SoilTemp\":16}

but when I look at what is actually sent to Ubidots using Requestb.in - I see the raw data looks like this:

{"SoilTemp":"16","Watering":{"context":"","value":"[object Object]"},"Moisture":"517"}

What is happening here? How did the JSON get changed from what is listed in the console to what was sent to Ubidots?

Thanks,

Chip

I’m literally about to try much the same thing myself so don’t have a quick answer for you @rikkas7 might be the man to ask as he wrote this pretty extensive article on JSON https://github.com/rickkas7/particle-webhooks . JSON, webhooks etc are all new to me too so I’ve been stumbling around like you. If I was to guess the “Interpreter” on Particle that turns your published string into some JSON before sending it to Ubidots needs some quotes or escape characters in there somewhere to properly convert your string. I’m pretty sure I saw an example that used context however, possibly in here?

@Viscacha,

Thank you for the encouragement. I would like to figure this out. I have been going through @rickkas7 tutorial and the firmware docs and it may be that adding context is more complicated than what the Particle Webhook - JSON approach can handle. I may need to use the “body” approach and this is covered in Rick K’s tutorial.

@mariahernandez or @aguspg I need your help on the format of the request as I can’t seem to find a good example of context for a variable outside of Lat and Long. Using, one of those as a starting point, I have constructed the following CURL request (edited for privacy):

curl -XPOST -H 'Content-Type: application/json;' -H 'X-Auth-Token: (my token)' -d '{"SoilTemp":"19","Watering":{"value": "0", "context": "Oops"},"Moisture":"516"}' https://things.ubidots.com/api/v1.6/devices/(my device API Label)

I am getting a weird response that I need to figure out. I have searched the Ubidots API reference and forums and am coming up empty. Here is the response:

{"watering": [{"status_code": 400, "errors": {"context": ["'Oops' value must be a dict."]}}], "soiltemp": [{"status_code": 204}], "moisture": [{"status_code": 204}]}

I could not find a reference to error code 204 in the response code documentation and I could find no reference to “”‘Oops’ value must be a dict."". Can you please tell me what I am doing wrong.

My hope is that I can solve this from both ends: get the curl command right and then figure out how to create a “body” style Webhook from the command line interface.

Any help or suggestions are appreciated.

Chip

HTTP response codes are standardised, so no need for redundant docs by Particle or Ubidots IMO (when they do, it’ll be to add extra meaning for their special cases)
https://httpstatuses.com/

204 = (“success” as all 2xx codes - but …) no content

@ScruffR,

Thank you for the link, I have bookmarked it for future reference.

I need to better understand how to troubleshoot these issues. For example, status code 204 means success but “no content” for SoilTemp yet, I sent what looks like a valid key / value pair: “SoilTemp”:“16”

I appreciate your help.

Thanks,

Chip

I’m not sure, but how about case sensitivity (SoilTemp vs. soiltemp & Moisture vs. moisture)?

@ScruffR,

I looked at that and it seems that Ubidots takes SoilTemp and makes it lower case as the Webhook send with Caps but Ubidots assigns it an all lower case API label. This is from the JSON Webhook I am using now and that works perfectly.

Still, it is likely a little thing like a quote or a delimiter that is causing this to fail so I appreciate your input.

Chip

Greetings @chipmc, looping into your issue you are building in a wrong way your context, the context is a key-value dictionary, so your payload should be something like this:

{"SoilTemp":"19","Watering":{"value": "0", "context": {"key1":"Oops"}},"Moisture":"516"}' https://things.ubidots.com/api/v1.6/devices/{DEVICE_LABEL}

So please try with this command:

curl -X POST -H 'Content-Type: application/json;' -H 'X-Auth-Token: {PUT_HERE_YOUR_TOKEN} -d '{"SoilTemp":"19","Watering":{"value": "0", "context": {"key1":"Oops"}},"Moisture":"516"}' https://things.ubidots.com/api/v1.6/devices/{PUT_HERE_YOUR_DEVICE_LABEL}

Regards

1 Like

@jotathebest,

Thank you! That worked, got the response code:
{“watering”: [{“status_code”: 201}], “soiltemp”: [{“status_code”: 201}], “moisture”: [{“status_code”: 201}]}

But, when I look at the data point in Ubidots, the “Context” column is blank. How do I display this context value in the Ubidots UI?

Chip

Greetings @chipmc, it is pretty strange your issue, at my side is working properly:

Keep in mind that with the payload of the previous example, the only variable with context data is "Watering" so that is the one that you should check. Can you gently try again?

Regards

@jotathebest,

Thank you for encouraging me to try again. It worked! Now I need to see If I can turn this into a Particle Webhook. Do you have any good examples of using mustache templates to parse the Ubidots response?

Thanks,

Chip

OK,

So, I think I have made some progress in finding the issue.

  1. With @jotathebest and @mariahernandez help, I now have a curl command that will send the non-GPS context to Ubidots. Here is the response code I get:
{"watering": [{"status_code": 201}], "soiltemp": [{"status_code": 201}], "moisture": [{"status_code": 201}]}
  1. However, when I send that exact same string using the Webhook. I get a different result.

My code snippet:

  String data = "{\"SoilTemp\":\"19\",\"Watering\":{\"value\": \"0\", \"context\": {\"key1\":\"Oops\"}},\"Moisture\":\"516\"}";
  Particle.publish("AquaMaster", data, PRIVATE);

My JSON template in the Webhook:

{
    "SoilTemp":"{{SoilTemp}}",
    "Watering":
        {"value": "{{Watering}}", 
        "context": 
            {"key1":"{{Context}}"
            }
        },
    "Moisture":"{{Moisture}}"
}

Now I get this response in the console:

  1. When I redirect the Webhook to Requestb.in, I can see that the JSON is getting garbled:
    ‘’’
    {“Moisture”:“516”,“Watering”:{“context”:{“key1”:""},“value”:"[object Object]"},“SoilTemp”:“19”}
    ‘’’
    The Context and the value for “watering” is not being sent.

Is this a limitation of what a JSON WebHook can do? Do I need to move to the “Body” style. I don’t think this is an Ubidots issue - it seems to be a problem on the Particle side.

Any ideas?

Thanks,

Chip

Hi, unfortunately I do not have a single parser in a snippet, but you can refer to any of our functions to get values from Ubidots, there you can find a reference piece of code to reference, i.e inside the ESP8266 library: https://github.com/ubidots/ubidots-esp8266/blob/master/UbidotsMicroESP8266.cpp#L186

Hope it helps you.

@jotathebest,

Got it.

Thank you!

Chip

@jotathebest, @mariahernandez, @aguspg, @rickkas7

I have been able to figure out how to add context to my datapoints with a Web hook to Ubidots. It was not easy for two reasons:

  1. There are no good examples of non-gps context
  2. There are not great tools for debugging a web hook

My hope is that this post will help the next person trying to send non-GPS data to Ubidots using a Webhook.

Here is the approach:

  1. With he help of the good folks from Ubidots, I determined the correct format for a curl command that would create a new datapoint on Ubidots with “context”. It was:
curl -XPOST -H 'Content-Type: application/json;' -H 'X-Auth-Token: My Token' -d '{"SoilTemp":"19","Watering":{"value": "0", "context": {"key1":"Oops"}},"Moisture":"516"}' https://things.ubidots.com/api/v1.6/devices/My Device API Key
  1. There are three ways to send Webhooks: Form, JSON and Body. Don’t waste your time on Form or JSON - they will not work for JSON which contains more than a simple one-layer key / value payload. Go straight to the “Body” method.

  2. Read @rickkas7 's tutorial found here.

  3. Create a whatever.json file using this template. Mine looks like this:

{
  "event": "Ubidots_hook",
  "url": "https://things.ubidots.com/api/v1.6/devices/My Device API Key",
  "headers": {
    "X-Auth-Token": "My Token"
  },
  "requestType": "POST",
  "mydevices": true,
  "noDefaults": true,
  "json":{
    "SoilTemp":"19",
    "Watering":{
      "value": "0",
      "context": {
        "key1":"Oops"
        }
    },
    "Moisture":"516"
  }
}

Use the steps in Rick’s tutorial for the steps to “create” and “publish” the web hook and make sure it is received by Ubidots and generates a “201” response code. See this site for the standard HTTP status codes during this step (thanks @ScruffR).

  1. If you have any problems at this point, Use @rickkas7 's mustache tester and redirect to a Requestb.in URL to see the JSON Payload. Mine was:
{"Moisture":"516","Watering":{"context":{"key1":"Oops"},"value":"0"},"SoilTemp":"19"}
  1. Then go to Ubidots and make sure that a new data point was created for “watering” and that datapoint had a context of “Key1:Oops”.

    . OK, so now, we can create a new datapoint on Ubidots from the command line using dummy data via a Webhook.

  2. The next step is to replace the String values used in troubleshooting with variables which are provided in your sketch. This is actually fairly easy when you use the Body web hook. All you need to do is name the variables in the whatever.JSON

{
  "event": "Ubidots_hook",
  "url": "https://things.ubidots.com/api/v1.6/devices/My device",
  "headers": {
    "X-Auth-Token": "My Token"
  },
  "requestType": "POST",
  "mydevices": true,
  "noDefaults": true,
  "responseTemplate": "{{watering.0.status_code}}",
  "json":{
    "SoilTemp":"{{SoilTemp}}",
    "Watering":{
      "value": "{{Watering}}",
      "context": {
        "key1":"{{key1}}"
        }
    },
    "Moisture":"{{Moisture}}"
  }
}

Then, put the key value pairs into your code:

  char data[256];
  snprintf(data, sizeof(data), "{\"Moisture\":%i, \"Watering\":%i, \"key1\":\"%s\", \"SoilTemp\":%i}",capValue, wateringMinutes, wateringContext, soilTemp);
  Particle.publish("Ubidots_hook", data , PRIVATE);

And the new data points are created - adding context to each of the “Watering” entries.

Since I also included the response template in the web hook, I will get a simple HTTP response code (i.e. “201” when a datapoint was successfully created) back from Ubidots which will make writing the response handler a breeze. I was able to get the response template back by simply pasting the Ubidots JSON response into the Mustache tester and then worked with the response template until I got the right output.

I hope this has been helpful and you can put the full power of Web hooks to work as you integrate your Particle device with backend IOT services such as Ubidots.

Thanks,

Chip

2 Likes

You can also do this using the console, Products for example don’t support creating webhooks via the console using a JSON file.

Send it a string like this {“w”:33,“s”:“Pebbles”} and value and context arrive as expected the other end @ Ubidots. At the other end this http://help.ubidots.com/user-guides/using-context-to-display-text-in-ubidots-widgets might be useful so you can display that context, sadly they haven’t made any of the other widgets editable in such a way as to display context which is a shame.

Its important your context is encased in quotes, I think anything not in quotes Ubidots will attempt to read as a string representation of a number.

1 Like