Проблема с реализацией метода прямого модуля в Azure IoT Edge Module с использованием azure -iot-sdk- c SDK - PullRequest
1 голос
/ 15 января 2020

Полное раскрытие, я задал этот вопрос на Azure IoT SDK C проекте github, но так как они рекомендуют смотреть на StackOverflow, я решил опубликовать здесь также.

У меня проблемы с реализацией обработчика метода прямого модуля в моем модуле IoT Edge на основе azure -iot-sdk- c. Мне не удалось найти страницу документации с примером реализации, поэтому я собрал свою реализацию из различных страниц документации SDK и «примеров» модульных тестов.

Чтобы проверить это, у меня есть выделенный Linux основанный P C (Ubuntu 18.04) под управлением iotedge 1.0.8-2. Я вижу, что мой модуль запускается, печатает свою версию и запускает сообщение обратного вызова состояния соединения. Я даже вижу, что обратный вызов ModuleTwin запускается и печатает полезную нагрузку, когда я вручную редактирую идентификатор модуля для своего устройства на портале.

Однако, когда я пытаюсь вручную вызвать метод Direct для моего модуля в моем устройстве на портале, я не вижу ничего напечатанного и получаю следующую ошибку на портале:

{"message":"GatewayTimeout:{\r\n  \"Message\": \"{\\\"errorCode\\\":504101,\\\"trackingId\\\":\\\"8215e001484d41a19245639844f44f78-G:9-TimeStamp:01/14/2020 21:20:42-G:0-TimeStamp:01/14/2020 21:20:42\\\",\\\"message\\\":\\\"Timed out waiting for the response from device.\\\",\\\"info\\\":{},\\\"timestampUtc\\\":\\\"2020-01-14T21:20:42.0556758Z\\\"}\",\r\n  \"ExceptionMessage\": \"\"\r\n}"}

Соответствующий код ниже. Я посмотрел на StackOverflow, но примеры не основаны на C SDK. Где я иду не так с прямыми методами модуля? Спасибо!

Обновление : Интересное наблюдение состоит в том, что если я изменю этот код на использование MQTT из AMQP, то все будет работать. Разве AMQP не поддерживается для методов прямого модуля?

#include <iothub_module_client_ll.h>
#include <iothub_client_options.h>
#include <iothub_message.h>
#include <azure_c_shared_utility/threadapi.h>
#include <azure_c_shared_utility/crt_abstractions.h>
#include <azure_c_shared_utility/platform.h>
#include <azure_c_shared_utility/shared_util_options.h>
#include <iothubtransportamqp.h>
#include <iothub.h>
#include <time.h>

#include <stdio.h>
#include <stdlib.h>

// Linker defined build information (see Makefile)
extern char   __BUILD_DATE;
extern char   __BUILD_NUMBER;

// Set the default value for module communication (e.g. AMQP) log tracing, yet
// allow compile time overrides.
#ifndef LOG_TRACE_ENABLED
  #define LOG_TRACE_ENABLED 0
#endif

static void moduleTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* /*userContextCallback*/)
{
    EPRINT("DEBUG: Module Twin callback called with (state=%s)", MU_ENUM_TO_STRING(DEVICE_TWIN_UPDATE_STATE, update_state));
    EPRINT("DEBUG: payload=%.*s", (int)size, (const char *)payLoad);
    fflush(NULL);

    //JSON_Value *root_value = json_parse_string(payLoad);
    //JSON_Object *root_object = json_value_get_object(root_value);
    //if (json_object_dotget_value(root_object, "desired.TemperatureThreshold") != NULL) {
    //    temperatureThreshold = json_object_dotget_number(root_object, "desired.TemperatureThreshold");
    //}
    //if (json_object_get_value(root_object, "TemperatureThreshold") != NULL) {
    //    temperatureThreshold = json_object_get_number(root_object, "TemperatureThreshold");
    //}
}

static int DirectMethodCb(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* /*userContextCallback*/)
{
  const char *METHOD_NAME = "TestMethod";
  const int METHOD_RESPONSE_SUCCESS = 200;
  const int METHOD_RESPONSE_ERROR = 401;

  int responseCode;

  EPRINT("DEBUG: Method name:    %s", method_name);
  EPRINT("DEBUG: Method payload: %.*s", (int)size, (const char*)payload);

  if (strcmp(METHOD_NAME, method_name))
  {
    EPRINT("Method name incorrect - expected %s but got %s", METHOD_NAME, method_name);
    responseCode = METHOD_RESPONSE_ERROR;
  }
  /*
  else if (size != strlen(expectedMethodPayload))
  {
    LogError("payload size incorect - expected %zu but got %zu", strlen(expectedMethodPayload), size);
    responseCode = METHOD_RESPONSE_ERROR;
  }
  else if (memcmp(payload, expectedMethodPayload, size))
  {
    LogError("Payload strings do not match");
    responseCode = METHOD_RESPONSE_ERROR;
  }
  */
  else
  {
    *resp_size = size;
    if (size == 0)
    {
      *response = NULL;
      EPRINT("DEBUG: Empty, but good response");
      responseCode = METHOD_RESPONSE_SUCCESS;
    }
    else
    {
      if ((*response = (unsigned char*)malloc(*resp_size)) == NULL)
      {
        EPRINT("allocation failure");
        responseCode = METHOD_RESPONSE_ERROR;
      }
      else
      {
        (void)memcpy(*response, payload, *resp_size);
        EPRINT("DEBUG: All good - echoing back the payload");
        responseCode = METHOD_RESPONSE_SUCCESS;
      }
    }
  }

  EPRINT("DEBUG: completing with return code %d", responseCode);
  fflush(NULL);
  return responseCode;
}

static void ConnectionStatusCb(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* /*userContextCallback*/)
{
  EPRINT("DEBUG: ConnectionStatusCb(status=%d %s, reason=%d %s",
      result, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS, result),
      reason, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, reason)
      );
  fflush(NULL);
}

int main(void)
{
  IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle = nullptr;
  int retval = 1;

  do
  {
    printf("\n\n=======================\n");
    printf("Build date  : %lu\n", (unsigned long) &__BUILD_DATE);
    printf("Build number: %lu\n", (unsigned long) &__BUILD_NUMBER);
    fflush(NULL);

    srand((unsigned int)time(NULL));

    if (0 != IoTHub_Init())
    {
      EPRINT("Failed to initialize the platform.");
      break;
    }

    iotHubModuleClientHandle = IoTHubModuleClient_LL_CreateFromEnvironment(AMQP_Protocol);
    if (nullptr == iotHubModuleClientHandle)
    {
      EPRINT("IoTHubModuleClient_LL_CreateFromEnvironment failed");
      break;
    }

    IOTHUB_CLIENT_RESULT result = IoTHubModuleClient_LL_SetModuleMethodCallback(iotHubModuleClientHandle, DirectMethodCb, iotHubModuleClientHandle);
    if (IOTHUB_CLIENT_OK != result)
    {
      EPRINT("IoTHubModuleClient_SetModuleMethodCallback failed: %d", result);
      break;
    }

    result = IoTHubModuleClient_LL_SetConnectionStatusCallback(iotHubModuleClientHandle, ConnectionStatusCb, iotHubModuleClientHandle);
    if (IOTHUB_CLIENT_OK != result)
    {
      EPRINT("IoTHubDeviceClient_SetConnectionStatusCallback failed: %d", result);
      break;
    }

#if LOG_TRACE_ENABLED
    bool traceOn = true;
    IoTHubModuleClient_LL_SetOption(iotHubModuleClientHandle, OPTION_LOG_TRACE, &traceOn);
#endif // LOG_TRACE_ENABLED

    result = IoTHubModuleClient_LL_SetModuleTwinCallback(iotHubModuleClientHandle, moduleTwinCallback, iotHubModuleClientHandle);
    if (IOTHUB_CLIENT_OK != result)
    {
      EPRINT("IoTHubModuleClient_LL_SetModuleTwinCallback failed: %d", result);
      break;
    }

    while (true)
    {
      IoTHubModuleClient_LL_DoWork(iotHubModuleClientHandle);
      ThreadAPI_Sleep(100);
    }
  } while(false);

  if (nullptr != iotHubModuleClientHandle)
  {
    IoTHubModuleClient_LL_Destroy(iotHubModuleClientHandle);
  }
  IoTHub_Deinit();

  return retval;
}
...