Merge pull request #9892 from Staars/mi32

MI_ESP32: add new commands, add mqtt output
This commit is contained in:
Theo Arends 2020-11-17 11:34:03 +01:00 committed by GitHub
commit 8fab895eca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 126 additions and 16 deletions

View File

@ -20,6 +20,8 @@
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
Version yyyymmdd Action Description Version yyyymmdd Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
0.9.1.7 20201116 changed - small bugfixes, add BLOCK and OPTION command, send BLE scan via MQTT
-------
0.9.1.6 20201022 changed - Beacon support, RSSI at TELEPERIOD, refactoring 0.9.1.6 20201022 changed - Beacon support, RSSI at TELEPERIOD, refactoring
------- -------
0.9.1.5 20201021 changed - HASS related ('null', hold back discovery), number of found sensors for RULES 0.9.1.5 20201021 changed - HASS related ('null', hold back discovery), number of found sensors for RULES
@ -80,10 +82,12 @@ struct {
uint32_t willSetUnit:1; uint32_t willSetUnit:1;
uint32_t shallTriggerTele:1; uint32_t shallTriggerTele:1;
uint32_t triggeredTele:1; uint32_t triggeredTele:1;
uint32_t shallClearResults:1; // BLE scan results uint32_t shallClearResults:1; // BLE scan results
uint32_t shallShowStatusInfo:1; // react to amount of found sensors via RULES uint32_t shallShowStatusInfo:1; // react to amount of found sensors via RULES
uint32_t firstAutodiscoveryDone:1; uint32_t firstAutodiscoveryDone:1;
uint32_t activeBeacon; uint32_t activeBeacon:1;
uint32_t shallShowScanResult:1;
uint32_t shallShowBlockList:1;
}; };
uint32_t all = 0; uint32_t all = 0;
} mode; } mode;
@ -271,10 +275,15 @@ struct generic_beacon_t {
bool active = false; bool active = false;
}; };
struct MAC_t {
uint8_t buf[6];
};
std::vector<mi_sensor_t> MIBLEsensors; std::vector<mi_sensor_t> MIBLEsensors;
std::vector<mi_bindKey_t> MIBLEbindKeys; std::vector<mi_bindKey_t> MIBLEbindKeys;
std::array<generic_beacon_t,4> MIBLEbeacons; // we support a fixed number std::array<generic_beacon_t,4> MIBLEbeacons; // we support a fixed number
std::vector<scan_entry_t> MINBLEscanResult; std::vector<scan_entry_t> MIBLEscanResult;
std::vector<MAC_t> MIBLEBlockList;
static BLEScan* MI32Scan; static BLEScan* MI32Scan;
@ -288,13 +297,13 @@ const char kMI32_Commands[] PROGMEM = D_CMND_MI32 "|"
#ifdef USE_MI_DECRYPTION #ifdef USE_MI_DECRYPTION
"Key|" "Key|"
#endif // USE_MI_DECRYPTION #endif // USE_MI_DECRYPTION
"Period|Time|Page|Battery|Unit|Beacon"; "Period|Time|Page|Battery|Unit|Beacon|Block|Option";
void (*const MI32_Commands[])(void) PROGMEM = { void (*const MI32_Commands[])(void) PROGMEM = {
#ifdef USE_MI_DECRYPTION #ifdef USE_MI_DECRYPTION
&CmndMi32Key, &CmndMi32Key,
#endif // USE_MI_DECRYPTION #endif // USE_MI_DECRYPTION
&CmndMi32Period, &CmndMi32Time, &CmndMi32Page, &CmndMi32Battery, &CmndMi32Unit, &CmndMi32Beacon }; &CmndMi32Period, &CmndMi32Time, &CmndMi32Page, &CmndMi32Battery, &CmndMi32Unit, &CmndMi32Beacon, &CmndMi32Block, &CmndMi32Option };
#define FLORA 1 #define FLORA 1
#define MJ_HT_V1 2 #define MJ_HT_V1 2
@ -350,7 +359,9 @@ enum MI32_Commands { // commands useable in console or rules
CMND_MI32_BATTERY, // read all battery levels CMND_MI32_BATTERY, // read all battery levels
CMND_MI32_UNIT, // toggles the displayed unit between C/F (LYWSD02) CMND_MI32_UNIT, // toggles the displayed unit between C/F (LYWSD02)
CMND_MI32_KEY, // add bind key to a mac for packet decryption CMND_MI32_KEY, // add bind key to a mac for packet decryption
CMND_MI32_BEACON // add up to 4 beacons defined by their MAC addresses CMND_MI32_BEACON, // add up to 4 beacons defined by their MAC addresses
CMND_MI32_BLOCK, // block BLE sensors defined by their MAC addresses
CMND_MI32_OPTION // change driver options at runtime
}; };
enum MI32_TASK { enum MI32_TASK {
@ -420,12 +431,15 @@ class MI32AdvCallbacks: public NimBLEAdvertisedDeviceCallbacks {
size_t ServiceDataLength = advertisedDevice->getServiceData(0).length(); size_t ServiceDataLength = advertisedDevice->getServiceData(0).length();
if(UUID==0xfe95) { if(UUID==0xfe95) {
if(MI32isInBlockList(addr) == true) return;
MI32ParseResponse((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI); MI32ParseResponse((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
} }
else if(UUID==0xfdcd) { else if(UUID==0xfdcd) {
if(MI32isInBlockList(addr) == true) return;
MI32parseCGD1Packet((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI); MI32parseCGD1Packet((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
} }
else if(UUID==0x181a) { //ATC else if(UUID==0x181a) { //ATC
if(MI32isInBlockList(addr) == true) return;
MI32ParseATCPacket((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI); MI32ParseATCPacket((char*)advertisedDevice->getServiceData(0).data(),ServiceDataLength, addr, RSSI);
} }
else { else {
@ -754,7 +768,7 @@ void MI32StatusInfo() {
void MI32PreInit(void) { void MI32PreInit(void) {
MIBLEsensors.reserve(10); MIBLEsensors.reserve(10);
MIBLEbindKeys.reserve(10); MIBLEbindKeys.reserve(10);
MINBLEscanResult.reserve(20); MIBLEscanResult.reserve(20);
MI32.mode.init = false; MI32.mode.init = false;
//test section for options //test section for options
@ -1534,12 +1548,12 @@ void MI32HandleGenericBeacon(uint8_t* payload, size_t payloadLength, int RSSI, u
return; return;
} }
// else handle scan // else handle scan
if(MINBLEscanResult.size()>19) { if(MIBLEscanResult.size()>19) {
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: Scan buffer full")); AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: Scan buffer full"));
MI32.state.beaconScanCounter = 1; MI32.state.beaconScanCounter = 1;
return; return;
} }
for(auto _scanResult : MINBLEscanResult){ for(auto _scanResult : MIBLEscanResult){
if(memcmp(addr,_scanResult.MAC,6)==0){ if(memcmp(addr,_scanResult.MAC,6)==0){
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: known device")); // AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: known device"));
return; return;
@ -1552,7 +1566,7 @@ void MI32HandleGenericBeacon(uint8_t* payload, size_t payloadLength, int RSSI, u
_new.UUID = 0; _new.UUID = 0;
memcpy(_new.MAC,addr,sizeof(_new.MAC)); memcpy(_new.MAC,addr,sizeof(_new.MAC));
MI32ParseGenericBeacon(payload,payloadLength,&_new.CID,&_new.SVC,&_new.UUID); MI32ParseGenericBeacon(payload,payloadLength,&_new.CID,&_new.SVC,&_new.UUID);
MINBLEscanResult.push_back(_new); MIBLEscanResult.push_back(_new);
} }
@ -1585,13 +1599,43 @@ void MI32addBeacon(uint8_t index, char* data){
* *
*/ */
void MI32showScanResults(){ void MI32showScanResults(){
AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: found %u devices in scan:"), MINBLEscanResult.size()); size_t _size = MIBLEscanResult.size();
for(auto _scanResult : MINBLEscanResult){ ResponseAppend_P(PSTR(",\"BLEScan\":{\"Found\":%u,\"Devices\":["), _size);
for(auto _scanResult : MIBLEscanResult){
char _MAC[18]; char _MAC[18];
ToHex_P(_scanResult.MAC,6,_MAC,18,':'); ToHex_P(_scanResult.MAC,6,_MAC,18,':');
AddLog_P(LOG_LEVEL_INFO,PSTR("MAC: %s _ CID: %04x _ SVC: %04x _ UUID: %04x _ RSSI: %d"), _MAC, _scanResult.CID, _scanResult.SVC, _scanResult.UUID, _scanResult.RSSI); ResponseAppend_P(PSTR("{\"MAC\":\"%s\",\"CID\":\"0x%04x\",\"SVC\":\"0x%04x\",\"UUID\":\"0x%04x\",\"RSSI\":%d},"), _MAC, _scanResult.CID, _scanResult.SVC, _scanResult.UUID, _scanResult.RSSI);
} }
MINBLEscanResult.clear(); if(_size != 0)TasmotaGlobal.mqtt_data[strlen(TasmotaGlobal.mqtt_data)-1] = 0; // delete last comma
ResponseAppend_P(PSTR("]}"));
MIBLEscanResult.clear();
MI32.mode.shallShowScanResult = 0;
}
void MI32showBlockList(){
ResponseAppend_P(PSTR(",\"Block\":["));
for(auto _scanResult : MIBLEBlockList){
char _MAC[18];
ToHex_P(_scanResult.buf,6,_MAC,18,':');
ResponseAppend_P(PSTR("\"%s\","), _MAC);
}
if(MIBLEBlockList.size()!=0) TasmotaGlobal.mqtt_data[strlen(TasmotaGlobal.mqtt_data)-1] = 0; // delete last comma
ResponseAppend_P(PSTR("]"));
MI32.mode.shallShowBlockList = 0;
}
bool MI32isInBlockList(uint8_t* MAC){
bool isBlocked = false;
for(auto &_blockedMAC : MIBLEBlockList){
if(memcmp(_blockedMAC.buf,MAC,6) == 0) isBlocked = true;
}
return isBlocked;
}
void MI32removeMIBLEsensor(uint8_t* MAC){
MIBLEsensors.erase( std::remove_if( MIBLEsensors.begin() , MIBLEsensors.end(), [MAC]( mi_sensor_t _sensor )->bool
{ return (memcmp(_sensor.MAC,MAC,6) == 0); }
), end( MIBLEsensors ) );
} }
/***********************************************************************\ /***********************************************************************\
* Read data from connections * Read data from connections
@ -1691,7 +1735,8 @@ void MI32EverySecond(bool restart){
if(MI32.state.beaconScanCounter!=0){ if(MI32.state.beaconScanCounter!=0){
MI32.state.beaconScanCounter--; MI32.state.beaconScanCounter--;
if(MI32.state.beaconScanCounter==0){ if(MI32.state.beaconScanCounter==0){
MI32showScanResults(); MI32.mode.shallShowScanResult = 1;
MI32triggerTele();
} }
} }
@ -1875,11 +1920,70 @@ void CmndMi32Beacon(void) {
} }
} }
void CmndMi32Block(void){
if (XdrvMailbox.data_len == 0) {
switch (XdrvMailbox.index) {
case 0:
MIBLEBlockList.clear();
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: size of ilist: %u"), MIBLEBlockList.size());
ResponseCmndIdxChar(PSTR("block list cleared"));
break;
case 1:
ResponseCmndIdxChar(PSTR("show block list"));
break;
}
}
else {
MAC_t _MACasBytes;
MI32HexStringToBytes(XdrvMailbox.data,_MACasBytes.buf);
switch (XdrvMailbox.index) {
case 0:
MIBLEBlockList.erase( std::remove_if( begin( MIBLEBlockList ), end( MIBLEBlockList ), [_MACasBytes]( MAC_t& _entry )->bool
{ return (memcmp(_entry.buf,_MACasBytes.buf,6) == 0); }
), end( MIBLEBlockList ) );
ResponseCmndIdxChar(PSTR("MAC not blocked anymore"));
break;
case 1:
bool _notYetInList = true;
for (auto &_entry : MIBLEBlockList) {
if (memcmp(_entry.buf,_MACasBytes.buf,6) == 0){
_notYetInList = false;
}
}
if (_notYetInList) {
MIBLEBlockList.push_back(_MACasBytes);
ResponseCmndIdxChar(XdrvMailbox.data);
MI32removeMIBLEsensor(_MACasBytes.buf);
}
// AddLog_P(LOG_LEVEL_INFO,PSTR("MI32: size of ilist: %u"), MIBLEBlockList.size());
break;
}
}
MI32.mode.shallShowBlockList = 1;
MI32triggerTele();
}
void CmndMi32Option(void){
bool onOff = atoi(XdrvMailbox.data);
switch(XdrvMailbox.index) {
case 0:
MI32.option.allwaysAggregate = onOff;
break;
case 1:
MI32.option.noSummary = onOff;
break;
case 2:
MI32.option.directBridgeMode = onOff;
break;
}
ResponseCmndDone();
}
/*********************************************************************************************\ /*********************************************************************************************\
* Presentation * Presentation
\*********************************************************************************************/ \*********************************************************************************************/
const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0916a{m}%u%s / %u{e}"; const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0917{m}%u%s / %u{e}";
const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}"; const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}";
const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}"; const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}";
const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u %%{e}"; const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u %%{e}";
@ -1892,6 +1996,12 @@ const char HTTP_MI32_HL[] PROGMEM = "{s}<hr>{m}<hr>{e}";
void MI32Show(bool json) void MI32Show(bool json)
{ {
if (json) { if (json) {
if(MI32.mode.shallShowScanResult) {
return MI32showScanResults();
}
else if(MI32.mode.shallShowBlockList) {
return MI32showBlockList();
}
#ifdef USE_HOME_ASSISTANT #ifdef USE_HOME_ASSISTANT
bool _noSummarySave = MI32.option.noSummary; bool _noSummarySave = MI32.option.noSummary;
bool _minimalSummarySave = MI32.option.minimalSummary; bool _minimalSummarySave = MI32.option.minimalSummary;