ThingSpeak route(s) for multiple devices

Hi all,

I’m successfully using a Notehub route to send data from one device (Swan+n/c-F) to a ThingSpeak channel. Now I want to add multiple routes so each device sends its data to its own ThingSpeak channel.

How would I implement that? Is it as simple as creating a separate route for each device and giving each JSONata expression its own API key? Or do you somehow use the HTTP headers to distinguish and route each event to the right channel using a single ThingSpeak route?

I’ve read through the ThingSpeak routing tutorial and I’ve searched the forum for clues, and as is probably blatantly obvious I’m pretty new to JSON and the logic of the inner workings of routing code, so any suggestions for additional tutorials or a particular doc I should read would be awesome.

My seven devices will send all the same info and all the ThingSpeak channels will be set up with the same fields. Below is a copy of my working JSONata expression.

thanks!!
…Norm…

{
“api_key”:“”,
“field1”: body.airTmpC,
“field2”: body.humid,
“field3”: body.wTmpC@Sonde,
“field4”: body.DO,
“field5”: body.EC,
“field6”: body.Salty,
“field7”: body.TDS,
“field8”: body.pH
}

Hey @noforan,

You have a couple of different options here.

  1. If you want to create a channel per device, you’ll have an API Key for each device, but you can set the key as an environment variable on each device and then use placeholder substitution in the JSONata for your route, like below. This way you only need one route and the key is set on the device.
{
“api_key”: [$device_key],
“field1”: body.airTmpC,
“field2”: body.humid,
“field3”: body.wTmpC@Sonde,
“field4”: body.DO,
“field5”: body.EC,
“field6”: body.Salty,
“field7”: body.TDS,
“field8”: body.pH
}
  1. The other option would be to have just a single channel, but pass the Device UID to ThingSpeak as a field and use that for grouping on the ThingSpeak side. Like so:
{
“api_key”: "your_key",
"field1": device,
“field2”: body.airTmpC,
“field3”: body.humid,
“field4”: body.wTmpC@Sonde,
“field5”: body.DO,
“field6”: body.EC,
“field7”: body.Salty,
“field8”: body.TDS
}

This might not be an option if you’re already using all eight fields, however.

hope that helps!

1 Like

@bsatrom – Thank you sir!

I opted for your first suggestion as I do want to have one device per channel and capture all 8 readings for each device. I read through the links to the Environmental variables and placeholder variable substitution, which are well written and very clear (to me).

I opted for the 2nd method of setting environmental variables, i.e. via setting / creating a Notehub device variable, because if I’ve understood correctly, using the first method would mean I’d need a unique sketch for each device where there’d be a unique env.set statement for each device. I’d rather have the same device firmware sketch and be able to set it at the Notehub level.

I’ve set: device_key equal to the ThingSpeak API write key for that channel.

In my Routes I’ve altered the JSONata expression to match your example.

On Notehub I got an event that seemed to confirm the change. It cited a file: _env.db
In the body it shows:
{
“_tags”: “BOB-04”,
“device_key”: “<theT/S-API-key>”
}

I’m receiving data on Notehub, and the route logs for each received sensors.qo event say: Status 200…ThingSpeak…Response 0.

So I think I’ve understood the documentation and set things up correctly, but no data is showing up on ThingSpeak. Do you have any thoughts or suggestions on how to further t/s? Does it sound like I’ve missed something?

cheers,
…Norm…

Hey @noforan It’s been a while since I’ve used ThingSpeak, but a 200 from them is a good sign. Do they have any debug logs on their end?

Hi @bsatrom,

I’ll have to look into how you get debug logs from ThingSpeak as I don’t see any obvious way to get them from the channels settings, nor from a few searches of their forum and documentation.

I did notice that prior to messing with the variable substitution JSONata expression, the Route logs provided much more in the way of a reported response. Rather than simply a 0 (zero), there was e.g. this:

{“channel_id”:2062279,“created_at”:“2023-03-27T15:18:22Z”,“entry_id”:1370,“field1”:15.10000038146973,“field2”:90.0999984741211,“field3”:13.75,“field4”:14.94999980926514,“field5”:16200,“field6”:9.399999618530273,“field7”:8752,“field8”:8.342000007629395,“latitude”:null,“longitude”:null,“elevation”:null,“status”:null}

In a post on the ThingSpeak forum I read (in part): “If you are using the REST API, there is a standard HTTP response code and an object containing the updated data or the number of entries in the channel, depending on your parameters sent.”

So I believe the above is ThingSpeak’s returned object confirming what it received along with the ID of the channel and some other fields.

If the response in the route log is just a zero then I think the route is working (based on the Status = 200), but what has been sent is not what ThingSpeak expects, so doesn’t process it.

I created a new route to webhook.site thinking that perhaps I could see the actual output with the variable substitution in place, but for some reason I could not get any data to appear at the webhook.site. I’ll spend some more time tomorrow seeing if I can make that route work and if it provides anything useful.

And I’ll search some more for a way to get debug logs for the connection on the ThingSpeak side.

Hey @noforan now I remember. ThingSpeak has a quirk where they return a 200 without a clear indication that invalid data was provided. So something in what you’re sending isn’t right. Did anything else change other than setting the Key via environment variables?

One idea would be to set-up a “debug” route via webhook.site just to see what the payload going into ThingSpeak looks like. It could be that the key is incorrect, or not set properly on the device environment variable.

Hi @bsatrom,

Finally got the route to webhook.site to work. IDK what I was doing wrong last night, but it’s receiving data now. There is seems to be a pretty significant delay before the data will show up on the webhook.site page, and not every event gets routed.

In any case, the problem would appear that the square brackets are retained in the actual message after the transformation…here’s what shows up at the test URL:

{
“api_key”: [
“WVD2T0YOJGY9ZNGU”
],
“field1”: 19.29999923706055,
“field2”: 78.4000015258789,
“field3”: 10.25,
“field4”: 7.119999885559082,
“field5”: 25880,
“field6”: 15.47999954223633,
“field7”: 13980,
“field8”: “9.014”
}

Also, I have data originating from two different remotes and the raw content arriving at the Webhook.site shows the correct API write key for each is being pulled from their respective environmental variable fields – so that part is working.

It’s just that the square brackets are not getting striped-out so the syntax of the message arriving at ThingSpeak is incorrect – at least that’s my theory.

Possible that “device_key” is reserved (a reserved field) by BluesW for something else?

I’ve checked a dozen times, but just for sanity’s sake, here again is the whole expression:

{
“api_key”: [$device_key],
“field1”: body.airTmpC,
“field2”: body.humid,
“field3”: body.wTmpC@Sonde,
“field4”: body.DO,
“field5”: body.EC,
“field6”: body.Salty,
“field7”: body.TDS,
“field8”: body.pH
}

hi @bsatrom,

Decided just to try removing the square brackets and leave the $device_key and see what happens…and voila!

Webhook.site now shows just the correctly substituted key (depending on which site sent it) inside double quotes.

I updated my route to ThingSpeak to match…and it works! :sunglasses:

1 Like

That’s great @noforan! Glad to hear you got it working.

@bsatrom – thanks for the guidance and assist!

Final note: I would recommend the documentation be updated in the Placeholder Variable Substitution section. Here it says: “Environmental variables are identified by a $ immediately after the first square bracket. For example, [$phone_number] or [$_contact_name].”

Please correct me if I am wrong but the environmental variables should be denoted by using only the $ symbol – no square brackets are needed. As implied above I’ve only tested this for a ThingSpeak route, so further testing by your team might be warranted to see if that’s a special case or there are other factors at play.

cheers,
…Norm…

1 Like