• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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
 
Сверху Снизу