Skip to content

Commit

Permalink
Add Support for Avago Tech Bluetooth Buttons (#20088)
Browse files Browse the repository at this point in the history
  • Loading branch information
kabongsteve committed Nov 23, 2023
1 parent 1c60527 commit 3568b55
Showing 1 changed file with 84 additions and 5 deletions.
89 changes: 84 additions & 5 deletions tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
--------------------------------------------------------------------------------------------
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.
Add MI32Option6 1 to switch to tele/tasmota_ble/<somename> style MQTT independent of HASS discovery.
-------
Expand Down Expand Up @@ -483,8 +485,9 @@ void (*const MI32_Commands[])(void) PROGMEM = {
#define MI_SCALE_V1 15
#define MI_SCALE_V2 16
#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]={
0x0000, // Unkown
Expand All @@ -504,6 +507,7 @@ const uint16_t kMI32DeviceID[MI_MI32_TYPES]={
0x181d, // Mi Scale V1
0x181b, // Mi Scale V2
0x066f, // CGDK2
0x004e // Avago Tech Bluetooth Buttons (Company Id)
};

const char kMI32DeviceType0[] PROGMEM = "Unknown";
Expand All @@ -523,7 +527,8 @@ const char kMI32DeviceType13[] PROGMEM ="DOOR";
const char kMI32DeviceType14[] PROGMEM ="MISCALEV1";
const char kMI32DeviceType15[] PROGMEM ="MISCALEV2";
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 UNITWRITE_FUNCTION(int slot, int unit);
Expand Down Expand Up @@ -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 uint8_t ATBTN_Addr[] = { 0xc1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6 }; // All Avago Buttons seem to use same source address

/*********************************************************************************************\
* enumerations
Expand Down Expand Up @@ -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();

if (svcdataCount == 0) {
Expand Down Expand Up @@ -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 _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
*/
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);
bool _success = false;
Expand All @@ -1490,7 +1506,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
if(MIBLEsensors[i].lastCnt==counter) {
// 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());
//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);
MIBLEsensors[i].lastCnt = counter;
Expand Down Expand Up @@ -1523,7 +1539,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.lux = 0x00ffffff;
_newSensor.light = -1;
_newSensor.Btn = -1;

_newSensor.lastCnt = counter;
switch (_type)
{
case MI_FLORA:
Expand Down Expand Up @@ -1566,6 +1582,11 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.feature.scale=1;
_newSensor.feature.impedance=1;
break;
case AT_BTN:
_newSensor.feature.Btn=1;
_newSensor.needkey = KEY_NOT_REQUIRED;
break;

default:
_newSensor.hum=NAN;
_newSensor.feature.temp=1;
Expand Down Expand Up @@ -2134,6 +2155,61 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
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.
void MI32ParseResponse(const uint8_t *buf, uint16_t bufsize, const uint8_t* addr, int RSSI) {
Expand Down Expand Up @@ -2745,6 +2821,9 @@ void MI32TimeoutSensors(){
// remove devices for which the adverts have timed out
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]){
// 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)){
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]);
Expand Down

0 comments on commit 3568b55

Please sign in to comment.