Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot send message to cloud if in callback of message received #597

Closed
jcagme opened this issue Aug 16, 2018 · 5 comments
Closed

Cannot send message to cloud if in callback of message received #597

jcagme opened this issue Aug 16, 2018 · 5 comments
Assignees
Labels

Comments

@jcagme
Copy link

jcagme commented Aug 16, 2018

I think this related to: #26 which has been closed for a while so:

I'm on macOS High Sierra 10.13.6 using the AzureIotHub libraries version 1.0.44 for Arduino.

If I try to send a message to the cloud in the callback of the message received it is not sent at all.

Here is a snippet of my code:

#include <AzureIoTHub.h>
#include <AzureIoTProtocol_MQTT.h>
#include <AzureIoTUtility.h>

static IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle;

void setup() {

  time_t epochTime;
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");

  while (true)
  {
    epochTime = time(NULL);

    if (epochTime == 0)
    {
      Serial.println("Fetching NTP epoch time failed! Waiting 2 seconds to retry.");
      delay(2000);
    }
    else
    {
      Serial.printf("Fetched NTP epoch time is: %lu.\r\n", epochTime);
      break;
    }
  }

  iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, MQTT_Protocol);

  if (iotHubClientHandle == NULL)
  {
    Serial.println("Failed on IoTHubClient_CreateFromConnectionString.");
  }
  else
  {
    IoTHubClient_LL_SetOption(iotHubClientHandle, "product_info", "random string");
    IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, receiveMessageCallback, NULL);
    IoTHubClient_LL_SetDeviceMethodCallback(iotHubClientHandle, deviceMethodCallback, NULL);
  }
}

void loop() {
  IoTHubClient_LL_DoWork(iotHubClientHandle);
}

IOTHUBMESSAGE_DISPOSITION_RESULT receiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void *userContextCallback)
{
  Serial.println("Message received");
  IOTHUBMESSAGE_DISPOSITION_RESULT result;
  const unsigned char *buffer;
  size_t size;
  if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK)
  {
    Serial.println("Unable to IoTHubMessage_GetByteArray.");
    result = IOTHUBMESSAGE_REJECTED;
  }
  else
  {
    /*buffer is not zero terminated*/
    char *cmd = (char *)malloc(size + 1);

    if (cmd == NULL)
    {
      return IOTHUBMESSAGE_ABANDONED;
    }

    strncpy(cmd, (const char *)buffer, size);
    cmd[size] = '\0';
    sendMessage(iotHubClientHandle, "message");
    free(cmd);
  }

  return IOTHUBMESSAGE_ACCEPTED;
}

static void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, int lightState)
{
  char buffer[MESSAGE_MAX_LEN];

  IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char *)buffer, strlen(buffer));

  if (messageHandle == NULL)
  {
    Serial.println("Unable to create a new IoTHubMessage.");
  }
  else
  {
    char st[1];
    itoa(lightState, st, 10);

    MAP_HANDLE properties = IoTHubMessage_Properties(messageHandle);
    Map_Add(properties, "device_id", DEVICE_ID);

    Serial.printf("Sending message: %s.\r\n", buffer);

    if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, NULL) != IOTHUB_CLIENT_OK)
    {
      Serial.println("Failed to hand over the message to IoTHubClient.");
    }
    else
    {
      Serial.println("IoTHubClient accepted the message for delivery.");
    }

    IoTHubMessage_Destroy(messageHandle);
  }
}

// This is never called
static void sendCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void *userContextCallback)
{
  if (IOTHUB_CLIENT_CONFIRMATION_OK == result)
  {
    Serial.println("Message sent to Azure IoT Hub");
  }
  else
  {
    Serial.println("Failed to send message to Azure IoT Hub");
  }
}

Any suggestions?

@jspaith
Copy link
Contributor

jspaith commented Aug 17, 2018

This should work. I know for MQTT and in IoT Edge, a common scenario is we get sending messages inside a callback. However for this case we use IoTHubMessage_Clone to create a new message object so the lifetime is more clear.

Also I see you're doing IoTHubClient_LL_DoWork - though not where its called. Even after processing the message in callback, you'll need to keep invoking IoTHubClient_LL_DoWork so that the message loop keeps running so we have a chance to send the data across.

Finally if this doesn't help, more logs might. Something like

        bool traceOn = true;
        (void)IoTHubClient_SetOption(iothub_handle, OPTION_LOG_TRACE, &traceOn);

@jcagme
Copy link
Author

jcagme commented Aug 18, 2018

Also I see you're doing IoTHubClient_LL_DoWork - though not where its called. Even after processing the message in callback, you'll need to keep invoking IoTHubClient_LL_DoWork so that the message loop keeps running so we have a chance to send the data across.

Well actually it is called all the time since it is in loop(), right?

Also I forgot mentioning that if I call the sendMessage method directly (not through receiveMessageCallback) things works fine.

@ewertons ewertons self-assigned this Aug 20, 2018
@ewertons
Copy link
Contributor

Hi @jcagme ,
actually looking at your description it makes sense the message would not be sent.

Calling any Azure IoT C SDK function from the LL module from one of its callbacks is not supported in a multi-threaded scenario unless your provide the appropriate locks around the internal queues.
The LL module is intended to be used for synchronous programming.

The convenience layer (threaded, non LL module) does that for you and supports calling any function from within the callbacks, but I believe it wouldn't be applicable to your arduino project.

So long story short, this behavior is by design.

@ewertons
Copy link
Contributor

@jcagme ,
we will close this issue since it has been idle for a while, but please feel free to reopen it if you would like to follow up on this subject.
Thanks for using the Azure IoT SDKs!

@az-iot-builder-01
Copy link
Collaborator

@jcagme, thank you for your contribution to our open-sourced project! Please help us improve by filling out this 2-minute customer satisfaction survey

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants