Add Support for Avago Tech Bluetooth Buttons (#20088)

This commit is contained in:
Steve 2023-11-23 22:00:34 +11:00 committed by GitHub
parent 1c60527099
commit 3568b559e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -24,6 +24,8 @@
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
Version yyyymmdd Action Description Version yyyymmdd Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
0.9.2.2 20231123 changed - added support for Avago Tech Bluetooth buttons
-------
0.9.2.1 20210217 changed - make features alos depend on received data - i.e. 'unknown' devices will show what they send. 0.9.2.1 20210217 changed - make features alos depend on received data - i.e. 'unknown' devices will show what they send.
Add MI32Option6 1 to switch to tele/tasmota_ble/<somename> style MQTT independent of HASS discovery. Add MI32Option6 1 to switch to tele/tasmota_ble/<somename> style MQTT independent of HASS discovery.
------- -------
@ -483,8 +485,9 @@ void (*const MI32_Commands[])(void) PROGMEM = {
#define MI_SCALE_V1 15 #define MI_SCALE_V1 15
#define MI_SCALE_V2 16 #define MI_SCALE_V2 16
#define MI_CGDK2 17 #define MI_CGDK2 17
#define AT_BTN 18
#define MI_MI32_TYPES 17 //count this manually #define MI_MI32_TYPES 18 //count this manually
const uint16_t kMI32DeviceID[MI_MI32_TYPES]={ const uint16_t kMI32DeviceID[MI_MI32_TYPES]={
0x0000, // Unkown 0x0000, // Unkown
@ -504,6 +507,7 @@ const uint16_t kMI32DeviceID[MI_MI32_TYPES]={
0x181d, // Mi Scale V1 0x181d, // Mi Scale V1
0x181b, // Mi Scale V2 0x181b, // Mi Scale V2
0x066f, // CGDK2 0x066f, // CGDK2
0x004e // Avago Tech Bluetooth Buttons (Company Id)
}; };
const char kMI32DeviceType0[] PROGMEM = "Unknown"; const char kMI32DeviceType0[] PROGMEM = "Unknown";
@ -523,7 +527,8 @@ const char kMI32DeviceType13[] PROGMEM ="DOOR";
const char kMI32DeviceType14[] PROGMEM ="MISCALEV1"; const char kMI32DeviceType14[] PROGMEM ="MISCALEV1";
const char kMI32DeviceType15[] PROGMEM ="MISCALEV2"; const char kMI32DeviceType15[] PROGMEM ="MISCALEV2";
const char kMI32DeviceType16[] PROGMEM ="CGDK2"; const char kMI32DeviceType16[] PROGMEM ="CGDK2";
const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType0,kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10,kMI32DeviceType11,kMI32DeviceType12,kMI32DeviceType13,kMI32DeviceType14,kMI32DeviceType15,kMI32DeviceType16}; const char kMI32DeviceType17[] PROGMEM ="ATBTN";
const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType0,kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10,kMI32DeviceType11,kMI32DeviceType12,kMI32DeviceType13,kMI32DeviceType14,kMI32DeviceType15,kMI32DeviceType16,kMI32DeviceType17};
typedef int BATREAD_FUNCTION(int slot); typedef int BATREAD_FUNCTION(int slot);
typedef int UNITWRITE_FUNCTION(int slot, int unit); typedef int UNITWRITE_FUNCTION(int slot, int unit);
@ -558,6 +563,7 @@ const char FLORA_Svc[] PROGMEM = "00001204-0000-1000-8000-00805F9
const char FLORA_BattChar[] PROGMEM = "00001A02-0000-1000-8000-00805F9B34FB"; const char FLORA_BattChar[] PROGMEM = "00001A02-0000-1000-8000-00805F9B34FB";
const uint8_t ATBTN_Addr[] = { 0xc1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6 }; // All Avago Buttons seem to use same source address
/*********************************************************************************************\ /*********************************************************************************************\
* enumerations * enumerations
@ -1057,6 +1063,14 @@ int MI32advertismentCallback(BLE_ESP32::ble_advertisment_t *pStruct)
} }
} }
// ATBTN uses manufacturer data and not a service - bit more like an IBeacon
if (memcmp(ATBTN_Addr, addr, 6) == 0)
{
//AddLog(LOG_LEVEL_INFO, PSTR("M32: AvagoBtn: %s"), advertisedDevice->toString().c_str());
MI32ParseATBtn((uint8_t*)advertisedDevice->getManufacturerData().data(), advertisedDevice->getManufacturerData().length(), addr, RSSI);
return 0;
}
int svcdataCount = advertisedDevice->getServiceDataCount(); int svcdataCount = advertisedDevice->getServiceDataCount();
if (svcdataCount == 0) { if (svcdataCount == 0) {
@ -1463,9 +1477,11 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
* *
* @param _MAC BLE address of the sensor * @param _MAC BLE address of the sensor
* @param _type Type number of the sensor * @param _type Type number of the sensor
* @param counter sequence number of broadcast - same for duplicates
* @paramm ignoreDulicates ignore if counter matches lastCnt and previous broardcasts
* @return uint32_t Known or new slot in the sensors-vector * @return uint32_t Known or new slot in the sensors-vector
*/ */
uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter){ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter, bool ignoreDuplicate = false){
//AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: %s: will test ID-type: %x"),D_CMND_MI32, _type); //AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: %s: will test ID-type: %x"),D_CMND_MI32, _type);
bool _success = false; bool _success = false;
@ -1490,7 +1506,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
if(MIBLEsensors[i].lastCnt==counter) { if(MIBLEsensors[i].lastCnt==counter) {
// AddLog(LOG_LEVEL_DEBUG,PSTR("Old packet")); // AddLog(LOG_LEVEL_DEBUG,PSTR("Old packet"));
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: %s: slot: %u/%u - ign repeat"),D_CMND_MI32, i, MIBLEsensors.size()); if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: %s: slot: %u/%u - ign repeat"),D_CMND_MI32, i, MIBLEsensors.size());
//return 0xff; // packet received before, stop here if(ignoreDuplicate) return 0xff; // packet received before, stop here
} }
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Frame %d, last %d"), counter, MIBLEsensors[i].lastCnt); if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Frame %d, last %d"), counter, MIBLEsensors[i].lastCnt);
MIBLEsensors[i].lastCnt = counter; MIBLEsensors[i].lastCnt = counter;
@ -1523,7 +1539,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.lux = 0x00ffffff; _newSensor.lux = 0x00ffffff;
_newSensor.light = -1; _newSensor.light = -1;
_newSensor.Btn = -1; _newSensor.Btn = -1;
_newSensor.lastCnt = counter;
switch (_type) switch (_type)
{ {
case MI_FLORA: case MI_FLORA:
@ -1566,6 +1582,11 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.feature.scale=1; _newSensor.feature.scale=1;
_newSensor.feature.impedance=1; _newSensor.feature.impedance=1;
break; break;
case AT_BTN:
_newSensor.feature.Btn=1;
_newSensor.needkey = KEY_NOT_REQUIRED;
break;
default: default:
_newSensor.hum=NAN; _newSensor.hum=NAN;
_newSensor.feature.temp=1; _newSensor.feature.temp=1;
@ -2134,6 +2155,61 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
return res; return res;
} }
/*
AT Button Manufacturer Data
0 Company ID = 2 bytes
2 Unknown = 4 bytes 7fffffff
6 Counter = 1 byte
7 Unknown = 1 byte 05
8 Switch = 2 bytes
10 Unknown = 1 byte 00
11 Button = 1 bytes 0x (x = 1 to 3)
12 Unknown = 4 bytes 50000100
*/
struct __attribute__ ((packed)) ATBtn_data
{
uint16_t company_id;
uint32_t unknown1;
uint8_t counter;
uint8_t unknown2;
union {
struct {
uint8_t switch1;
uint8_t switch2;
};
uint16_t switch_id;
};
uint8_t unknown3;
uint8_t button_id;
uint32_t unknown4;
};
void MI32ParseATBtn(uint8_t *buf, uint16_t bufsize, const uint8_t* addr, int RSSI) {
ATBtn_data* data = (ATBtn_data*)buf;
// AddLog(LOG_LEVEL_INFO,PSTR("ATBTN %04x, %d, Counter(%u) Switch(%04x), Button(%x) %x"), data->company_id, bufsize, data->counter, data->switch_id, data->button_id, kMI32DeviceID[AT_BTN-1]);
if (bufsize != sizeof(ATBtn_data) || data->company_id != kMI32DeviceID[AT_BTN-1])
return;
// since all have same address, we'll move the "switch Id" into the last two addr fields to give each switch a unique MAC address
uint8_t _addr[6];
memcpy(_addr,addr,6);
_addr[4] = data->switch1;
_addr[5] = data->switch2;
uint32_t _slot = MIBLEgetSensorSlot(_addr, kMI32DeviceID[AT_BTN-1], data->counter, true);
if(_slot==0xff) return;
// AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), MI32getDeviceName(_slot),_slot);
MIBLEsensors[_slot].RSSI=RSSI;
MIBLEsensors[_slot].lastTime = millis();
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MIBLEsensors[_slot].feature.Btn = 1;
MIBLEsensors[_slot].Btn = data->button_id;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// this SHOULD parse any MI packet, including encrypted. // this SHOULD parse any MI packet, including encrypted.
void MI32ParseResponse(const uint8_t *buf, uint16_t bufsize, const uint8_t* addr, int RSSI) { void MI32ParseResponse(const uint8_t *buf, uint16_t bufsize, const uint8_t* addr, int RSSI) {
@ -2745,6 +2821,9 @@ void MI32TimeoutSensors(){
// remove devices for which the adverts have timed out // remove devices for which the adverts have timed out
for (int i = MIBLEsensors.size()-1; i >= 0 ; i--) { for (int i = MIBLEsensors.size()-1; i >= 0 ; i--) {
//if (MIBLEsensors[i].MAC[2] || MIBLEsensors[i].MAC[3] || MIBLEsensors[i].MAC[4] || MIBLEsensors[i].MAC[5]){ //if (MIBLEsensors[i].MAC[2] || MIBLEsensors[i].MAC[3] || MIBLEsensors[i].MAC[4] || MIBLEsensors[i].MAC[5]){
// Since we use a pseudo MAC for the ATBTN slots we need to ignore these warnings
if (memcmp(MIBLEsensors[i].MAC, ATBTN_Addr, 4) == 0) // Skip pseudo AT BTN addresses
continue;
if (!BLE_ESP32::devicePresent(MIBLEsensors[i].MAC)){ if (!BLE_ESP32::devicePresent(MIBLEsensors[i].MAC)){
uint8_t *mac = MIBLEsensors[i].MAC; uint8_t *mac = MIBLEsensors[i].MAC;
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Dev no longer present MAC: %02x%02x%02x%02x%02x%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Dev no longer present MAC: %02x%02x%02x%02x%02x%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);