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

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

Slacky

Member
Я нашел, где накосячил.

Скопировал и изменил, а то, что еще один сервис не нужен, не понял.

C:
///////////////////////////////////// ATT  HANDLER define ///////////////////////////////////////
typedef enum
{
    ...

    //// Count service ////
    /**********************************************************************************************/
    HOT_PS_H,                              //UUID: 2800,    VALUE: uuid 183B
    HOT_LEVEL_INPUT_CD_H,                  //UUID: 2803,    VALUE:              Prop: Read | Notify
    HOT_LEVEL_INPUT_DP_H,                  //UUID: 2AEA,    VALUE: hot count
    HOT_LEVEL_INPUT_CCB_H,                 //UUID: 2902,    VALUE: hotValCCC

    COLD_PS_H,                              //UUID: 2800,   VALUE: uuid 183B
    COLD_LEVEL_INPUT_CD_H,                  //UUID: 2803,   VALUE:              Prop: Read | Notify
    COLD_LEVEL_INPUT_DP_H,                  //UUID: 2AEB,   VALUE: hot count
    COLD_LEVEL_INPUT_CCB_H,                 //UUID: 2902,   VALUE: hotValCCC
    
    ...
}
Убрал COLD_PS_H и все заработало ...
 

Slacky

Member
По поводу whitelist'а .

Хранит модуль в памяти адрес таким образом addr[0] - первая пара, addr[5] - последняя пара.

Но все равно в тупую whitelist не заработал. Но заработал немного по другому.
C:
    smp_param_save_t  bondInfo;
    u8 bond_number = blc_smp_param_getCurrentBondingDeviceNumber();  //get bonded device number
    if(bond_number)   //get latest device info
    {
        bls_smp_param_loadByIndex( bond_number - 1, &bondInfo);  //get the latest bonding device (index: bond_number-1 )
    }


    ll_whiteList_reset();       //clear whitelist
    ll_resolvingList_reset(); //clear resolving list


    if(bond_number)  //use whitelist to filter master device
    {
        app_whilteList_enable = 1;

        //if master device use RPA(resolvable private address), must add irk to resolving list
        if( IS_RESOLVABLE_PRIVATE_ADDR(bondInfo.peer_addr_type, bondInfo.peer_addr) ){
            //resolvable private address, should add peer irk to resolving list
            ll_resolvingList_add(bondInfo.peer_id_adrType, bondInfo.peer_id_addr, bondInfo.peer_irk, NULL);  //no local IRK
            ll_resolvingList_setAddrResolutionEnable(1);
        }
        else{
            //if not resolvable random address, add peer address to whitelist
            ll_whiteList_add(bondInfo.peer_addr_type, bondInfo.peer_addr);
        }


        bls_ll_setAdvParam( ADV_INTERVAL_30MS, ADV_INTERVAL_30MS, \
                            ADV_TYPE_CONNECTABLE_UNDIRECTED, OWN_ADDRESS_PUBLIC, \
                            0,  NULL, BLT_ENABLE_ADV_ALL, ADV_FP_ALLOW_SCAN_WL_ALLOW_CONN_WL);

    }
    else
    {

        bls_ll_setAdvParam( ADV_INTERVAL_30MS, ADV_INTERVAL_30MS,
                            ADV_TYPE_CONNECTABLE_UNDIRECTED, OWN_ADDRESS_PUBLIC,
                            0,  NULL, BLT_ENABLE_ADV_ALL, ADV_FP_NONE);
    }


    bls_ll_setAdvEnable(1);  //adv enable

В общем я его с минимальными переделками адаптировал под себя и теперь мы имеем такой алгоритм. Если устройство новое, только что-то запрограммированное, то пускаем любого. При первом соединении и сопряжении, модуль запоминает устройство и все последующие соединения возможны только с этого устройства. Рекламу могут принимать все.

В общем осталось дождаться платы и измерить ток потребления. Ну и испытать в реальном времени :))
 

pvvx

Активный участник сообщества
По поводу whitelist'а .
...
Если устройство новое, только что-то запрограммированное, то пускаем любого. При первом соединении и сопряжении, модуль запоминает устройство и все последующие соединения возможны только с этого устройства. Рекламу могут принимать все.
Возможно проще будет использовать "пинкод"?
У вас таблица атрибутов в ret-RAM ? - attribute_data_retention_ attribute_t my_Attributes[]
Тогда удобнее менять атрибуты (посредством замены флага на ATT_PERMISSIONS_SECURE_CONN_RDWR) - сделать доступ к разным атрибутам только тем кому разрешено...
А с остальными атрибутами (их информацией и функциями) дать возможность работать всем.
BLE имеет такую нужную фичу, которой нет в WiFi. Имея разные пароли или какие другие варианты ограничений или приоритетов доступа - организуете каждому свои доступные функции.
 

Slacky

Member
Возможно проще будет использовать "пинкод"?
Не, чисто по логике работы устройства, лишнее. Там нужно один раз зайти, выставить начальное значение счетчиков и кол-во литров на 1 импульс и выйти. Больше там никому делать нечего.
 

Slacky

Member
По поводу whitelist'а .

Хранит модуль в памяти адрес таким образом addr[0] - первая пара, addr[5] - последняя пара.
Сейчас перечитал, неоднозначно получилось.

На самом деле так. Адрес в телефоне 11:22:33:44:55:66. То в переменной он так addr[0] - 66, addr[1] - 55 и т.д.
 

Slacky

Member
Там рассматривается полное сообщение от адаптера BT.
В нем есть "Header: 043E1B02010000A5808FE648540F", который дает адаптер, а вы передаете только
  • Adverting payload 0201060B161C182302C4090303BF13
И в нем "020106" - это типичный но не обязательный флаг, и только следующая часть является самим HA-BLE сообщением.
0B161C182302C4090303BF13
0B - размер
16 - тип -uuid 16
1C18 - uuid 16 HA-BLE
2302C4090303BF13 - а это уже данные в HA-BLE
Возвращаюсь к формату пакетов.

Установил сниффер. Работает вот на такой платке от Nordic

nRF52840-Dongle-rev2-prod page.jpg
Не уверен, что пакет показан полностью, но там ничего похожего на

043E1B02010000A5808FE648540F0201060B161C182302C4090303BF13CC

нет.

Есть вот такое.

sniff1.jpg

sniff2.jpg

Вопросов отсюда следут несколько.

1. Если это показан не полный физический пакет, то все-таки чем смотреть полный?
2. Если это полный физический пакет, то как добиться правильного HCI формата?

Спасибо.
 

pvvx

Активный участник сообщества
У сниффера свой формат. Wireshark вам всё сам показывает разметку блока данных от сниффера - зачем спрашивать?
Физический формат пакета нарисован, к примеру, тут -> Advertising Packet Format
Более подробно в спеках/доках на сайте https://www.bluetooth.com/
 

Slacky

Member
У сниффера свой формат. Wireshark вам всё сам показывает разметку блока данных от сниффера - зачем спрашивать?
Физический формат пакета нарисован, к примеру, тут -> Advertising Packet Format
Более подробно в спеках/доках на сайте https://www.bluetooth.com/
Да все просто оказалось. HCI device в Debian'е есть, но ничего не работает. Ну и BLE Monitor тоже ничего не показывает, хотя свисток видит. Потому и не понятно было, может я формат какой не тот подаю.

Порыл google. Нашел систок, который 100% работает под Debian'ом. Купил. Все завелось и BLE Monitor увидел 1 устройство и 3 объекта (вот вопрос, почему не 4).

Т.е. BLE Monitor увидел батарейку, RSSI и один счетчик (последний) вместо двух.

А теперь глупый вопрос почему счетчиков только один. Где я налажал? Или нельзя в одном пакете пересылать два счетчика?

C:
typedef struct __attribute__((packed)) _adv_head_uuid16_t {
    uint8_t  size;
    uint8_t  type;       /* 0x16, 16-bit UUID            */
    uint16_t UUID;       /* 0x181C, GATT Service HA_BLE  */
} adv_head_uuid16_t;

typedef struct __attribute__((packed)) _adv_battery_t {
    uint8_t     type_len;               /* HaBleType_uint (5-7 bit) | length (0-4 bit or 0x1F) */
    uint8_t     id;                     /* HaBleID_battery                                     */
    uint8_t     level;
} adv_battery_t;

typedef struct __attribute__((packed)) _adv_counter_t {
    uint8_t     type_len;               /* HaBleType_uint (5-7 bit) | length (0-4 bit or 0x1F) */
    uint8_t     id;                     /* HaBleID_count                                       */
    uint32_t    counter;
} adv_counter_t;

typedef struct __attribute__((packed)) _adv_data_t {
    uint8_t             flg_size;       /* 0x02                                      */
    uint8_t             flg_type;       /* 0x01                                      */
    uint8_t             flg;            /* 0x06                                      */
    adv_head_uuid16_t   head;
    uint8_t             type_len;       /* HaBleType_uint | length (0-4 bit or 0x1F) */
    uint8_t             id;             /* HaBleID_PacketId                          */
    uint8_t             pid;            /* 0 .. 255                                  */
    adv_battery_t       adv_battery;
    adv_counter_t       adv_hot;
    adv_counter_t       adv_cold;
} adv_data_t;

C:
    _attribute_data_retention_ adv_data_t adv_data;

    adv_data.flg_size  = 0x02;              /* size  */
    adv_data.flg_type  = GAP_ADTYPE_FLAGS;  /* 0x01  */
    adv_data.flg       = 0x06;              /* flags */

    adv_data.head.size = (sizeof(adv_head_uuid16_t) + 3 + sizeof(adv_battery_t) + (sizeof(adv_counter_t)*2) - 1) & 0xFF;
    adv_data.head.type =  GAP_ADTYPE_SERVICE_DATA_UUID_16BIT;
    adv_data.head.UUID = ADV_HA_BLE_NS_UUID16;

    adv_data.type_len  = HaBleType_uint | ((sizeof(adv_data.id) + sizeof(adv_data.pid)) & 0x1F);
    adv_data.id        = HaBleID_PacketId;
    adv_data.pid       = 0;

    adv_data.adv_battery.type_len = HaBleType_uint |
            ((sizeof(adv_data.adv_battery.id) + sizeof(adv_data.adv_battery.level)) & 0x1F);
    adv_data.adv_battery.id       = HaBleID_battery;
    adv_data.adv_battery.level = battery_level;

    adv_data.adv_hot.type_len = HaBleType_uint |
            ((sizeof(adv_data.adv_hot.id) + sizeof(adv_data.adv_hot.counter)) & 0x1F);
    adv_data.adv_hot.id  = HaBleID_count;
    adv_data.adv_hot.counter = watermeter_config.counters.hot_water_count;

    adv_data.adv_cold.type_len = HaBleType_uint |
            ((sizeof(adv_data.adv_cold.id) + sizeof(adv_data.adv_cold.counter)) & 0x1F);
    adv_data.adv_cold.id  = HaBleID_count;
    adv_data.adv_cold.counter = watermeter_config.counters.cold_water_count;
 

Slacky

Member
Упс, оказывается у меня все правильно. Это BLE Monitor не может иметь больше одного измерения одного типа в одном пакете ...
 

pvvx

Активный участник сообщества
Упс, оказывается у меня все правильно. Это BLE Monitor не может иметь больше одного измерения одного типа в одном пакете ...
 

Slacky

Member
Спасибо, видел. И даже проверял. Кривой он у него ...

Если стандартный пишет

Код:
sensor.ble_battery    100%
sensor.ble_count    65546
sensor.ble_rssi        -80
То этот

Код:
sensor.ble_count    100%
sensor.ble_count    65546
sensor.ble_count    1000
sensor.ble_rssi        -80
Т.е. он батарею определил, как счетчик ...
 

pvvx

Активный участник сообщества
@Slacky - А что там в самом HA с BLE датчиками? Я пока не обновлял HA (занят другими делами) и не знаю что тама произошло... Ernst79 пишет:
Важное объявление о будущем монитора BLE
Home Assistant 2022.8 имеет (улучшенную) поддержку пассивных устройств BLE непосредственно в Home Assistant. Для каждого бренда будет разработана базовая интеграция BLE, чтобы обслуживание можно было разделить между большим количеством людей, используя новейшие пакеты Bluetooth (bleak).
 

Slacky

Member
@Slacky - А что там в самом HA с BLE датчиками? Я пока не обновлял HA (занят другими делами) и не знаю что тама произошло... Ernst79 пишет:
Важное объявление о будущем монитора BLE
Home Assistant 2022.8 имеет (улучшенную) поддержку пассивных устройств BLE непосредственно в Home Assistant. Для каждого бренда будет разработана базовая интеграция BLE, чтобы обслуживание можно было разделить между большим количеством людей, используя новейшие пакеты Bluetooth (bleak).
Я сильно HA не ковырял на эту тему. Нужно проверить. Но на вопрос про два датчика одного типа Ernst79 ответил и посоветовал следующее - https://github.com/custom-components/ble_monitor/issues/987
 

pvvx

Активный участник сообщества
Я сильно HA не ковырял на эту тему. Нужно проверить. Но на вопрос про два датчика одного типа Ernst79 ответил и посоветовал следующее - https://github.com/custom-components/ble_monitor/issues/987
Это я уже видел. Ранее был разговор, но Ernst был занят переездом...
А HA у меня пока только точит SSD (на нем система и база HA):
1660145416821.png
Более 7 ГБ в сутки, при истории в 1 месяц и минимум дискрет записи событий в 1 минуту. Ранее проверял - уменьшение глубины истории на неделю и прочее не сильно влияют...
База данных при месяце логов около 3+ ГБ и он её каждый день переписывает :eek:
И плюс MMC трет (temp и logs):
1660145495075.png
 

millworm

New member
на али есть вот такие датчики влажности https://aliexpress.ru/item/32976733373.html
хватит ли в tb-04 шим чтобы выкинуть tlc555\ne555 и генерировать сигнал с него?
сейчас собрал их рядом, но что-то прожорливая схема получилась и за 1.5 месяца cr2032 посадила. хотелось бы чтобы хватало где-то на пол года
 

millworm

New member
если правильно посчитал на калькуляторах к ne555, то получается, что там что-то около 1МГц при 50%
а в коде наверное вот так. только я вот что-то не очень уверен в этом
C++:
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, 17);

gpio_set_func(GPIO_PC4, PWM2_ID);
pwm_set_mode(PWM2_ID, PWM_NORMAL_MODE);
pwm_set_cycle_and_duty(PWM2_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US),  (u16) (500 * CLOCK_SYS_CLOCK_1US) );
pwm_start(PWM2_ID);
 

pvvx

Активный участник сообщества
если правильно посчитал на калькуляторах к ne555, то получается, что там что-то около 1МГц при 50%
Для емкостного, ради сокращения схемы и повышения точности надо не 50% заполнения, т.е. примерно так:
C:
// R = 7.5 kOm, BAV99, C 10..100 nF

#define CHL_ADC1     7    // B6P
#define GPIO_ADC1     GPIO_PB6
#define PWM_PIN        GPIO_PB5
#define AS_PWMx        AS_PWM5
#define PWM_ID        PWM5_ID

static void pwm_init(void) {
    reg_clk_en0 |= FLD_CLK0_PWM_EN;
    reg_pwm_clk = 0;
    pwm_set_mode(PWM_ID, PWM_NORMAL_MODE);
    pwm_set_phase(PWM_ID, 0);   //no phase at pwm beginning
    pwm_set_cycle_and_duty(PWM_ID, 12, 1); // значения вывести в настройку
    pwm_start(PWM_ID);
    gpio_set_func(PWM_PIN, AS_PWMx);
}

uint16_t get_adc_rh_mv(uint32_t p_ain) {
    gpio_setup_up_down_resistor(GPIO_ADC1, PM_PIN_UP_DOWN_FLOAT);
    pwm_init();
    pm_wait_us(16000); // время замера вывести в настройку
    uint16_t mv = get_adc_mv(p_ain);
    pwm_stop(PWM_ID);
    gpio_setup_up_down_resistor(GPIO_ADC1, PM_PIN_PULLDOWN_100K);
    return mv;
}

...
rh_mv = get_adc_rh_mv(CHL_ADC1);
...
(используются процедуры из этого проекта)
Некоторые переменные необходимо вынести в настройку, т.к. будут отличаться для разных электродов и назначения замера.
 

pvvx

Активный участник сообщества
Смысл там в том, что PWM дает среднее напряжение равное смещению на диоде. Диод выпрямляет только пики импульсов, которые сглаживаются емкостью электрода. Получается чувствительность до пары пФ, а схема имеет всего один резистор (около 7.5 кОм), один быстрый диод и накопительный конденсатор (10..100 nF).
Время PWM влияет на значение уровня до которого зарядится конденсатор. После замера вход ADC разряжает конденсатор.
 

pvvx

Активный участник сообщества
В данном случае выпрямляемый от PWM импульс имеет огибающую пиков в 12 MГц (12 к 1 от 24МГц). За 16 ms конденсатор в десятки нФ успевает зарядиться до напряжения, которое достаточно для измерения ADC.
Отношение импульса-паузы в PWM и время генерации и подбирается под необходимый электрод и уровень заряда конденсатора для более менее точности замера по чувствительности ADC.
Настройка (калибровка) может быть автоматизирована - там ничего сложного нет.
 
Сверху Снизу