How to include Device Name (Not just Device ID) in SMS when using Messaging Cloud API (Twilio)

I am using Twilio along with Webhooks to send SMS’s to notify users of a condition indicating need for repair at various locations (NORTH, CENTRAL, SOUTH, etc. x 100). When creating the Webhook, I found the documentation stating that the pre-defined webhooks available for use in the message Body only include DEVICE ID, EVENT NAME, EVENT VALUE, and PUBLISHED AT.

However, I have named each device according to location and the repair notification process would be greatly simplified if the SMS included the Device Name instead of the Device ID. Is there a simple way to include the Device Name in the SMS rather than or in addition to the Device ID. This is possible using IFTTT Webhooks, but I would rather not use IFTTT for reliability reasons.

1 Like

The device name will not be added by the webhook services, so you’d need to actively embed it in your event payload.

Although this would be a nice feature to propose, which can be done via a GitHub “issue” report here

Thanks ScruffR. I’ll propose that.

By actively embedding it in the event payload, do you mean to manually include that in the Event Value when publishing? Or is there another way to do this similar to how IFTTT can include it? If so, could you direct me to any resources you’re aware of to learn how to do this? I just don’t want to have to write 100 different Particle scripts for each device at each location. Sorry, I’m pretty new to the whole webhook/cloud API business.

You’d just add the device name in the data field.
And here you can find the way how your device can request its name from the cloud (one sketch for all devices)
https://docs.particle.io/reference/firmware/photon/#get-device-name

That is a brilliant idea. I have been able to obtain and serially print the device name but have been unable to save the device name for later use in Event Contents/Body. I attempted to make a global variable “String dev_name” and write String(data) (which is the Device Name) to it in the handler function when using Particle.Subscribe. However, dev_name is not overwriting and is remaining NULL. I also tried to first save “data” to the buffer using strcpy and strcpy_P then to the variable but to no avail. See below for example code. How does one save “data” as a String for later use?

---------- Code ----------

String dev_name;

void handler(const char *topic, const char *data) {
    Serial.println("received " + String(topic) + ": " + String(data));
    dev_name = String(data);
}

void setup() {
    Particle.subscribe("particle/device/name", handler);
    Particle.publish("twilio_sms", dev_name, PRIVATE);
    Serial.begin(115200);
}

void loop() {
    Serial.println("That's all!  You can restart or edit the code now.");
    delay(60000);
}

ALSO TRIED:

char buffer[8] = "       ";
String dev_name;

void handler(const char *topic, const char *data) {
    Serial.println("received " + String(topic) + ": " + String(data));
    strcpy(buffer, data);
    dev_name = String(buffer);
}

void setup() {
    Particle.subscribe("particle/device/name", handler);
  Particle.publish("twilio_sms", dev_name, PRIVATE);
  Serial.begin(115200);
}

void loop() {
    // Serial.println("That's all!  You can restart or edit the code now.");
    delay(60000);
}

First, I’d stay away from String and stick with char[] which can also be passed to Particle.publish().
And second, subscribing alone isn’t enough. You also need to ask the cloud to send you the name to your subscription.

char dev_name[32] = "";
bool publishName = false;

void handler(const char *topic, const char *data) {
  strncpy(dev_name, data, sizeof(dev_name)-1);
  Serial.printlnf("received %s: %s", topic, dev_name);
  publishName = true;
}

void setup() {
  Particle.subscribe("particle/device/name", handler);
  Particle.publish("particle/device/name");  // <-- ask the cloud for the name to be sent to you
}

void loop() {
  if (publishName) {
    Particle.publish("twilio_sms", dev_name, PRIVATE);
    delay(1000); // to ensure adhering to rate limit
    publishName = false;
  }
}
4 Likes

Here is another way we were able to accomplish something similar.
This only works if you have your own server of some kind.

We watch the event stream where we then pull the CoreID from the JSON.
https://api.spark.io/v1/devices/events/?access_token=XXXXXXXXXX

Then, if we do not already have the Device Name, we hit the device API with that CoreID.
https://api.spark.io/v1/devices/COREIDGOESHERE/?access_token=XXXXXXXXXXX

You can get the device name from the JSON this returns.

The device name caches next to the CoreID for future reference in our database.

Hello,

I am new to Particle and also fairly new to IoT. I would like to display my device name and also was trying to flash two different electrons with same firmware. I currently hard coded the device name into the firmware but I am looking for a much better solution. For some reason particle json does not accept string or float values. Is there something I am doing wrong. Can someone help me with that.

Welcome to the community :+1:
We are happy to help, however for the most common questions like

The docs would be the first resource to pull :wink:
https://docs.particle.io/reference/firmware/electron/#get-device-name

With that info, I'm sure the second part of the question will become self-evident

@ScruffR I did refer to the document you mentioned. I have created a webhook with custom body. It has issues displaying string. It displays only integers and float.

Can you show the code you are using?

I know this was almost 2 years ago, but I implemented this in my code today and had some unexpected behavior. Initially I tried a shortcut leaving the loop empty and moving the publish to Twilio_sms directly under the publish to "particle/device/name" with a 1 sec delay between them. I thought this would work and only send the SMS once while not having to include the publishName flag, but i was receiving a "null" by SMS. Once I moved the twilio_sms publish into the loop, it worked.

Two Questions:

  1. Why did it only work with the twilio_sms publish in the loop. I'm an entry level coder, but I'm sure there's a basic explanation.
  2. I haven't researched this more than 15 min, but since I'm writing this post. Is there a simple way to concatenate the device name with another message such as "Device01 restarted" (assuming the device is called device01). With the below code, it compiles, but returns only the device name.
char dev_name[32] = "";
char restarted_msg[11] = "_restarted";
bool publishName = false;

void handler(const char *topic, const char *data){
        strncpy(dev_name, data, sizeof(dev_name)-1);
        publishName = true;
    }

void setup() {
    Particle.subscribe("particle/device/name", handler);
    Particle.publish("particle/device/name");
    strcat(dev_name, restarted_msg);
}

void loop() {
    if (publishName) {
        Particle.publish("twilio_sms", dev_name, PRIVATE);
        delay(1000);
        publishName = false;
    }
}

You are requesting the device name from the cloud - which is an asynchronous action.
The Particle.publish() call only sends the request to the cloud, it doesn’t wait for the response. The time for the response to come in and be treated via your subscribe handler was obviously longer than your delay. delay(1000) only lets the cloud tasks run once every 1000ms, so even if the response was already there the device OS couldn’t actually deal with it in the first 1000ms of that delay.

If you write it like this it should also work

void setup() {
    Particle.subscribe("particle/device/name", handler);
    Particle.publish("particle/device/name");
    // allow for up to 3 sec and maximum time to attend to cloud tasks
    for (uint32_t ms = millis(); millis() - ms < 3000 && !publishName; Particle.process());
    Particle.publish("twilio_sms", dev_name, PRIVATE);
}
2 Likes

Very helpful as always.
I didn’t think about the delay also locking up the system from dealing with the response. That clarifies it and I’ll use your alternative stalling method going forward. I just wanted to make sure I wasn’t missing some fundamental principle of how the setup and loop functions interact.

1 Like

@ScruffR

I tried the code below with SYSTEM_THREAD(ENABLED); and it won’t work. Any suggestions on how to get this working with that enabled?

void setup() {
    Particle.subscribe("particle/device/name", handler);
    Particle.publish("particle/device/name");
    // allow for up to 3 sec and maximum time to attend to cloud tasks
    for (uint32_t ms = millis(); millis() - ms < 3000 && !publishName; Particle.process());
    Particle.publish("twilio_sms", dev_name, PRIVATE);
}

You need to waitFor(Particle.connected, 300000) before Particle.publish()

That worked but I’m running into an odd issue.
I created at app the that will process the device rename and after 3 seconds invoke a System.reset(); function. The device reboots but I still get the old name when having this code in the setup

Particle.subscribe("particle/device/name", handler);
waitFor(Particle.connected, 300000)
Particle.publish("particle/device/name");

When I completely power off and power on device it works as designed. What is so special about System.reset() that doesn’t allow the device to get the new name pulled properly?

Also, it worked fine prior to 1.5.0.

To tell more we’d need to know how exactly you are renaming the device, how your subscribe handler works and how you have the device name stored on your device.

The apps successfully rename the device because the Console shows the updated name.
I have an iOS and Android app and use code similar to the following

iOS

myPhoton!.rename("myNewDeviceName", completion: { (error:Error?) -> Void in
    if (error == nil) {
        print("Device successfully renamed")
// Call Reset Function
    }
})

Android

particleDevice.setName(newName); // Call Reset Function

Particle Code

void setup() {
*****Other code*******

 Particle.function("RT",cloudResetFunction);

  Particle.subscribe("particle/device/name", handler);
  waitFor(Particle.connected, 300000);
 for (uint32_t ms = millis(); millis() - ms < 3000; Particle.process());
  
 Particle.publish("particle/device/name");

*****Other code*******

void loop{
*****Other code*******

 if ((resetFlag) && (millis() - rebootSync >=  rebootDelayMillis)) {
	
	   Particle.publish("Debug","Remote Reset Initiated",300,PRIVATE);
	   delay(4000);
        System.reset();


*****Other code*******
}


void handler(const char *topic, const char *data) {
  strncpy(dev_name, data, sizeof(dev_name)-1);
  deviceName = dev_name;
  
 
 
}

int cloudResetFunction(String command) {
       resetFlag = true;
       rebootSync=millis();
       return 0;            
    }

}

Are any of your variables retained?
That's what I was trying to get at with this

Why are you doing this

dev_name already seems to be a global variable and deviceName seems to be a String which seems to be superfluous and better avoided anyway :wink:

BTW, have you tried increasing the propagation time (e.g. 60sec vs. 3sec) for the new name to trickle down the entire Particle infrastructure?