[SOLVED ]Send Data to Particle Argon using HTML canvas Example 2: Simple text box to set a variable

Goodday. Im trying to get the following to work with my particle Argon
https://help.ubidots.com/en/articles/754634-html-canvas-widget-examples Example 2.

I have done the following but think im missing some crucial steps.

  1. Create the widget as per example HTML,CSS,JS code.
  2. Add token and variable name. variable name in this case “shutterHourOpen”
  3. Create a new variable under devices with variable name “shutterHourOpen”
  4. create a new event

im not sure about the below ;

On my particle code

  #include "Particle.h"
  #include "TimeAlarms.h"
   #include "Ubidots.h"
   #include <string.h>
   #define UBIDOTS_TOKEN "BB??????????????6pxy31"
   #define DATA_SOURCE_TAG_DEVICE_API "e00fce6???????34dbe6c5"
   #define DATA_SOURCE_TAG_SHUTTER_HOUR_OPEN "shuttterHourOpen"

   float shuttterHourOpencontrol = 0;
   int i = 0;

  Ubidots ubidots(UBIDOTS_TOKEN, UBI_HTTP);

void setup() {
  Serial.begin(115200);
  Particle.subscribe("UbidotsWebhook", shutterHourOpenHandler);
}

float setShutterHourOpenControl(float valueHourOpen) {
   Serial.printf("control %f\n",valueHourOpen);
}

void shutterHourOpenHandler(const char *event, const char *data) {
  // Handle the integration response
 i++;
  Serial.println(i);
  Serial.print(event);
  Serial.print(", dataclose: ");
  if (data) {
   Serial.println(data);
   shuttterHourOpencontrol = setShutterHourOpenControl(atof(data));
    Serial.printf("shutterHourOpen %f\n",shuttterHourOpencontrol);
 } else {
   Serial.println("NULL");
 }

}

void loop() {    

}

Currently on my dashboard im not getting “value sent” message when the button is pressed. On my device variable I also dont get any values, I presume my problem is in my event trigger setup.

thanks for any assistance :slight_smile:

Hello @Melt777,

Let me first start with a recommendation that will facilitate entering manual data. Although the HTML canvas example is an option, Ubidots already provides a Manual Input Widget, so instead, use this one to enter the data and further trigger your event.

Following up, given you’re trying to send data to Particle cloud and then have it downlink to your device through the Particle.subscribe() function, you actually need to point your Webhooks not to Ubidots but to particle cloud. In Section 6 of this article you’ll find the detail explanation to pull it off.
In a nutshell, here’s how your Ubidots event trigger and webhook action should look like:


Doing so will get the trigger value sent to the Device and process by your Handler.

One last comment, it is on purpose that your setShutterHourOpenControl() function doesn’t not return a float as is expected from its definition signature ?

Best,

–David

Hi @DSR, thanks for replying.

I am familiar with the switch widget and I am currently using that in combination with the slider widget. Not ideal but I can set “shutter OPEN hour:minute” as well as “shutter CLOSE hour:minute”


I then retrieve these values and store it for TimeAlarm lib.

   valueShutterHourOpen = ubidots.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_HOUR_OPEN);
   valueShutterMinuteOpen = ubidots.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_MINUTE_OPEN);
   valueShutterHourClose = ubidots.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_HOUR_CLOSE);
   valueShutterMinuteClose = ubidots.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_MINUTE_CLOSE);
   Serial.printf("shutter OPEN %.f:%.f CLOSE %.f:%.f\n",valueShutterHourOpen,valueShutterMinuteOpen,valueShutterHourClose,valueShutterMinuteClose);

   // create the alarms 
   Alarm.alarmRepeat(valueShutterHourOpen,valueShutterMinuteOpen,0, shutterOpenAlarm); 
   Alarm.alarmRepeat(valueShutterHourClose,valueShutterMinuteClose,0,shutterCloseAlarm); 

using ubidots.get() I need to declare Ubidots ubidots(UBIDOTS_TOKEN, UBI_HTTP);

But I also need to send updates to my dashboard which means I need to use
Ubidots ubidots(“timerwebhook”, UBI_PARTICLE);

Am I correct in saying I can switch between between the two protocalls using ubidots.setCloudProtocol(UBI_PARTICLE); and ubidots.setCloudProtocol(UBI_HTTP) ?

I use ubidots.get() to load the values from the dashboard when the device start up and I intend to use the subscribe method to update the values should they be changed during operation.

I will look at the return value now when I rewrite the subscribe section.

Hi @Melt777,

Using UBI_PARTICLE, that is, webhooks, doesn’t allow retrieving data, just as you’ve discovered already, it works only to send data.
Moving forward, the ubidots.setCloudProtocol() is only used when using Mesh networks but in this case you’re using the Argon as is, not as a Mesh gateway. With that being said I recommend creating 2 different library instances as shown below, one to send data, the other to retrieve it.

#ifndef UBIDOTS_TOKEN
#define UBIDOTS_TOKEN "Your_Token"  // Put here your Ubidots TOKEN
#endif

Ubidots ubidots1(“timerwebhook”, UBI_PARTICLE); // To send data using webhooks
Ubidots ubidots2(UBIDOTS_TOKEN, UBI_HTTP); // To retrieve data

So your code would be:

valueShutterHourOpen = ubidots2.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_HOUR_OPEN);
valueShutterMinuteOpen = ubidots2.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_MINUTE_OPEN);
valueShutterHourClose = ubidots2.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_HOUR_CLOSE);
valueShutterMinuteClose = ubidots2.get(DATA_SOURCE_TAG_DEVICE_API,DATA_SOURCE_TAG_SHUTTER_MINUTE_CLOSE);

Last but no least, you could simply use the HTTP to do the bidirectional communications.

Best,

–David

@dsr David thank you, I have decided use birectional communication using HTTP and all seems to be working well. I did not know you can use two different lib instances so will keep that in mind. My only problem now is that im sitting with a lot of variables in my device. 28 variables for 7 days a week for one on/off time slot per day. Bringing me back to the HTML example 2. I was thinking of entering them in one go. i.e 12301450 (12:30 to 14:50) or as a string like suggested here [SOLVED] Control widget to publish a simple text string

is there any documentation on how to setup the body of the HTML widget of that example to send the string entered to the ubidot ‘RAW’ variable created so that I can subscribe to it. (is that not in essence what the switch and slider widget does.) I may be approaching this completely wrong. (I dont understand the solution that Jose proposed.

@Melt777

Glad to know you decided to take the HTTP option for your comms.

Following up, I’m afraid the HTML approach accompanied by the usage of the Particle library with HTTP won’t work as you expect. Let me explain why, the get() method in the library returns only the last value of the variable, not its context and there is where you’d send the data as string from the HTML canvas. With that being said, I think the best way to proceed right now is your proposal, that is, sending a value as 12301450 and parse from the Argon into 12:30 - 14:50.

Furthermore, given your need to schedule time frames for ON/OFF period, I wanted to tell you that our dev team is currently working in what is known as Scheduled Events. This will allow to trigger events based on specific days of the week and times, rather than values from variables.
Please note this is a work in progress, but we’re expecting to roll it out soon.

Last but no least, I noticed you have another community thread (Switch widget with Particle error status 400), and I thought of asking you to explain a bit more the workflow described on that thread. So far I’m confused whether the problem is sending data from the Argon to Ubidots or viceversa. I’ll be attentive to your response in that thread,

Let me know if I can be of additional assistance.

Thank for all the info David.
I will eagerly wait for the schedule event widget it will be well received.

Coming back to my initial question https://help.ubidots.com/en/articles/754634-html-canvas-widget-examples Example 2. It only demonstrates the HTML, CS and JS code. From there how is the event set up to send the string. My screen shot show how I set it up but I think my Body is incorrect
image

Do I still “get” and “Subscribe” to the string as I would to a variable?

I cant see the string being updated in my device variable.

@Melt777,

I’m looking to the event setup and it seems as you’d like to send the text to Ubidots, but that’s already done from the HTML canvas. Also, as mentioned before, sending text is also posible using the Manual Input widget just the same as in the HTML but with less trouble.

What I understand is that you’re actually looking for to send this text to your Particle device, isn’t? If so, it needs to be done subscribing to a Particle event from your device and trigger it from Ubidots Events engine as describe in Section 6 of the below article

Note this is the only way as none of the libraries will retrieve the text part of the dot, only the last value.

Let me know if it makes sense.

Thanks @dsr, the manual widget is perfect, for some reason I did not see or try it.

I did some quick testing using MQTT. Im using the below code to extract the variable label out of the topic and the slider value out of the payload. I dont know if there is a more straight forward method to do it.

unsigned int valueShutterHourOpen = 0;
unsigned int valueShutterHourClose = 0;
unsigned int valueShutterMinuteOpen = 0;
unsigned int valueShutterMinuteClose = 0;
char topicCopy[150] =""; // holds a copy of a topic
char *variableNameFound; // used to compare incoming payload with current variable

void setup() {
    Particle.subscribe("particle/device/name", Name_of_Device);
    softDelay(3000);
    Particle.publish("particle/device/name");//ask the cloud for the name to be sent to you
    softDelay(3000);
    clientMQTT.connect(5);
  if (clientMQTT.isConnected()) {
      clientMQTT.ubidotsSubscribe(dev_name, "shutterhouropen");
      clientMQTT.ubidotsSubscribe(dev_name, "shutterhourclose");
      clientMQTT.ubidotsSubscribe(dev_name, "shutterminuteopen");
      clientMQTT.ubidotsSubscribe(dev_name, "shutterminuteclose");
   }
 }

 void callback(char* topic, uint8_t* payload, unsigned int length) {
       
        Serial.print("Message arrived [");
        Serial.print(topic);
        Serial.print("] ");
        Serial.print("payload obtained from server:");
        for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);  // prints the answer of the broker for debug purpose
     }

    // do something with the topic payload - check variable name and assign payload
    payload[length] = '\0'; // NULL terminate the array
    unsigned int payloadInt = atoi((char *)payload); // convert to int
    //look for variable name in topic so we can assign payload
    memcpy(topicCopy,topic,150); // make a copy of topic
    //Find first occurrence of variablenames in the topic then assign the payload
    variableNameFound = strstr(topicCopy, "shutterhouropen"); // compares payload to variable
    // Prints the result 
      if (variableNameFound) { 
          Serial.printf("variableNameFound found\n"); 
          valueShutterHourOpen=payloadInt; //assign the payload value to local variable
          Serial.printf("valueShutterHourOpen %d \n",valueShutterHourOpen); 
      } else
          Serial.printf("variableNameFound not found\n"); 

     // repeat procedure to find all the variable labels and assign payload.
        .
        .
        .
        .
     }

 void loop() {    
     if (!clientMQTT.isConnected()) {
        clientMQTT.connect(5);
      }
   clientMQTT.loop();
   delay(5000);
 }

@Melt777,

Glad you’ve seen the Manual Input widget now. Keep it as an option.

Now, they way you’re doing the variable parsing is actually the way to proceed. I have although a function to parse the variable label out of the topic that will make your code shorter or more organizaed, I think. Here it is:

const uint8_t NUMBER_OF_VARIABLES = 1;  // Number of variable to subscribe to
char* variable_labels[NUMBER_OF_VARIABLES] = {"VARIABLE-LABEL"};  // labels of the variable to subscribe to

// Parse topic to extract the variable label which changed value
void get_variable_label_from_topic(char* topic, char* variable_label) {
  Serial.print("topic:");
  Serial.println(topic);
  sprintf(variable_label, "");
  for (int i = 0; i < NUMBER_OF_VARIABLES; i++) {
    char* result_lv = strstr(topic, variable_labels[i]);
    if (result_lv != NULL) {
      uint8_t len = strlen(result_lv);
      char result[100];
      uint8_t i = 0;
      for (i = 0; i < len - 3; i++) {
        result[i] = result_lv[i];
      }
      result[i] = '\0';
      Serial.print("Label is: ");
      Serial.println(result);
      sprintf(variable_label, "%s", result);
      break;
    }
  }
}

void callback(char* topic, uint8_t* payload, unsigned int length) {
  char* variable_label = (char*)malloc(sizeof(char) * 30); // Change side based on your labels length
  get_variable_label_from_topic(topic, variable_label);
  // Apply your logic based on the label extracted from the topic.
}

–David

Thank you @dsr works like a charm.