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