• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

BLE модули TB-04/TB-03F (TLSR8253F512)

nikolz

Well-known member
А нет никакой ссылки. Протокола в открытом доступе нет. И у меня его нет. Wireshark немного помог ...

Можете посмотреть, что я накалякал :) - https://slacky1965.github.io/electricity_meter_ble/

Вот тут еще обсуждение - https://www.radiokot.ru/forum/viewtopic.php?f=25&t=171991&sid=039243297acb0ce1b677287ae40e41c2

Но нужно учитывать, что ответ может быть разной длины. У меня два обсолютно одинаковых счетчиков присылали ответы с разницей в один байт. Оригинальная программа оба счетчика читала корректно.

Код:
735520008d4effff0500000000ae55 - запрос 15
73551a00ffffxxxx0530067500  |3af51400|a2203001|0000|44050600|91240600|65cb0800|00000000|bc55 - ответ 41
73551a00ffff8d4e053006731100|bad62300|a2203001|0000|ea260b00|598d0a00|77220e00|00000000|6d55 - ответ 42
              head          | sum    |    ?   | ?  | tariff1| tariff2| tariff3| tariff4|
В приходящем ответе мы точно знаем несколько вещей.
1 байт всегда 73
2 байт всегда 55
3 байт содержит длину полезной нагрузки.
4 байт всегда 00
5-6 байты тип соединения (для оптопорта это всегда FFFF)
7-8 адрес устройства
9 команда
предпоследний байт - crc
последний байт всегда 55

Считываем сразу весь буфер. Проверяем. Зная размер считанного, размер неменяющегося (первые 9 байт) и размер полезной нагрузки (3-й байт) просто вырезаем всю меняющуюся середину. И получаем всегда вот такой пакет
Код:
73551a00ffff8d4e05|bad62300|a2203001|0000|ea260b00|598d0a00|77220e00|00000000|6d55
Команды

C:
typedef enum _cmd_t {
    cmd_open_channel        = 0x01,
    cmd_current_data        = 0x05,
    cmd_volts_data          = 0x29,
    cmd_amps_data           = 0x2c,
    cmd_power_data          = 0x2d,
} cmd_t;
это похоже на типичный протокол датчиков через UART- по асинхронному последовательному каналу)
-----------------------
Может лучше ничего не преобразовывать, а сделать прозрачный мост счетчик-компьютер или смартфон.
Все преобразования делать на пк или смартфоне.
тогда устройство передачи будет универсальным простым и тупым. - сделал раз и забыл.
 

pvvx

Активный участник сообщества
Может лучше ничего не преобразовывать, а сделать прозрачный мост счетчик-компьютер или смартфон.
Все преобразования делать на пк или смартфоне.
тогда устройство передачи будет универсальным простым и тупым. - сделал раз и забыл.
Тогда нужна постоянная связь и постоянная работа компьютера. И никаких логов на устройстве.
Опять появился "вышедший погулять nikolz" с глупыми предложениями.
 

Slacky

Member
Вот лучше помогите определить алгоритм crc от счетчика.

crc - предпоследний байт в пакете. При подсчете два первых и два последних байта не учитываются (во всяком случае для пакета, который мы отправляем в счетчик).

Есть такой код
C:
static uint8_t checksum(const uint8_t *src_buffer, uint8_t len) {
  // skip 73 55 header (and 55 footer is beyond checksum anyway)
  const uint8_t* table = &src_buffer[2];
  const uint8_t packet_len = len - 4;

  const uint8_t generator = 0xA9;

  uint8_t crc = 0;
  for(const uint8_t* ptr = table; ptr < table + packet_len; ptr++){
    crc ^= *ptr;
    for (uint8_t bit = 8; bit > 0; bit--)
      if (crc & 0x80)
        crc = (crc << 1) ^ generator;
      else
        crc <<= 1;
  }

  return crc;
}
Если ему подусунуть пакет, который мы формируем и отправляем в счетчик, то все хорошо, crc правильная.

Пара примеров
Код:
735520008d4effff0100000000d655
735520008d4effff30000000001355
735521008d4effff0a00000000017055
Но в приходящем пакете от счетчика это уже не работает. Я прогнал generator от 0 до 255 - не-а.
Вот пакеты.
Код:
73550400ffff8d4e0130067311000a048d4e0655
73551f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a55
73550700ffff8d4e1c30067311001b031301100117e655
 

pvvx

Активный участник сообщества
А на какие поля идет расчет CRC в отправляемом пакете от счетчика?
Без счетчика и всей системы этого не разобрать. Нужно много логов и времени для ковыряния в этом. Нужно написать какой-то скрипт с перебором вариантов расчета CRC, типа на Питоне, да запустить на громадный лог принятых фреймов...
 

nikolz

Well-known member
Тогда нужна постоянная связь и постоянная работа компьютера. И никаких логов на устройстве.
Опять появился "вышедший погулять nikolz" с глупыми предложениями.
глупыми бывают не вопросы а ответы.
И нахрена постоянная связь и лог на устройстве, если в сообщении содержится конкретные показания на конкретную дату.
т е когда надо тогда и читаем.
а собирать историю в архивы бессмысленно.
Вы вот собираете уже надцать лет температуру на улице.
Ну и нафига?
 

nikolz

Well-known member
Вот лучше помогите определить алгоритм crc от счетчика.

crc - предпоследний байт в пакете. При подсчете два первых и два последних байта не учитываются (во всяком случае для пакета, который мы отправляем в счетчик).

Есть такой код
C:
static uint8_t checksum(const uint8_t *src_buffer, uint8_t len) {
  // skip 73 55 header (and 55 footer is beyond checksum anyway)
  const uint8_t* table = &src_buffer[2];
  const uint8_t packet_len = len - 4;

  const uint8_t generator = 0xA9;

  uint8_t crc = 0;
  for(const uint8_t* ptr = table; ptr < table + packet_len; ptr++){
    crc ^= *ptr;
    for (uint8_t bit = 8; bit > 0; bit--)
      if (crc & 0x80)
        crc = (crc << 1) ^ generator;
      else
        crc <<= 1;
  }

  return crc;
}
Если ему подусунуть пакет, который мы формируем и отправляем в счетчик, то все хорошо, crc правильная.

Пара примеров
Код:
735520008d4effff0100000000d655
735520008d4effff30000000001355
735521008d4effff0a00000000017055
Но в приходящем пакете от счетчика это уже не работает. Я прогнал generator от 0 до 255 - не-а.
Вот пакеты.
Код:
73550400ffff8d4e0130067311000a048d4e0655
73551f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a55
73550700ffff8d4e1c30067311001b031301100117e655
как правило CRC - это просто сумма значений из которой берется лишь 1 или 2 байта в зависимости от того по какому модулю считаем.
В данном случае - 1 байт.
 

pvvx

Активный участник сообщества
глупыми бывают не вопросы а ответы.
И нахрена постоянная связь и лог на устройстве, если в сообщении содержится конкретные показания на конкретную дату.
т е когда надо тогда и читаем.
Логи указывают когда и что было.
Сидеть сутками и мониторить никто не собирается.
а собирать историю в архивы бессмысленно.
Вы вот собираете уже надцать лет температуру на улице.
Ну и нафига?
Для оценки правильности выбранных материалов и конструктивов в домашнем строительстве.
Вам это не грозит - в вашей больнице всё казенное и типовое :p
 

nikolz

Well-known member
алгоритм CRC такой:
--------------------
CRC считаем по len - 4 байтам пакета;
---------------
начальное значение crc = 0;
----------------
В цикле считаем:
CRC=CRC^байт - сложение по модулю 2 (исключающее ИЛИ)
для каждого бита CRC,
начиная со старшего в цикле вычисляем;
если бит 1, то следующее значение crc = (crc << 1) ^ 0xA9;
иначе следующее значение просто сдвигается на 1 разряд crc = (crc << 1)
--------------
т е два цикла
первый по байтам
и в него вложен цикл по битам каждого байта
 

nikolz

Well-known member
Логи указывают когда и что было.
Сидеть сутками и мониторить никто не собирается.

Для оценки правильности выбранных материалов и конструктивов в домашнем строительстве.
Вам это не грозит - в вашей больнице всё казенное и типовое :p
прикольно, Вы же уже построили.
И после этого поняли что выбрали неправильно?
Надо было сначала у специальстов по строительству спросить, а не заниматься ползучим эмпиризмом - а-ля кулибенщеной.
 

Slacky

Member
алгоритм CRC такой:
--------------------
CRC считаем по len - 4 байтам пакета;
---------------
начальное значение crc = 0;
----------------
В цикле считаем:
CRC=CRC^байт - сложение по модулю 2 (исключающее ИЛИ)
для каждого бита CRC,
начиная со старшего в цикле вычисляем;
если бит 1, то следующее значение crc = (crc << 1) ^ 0xA9;
иначе следующее значение просто сдвигается на 1 разряд crc = (crc << 1)
--------------
т е два цикла
первый по байтам
и в него вложен цикл по битам каждого байта
Вопрос - а зачем Вы сделали вольный пересказ куска кода, который я привёл? Что он делает, я и так знаю...
 

nikolz

Well-known member
вот что нашел на данный протокол
Первый байт =0x73
содержит следующую информацию :

8754321
Класс тэгаПростой/Составной тэгНомер тэга (0-30)
Биты класса (8 и 7 биты) определяют, является ли тип объекта универсальным (целое, вещественное и т.п.) или нет (например, программы при обмене используют свой тип данных)

Бит 8Бит 7Описание
00Тип универсальный
01Тип определяется приложением
10Тип зависит от контекста.
11Определяется закрытой спецификацией
Бит 6 тэга принимает значения: 0 –блок значения содержит ровно 1 экземпляр данного типа (например, одно целое число); 1 – может содержать произвольное количество значений данного типа (в т.ч. и 0).
т е 73 означает, что это тег с номером 3 содержимое определяется закрытой спецификацией и может содержать произвольное количество данных
 

pvvx

Активный участник сообщества
прикольно, Вы же уже построили.
И после этого поняли что выбрали неправильно?
Надо было сначала у специальстов по строительству спросить, а не заниматься ползучим эмпиризмом - а-ля кулибенщеной.
Не - всё отлично. А хочу усовершенствовать на других объектах.
Про ваших специалистов уже наслышан, сравнивая с вашими опусами :)
 

pvvx

Активный участник сообщества
Вопрос - а зачем Вы сделали вольный пересказ куска кода, который я привёл? Что он делает, я и так знаю...
У него такой стиль опусов. Он сюда выходит погулять и часто про это сам пишет. Не воспринимайте суръезно. Клоуны тоже нужны.
Он вроде от человекоподобных произошел, а не chatgpt.
 

pvvx

Активный участник сообщества
Да, и chatgpt наверно уже сможет написать вам программу для вычисления CRC в отличии от nikolz.
 

pecherskih

Member
У него такой стиль опусов. Он сюда выходит погулять и часто про это сам пишет. Не воспринимайте суръезно. Клоуны тоже нужны.
Он вроде от человекоподобных произошел, а не chatgpt.
Про клоунов - это прямо в точку :) Я всегда с нетерпением жду ваших комментариев к постам других авторов. :ROFLMAO: (y)
 

pvvx

Активный участник сообщества
73550400ffff8d4e0130067311000a048d4e0655
73551f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a55
73550700ffff8d4e1c30067311001b031301100117e655
polynomial = 0x80 :unsure:
Python:
import binascii

def AddCrc(crc, n, pol):
    for nbit in range(0,8):
        if ( n ^ crc ) & 0x80:
            crc = ( crc << 1 ) ^ pol
        else:
            crc = ( crc << 1 )
        n = n << 1
    return crc & 0xFF

def Crc8(data, pol, start=0):
    crc = start
    for i in range(len(data)):
        crc = AddCrc(crc, data[i], pol)
    return crc & 0xFF

#=============================
# main()
#=============================
#73550400ffff8d4e0130067311000a048d4e0655
#73551f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a55
#73550700ffff8d4e1c30067311001b031301100117e655
def main():
    print()
    print("====== Test crc8 -----------------------------------------")
    data = binascii.unhexlify('0400ffff8d4e0130067311000a048d4e06')
    print("data:", data.hex())
    crc = Crc8(data, 0x80)
    print('crc8: %02x' % (crc))
    data = binascii.unhexlify('1f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a')
    print("data:", data.hex())
    crc = Crc8(data, 0x80)
    print('crc8: %02x' % (crc))
    data = binascii.unhexlify('0700ffff8d4e1c30067311001b031301100117e6')
    print("data:", data.hex())
    crc = Crc8(data, 0x80)
    print('crc8: %02x' % (crc))


if __name__ == '__main__':
    main()
====== Test crc8 -----------------------------------------
data: 0400ffff8d4e0130067311000a048d4e06
crc8: 00
data: 1f00ffff8d4e3030067311002c0a045bb66ae617077e6cd9020000e6b0ac1b95110302000000040000fb0a2a
crc8: 00
data: 0700ffff8d4e1c30067311001b031301100117e6
crc8: 00
 

nikolz

Well-known member
Выяснил, что счетчик Каскад разработала не фирма Каскад, они лишь его производят.
Поэтому протокол надо искать не у них.
протокол дают лишь по запросу юр лиц.
 

nikolz

Well-known member
нашел в документации разработчика другого умного счетчика
вот такой алгоритм вычисления контрольной суммы.
Попробуйте, может подойдет:
--------------
crc8 = 0;
for(i= 0; i< Length; i++){
crc8= crc8tab[crc8 ^ Buffer];
}
 

pvvx

Активный участник сообщества
Я прогнал generator от 0 до 255 - не-а.
0x80 почти всегда даст 0.

На 0xA9 все ваши отсылаемые строки сразу - ok
====== Test crc8 -----------------------------------------
data: 20008d4effff0100000000d620008d4effff30000000001321008d4effff0a000000000170
crc8: 00 (70)

А вот принятые - нет соответствия для crc8
 
Сверху Снизу