mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 03:06:33 +00:00
add BTHOME (#20625)
This commit is contained in:
parent
95b03592dc
commit
083ddad683
@ -141,6 +141,14 @@ struct ATCPacket_t{ //and PVVX
|
||||
};
|
||||
};
|
||||
|
||||
struct BTHome_info_t{
|
||||
uint8_t encrypted:1;
|
||||
uint8_t reserved:1;
|
||||
uint8_t triggered:1;
|
||||
uint8_t reserved2:2;
|
||||
uint8_t version:2;
|
||||
};
|
||||
|
||||
struct BLERingBufferItem_t{
|
||||
uint16_t returnCharUUID;
|
||||
uint16_t handle;
|
||||
@ -349,8 +357,9 @@ void (*const MI32_Commands[])(void) PROGMEM = {&CmndMi32Key, &CmndMi32Name,&Cmnd
|
||||
#define PVVX 15
|
||||
#define YLKG08 16
|
||||
#define YLAI003 17
|
||||
#define BTHOME 18
|
||||
|
||||
#define MI32_TYPES 17 //count this manually
|
||||
#define MI32_TYPES 18 //count this manually
|
||||
|
||||
const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora
|
||||
0x01aa, // MJ_HT_V1
|
||||
@ -369,9 +378,10 @@ const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora
|
||||
0x944a, // PVVX -> this is a fake ID
|
||||
0x03b6, // YLKG08 and YLKG07 - version w/wo mains
|
||||
0x07bf, // YLAI003
|
||||
0xb770, // BTHome -> fake ID
|
||||
};
|
||||
|
||||
const char kMI32DeviceType[] PROGMEM = {"Flora|MJ_HT_V1|LYWSD02|LYWSD03|CGG1|CGD1|NLIGHT|MJYD2S|YLYK01|MHOC401|MHOC303|ATC|MCCGQ02|SJWS01L|PVVX|YLKG08|YLAI003"};
|
||||
const char kMI32DeviceType[] PROGMEM = {"Flora|MJ_HT_V1|LYWSD02|LYWSD03|CGG1|CGD1|NLIGHT|MJYD2S|YLYK01|MHOC401|MHOC303|ATC|MCCGQ02|SJWS01L|PVVX|YLKG08|YLAI003|BTHOME"};
|
||||
|
||||
const char kMI32_ConnErrorMsg[] PROGMEM = "no Error|could not connect|did disconnect|got no service|got no characteristic|can not read|can not notify|can not write|did not write|notify time out";
|
||||
|
||||
|
@ -138,10 +138,14 @@ class MI32AdvCallbacks: public NimBLEScanCallbacks {
|
||||
if(UUID==0xfe95) {
|
||||
MI32ParseResponse((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
|
||||
}
|
||||
else if(UUID==0xfdcd) {
|
||||
else if(UUID==0xfcd2) {
|
||||
std::string optionalName = advertisedDevice->getName();
|
||||
MI32parseBTHomePacket((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI, optionalName.c_str());
|
||||
}
|
||||
else if(UUID==0xfdcd) { // deprecated
|
||||
MI32parseCGD1Packet((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
|
||||
}
|
||||
else if(UUID==0x181a) { //ATC and PVVX
|
||||
else if(UUID==0x181a) { //ATC and PVVX - deprecated, change FW setting of these devices to BTHome V2
|
||||
MI32ParseATCPacket((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
|
||||
}
|
||||
_mutex = false;
|
||||
@ -435,7 +439,7 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
|
||||
* @param _type Type number of the sensor
|
||||
* @return uint32_t Known or new slot in the sensors-vector
|
||||
*/
|
||||
uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter){
|
||||
uint32_t MIBLEgetSensorSlot(uint8_t * _MAC, uint16_t _type, uint8_t counter){
|
||||
DEBUG_SENSOR_LOG(PSTR("%s: will test ID-type: %x"),D_CMND_MI32, _type);
|
||||
uint16_t _pid = _type; // save for unknown types
|
||||
bool _success = false;
|
||||
@ -450,7 +454,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
|
||||
|
||||
DEBUG_SENSOR_LOG(PSTR("%s: vector size %u"),D_CMND_MI32, MIBLEsensors.size());
|
||||
for(uint32_t i=0; i<MIBLEsensors.size(); i++){
|
||||
if(memcmp(_MAC,MIBLEsensors[i].MAC,sizeof(_MAC))==0){
|
||||
if(memcmp(_MAC,MIBLEsensors[i].MAC,6)==0){
|
||||
DEBUG_SENSOR_LOG(PSTR("%s: known sensor at slot: %u"),D_CMND_MI32, i);
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("Counters: %x %x"),MIBLEsensors[i].lastCnt, counter);
|
||||
if(MIBLEsensors[i].lastCnt==counter) {
|
||||
@ -468,7 +472,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
|
||||
}
|
||||
DEBUG_SENSOR_LOG(PSTR("%s: found new sensor"),D_CMND_MI32);
|
||||
mi_sensor_t _newSensor;
|
||||
memcpy(_newSensor.MAC,_MAC, sizeof(_MAC));
|
||||
memcpy(_newSensor.MAC,_MAC, 6);
|
||||
_newSensor.PID = _pid;
|
||||
_newSensor.type = _type;
|
||||
_newSensor.eventType.raw = 0;
|
||||
@ -509,7 +513,6 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
|
||||
_newSensor.feature.NMT=1;
|
||||
_newSensor.feature.lux=1;
|
||||
_newSensor.feature.bat=1;
|
||||
_newSensor.feature.bat=1;
|
||||
_newSensor.NMT=0;
|
||||
break;
|
||||
case YLYK01: case YLKG08: case YLAI003:
|
||||
@ -579,20 +582,20 @@ void MI32addHistory(uint8_t *history, float value, uint32_t type){
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history hour: %u"),_hour);
|
||||
switch(type){
|
||||
case 0: //temperature
|
||||
history[_hour] = (((uint8_t)(value + 5.0f)/4)+1) + 0b10000000; //temp
|
||||
history[_hour] = ((((value + 5.0f)/4) + 1) + 0b10000000); //temp
|
||||
break;
|
||||
case 1: //humidity
|
||||
history[_hour] = (((uint8_t)(value/5 ))+1) + 0b10000000; //hum
|
||||
history[_hour] = (((value/5.0f) + 1) + 0b10000000) ; //hum
|
||||
break;
|
||||
case 2: //light
|
||||
if(value>100.0f) value=100.0f; //clamp it for now
|
||||
history[_hour] = (((uint8_t)(value/5.0f))+1) + 0b10000000; //lux
|
||||
history[_hour] = (((value/5.0f) + 1) + 0b10000000); //lux
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history lux: %u in hour:%u"),history[_hour], _hour);
|
||||
break;
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
case 100: // energy
|
||||
if(value == 0.0f) value = 1.0f;
|
||||
uint8_t _watt = ((uint8_t)(MI32ln(value))*2) + 0b10000000; //watt
|
||||
uint8_t _watt = ((MI32ln(value)*2) + 0b10000000); //watt
|
||||
history[_hour] = _watt;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history energy: %u for value:%u"),history[_hour], value); //still playing with the mapping
|
||||
break;
|
||||
@ -997,6 +1000,9 @@ void MI32saveConfig(){
|
||||
if(_sensor.name != nullptr){
|
||||
snprintf_P(_name_feat,64,PSTR(",\"name\":\"%s\",\"feat\":%u"),_sensor.name,_sensor.feature.raw);
|
||||
}
|
||||
else if(_sensor.type == BTHOME && _sensor.name == nullptr){
|
||||
snprintf_P(_name_feat,64,PSTR(",\"feat\":%u"),_sensor.feature.raw);
|
||||
}
|
||||
else{
|
||||
_name_feat[0] = 0;
|
||||
}
|
||||
@ -1812,6 +1818,70 @@ if(decryptRet!=0){
|
||||
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
|
||||
}
|
||||
|
||||
void MI32parseBTHomePacket(char * _buf, uint32_t length, uint8_t addr[6], int RSSI, const char* optionalName){
|
||||
uint32_t _slot;
|
||||
_slot = MIBLEgetSensorSlot(addr, 0xb770, 0); // fake ID, constant fake counter
|
||||
if (optionalName[0] != '\0'){
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), optionalName,_slot);
|
||||
}
|
||||
MIBLEsensors[_slot].RSSI = RSSI;
|
||||
MIBLEsensors[_slot].lastTime = millis();
|
||||
|
||||
BTHome_info_t info = (BTHome_info_t)_buf[0];
|
||||
MIBLEsensors[_slot].feature.needsKey = info.encrypted;
|
||||
|
||||
uint32_t idx = 1;
|
||||
while(idx < length - 1){
|
||||
switch(_buf[idx]){
|
||||
case 0:
|
||||
if(_buf[idx+1] == MIBLEsensors[_slot].lastCnt){
|
||||
return; // known packet
|
||||
}
|
||||
MIBLEsensors[_slot].lastCnt = _buf[idx+1];
|
||||
idx += 2;
|
||||
break;
|
||||
case 1:
|
||||
MIBLEsensors[_slot].bat = _buf[idx+1];
|
||||
MIBLEsensors[_slot].eventType.bat = 1;
|
||||
MIBLEsensors[_slot].feature.bat = 1;
|
||||
idx += 2;
|
||||
break;
|
||||
case 2:
|
||||
MIBLEsensors[_slot].temp = (int16_t)(_buf[idx+1]|_buf[idx+2] << 8)/100.0f;
|
||||
MIBLEsensors[_slot].eventType.temp = 1;
|
||||
MIBLEsensors[_slot].feature.temp = 1;
|
||||
MI32addHistory(MIBLEsensors[_slot].temp_history, (float)MIBLEsensors[_slot].temp, 0);
|
||||
idx += 3;
|
||||
break;
|
||||
case 3:
|
||||
MIBLEsensors[_slot].hum = (uint16_t)(_buf[idx+1]|_buf[idx+2] << 8)/100.0f;
|
||||
MIBLEsensors[_slot].eventType.hum = 1;
|
||||
MIBLEsensors[_slot].feature.hum = 1;
|
||||
MI32addHistory(MIBLEsensors[_slot].hum_history, (float)MIBLEsensors[_slot].hum, 1);
|
||||
idx += 3;
|
||||
break;
|
||||
case 0x0b:
|
||||
// power ??
|
||||
idx += 2;
|
||||
break;
|
||||
case 0x0c:
|
||||
//voltage
|
||||
idx += 2;
|
||||
break;
|
||||
default:
|
||||
AddLog(LOG_LEVEL_INFO,PSTR("M32: unknown BTHome data type: %u, discard rest of data buffer!"),_buf[idx]);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_buf,length);
|
||||
idx = length; // "break"
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
bitSet(MI32.widgetSlot,_slot);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
|
||||
}
|
||||
|
||||
void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int RSSI){
|
||||
ATCPacket_t *_packet = (ATCPacket_t*)_buf;
|
||||
bool isATC = (length == 0x0d);
|
||||
@ -1846,7 +1916,6 @@ void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int RSSI)
|
||||
#endif //USE_MI_EXT_GUI
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
|
||||
|
||||
}
|
||||
|
||||
void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int RSSI){ // no MiBeacon
|
||||
@ -2050,6 +2119,10 @@ void CmndMi32Key(void) {
|
||||
}
|
||||
|
||||
void CmndMi32Name(void) {
|
||||
if(XdrvMailbox.index > MIBLEsensors.size() - 1){
|
||||
ResponseCmndDone();
|
||||
return;
|
||||
}
|
||||
if(MIBLEsensors[XdrvMailbox.index].name != nullptr){
|
||||
delete []MIBLEsensors[XdrvMailbox.index].name;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user