При использовании API одного элемента все работает правильно, но когда я переключаюсь на массовое создание с помощью UA_Client_MonitoredItems_createDataChanges(), отслеживаемые элементы успешно создаются, но обратные вызовы для изменения данных никогда не запускаются.
Ниже приведен упрощенный пример. версия двух моих реализаций.
✔ Рабочая реализация (создание одного отслеживаемого элемента)
Эта версия подписывается на каждый тег индивидуально с помощью UA_Client_MonitoredItems_createDataChange():
Код: Выделить всё
UA_MonitoredItemCreateResult monResponse =
UA_Client_MonitoredItems_createDataChange(
client,
subscriptionId,
UA_TIMESTAMPSTORETURN_BOTH,
monRequest,
monContext,
handler_DataChange,
nullptr);
- Все отслеживаемые элементы создаются
- Обратные вызовы вызываются правильно
- Значения поступают нормально
Когда я переключаюсь на пакетный API:
Код: Выделить всё
UA_CreateMonitoredItemsResponse resp =
UA_Client_MonitoredItems_createDataChanges(
client,
req,
ctxRaw.data(),
cbRaw.data(),
nullptr);
✔ Отслеживаемые элементы создаются успешно (сервер возвращает GOOD)
✔ Я получаю правильный MonitoredItemId для всех элементов
Вот соответствующая часть массовой реализации:
Код: Выделить всё
UA_CreateMonitoredItemsRequest req;
UA_CreateMonitoredItemsRequest_init(&req);
req.subscriptionId = subscriptionId;
req.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
req.itemsToCreateSize = tags.size();
req.itemsToCreate = (UA_MonitoredItemCreateRequest*)UA_Array_new(
tags.size(),
&UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST]);
// persistent storage (to keep contexts alive)
auto& ctxList = subscriptionContexts[subscriptionId];
auto& cbList = subscriptionCallbacks[subscriptionId];
for (size_t i = 0; i < tags.size(); i++) {
UA_MonitoredItemCreateRequest_init(&req.itemsToCreate[i]);
UA_NodeId nodeId = parseNodeIdFromAddress(tags[i]->address, logger);
UA_NodeId_copy(&nodeId, &req.itemsToCreate[i].itemToMonitor.nodeId);
req.itemsToCreate[i].itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE;
// Store context in a stable buffer
auto ctx = std::make_unique();
ctx->deviceId = device->uniqueId;
ctx->tag = tags[i];
ctxList.push_back(std::move(ctx));
// Store callback
cbList.push_back(handler_DataChange);
UA_NodeId_clear(&nodeId);
}
// prepare raw pointer arrays
std::vector ctxRaw;
for (auto& c : ctxList) ctxRaw.push_back(c.get());
std::vector cbRaw;
for (auto& cb : cbList) cbRaw.push_back(cb);
UA_CreateMonitoredItemsResponse resp =
UA_Client_MonitoredItems_createDataChanges(
client,
req,
ctxRaw.data(),
cbRaw.data(),
nullptr);
- resp.responseHeader.serviceResult == UA_STATUSCODE_GOOD
- Все resp.results.statusCode == UA_STATUSCODE_GOOD
- В журнале показаны все отслеживаемые элементы считаются успешно подписанными
- Но никакие изменения значений никогда не доставляются в мой обратный вызов
Что я уже проверял
- Обратные вызовы хранятся в постоянном std::vector → они НЕ выходят за рамки
- Объекты контекста принадлежат unique_ptr и остаются активными на протяжении всей подписки.
- Та же функция обратного вызова отлично работает в режиме одного элемента.
- Сервер публикует значения нормально.
- Параметры подписки (samplingInterval,queueSize и т. д.) верны
- Клиент получает ответы на публикацию, но не содержит уведомлений
Мой вопрос?
Почему UA_Client_MonitoredItems_createDataChanges() успешно создает отслеживаемые элементы, но никогда не доставляет обратные вызовы для изменения данных, даже если тот же обратный вызов работает при создании одного элемента?
Есть ли что-то особенное в том, как должны быть структурированы массивы обратных вызовов/контекста для этого API?
Нужно ли мне хранить их в определенном формате или порядке?
Или существует ли известное ограничение/ошибка в open62541, касающаяся массового создания отслеживаемых элементов?>
Подробнее здесь: https://stackoverflow.com/questions/798 ... hanges-doe
Мобильная версия