Reporting, его проблемы и особенности.
Добавлено: Вт авг 26, 2025 3:16 pm
Пост выше - не разобрался до конца, хотя казалось, что все понятно, но почему тогда остались вопросы?
Итак я читал доки, смотрел код, делал свою версию прошивки для счетчика. Пришел в очередной раз к тому, что в целом проект Bacchus777/Mercury сделан достаточно хорошо и я лишь незначительно делаю по своему и многое переношу как есть из оригинального проекта, т.е. хотелось бы переписать лучше, но не могу
. Однако расследование работы z-lib от TI приводит к тому, что все работает не совсем так.
Вызов данной функции проверяет есть ли изменение параметра в рамках заданного критерия и если есть, то, нет, не запускает, а сбрасывает время очередной отправки отчета на "пора"!
Если посмотреть в том же zigbee2mqtt на закладку "отчеты" в нашем устройстве, то там будет конфигурация этих отчетов. Минимальное время отправки (нельзя отправлять отчет чаще), максимальное время отправки (если это время превысится, то надо отправить отчет обязательно) и критерий (дельта, т.е. значение должно изменится более чем на эту величину).
Так же в документации от TI написано, что параметры репорта, для оптимизации, усредняются до одного значения для всех параметром на кластер конечной точки. Т.о. для всех параметров репорты будут отправляться по одному критерию, но если параметр не менялся, то репорт будет отправлен общему максимальному времени репорта.
Когда функция "bdb_RepChangedAttrValue" вызывается один раз только для параметра "RMS_VOLTAGE", если этот параметр не менялся, то репорта не будет, даже если изменились другие параметры. А чтобы репорт отправлялся наверняка, необходимо bdb_RepChangedAttrValue вызвать для каждого параметра из 3-х (в данном случае), чтобы репорт точно отправился, если изменился любой из параметров.
В случае же с параметром "CURR_TIER1_SUMM_DLVD" все несколько хуже, т.к. параметр типа ZCL_UINT48. Дело в том, что cc2530 и аналогичные контроллеры являются 8-ми битными и компилятор 8051 не умеет в 64 бита. Нет типа int64, а значит нет ничего более чем int32 (странно что хоть это есть). Для того чтобы сравнить разницу, нужна арифметика на 64 бита, а ее нет. Можно конечно ее прикрутить искусственно, но никто не захотел и просто исключили типы размером более чем 32 из проверки и они считаются как без изменений! И тут опять необходимо или переписывать bdb_reporting или решать проблему обходными путями. Т.е. вызов выше НЕ РАБОТАЕТ вообще. Но сообщения приходят по максимальному времени репорта.
Если посмотрим в предложенный внешний конвертер для zigbee2mqtt:
то мы видим, что maximumReportInterval устанавливается в значение 30, т.е. это соответствует желаемому времени отправки репорта по умолчанию "measurement_period" и создается впечатление, что все работает корректно.
Но и это еще не все.
В функции bdb_RepReport, собирается сам репорт вот так:
Где attrRec - данные по параметру, а dataPtr в нем - это указатель на значение.
Если тип данных "аналоговый", то мы его сохраняем, для фиксирования изменений (lastValueReported). Вот только для типов размерностью более 32 это не используется. А патч предлагается народом сводящийся к:
причем всегда, а ведь типы данных - это не не только эти пресловутые "Аналоговые". Эксперимент выше я делал на строках, а строка имеет размер больше чем BDBREPORTING_MAX_ANALOG_ATTR_SIZE. Как результат получались ошибки - вот он тот конь в вакууме.
Я не помню, на какой версии "bdb_RepReporting.c" я проводил эксперименты, патченной как предложено или по своему варианту, где исправлял только "bdb_RepFindAttrEntry", но вероятнее всего это тоже был кривой патченный файл и именно он был причиной глюков.
А еще, чтобы в репортах получать обновления поля, необходимо этот репорт завести, т.е. просто завести кластер с параметром недостаточно. Надо завести репорт именн для поля, ибо в репорт будут включены только те поля которые заявлены в репорте для данного кластера и конечной точки.
Итого, для нестандартных типов, необходимо или НЕ использовать репорты, а именно отправлять данные принудительно, или, настраивать репорты, но заводить дополнительный параметр в кластере с разрядом 32 или меньше, его так же репортить и делать в нем регулярные изменения, что будет искусственно провоцировать репорт всего кластера. Еще можно самостоятельно вызывать метод "bdb_RepStartReporting( );", чтобы провоцировать репепорт вручную.
Из более сложных решений: реализовать сравнение типов разрядностью более 32.
Итак я читал доки, смотрел код, делал свою версию прошивки для счетчика. Пришел в очередной раз к тому, что в целом проект Bacchus777/Mercury сделан достаточно хорошо и я лишь незначительно делаю по своему и многое переношу как есть из оригинального проекта, т.е. хотелось бы переписать лучше, но не могу

Код: Выделить всё
bdb_RepChangedAttrValue(FIRST_ENDPOINT, ELECTRICAL, ATTRID_ELECTRICAL_MEASUREMENT_RMS_VOLTAGE);
Если посмотреть в том же zigbee2mqtt на закладку "отчеты" в нашем устройстве, то там будет конфигурация этих отчетов. Минимальное время отправки (нельзя отправлять отчет чаще), максимальное время отправки (если это время превысится, то надо отправить отчет обязательно) и критерий (дельта, т.е. значение должно изменится более чем на эту величину).
Так же в документации от TI написано, что параметры репорта, для оптимизации, усредняются до одного значения для всех параметром на кластер конечной точки. Т.о. для всех параметров репорты будут отправляться по одному критерию, но если параметр не менялся, то репорт будет отправлен общему максимальному времени репорта.
Когда функция "bdb_RepChangedAttrValue" вызывается один раз только для параметра "RMS_VOLTAGE", если этот параметр не менялся, то репорта не будет, даже если изменились другие параметры. А чтобы репорт отправлялся наверняка, необходимо bdb_RepChangedAttrValue вызвать для каждого параметра из 3-х (в данном случае), чтобы репорт точно отправился, если изменился любой из параметров.
Код: Выделить всё
bdb_RepChangedAttrValue(SECOND_ENDPOINT, SE_METERING, ATTRID_SE_METERING_CURR_TIER1_SUMM_DLVD);
Если посмотрим в предложенный внешний конвертер для zigbee2mqtt:
Код: Выделить всё
await second_endpoint.configureReporting('seMetering', [{attribute: 'currentSummDelivered', minimumReportInterval: 0, maximumReportInterval: 30, reportableChange: 0}]);
await second_endpoint.configureReporting('seMetering', [{attribute: 'currentTier1SummDelivered', minimumReportInterval: 0, maximumReportInterval: 30, reportableChange: 0}]);
await second_endpoint.configureReporting('seMetering', [{attribute: 'currentTier2SummDelivered', minimumReportInterval: 0, maximumReportInterval: 30, reportableChange: 0}]);
await second_endpoint.configureReporting('seMetering', [{attribute: 'currentTier3SummDelivered', minimumReportInterval: 0, maximumReportInterval: 30, reportableChange: 0}]);
await second_endpoint.configureReporting('seMetering', [{attribute: 'currentTier4SummDelivered', minimumReportInterval: 0, maximumReportInterval: 30, reportableChange: 0}]);
Но и это еще не все.
В функции bdb_RepReport, собирается сам репорт вот так:
Код: Выделить всё
pReportCmd->attrList[i].dataType = attrRec.dataType;
pReportCmd->attrList[i].attrData = attrRec.dataPtr;
//Update last value reported
if( zclAnalogDataType( attrRec.dataType ) ) {
//Only if the datatype is analog
osal_memset( attrListItem->data->lastValueReported,0x00, BDBREPORTING_MAX_ANALOG_ATTR_SIZE );
osal_memcpy( attrListItem->data->lastValueReported, attrRec.dataPtr, zclGetDataTypeLength( attrRec.dataType ) );
}
Если тип данных "аналоговый", то мы его сохраняем, для фиксирования изменений (lastValueReported). Вот только для типов размерностью более 32 это не используется. А патч предлагается народом сводящийся к:
Код: Выделить всё
MAP_osal_memcpy( dataPtr, attrRec.dataPtr, BDBREPORTING_MAX_ANALOG_ATTR_SIZE );
pReportCmd->attrList[i].attrData = dataPtr;
Я не помню, на какой версии "bdb_RepReporting.c" я проводил эксперименты, патченной как предложено или по своему варианту, где исправлял только "bdb_RepFindAttrEntry", но вероятнее всего это тоже был кривой патченный файл и именно он был причиной глюков.
А еще, чтобы в репортах получать обновления поля, необходимо этот репорт завести, т.е. просто завести кластер с параметром недостаточно. Надо завести репорт именн для поля, ибо в репорт будут включены только те поля которые заявлены в репорте для данного кластера и конечной точки.
Итого, для нестандартных типов, необходимо или НЕ использовать репорты, а именно отправлять данные принудительно, или, настраивать репорты, но заводить дополнительный параметр в кластере с разрядом 32 или меньше, его так же репортить и делать в нем регулярные изменения, что будет искусственно провоцировать репорт всего кластера. Еще можно самостоятельно вызывать метод "bdb_RepStartReporting( );", чтобы провоцировать репепорт вручную.
Из более сложных решений: реализовать сравнение типов разрядностью более 32.