2020-04-21 08:58:33 +01:00
/*
2021-01-27 10:16:30 +00:00
xsns_62_esp32_mi . ino - MI - BLE - sensors via ESP32 support for Tasmota
enabled by ESP32 & & ! USE_BLE_ESP32
if ( ESP32 & & USE_BLE_ESP32 ) then xsns_62_esp32_mi_ble . ino is used
2020-04-21 08:58:33 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Christian Baars and Theo Arends
2020-04-21 08:58:33 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Version yyyymmdd Action Description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2022-03-26 09:52:45 +00:00
0.9 .5 .5 20220326 changed - refactored connection task for asynchronous op , add response option ,
fixed MI32Key command
- - - - - - -
2022-03-25 09:15:58 +00:00
0.9 .5 .4 20220325 changed - add Berry adv_watch and adv_block to BLE class
- - - - - - -
2022-03-16 07:41:04 +00:00
0.9 .5 .3 20220315 changed - reworked Berry part , active scanning and holding active connections possible , new format of advertisement buffer
- - - - - - -
2022-02-11 17:03:22 +00:00
0.9 .5 .1 20220209 changed - rename YEERC to YLYK01 , add dimmer YLKG08 ( incl . YLKG07 ) , change button report scheme
- - - - - - -
2022-01-17 18:47:56 +00:00
0.9 .5 .0 20211016 changed - major rewrite , added mi32cfg ( file and command ) , Homekit - Bridge ,
extended GUI ,
removed BLOCK , PERIOD , TIME , UNIT , BATTERY and PAGE - > replaced via Berry - Support
2020-08-02 14:07:18 +01:00
- - - - - - -
2022-01-17 18:47:56 +00:00
0.9 .1 .7 20201116 changed - small bugfixes , add BLOCK and OPTION command , send BLE scan via MQTT
2020-07-15 16:41:12 +01:00
- - - - - - -
2022-02-11 17:03:22 +00:00
0.9 .1 .0 20200712 changed - add lights and YLYK01 , add pure passive mode with decryption ,
2020-07-12 17:17:27 +01:00
lots of refactoring
- - - - - - -
2020-07-06 19:10:43 +01:00
0.9 .0 .1 20200706 changed - adapt to new NimBLE - API , tweak scan process
2020-07-12 17:17:27 +01:00
- - - - - - -
2020-04-21 08:58:33 +01:00
0.9 .0 .0 20200413 started - initial development by Christian Baars
forked - from arendst / tasmota - https : //github.com/arendst/Tasmota
*/
2021-01-17 17:08:54 +00:00
# ifndef USE_BLE_ESP32
2020-04-21 10:06:30 +01:00
# ifdef ESP32 // ESP32 only. Use define USE_HM10 for ESP8266 support
2022-02-12 19:01:12 +00:00
# if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3
2020-04-21 10:06:30 +01:00
2020-04-21 08:58:33 +01:00
# ifdef USE_MI_ESP32
2022-01-17 18:47:56 +00:00
# ifdef USE_ENERGY_SENSOR
2022-02-11 17:03:22 +00:00
// #define USE_MI_ESP32_ENERGY //prepare for some GUI extensions
2022-01-17 18:47:56 +00:00
# endif
2020-04-21 08:58:33 +01:00
# define XSNS_62 62
# include <NimBLEDevice.h>
# include <vector>
2022-01-17 18:47:56 +00:00
# include <t_bearssl.h>
2020-04-21 08:58:33 +01:00
2022-01-17 18:47:56 +00:00
# include "xsns_62_esp32_mi.h"
2020-07-12 17:17:27 +01:00
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
extern " C " void mi_homekit_main ( void ) ;
extern " C " void mi_homekit_update_value ( void * handle , float value , uint32_t type ) ;
extern " C " void mi_homekit_stop ( ) ;
void MI32getSetupCodeFromMAC ( char * code ) ;
# endif //USE_MI_HOMEKIT
2020-07-12 17:17:27 +01:00
2020-09-16 07:03:55 +01:00
2022-01-17 18:47:56 +00:00
void MI32scanEndedCB ( NimBLEScanResults results ) ;
void MI32notifyCB ( NimBLERemoteCharacteristic * pRemoteCharacteristic , uint8_t * pData , size_t length , bool isNotify ) ;
void MI32AddKey ( mi_bindKey_t keyMAC ) ;
2020-11-17 08:30:59 +00:00
2020-04-21 08:58:33 +01:00
std : : vector < mi_sensor_t > MIBLEsensors ;
2020-07-12 17:17:27 +01:00
static BLEScan * MI32Scan ;
2020-04-21 08:58:33 +01:00
/*********************************************************************************************\
* Classes
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class MI32SensorCallback : public NimBLEClientCallbacks {
void onConnect ( NimBLEClient * pclient ) {
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("connected %s"), kMI32DeviceType[(MIBLEsensors[MI32.conCtx->slot].type)-1]);
MI32 . infoMsg = MI32_DID_CONNECT ;
2020-04-21 08:58:33 +01:00
MI32 . mode . willConnect = 0 ;
MI32 . mode . connected = 1 ;
}
void onDisconnect ( NimBLEClient * pclient ) {
MI32 . mode . connected = 0 ;
2022-03-26 09:52:45 +00:00
MI32 . infoMsg = MI32_DID_DISCONNECT ;
MI32 . conCtx - > error = MI32_CONN_DID_DISCCONNECT ;
MI32 . mode . triggerBerryConnCB = 1 ; //mainly for unexpected or requested disconnects
2022-01-17 18:47:56 +00:00
//AddLog(LOG_LEVEL_DEBUG,PSTR("disconnected"));
2020-04-21 08:58:33 +01:00
}
bool onConnParamsUpdateRequest ( NimBLEClient * MI32Client , const ble_gap_upd_params * params ) {
if ( params - > itvl_min < 24 ) { /** 1.25ms units */
return false ;
} else if ( params - > itvl_max > 40 ) { /** 1.25ms units */
return false ;
} else if ( params - > latency > 2 ) { /** Number of intervals allowed to skip */
return false ;
} else if ( params - > supervision_timeout > 100 ) { /** 10ms units */
return false ;
}
2020-04-21 10:06:30 +01:00
return true ;
2020-04-21 08:58:33 +01:00
}
} ;
class MI32AdvCallbacks : public NimBLEAdvertisedDeviceCallbacks {
void onResult ( NimBLEAdvertisedDevice * advertisedDevice ) {
2022-01-17 18:47:56 +00:00
static bool _mutex = false ;
if ( _mutex ) return ;
_mutex = true ;
2020-10-23 09:18:57 +01:00
int RSSI = advertisedDevice - > getRSSI ( ) ;
2020-04-21 08:58:33 +01:00
uint8_t addr [ 6 ] ;
memcpy ( addr , advertisedDevice - > getAddress ( ) . getNative ( ) , 6 ) ;
MI32_ReverseMAC ( addr ) ;
2022-01-17 18:47:56 +00:00
size_t ServiceDataLength = 0 ;
if ( MI32 . beAdvCB ! = nullptr & & MI32 . mode . triggerBerryAdvCB = = 0 ) {
berryAdvPacket_t * _packet = ( berryAdvPacket_t * ) MI32 . beAdvBuf ;
memcpy ( _packet - > MAC , addr , 6 ) ;
_packet - > addressType = advertisedDevice - > getAddressType ( ) ;
_packet - > RSSI = ( uint8_t ) RSSI ;
2022-03-16 07:41:04 +00:00
uint8_t * _payload = advertisedDevice - > getPayload ( ) ;
_packet - > length = advertisedDevice - > getPayloadLength ( ) ;
memcpy ( _packet - > payload , _payload , _packet - > length ) ;
2022-01-17 18:47:56 +00:00
MI32 . mode . triggerBerryAdvCB = 1 ;
}
2022-03-16 07:41:04 +00:00
if ( advertisedDevice - > getServiceDataCount ( ) = = 0 ) {
_mutex = false ;
return ;
}
uint16_t UUID = advertisedDevice - > getServiceDataUUID ( 0 ) . getNative ( ) - > u16 . value ;
ServiceDataLength = advertisedDevice - > getServiceData ( 0 ) . length ( ) ;
2020-10-23 09:18:57 +01:00
if ( UUID = = 0xfe95 ) {
MI32ParseResponse ( ( char * ) advertisedDevice - > getServiceData ( 0 ) . data ( ) , ServiceDataLength , addr , RSSI ) ;
2020-04-21 08:58:33 +01:00
}
2020-10-23 09:18:57 +01:00
else if ( UUID = = 0xfdcd ) {
MI32parseCGD1Packet ( ( char * ) advertisedDevice - > getServiceData ( 0 ) . data ( ) , ServiceDataLength , addr , RSSI ) ;
2020-05-29 23:41:49 +01:00
}
2022-01-17 18:47:56 +00:00
else if ( UUID = = 0x181a ) { //ATC and PVVX
2020-10-23 09:18:57 +01:00
MI32ParseATCPacket ( ( char * ) advertisedDevice - > getServiceData ( 0 ) . data ( ) , ServiceDataLength , addr , RSSI ) ;
2020-09-16 07:03:55 +01:00
}
2022-01-17 18:47:56 +00:00
_mutex = false ;
2020-04-21 08:58:33 +01:00
} ;
} ;
static MI32AdvCallbacks MI32ScanCallbacks ;
static MI32SensorCallback MI32SensorCB ;
static NimBLEClient * MI32Client ;
/*********************************************************************************************\
* BLE callback functions
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void MI32scanEndedCB ( NimBLEScanResults results ) {
2022-01-17 18:47:56 +00:00
MI32 . infoMsg = MI32_SCAN_ENDED ;
2020-04-21 08:58:33 +01:00
MI32 . mode . runningScan = 0 ;
}
void MI32notifyCB ( NimBLERemoteCharacteristic * pRemoteCharacteristic , uint8_t * pData , size_t length , bool isNotify ) {
2022-03-16 07:41:04 +00:00
if ( MI32 . mode . triggerBerryConnCB ) return ; //discard data, if we did not pass the old to Berry yet
2022-03-26 09:52:45 +00:00
if ( isNotify ) {
MI32 . infoMsg = MI32_GOT_NOTIFICATION ;
MI32 . conCtx - > buffer [ 0 ] = ( uint8_t ) length ;
memcpy ( MI32 . conCtx - > buffer + 1 , pData , length ) ;
MI32 . conCtx - > returnCharUUID = pRemoteCharacteristic - > getUUID ( ) . getNative ( ) - > u16 . value ;
MI32 . conCtx - > operation = 103 ;
MI32 . mode . triggerBerryConnCB = 1 ;
MI32 . mode . readingDone = 1 ;
}
2020-04-21 08:58:33 +01:00
}
/*********************************************************************************************\
* Helper functions
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-10-23 09:18:57 +01:00
/**
* @ brief Remove all colons from null terminated char array
2020-10-30 11:29:48 +00:00
*
2020-10-23 09:18:57 +01:00
* @ param _string Typically representing a MAC - address like AA : BB : CC : DD : EE : FF
*/
void MI32stripColon ( char * _string ) {
uint32_t _length = strlen ( _string ) ;
uint32_t _index = 0 ;
while ( _index < _length ) {
char c = _string [ _index ] ;
if ( c = = ' : ' ) {
memmove ( _string + _index , _string + _index + 1 , _length - _index ) ;
}
_index + + ;
}
_string [ _index ] = 0 ;
}
/**
* @ brief Convert string that repesents a hexadecimal number to a byte array
*
* @ param _string input string in format : AABBCCDDEEFF or AA : BB : CC : DD : EE : FF , caseinsensitive
* @ param _mac target byte array must match the correct size ( i . e . AA : BB - > uint8_t bytes [ 2 ] )
*/
void MI32HexStringToBytes ( char * _string , uint8_t * _byteArray ) {
MI32stripColon ( _string ) ;
UpperCase ( _string , _string ) ;
uint32_t index = 0 ;
uint32_t _end = strlen ( _string ) ;
memset ( _byteArray , 0 , _end / 2 ) ;
while ( index < _end ) {
char c = _string [ index ] ;
uint8_t value = 0 ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
value = ( c - ' 0 ' ) ;
else if ( c > = ' A ' & & c < = ' F ' )
value = ( 10 + ( c - ' A ' ) ) ;
_byteArray [ ( index / 2 ) ] + = value < < ( ( ( index + 1 ) % 2 ) * 4 ) ;
index + + ;
}
}
/**
* @ brief Reverse an array of 6 bytes
2020-10-30 11:29:48 +00:00
*
2020-10-23 09:18:57 +01:00
* @ param _mac a byte array of size 6 ( typicalliy representing a MAC address )
*/
2020-04-21 08:58:33 +01:00
void MI32_ReverseMAC ( uint8_t _mac [ ] ) {
uint8_t _reversedMAC [ 6 ] ;
for ( uint8_t i = 0 ; i < 6 ; i + + ) {
_reversedMAC [ 5 - i ] = _mac [ i ] ;
}
memcpy ( _mac , _reversedMAC , sizeof ( _reversedMAC ) ) ;
}
2022-01-17 18:47:56 +00:00
void MI32AddKey ( mi_bindKey_t keyMAC ) {
bool unknownMAC = true ;
2022-03-26 09:52:45 +00:00
for ( auto & _sensor : MIBLEsensors ) {
2022-01-17 18:47:56 +00:00
if ( memcmp ( keyMAC . MAC , _sensor . MAC , sizeof ( keyMAC . MAC ) ) = = 0 ) {
2022-03-26 09:52:45 +00:00
_sensor . key = new uint8_t [ 16 ] ;
memcpy ( _sensor . key , keyMAC . key , 16 ) ;
2022-01-17 18:47:56 +00:00
unknownMAC = false ;
2022-01-21 19:01:15 +00:00
_sensor . status . hasWrongKey = 0 ;
2022-03-26 09:52:45 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " add key to %s " ) , kMI32DeviceType [ _sensor . type - 1 ] ) ;
2020-07-12 17:17:27 +01:00
}
}
2022-01-17 18:47:56 +00:00
if ( unknownMAC ) {
AddLog ( LOG_LEVEL_ERROR , PSTR ( " M32: unknown MAC " ) ) ;
2020-07-12 17:17:27 +01:00
}
}
2022-01-17 18:47:56 +00:00
2020-07-12 17:17:27 +01:00
/**
* @ brief Decrypts payload in place
2020-10-30 11:29:48 +00:00
*
2020-07-12 17:17:27 +01:00
* @ param _buf - pointer to the buffer at position of PID
2020-10-20 13:49:10 +01:00
* @ param _bufSize - buffersize ( last position is two bytes behind last byte of TAG )
2022-01-17 18:47:56 +00:00
* @ param _payload - target buffer
* @ param _slot - sensor slot in the global vector
2020-07-12 17:17:27 +01:00
* @ return int - error code , 0 for success
*/
2022-01-17 18:47:56 +00:00
int MI32_decryptPacket ( char * _buf , uint16_t _bufSize , uint8_t * _payload , uint32 _slot ) {
// int32_t start = _getCycleCount();
mi_beacon_t * _beacon = ( mi_beacon_t * ) _buf ;
uint8_t nonce [ 13 ] ; //v3:13, v5:12
2022-02-11 17:03:22 +00:00
uint32_t nonceLen = 12 ; // most devices are v5
2022-01-17 18:47:56 +00:00
uint8_t tag [ 4 ] = { 0 } ;
2020-07-12 17:17:27 +01:00
const unsigned char authData [ 1 ] = { 0x11 } ;
2022-01-17 18:47:56 +00:00
size_t dataLen = _bufSize - 11 ; // _bufsize - frame - type - frame.counter - MAC
2020-07-12 17:17:27 +01:00
2022-01-17 18:47:56 +00:00
if ( MIBLEsensors [ _slot ] . key = = nullptr ) {
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: No Key found !!"));
return - 2 ;
}
uint32_t _version = ( uint32_t ) _beacon - > frame . version ;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: encrypted msg from %s with version:%u"),kMI32DeviceType[MIBLEsensors[_slot].type-1],_version);
if ( _version = = 5 ) {
if ( _beacon - > frame . includesMAC ) {
for ( uint32_t i = 0 ; i < 6 ; i + + ) {
nonce [ i ] = _beacon - > MAC [ i ] ;
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: has MAC"));
memcpy ( _payload , ( uint8_t * ) & _beacon - > capability , dataLen ) ; //special packet
dataLen - = 7 ;
2020-07-12 17:17:27 +01:00
}
2022-01-17 18:47:56 +00:00
else {
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: has no MAC"));
for ( uint32_t i = 0 ; i < 6 ; i + + ) {
nonce [ i ] = MIBLEsensors [ _slot ] . MAC [ 5 - i ] ;
}
dataLen = _bufSize - 5 ;
memcpy ( _payload , _beacon - > MAC , dataLen ) ; //special packet
dataLen - = 7 ;
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) _payload, dataLen);
}
// nonce: device MAC, device type, frame cnt, ext. cnt
memcpy ( ( uint8_t * ) & nonce + 6 , ( uint8_t * ) & _beacon - > productID , 2 ) ;
nonce [ 8 ] = _beacon - > counter ;
memcpy ( ( uint8_t * ) & nonce + 9 , ( uint8_t * ) & _payload [ dataLen ] , 3 ) ;
// memcpy((uint8_t*)&tag,(uint8_t*)&_payload[dataLen-4],4);
memcpy ( ( uint8_t * ) & tag , ( uint8_t * ) & _buf [ _bufSize - 4 ] , 4 ) ;
}
else if ( _version = = 3 ) {
// nonce: frame_ctrl, device type, ext. cnt, frame cnt, device MAC(only first 5 bytes)
memcpy ( _payload , ( uint8_t * ) & _beacon - > capability , dataLen ) ; //special packet
nonceLen = 13 ;
memcpy ( ( uint8_t * ) & nonce , ( uint8_t * ) & _beacon - > frame , 2 ) ;
memcpy ( ( uint8_t * ) & nonce + 2 , ( uint8_t * ) & _beacon - > productID , 2 ) ;
nonce [ 4 ] = _beacon - > counter ;
memcpy ( ( uint8_t * ) & nonce + 5 , ( uint8_t * ) & _buf [ _bufSize - 4 ] , 3 ) ;
for ( uint32_t i = 0 ; i < 5 ; i + + ) {
nonce [ i + 8 ] = _beacon - > MAC [ i ] ;
}
2022-02-11 17:03:22 +00:00
// tag[0] = _buf[_bufSize-1]; // it is unclear, if this value is a checksum
2022-01-17 18:47:56 +00:00
dataLen - = 4 ;
2020-10-20 13:49:10 +01:00
}
2022-01-17 18:47:56 +00:00
else {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: unexpected decryption version:%u " ) , _version ) ; // should never happen
2020-07-12 17:17:27 +01:00
}
2020-10-20 13:49:10 +01:00
br_aes_small_ctrcbc_keys keyCtx ;
2022-01-17 18:47:56 +00:00
br_aes_small_ctrcbc_init ( & keyCtx , MIBLEsensors [ _slot ] . key , 16 ) ;
2020-10-20 13:49:10 +01:00
br_ccm_context ctx ;
br_ccm_init ( & ctx , & keyCtx . vtable ) ;
2022-01-17 18:47:56 +00:00
br_ccm_reset ( & ctx , nonce , nonceLen , sizeof ( authData ) , dataLen , sizeof ( tag ) ) ;
2020-10-20 13:49:10 +01:00
br_ccm_aad_inject ( & ctx , authData , sizeof ( authData ) ) ;
br_ccm_flip ( & ctx ) ;
2022-01-17 18:47:56 +00:00
br_ccm_run ( & ctx , 0 , _payload , dataLen ) ;
2020-10-20 13:49:10 +01:00
2022-01-21 19:01:15 +00:00
if ( br_ccm_check_tag ( & ctx , & tag ) ) return 0 ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: decrypted in %.2f mSec"),enctime);
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) _payload, dataLen);
2022-02-11 17:03:22 +00:00
if ( _version = = 3 & & _payload [ 1 ] = = 0x10 ) return 0 ; // no known way to really verify decryption, but 0x10 is expected here for button events
2022-01-21 19:01:15 +00:00
return - 1 ; // wrong key ... maybe corrupt data packet too
2020-07-12 17:17:27 +01:00
}
2020-04-21 08:58:33 +01:00
/*********************************************************************************************\
* common functions
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ brief Return the slot number of a known sensor or return create new sensor slot
*
2020-07-12 17:17:27 +01:00
* @ param _MAC BLE address of the sensor
2020-04-21 08:58:33 +01:00
* @ param _type Type number of the sensor
* @ return uint32_t Known or new slot in the sensors - vector
*/
2020-07-12 17:17:27 +01:00
uint32_t MIBLEgetSensorSlot ( uint8_t ( & _MAC ) [ 6 ] , uint16_t _type , uint8_t counter ) {
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: will test ID-type: %x " ) , D_CMND_MI32 , _type ) ;
bool _success = false ;
2020-08-02 14:07:18 +01:00
for ( uint32_t i = 0 ; i < MI32_TYPES ; i + + ) { // i < sizeof(kMI32DeviceID) gives compiler warning
2020-07-12 17:17:27 +01:00
if ( _type = = kMI32DeviceID [ i ] ) {
2021-01-18 10:33:13 +00:00
DEBUG_SENSOR_LOG ( PSTR ( " M32: ID is type %u " ) , i ) ;
2020-04-21 08:58:33 +01:00
_type = i + 1 ;
_success = true ;
}
else {
2020-07-12 17:17:27 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: ID-type is not: %x " ) , D_CMND_MI32 , kMI32DeviceID [ i ] ) ;
2020-04-21 08:58:33 +01:00
}
}
if ( ! _success ) return 0xff ;
2020-04-21 10:06:30 +01:00
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: vector size %u " ) , D_CMND_MI32 , MIBLEsensors . size ( ) ) ;
for ( uint32_t i = 0 ; i < MIBLEsensors . size ( ) ; i + + ) {
2020-07-12 17:17:27 +01:00
if ( memcmp ( _MAC , MIBLEsensors [ i ] . MAC , sizeof ( _MAC ) ) = = 0 ) {
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: known sensor at slot: %u " ) , D_CMND_MI32 , i ) ;
2021-01-23 16:10:06 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Counters: %x %x"),MIBLEsensors[i].lastCnt, counter);
2020-07-12 17:17:27 +01:00
if ( MIBLEsensors [ i ] . lastCnt = = counter ) {
2021-01-23 16:10:06 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Old packet"));
2020-07-12 17:17:27 +01:00
return 0xff ; // packet received before, stop here
2020-04-21 08:58:33 +01:00
}
return i ;
}
2020-07-12 17:17:27 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: i: %x %x %x %x %x %x " ) , D_CMND_MI32 , MIBLEsensors [ i ] . MAC [ 5 ] , MIBLEsensors [ i ] . MAC [ 4 ] , MIBLEsensors [ i ] . MAC [ 3 ] , MIBLEsensors [ i ] . MAC [ 2 ] , MIBLEsensors [ i ] . MAC [ 1 ] , MIBLEsensors [ i ] . MAC [ 0 ] ) ;
DEBUG_SENSOR_LOG ( PSTR ( " %s: n: %x %x %x %x %x %x " ) , D_CMND_MI32 , _MAC [ 5 ] , _MAC [ 4 ] , _MAC [ 3 ] , _MAC [ 2 ] , _MAC [ 1 ] , _MAC [ 0 ] ) ;
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
if ( MI32 . mode . didGetConfig ) {
DEBUG_SENSOR_LOG ( PSTR ( " M32: ignore new sensor, because of loaded config " ) ) ;
return 0xff ; //discard the data
}
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " %s: found new sensor " ) , D_CMND_MI32 ) ;
mi_sensor_t _newSensor ;
2020-07-12 17:17:27 +01:00
memcpy ( _newSensor . MAC , _MAC , sizeof ( _MAC ) ) ;
2020-04-21 08:58:33 +01:00
_newSensor . type = _type ;
2020-07-20 07:51:17 +01:00
_newSensor . eventType . raw = 0 ;
_newSensor . feature . raw = 0 ;
2022-01-21 19:01:15 +00:00
_newSensor . status . raw = 0 ;
2022-01-17 18:47:56 +00:00
_newSensor . temp = NAN ;
_newSensor . temp_history = ( uint8_t * ) calloc ( 24 , 1 ) ;
2020-04-21 08:58:33 +01:00
_newSensor . bat = 0x00 ;
2022-01-17 18:47:56 +00:00
_newSensor . RSSI = 0 ;
2020-07-12 17:17:27 +01:00
_newSensor . lux = 0x00ffffff ;
2022-01-17 18:47:56 +00:00
_newSensor . lux_history = ( uint8_t * ) calloc ( 24 , 1 ) ;
_newSensor . key = nullptr ;
2020-04-21 08:58:33 +01:00
switch ( _type )
{
2020-07-12 17:17:27 +01:00
case FLORA :
2020-07-15 16:41:12 +01:00
_newSensor . moisture = 0xff ;
_newSensor . fertility = 0xffff ;
2020-07-12 20:19:40 +01:00
_newSensor . firmware [ 0 ] = ' \0 ' ;
2020-07-20 07:51:17 +01:00
_newSensor . feature . temp = 1 ;
_newSensor . feature . moist = 1 ;
_newSensor . feature . fert = 1 ;
_newSensor . feature . lux = 1 ;
_newSensor . feature . bat = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
_newSensor . light_hap_service = nullptr ;
# endif
2020-07-20 07:51:17 +01:00
break ;
2020-10-30 11:29:48 +00:00
case NLIGHT :
2020-07-20 07:51:17 +01:00
_newSensor . events = 0x00 ;
2022-01-17 18:47:56 +00:00
_newSensor . feature . motion = 1 ;
2020-07-20 07:51:17 +01:00
_newSensor . feature . NMT = 1 ;
2022-01-17 18:47:56 +00:00
_newSensor . NMT = 0 ;
# ifdef USE_MI_HOMEKIT
_newSensor . motion_hap_service = nullptr ;
# endif //USE_MI_HOMEKIT
2020-04-21 08:58:33 +01:00
break ;
2020-07-20 07:51:17 +01:00
case MJYD2S :
2020-07-12 17:17:27 +01:00
_newSensor . NMT = 0 ;
_newSensor . events = 0x00 ;
2022-01-17 18:47:56 +00:00
_newSensor . feature . motion = 1 ;
2020-07-20 07:51:17 +01:00
_newSensor . feature . NMT = 1 ;
_newSensor . feature . lux = 1 ;
_newSensor . feature . bat = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
_newSensor . light_hap_service = nullptr ;
_newSensor . motion_hap_service = nullptr ;
# endif //USE_MI_HOMEKIT
_newSensor . feature . bat = 1 ;
_newSensor . NMT = 0 ;
break ;
2022-02-11 17:03:22 +00:00
case YLYK01 : case YLKG08 :
_newSensor . feature . Btn = 1 ;
_newSensor . Btn = 99 ;
if ( _type = = YLKG08 ) {
_newSensor . feature . knob = 1 ;
_newSensor . dimmer = 0 ;
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
_newSensor . button_hap_service [ 0 ] = nullptr ;
# endif //USE_MI_HOMEKIT
break ;
case MCCGQ02 :
_newSensor . events = 0x00 ;
_newSensor . feature . bat = 1 ;
_newSensor . feature . door = 1 ;
# ifdef USE_MI_HOMEKIT
_newSensor . door_sensor_hap_service = nullptr ;
# endif //USE_MI_HOMEKIT
_newSensor . door = 255 ;
2020-07-20 07:51:17 +01:00
break ;
2022-01-17 18:47:56 +00:00
case SJWS01L :
_newSensor . feature . leak = 1 ;
_newSensor . feature . bat = 1 ;
2020-07-20 07:51:17 +01:00
_newSensor . feature . Btn = 1 ;
2022-01-17 18:47:56 +00:00
_newSensor . Btn = 99 ;
# ifdef USE_MI_HOMEKIT
_newSensor . leak_hap_service = nullptr ;
_newSensor . bat_hap_service = nullptr ;
_newSensor . button_hap_service [ 0 ] = nullptr ;
# endif //USE_MI_HOMEKIT
2020-04-21 08:58:33 +01:00
break ;
2020-07-15 16:41:12 +01:00
default :
_newSensor . hum = NAN ;
2022-01-17 18:47:56 +00:00
_newSensor . hum_history = ( uint8_t * ) calloc ( 24 , 1 ) ;
2020-07-20 07:51:17 +01:00
_newSensor . feature . temp = 1 ;
_newSensor . feature . hum = 1 ;
_newSensor . feature . tempHum = 1 ;
_newSensor . feature . bat = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
_newSensor . temp_hap_service = nullptr ;
_newSensor . hum_hap_service = nullptr ;
_newSensor . bat_hap_service = nullptr ;
# endif //USE_MI_HOMEKIT
2020-07-15 16:41:12 +01:00
break ;
2020-04-21 08:58:33 +01:00
}
MIBLEsensors . push_back ( _newSensor ) ;
2022-01-17 18:47:56 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: new %s at slot: %u " ) , kMI32DeviceType [ _type - 1 ] , MIBLEsensors . size ( ) - 1 ) ;
2020-10-21 07:26:38 +01:00
MI32 . mode . shallShowStatusInfo = 1 ;
2020-04-21 08:58:33 +01:00
return MIBLEsensors . size ( ) - 1 ;
} ;
2020-07-12 17:17:27 +01:00
/**
2022-01-17 18:47:56 +00:00
* @ brief trigger real - time message for motion or RC
2020-10-30 11:29:48 +00:00
*
2020-07-12 17:17:27 +01:00
*/
void MI32triggerTele ( void ) {
2021-04-05 10:10:53 +01:00
MI32 . mode . triggeredTele = 1 ;
MqttPublishTeleperiodSensor ( ) ;
2020-07-12 17:17:27 +01:00
}
2020-10-21 07:26:38 +01:00
2020-10-23 09:18:57 +01:00
/**
* @ brief Is called after every finding of new BLE sensor
2020-10-30 11:29:48 +00:00
*
2020-10-23 09:18:57 +01:00
*/
2020-10-21 07:26:38 +01:00
void MI32StatusInfo ( ) {
MI32 . mode . shallShowStatusInfo = 0 ;
2022-01-17 18:47:56 +00:00
Response_P ( PSTR ( " { \" M32 \" :{ \" found \" :%u}} " ) , MIBLEsensors . size ( ) ) ;
2021-04-04 11:04:36 +01:00
XdrvRulesProcess ( 0 ) ;
2020-10-21 07:26:38 +01:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
/**
* @ brief Saves a sensor value mapped to the graph range of 0 - 20 pixel , this function automatically reads the actual hour from system time
*
* @ param history - pointer to uint8_t [ 23 ]
* @ param value - value as float , this
* @ param type - internal type . for BLE : 0 - temperature , 1 - humidity , 2 - illuminance , for internal sensors : 100 - wattage
*/
void MI32addHistory ( uint8_t * history , float value , uint32_t type ) {
uint32_t _hour = ( LocalTime ( ) % SECS_PER_DAY ) / SECS_PER_HOUR ;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history hour: %u"),_hour);
switch ( type ) {
case 0 : //temperature
history [ _hour ] = ( ( ( uint8_t ) ( value + 5.0f ) / 4 ) + 1 ) + 0 b10000000 ; //temp
break ;
case 1 : //humidity
history [ _hour ] = ( ( ( uint8_t ) ( value / 5 ) ) + 1 ) + 0 b10000000 ; //hum
break ;
case 2 : //light
if ( value > 100.0f ) value = 100.0f ; //clamp it for now
history [ _hour ] = ( ( ( uint8_t ) ( value / 5.0f ) ) + 1 ) + 0 b10000000 ; //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 ) + 0 b10000000 ; //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 ;
# endif //USE_MI_ESP32_ENERGY
}
}
/**
* @ brief Returns a value betwenn 0 - 21 for use as a data point in the history graph of the extended web UI
*
* @ param history - pointer to uint8_t [ 23 ]
* @ param hour - hour of datapoint
* @ return uint8_t - value for the y - axis , should be between 0 - 21
*/
uint8_t MI32fetchHistory ( uint8_t * history , uint32_t hour ) {
if ( hour > 23 ) {
return 0 ; } //should never happen
if ( bitRead ( history [ hour ] , 7 ) = = 0 ) {
return 0 ; //invalidated data
}
return ( history [ hour ] ) - 0 b10000000 ;
}
/**
* @ brief Invalidates the history data of the following hour by setting MSB to 0 , should be called at FUNC_JSON_APPEND
*
*/
void Mi32invalidateOldHistory ( ) {
uint32_t _hour = ( LocalTime ( ) % SECS_PER_DAY ) / SECS_PER_HOUR ;
static uint32_t _lastInvalidatedHour = 99 ;
if ( _lastInvalidatedHour = = _hour ) {
return ;
}
uint32_t _nextHour = ( _hour > 22 ) ? 0 : _hour + 1 ;
for ( auto _sensor : MIBLEsensors ) {
if ( _sensor . feature . temp = = 1 ) {
bitClear ( _sensor . temp_history [ _nextHour ] , 7 ) ;
}
if ( _sensor . feature . hum = = 1 ) {
bitClear ( _sensor . hum_history [ _nextHour ] , 7 ) ;
}
if ( _sensor . feature . lux = = 1 ) {
bitClear ( _sensor . lux_history [ _nextHour ] , 7 ) ;
}
}
_lastInvalidatedHour = _hour ;
}
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
/*********************************************************************************************\
* init NimBLE
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-11-09 19:27:11 +00:00
void MI32PreInit ( void ) {
2022-01-17 18:47:56 +00:00
2020-11-09 19:27:11 +00:00
MI32 . mode . init = false ;
//test section for options
MI32 . option . allwaysAggregate = 1 ;
MI32 . option . noSummary = 0 ;
MI32 . option . minimalSummary = 0 ;
MI32 . option . directBridgeMode = 0 ;
MI32 . option . showRSSI = 1 ;
MI32 . option . ignoreBogusBattery = 1 ; // from advertisements
2022-01-17 18:47:56 +00:00
MI32loadCfg ( ) ;
if ( MIBLEsensors . size ( ) > 0 ) {
MI32 . mode . didGetConfig = 1 ;
}
MI32 . beAdvCB = nullptr ;
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: pre-init " ) ) ;
2020-11-09 19:27:11 +00:00
}
2020-04-21 08:58:33 +01:00
void MI32Init ( void ) {
2020-11-13 16:00:44 +00:00
if ( MI32 . mode . init ) { return ; }
2021-02-05 13:09:46 +00:00
if ( TasmotaGlobal . global_state . wifi_down & & TasmotaGlobal . global_state . eth_down ) { return ; }
2021-01-18 10:33:13 +00:00
2021-02-05 13:09:46 +00:00
if ( ! TasmotaGlobal . global_state . wifi_down ) {
TasmotaGlobal . wifi_stay_asleep = true ;
if ( WiFi . getSleep ( ) = = false ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: Put WiFi modem in sleep mode " ) ) ;
WiFi . setSleep ( true ) ; // Sleep
}
2020-11-11 17:02:39 +00:00
}
2020-11-13 16:00:44 +00:00
2022-01-17 18:47:56 +00:00
if ( MI32 . mode . didGetConfig ) {
MI32 . mode . didStartHAP = 0 ;
# ifdef USE_MI_HOMEKIT
MI32getSetupCodeFromMAC ( MI32 . hk_setup_code ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: Init HAP core " ) ) ;
mi_homekit_main ( ) ;
# else
MI32 . mode . didStartHAP = 1 ;
# endif //USE_MI_HOMEKIT
}
2020-04-21 08:58:33 +01:00
if ( ! MI32 . mode . init ) {
2022-05-27 19:51:59 +01:00
NimBLEDevice : : setScanFilterMode ( CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE ) ;
NimBLEDevice : : setScanDuplicateCacheSize ( 40 ) ; // will not be perfect for every situation (few vs many BLE devices nearby)
2022-03-16 07:41:04 +00:00
NimBLEDevice : : init ( " " ) ;
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: Init BLE device " ) ) ;
2020-04-21 08:58:33 +01:00
MI32 . mode . init = 1 ;
2022-03-26 09:52:45 +00:00
MI32 . mode . readyForNextConnJob = 1 ;
2022-03-16 07:41:04 +00:00
MI32StartTask ( MI32_TASK_SCAN ) ; // Let's get started !!
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
# ifdef USE_MI_ESP32_ENERGY
MI32 . energy_history = ( uint8_t * ) calloc ( 24 , 1 ) ;
# endif //USE_MI_ESP32_ENERGY
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
return ;
}
2022-01-17 18:47:56 +00:00
/*********************************************************************************************\
* Berry section - partly used by HomeKit too
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " {
2022-03-26 09:52:45 +00:00
bool MI32runBerryConnection ( uint8_t operation , bool response ) {
2022-01-17 18:47:56 +00:00
if ( MI32 . conCtx ! = nullptr ) {
2022-03-16 07:41:04 +00:00
MI32 . conCtx - > oneOp = ( operation > 9 ) ;
MI32 . conCtx - > operation = operation % 10 ;
2022-03-26 09:52:45 +00:00
MI32 . conCtx - > response = response ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: Berry connection op: %d, addrType: %d, oneOp: %u, response: %u " ) , MI32 . conCtx - > operation , MI32 . conCtx - > addrType , MI32 . conCtx - > oneOp , MI32 . conCtx - > response ) ;
2022-04-07 16:53:01 +01:00
if ( MI32 . conCtx - > oneOp ) {
2022-03-26 09:52:45 +00:00
MI32StartConnectionTask ( ) ;
}
else {
if ( MI32 . mode . connected ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: continue connection job " ) ) ;
MI32 . mode . triggerNextConnJob = 1 ;
if ( ! MI32 . mode . readyForNextConnJob ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: old connection job not finished yet!! " ) ) ;
}
}
else {
MI32StartConnectionTask ( ) ; //first job of many or unexpected disconnect
}
}
2022-01-17 18:47:56 +00:00
return true ;
}
return false ;
}
void MI32setBerryConnCB ( void * function , uint8_t * buffer ) {
if ( MI32 . conCtx = = nullptr ) {
MI32 . conCtx = new MI32connectionContextBerry_t ;
}
MI32 . conCtx - > buffer = buffer ;
MI32 . beConnCB = function ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: Connection Ctx created " ) ) ;
}
bool MI32setBerryCtxSvc ( const char * Svc ) {
if ( MI32 . conCtx ! = nullptr ) {
MI32 . conCtx - > serviceUUID = NimBLEUUID ( Svc ) ;
2022-03-26 09:52:45 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: SVC: %s " ) , MI32 . conCtx - > serviceUUID . toString ( ) . c_str ( ) ) ;
2022-01-17 18:47:56 +00:00
return true ;
}
return false ;
}
bool MI32setBerryCtxChr ( const char * Chr ) {
if ( MI32 . conCtx ! = nullptr ) {
MI32 . conCtx - > charUUID = NimBLEUUID ( Chr ) ;
2022-03-26 09:52:45 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: CHR: %s " ) , MI32 . conCtx - > charUUID . toString ( ) . c_str ( ) ) ;
2022-03-16 07:41:04 +00:00
uint16_t _uuid = MI32 . conCtx - > charUUID . getNative ( ) - > u16 . value ; //if not "notify op" -> present requested characteristic as return UUID
MI32 . conCtx - > returnCharUUID = _uuid ;
2022-03-26 09:52:45 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: return UUID: %04x " ) , MI32 . conCtx - > returnCharUUID ) ;
2022-01-17 18:47:56 +00:00
return true ;
}
return false ;
}
bool MI32setBerryCtxMAC ( uint8_t * MAC , uint8_t type ) {
if ( MI32 . conCtx ! = nullptr ) {
2022-03-16 07:41:04 +00:00
memcpy ( MI32 . conCtx - > MAC , MAC , 6 ) ;
2022-01-17 18:47:56 +00:00
if ( type < 4 ) MI32 . conCtx - > addrType = type ;
else MI32 . conCtx - > addrType = 0 ;
return true ;
}
return false ;
}
void MI32setBerryAdvCB ( void * function , uint8_t * buffer ) {
MI32 . beAdvCB = function ;
MI32 . beAdvBuf = buffer ;
}
2022-03-25 09:15:58 +00:00
bool MI32addMACtoBlockList ( uint8_t * MAC , uint8_t type ) {
NimBLEDevice : : addIgnored ( NimBLEAddress ( MAC , type ) ) ;
return NimBLEDevice : : isIgnored ( NimBLEAddress ( MAC , type ) ) ;
}
bool MI32addMACtoWatchList ( uint8_t * MAC , uint8_t type ) {
NimBLEAddress _newAddress = NimBLEAddress ( MAC , type ) ;
if ( MI32Scan = = nullptr ) {
if ( ! NimBLEDevice : : whiteListAdd ( _newAddress ) ) {
return false ;
}
}
else {
bool _runningScan = MI32Scan - > stop ( ) ;
if ( NimBLEDevice : : whiteListAdd ( _newAddress ) ) {
MI32Scan - > setFilterPolicy ( BLE_HCI_SCAN_FILT_USE_WL ) ;
if ( _runningScan ) MI32Scan - > start ( 0 , MI32scanEndedCB , false ) ;
}
else {
if ( _runningScan ) MI32Scan - > start ( 0 , MI32scanEndedCB , false ) ;
return false ;
}
}
2022-03-26 09:52:45 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: add %s to watchlist of size: %u " ) , _newAddress . toString ( ) . c_str ( ) , NimBLEDevice : : getWhiteListCount ( ) ) ;
2022-03-25 09:15:58 +00:00
return true ;
}
2022-01-17 18:47:56 +00:00
void MI32setBatteryForSlot ( uint32_t slot , uint8_t value ) {
if ( slot > MIBLEsensors . size ( ) - 1 ) return ;
if ( MIBLEsensors [ slot ] . feature . bat ) {
MIBLEsensors [ slot ] . bat = value ;
}
}
void MI32setHumidityForSlot ( uint32_t slot , float value ) {
if ( slot > MIBLEsensors . size ( ) - 1 ) return ;
if ( MIBLEsensors [ slot ] . feature . hum ) {
MIBLEsensors [ slot ] . hum = value ;
}
}
void MI32setTemperatureForSlot ( uint32_t slot , float value ) {
if ( slot > MIBLEsensors . size ( ) - 1 ) return ;
if ( MIBLEsensors [ slot ] . feature . temp ) {
MIBLEsensors [ slot ] . temp = value ;
}
}
uint32_t MI32numberOfDevices ( ) {
return MIBLEsensors . size ( ) ;
}
uint8_t * MI32getDeviceMAC ( uint32_t slot ) {
if ( slot > MIBLEsensors . size ( ) - 1 ) return NULL ;
return MIBLEsensors [ slot ] . MAC ;
}
const char * MI32getDeviceName ( uint32_t slot ) {
if ( slot > MIBLEsensors . size ( ) - 1 ) return " " ;
return kMI32DeviceType [ MIBLEsensors [ slot ] . type - 1 ] ;
}
} //extern "C"
/*********************************************************************************************\
* Homekit section
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef USE_MI_HOMEKIT
extern " C " {
const char * MI32getSetupCode ( ) {
return ( const char * ) MI32 . hk_setup_code ;
}
uint32_t MI32numOfRelays ( ) {
if ( TasmotaGlobal . devices_present > 0 ) MI32 . HKinfoMsg = MI32_HAP_OUTLET_ADDED ;
return TasmotaGlobal . devices_present ;
}
void MI32setRelayFromHK ( uint32_t relay , bool onOff ) {
ExecuteCommandPower ( relay , onOff , SRC_IGNORE ) ;
}
uint32_t MI32getDeviceType ( uint32_t slot ) {
return MIBLEsensors [ slot ] . type ;
}
/**
* @ brief Get at least a bit of the status of the HAP core , i . e . to reduce the activy of the driver while doing the pairing
*
* @ param event
*/
void MI32passHapEvent ( uint32_t event ) {
switch ( event ) {
case 5 : //HAP_EVENT_PAIRING_STARTED
MI32suspendScanTask ( ) ;
default :
vTaskResume ( MI32 . ScanTask ) ;
}
if ( event = = 4 ) {
MI32 . HKinfoMsg = MI32_HAP_CONTROLLER_DISCONNECTED ;
MI32 . HKconnectedControllers - - ;
}
if ( event = = 3 ) {
MI32 . HKinfoMsg = MI32_HAP_CONTROLLER_CONNECTED ;
MI32 . HKconnectedControllers + + ;
}
}
void MI32didStartHAP ( bool HAPdidStart ) {
if ( HAPdidStart ) {
MI32 . mode . didStartHAP = 1 ;
MI32 . HKinfoMsg = MI32_HAP_DID_START ;
}
else {
MI32 . HKinfoMsg = MI32_HAP_DID_NOT_START ;
}
}
/**
* @ brief Simply store the writeable HAP characteristics as void pointers in the " main " driver for updates of the values
*
* @ param slot - sensor slot in MIBLEsensors
* @ param type - sensors type , except for the buttons this is equal to the mibeacon types
* @ param handle - a void ponter to a characteristic
*/
void MI32saveHAPhandles ( uint32_t slot , uint32_t type , void * handle ) {
// AddLog(LOG_LEVEL_INFO,PSTR("M32: pass ptr to hap service, type:%u"), type);
switch ( type ) {
case 1000 : case 1001 : case 1002 : case 1003 : case 1004 : case 1005 :
MIBLEsensors [ slot ] . button_hap_service [ type - 1000 ] = handle ;
break ;
case 0x04 :
MIBLEsensors [ slot ] . temp_hap_service = handle ;
break ;
case 0x06 :
MIBLEsensors [ slot ] . hum_hap_service = handle ;
break ;
case 0x0a :
MIBLEsensors [ slot ] . bat_hap_service = handle ;
break ;
case 0x07 :
MIBLEsensors [ slot ] . light_hap_service = handle ;
break ;
case 0x0f :
MIBLEsensors [ slot ] . motion_hap_service = handle ;
break ;
case 0x14 :
MIBLEsensors [ slot ] . leak_hap_service = handle ;
break ;
case 0x19 :
MIBLEsensors [ slot ] . door_sensor_hap_service = handle ;
break ;
case 0xf0 :
if ( slot > 3 ) break ; //support only 4 for now
MI32 . outlet_hap_service [ slot ] = handle ;
break ;
}
}
}
/**
* @ brief Creates a simplified setup code from the Wifi MAC for HomeKit by converting every ascii - converted byte to 1 , if it not 2 - 9
* Example : AABBCC1234f2
* - > 111 - 11 - 234
* This is no security feature , only for convenience
* * @ param setupcode
*/
void MI32getSetupCodeFromMAC ( char * setupcode ) {
uint8_t _mac [ 6 ] ;
char _macStr [ 13 ] = { 0 } ;
WiFi . macAddress ( _mac ) ;
ToHex_P ( _mac , 6 , _macStr , 13 ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: Wifi MAC: %s " ) , _macStr ) ;
for ( int i = 0 ; i < 10 ; i + + ) {
if ( _macStr [ i ] > ' 9 ' | | _macStr [ i ] < ' 1 ' ) setupcode [ i ] = ' 1 ' ;
else setupcode [ i ] = _macStr [ i ] ;
}
setupcode [ 3 ] = ' - ' ;
setupcode [ 6 ] = ' - ' ;
setupcode [ 10 ] = 0 ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: HK setup code: %s " ) , setupcode ) ;
return ;
}
# endif //USE_MI_HOMEKIT
/*********************************************************************************************\
* Config section
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void MI32loadCfg ( ) {
if ( TfsFileExists ( " /mi32cfg " ) ) {
MIBLEsensors . reserve ( 10 ) ;
const size_t _buf_size = 2048 ;
char * _filebuf = ( char * ) calloc ( _buf_size , 1 ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: found config file " ) ) ;
if ( TfsLoadFile ( " /mi32cfg " , ( uint8_t * ) _filebuf , _buf_size ) ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: %s " ) , _filebuf ) ;
JsonParser parser ( _filebuf ) ;
JsonParserToken root = parser . getRoot ( ) ;
if ( ! root ) { AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: invalid root " ) ) ; }
JsonParserArray arr = root . getArray ( ) ;
if ( ! arr ) { AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: invalid array object " ) ) ; ; }
bool _error ;
int32_t _numberOfDevices ;
for ( auto _dev : arr ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: found device in config file " ) ) ;
JsonParserObject _device = _dev . getObject ( ) ;
uint8_t _mac [ 6 ] ;
JsonParserToken _val = _device [ PSTR ( " MAC " ) ] ;
_error = true ;
if ( _val ) {
char * _macStr = ( char * ) _val . getStr ( ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: found MAC: %s " ) , _macStr ) ;
if ( strlen ( _macStr ) ! = 12 ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: wrong MAC length: %u " ) , strlen ( _macStr ) ) ;
break ;
}
MI32HexStringToBytes ( _macStr , _mac ) ;
_val = _device [ PSTR ( " PID " ) ] ;
if ( _val ) {
uint8_t _pid [ 2 ] ;
char * _pidStr = ( char * ) _val . getStr ( ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: found PID: %s " ) , _pidStr ) ;
if ( strlen ( _pidStr ) ! = 4 ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: wrong PID length: %u " ) , strlen ( _pidStr ) ) ;
break ;
}
MI32HexStringToBytes ( _pidStr , _pid ) ;
uint16_t _pid16 = _pid [ 0 ] * 256 + _pid [ 1 ] ;
_numberOfDevices = MIBLEgetSensorSlot ( _mac , _pid16 , 0 ) ;
_error = false ;
}
}
_val = _device [ PSTR ( " key " ) ] ;
if ( _val ) {
mi_bindKey_t _keyMAC ;
uint8_t * _key = ( uint8_t * ) malloc ( 16 ) ;
char * _keyStr = ( char * ) _val . getStr ( ) ;
if ( strlen ( _keyStr ) = = 0 ) {
continue ;
}
if ( strlen ( _keyStr ) ! = 32 ) {
_error = true ;
break ;
}
MI32HexStringToBytes ( _keyStr , _key ) ;
MIBLEsensors [ _numberOfDevices ] . key = _key ;
}
}
if ( ! _error ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: added %u devices from config file " ) , _numberOfDevices + 1 ) ;
}
}
free ( _filebuf ) ;
}
}
void MI32saveConfig ( ) {
const size_t _buf_size = 2048 ;
char * _filebuf = ( char * ) malloc ( _buf_size ) ;
_filebuf [ 0 ] = ' [ ' ;
uint32_t _pos = 1 ;
for ( auto _sensor : MIBLEsensors ) {
char _MAC [ 13 ] ;
ToHex_P ( _sensor . MAC , 6 , _MAC , 13 ) ;
char _key [ 33 ] ;
_key [ 0 ] = 0 ;
if ( _sensor . key ! = nullptr ) {
ToHex_P ( _sensor . key , 16 , _key , 33 ) ;
}
uint32_t _inc = snprintf_P ( _filebuf + _pos , 200 , PSTR ( " { \" MAC \" : \" %s \" , \" PID \" : \" %04x \" , \" key \" : \" %s \" }, " ) , _MAC , kMI32DeviceID [ _sensor . type - 1 ] , _key ) ;
_pos + = _inc ;
}
_filebuf [ _pos - 1 ] = ' ] ' ;
_filebuf [ _pos ] = ' \0 ' ;
if ( _pos > 2 ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: %s " ) , _filebuf ) ;
if ( TfsSaveFile ( " /mi32cfg " , ( uint8_t * ) _filebuf , _pos + 1 ) ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: %u bytes written to config " ) , _pos + 1 ) ;
}
}
else {
AddLog ( LOG_LEVEL_ERROR , PSTR ( " M32: nothing written to config " ) ) ;
}
free ( _filebuf ) ;
}
2020-04-21 08:58:33 +01:00
/*********************************************************************************************\
* Task section
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-17 18:47:56 +00:00
void MI32suspendScanTask ( void ) {
if ( MI32 . ScanTask ! = nullptr ) vTaskSuspend ( MI32 . ScanTask ) ;
}
2020-04-21 08:58:33 +01:00
void MI32StartTask ( uint32_t task ) {
2022-03-16 07:41:04 +00:00
if ( MI32 . mode . willConnect = = 1 ) return ; // we are in the middle of connecting to something ... do not interrupt this.
2020-04-21 08:58:33 +01:00
switch ( task ) {
case MI32_TASK_SCAN :
2022-03-16 07:41:04 +00:00
if ( MI32 . mode . connected = = 1 ) return ;
2020-04-21 08:58:33 +01:00
MI32StartScanTask ( ) ;
break ;
case MI32_TASK_CONN :
2022-03-16 07:41:04 +00:00
if ( MI32 . mode . canConnect = = 0 ) return ;
2022-05-27 19:51:59 +01:00
MI32 . mode . deleteScanTask = 1 ;
2022-01-17 18:47:56 +00:00
MI32StartConnectionTask ( ) ;
2020-05-29 19:18:39 +01:00
break ;
2020-04-21 08:58:33 +01:00
default :
break ;
}
}
void MI32StartScanTask ( ) {
if ( MI32 . mode . connected ) return ;
2022-01-17 18:47:56 +00:00
if ( MI32 . ScanTask ! = nullptr ) vTaskDelete ( MI32 . ScanTask ) ;
2020-04-21 08:58:33 +01:00
MI32 . mode . runningScan = 1 ;
xTaskCreatePinnedToCore (
MI32ScanTask , /* Function to implement the task */
" MI32ScanTask " , /* Name of the task */
2020-11-02 18:32:08 +00:00
2048 , /* Stack size in words */
2020-04-21 08:58:33 +01:00
NULL , /* Task input parameter */
0 , /* Priority of the task */
2022-01-17 18:47:56 +00:00
& MI32 . ScanTask , /* Task handle. */
2020-04-21 08:58:33 +01:00
0 ) ; /* Core where the task should run */
}
void MI32ScanTask ( void * pvParameters ) {
2022-01-17 18:47:56 +00:00
if ( MI32 . mode . didGetConfig ) {
vTaskDelay ( 5000 / portTICK_PERIOD_MS ) ;
}
2022-05-27 19:51:59 +01:00
MI32Scan = NimBLEDevice : : getScan ( ) ;
MI32Scan - > setAdvertisedDeviceCallbacks ( & MI32ScanCallbacks , false ) ;
2022-03-25 09:15:58 +00:00
if ( NimBLEDevice : : getWhiteListCount ( ) > 0 ) {
MI32Scan - > setFilterPolicy ( BLE_HCI_SCAN_FILT_USE_WL ) ;
}
else {
MI32Scan - > setFilterPolicy ( BLE_HCI_SCAN_FILT_NO_WL ) ;
}
2022-05-27 19:51:59 +01:00
MI32Scan - > setActiveScan ( MI32 . option . activeScan = = 1 ) ;
2022-01-17 18:47:56 +00:00
MI32Scan - > setMaxResults ( 0 ) ;
2022-03-25 09:15:58 +00:00
MI32Scan - > start ( 0 , MI32scanEndedCB , false ) ; // never stop scanning, will pause automatically while connecting
2022-05-27 19:51:59 +01:00
MI32 . infoMsg = MI32 . option . activeScan ? MI32_START_SCANNING_ACTIVE : MI32_START_SCANNING_PASSIVE ;
2022-01-17 18:47:56 +00:00
2020-04-21 08:58:33 +01:00
uint32_t timer = 0 ;
2020-07-12 17:17:27 +01:00
for ( ; ; ) {
2022-05-27 19:51:59 +01:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
if ( MI32 . mode . deleteScanTask ) {
MI32Scan - > stop ( ) ;
MI32 . mode . runningScan = 0 ;
break ;
}
if ( MI32 . mode . updateScan ) {
MI32Scan - > stop ( ) ;
MI32Scan - > setActiveScan ( MI32 . option . activeScan = = 1 ) ;
MI32Scan - > start ( 0 , true ) ;
MI32 . mode . updateScan = 0 ;
MI32 . infoMsg = MI32 . option . activeScan ? MI32_START_SCANNING_ACTIVE : MI32_START_SCANNING_PASSIVE ;
}
2020-04-21 08:58:33 +01:00
}
vTaskDelete ( NULL ) ;
}
2022-03-16 07:41:04 +00:00
bool MI32ConnectActiveSensor ( ) { // only use inside a task !!
2022-04-07 16:53:01 +01:00
if ( MI32 . conCtx - > operation = = 5 ) {
return false ;
}
2022-03-16 07:41:04 +00:00
NimBLEAddress _address = NimBLEAddress ( MI32 . conCtx - > MAC , MI32 . conCtx - > addrType ) ;
if ( MI32Client ! = nullptr ) {
if ( MI32Client - > isConnected ( ) & & MI32 . mode . connected = = 1 ) { //we only accept a "clean" state without obvious packet losses
if ( MI32 . conCtx - > operation = = 5 ) { //5 is the disconnect operation
NimBLEDevice : : deleteClient ( MI32Client ) ; // disconnect the old
return false ; // request disconnect
}
if ( MI32Client - > getPeerAddress ( ) = = _address ) {
MI32 . infoMsg = MI32_STILL_CONNECTED ;
return true ; // still connected -> keep it
}
else {
// AddLog(LOG_LEVEL_ERROR,PSTR("M32: disconnect %s"),MI32Client->getPeerAddress().toString().c_str());
NimBLEDevice : : deleteClient ( MI32Client ) ; // disconnect the old and connect the new
}
}
}
MI32Client = nullptr ;
if ( NimBLEDevice : : getClientListSize ( ) ) {
MI32Client = NimBLEDevice : : getClientByPeerAddress ( _address ) ;
}
if ( ! MI32Client ) {
MI32Client = NimBLEDevice : : createClient ( _address ) ;
MI32Client - > setClientCallbacks ( & MI32SensorCB , false ) ;
}
if ( ! MI32Client - > connect ( false ) ) {
NimBLEDevice : : deleteClient ( MI32Client ) ;
// AddLog(LOG_LEVEL_ERROR,PSTR("M32: did not connect client"));
return false ;
}
return true ;
}
2020-07-15 16:41:12 +01:00
2022-01-17 18:47:56 +00:00
bool MI32StartConnectionTask ( ) {
if ( MI32 . conCtx = = nullptr ) return false ;
if ( MI32 . conCtx - > buffer = = nullptr ) return false ;
MI32 . mode . willConnect = 1 ;
MI32Scan - > stop ( ) ;
MI32suspendScanTask ( ) ;
2020-04-21 08:58:33 +01:00
xTaskCreatePinnedToCore (
2022-01-17 18:47:56 +00:00
MI32ConnectionTask , /* Function to implement the task */
" MI32ConnectionTask " , /* Name of the task */
2020-07-12 17:17:27 +01:00
4096 , /* Stack size in words */
2020-04-21 08:58:33 +01:00
NULL , /* Task input parameter */
2022-01-17 18:47:56 +00:00
2 , /* Priority of the task */
& MI32 . ConnTask , /* Task handle. */
2020-04-21 08:58:33 +01:00
0 ) ; /* Core where the task should run */
2022-01-17 18:47:56 +00:00
return true ;
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
void MI32ConnectionTask ( void * pvParameters ) {
2022-04-07 16:53:01 +01:00
# if !defined(CONFIG_IDF_TARGET_ESP32C3) //needs more testing ...
2022-03-16 07:41:04 +00:00
NimBLEDevice : : setOwnAddrType ( BLE_OWN_ADDR_RANDOM , false ) ; //seems to be important for i.e. xbox controller, hopefully not breaking other things
NimBLEDevice : : setSecurityAuth ( true , true , true ) ;
2022-04-07 16:53:01 +01:00
# endif //CONFIG_IDF_TARGET_ESP32C3
2022-01-17 18:47:56 +00:00
MI32 . conCtx - > error = MI32_CONN_NO_ERROR ;
2020-05-29 23:41:49 +01:00
if ( MI32ConnectActiveSensor ( ) ) {
2022-01-17 18:47:56 +00:00
MI32 . mode . readingDone = 0 ;
2020-05-29 23:41:49 +01:00
uint32_t timer = 0 ;
while ( MI32 . mode . connected = = 0 ) {
if ( timer > 1000 ) {
MI32Client - > disconnect ( ) ;
2022-01-17 18:47:56 +00:00
NimBLEDevice : : deleteClient ( MI32Client ) ;
2020-05-29 23:41:49 +01:00
MI32 . mode . willConnect = 0 ;
2022-01-17 18:47:56 +00:00
MI32 . mode . triggerBerryConnCB = 1 ;
MI32 . conCtx - > error = MI32_CONN_NO_CONNECT ; // not connected
MI32StartTask ( MI32_TASK_SCAN ) ;
2020-05-29 23:41:49 +01:00
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
vTaskDelete ( NULL ) ;
}
timer + + ;
vTaskDelay ( 10 / portTICK_PERIOD_MS ) ;
}
2022-03-26 09:52:45 +00:00
MI32Client - > discoverAttributes ( ) ; // solves connection problems on i.e. yeelight dimmer
2022-01-17 18:47:56 +00:00
NimBLERemoteService * pSvc = nullptr ;
NimBLERemoteCharacteristic * pChr = nullptr ;
2020-05-29 23:41:49 +01:00
2022-03-26 09:52:45 +00:00
// AddLog(LOG_LEVEL_INFO,PSTR("M32: start connection loop"));
bool keepConnectionAlive = true ;
MI32 . mode . triggerNextConnJob = 1 ;
while ( keepConnectionAlive ) {
while ( MI32 . mode . triggerNextConnJob = = 0 ) {
vTaskDelay ( 50 / portTICK_PERIOD_MS ) ;
if ( MI32 . mode . connected = = 0 ) {
MI32StartTask ( MI32_TASK_SCAN ) ;
vTaskDelete ( NULL ) ;
}
// AddLog(LOG_LEVEL_INFO,PSTR("M32: wait ..."));
}
2022-04-07 16:53:01 +01:00
2022-03-26 09:52:45 +00:00
MI32 . mode . triggerNextConnJob = 0 ;
MI32 . mode . readyForNextConnJob = 0 ;
2022-04-07 16:53:01 +01:00
if ( MI32 . conCtx - > operation = = 5 ) {
MI32Client - > disconnect ( ) ;
break ;
}
2022-03-26 09:52:45 +00:00
pSvc = MI32Client - > getService ( MI32 . conCtx - > serviceUUID ) ;
if ( pSvc ) {
pChr = pSvc - > getCharacteristic ( MI32 . conCtx - > charUUID ) ;
}
else {
MI32 . conCtx - > error = MI32_CONN_NO_SERVICE ;
}
if ( pChr ) {
switch ( MI32 . conCtx - > operation ) {
case 1 :
if ( pChr - > canRead ( ) ) {
NimBLEAttValue _val = pChr - > readValue ( ) ;
MI32 . conCtx - > buffer [ 0 ] = _val . size ( ) ;
memcpy ( MI32 . conCtx - > buffer + 1 , _val . data ( ) , MI32 . conCtx - > buffer [ 0 ] ) ;
2022-01-17 18:47:56 +00:00
}
else {
2022-03-26 09:52:45 +00:00
MI32 . conCtx - > error = MI32_CONN_CAN_NOT_READ ;
2022-01-17 18:47:56 +00:00
}
2022-03-26 09:52:45 +00:00
break ;
case 2 :
2022-04-07 16:53:01 +01:00
if ( pChr - > canWrite ( ) | | pChr - > canWriteNoResponse ( ) ) {
2022-03-26 09:52:45 +00:00
uint8_t len = MI32 . conCtx - > buffer [ 0 ] ;
2022-04-07 16:53:01 +01:00
if ( pChr - > writeValue ( MI32 . conCtx - > buffer + 1 , len , MI32 . conCtx - > response & ! pChr - > canWriteNoResponse ( ) ) ) { // falls always back to "no response" if server provides both options
2022-03-26 09:52:45 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: write op done"));
}
else {
MI32 . conCtx - > error = MI32_CONN_DID_NOT_WRITE ;
}
}
else {
MI32 . conCtx - > error = MI32_CONN_CAN_NOT_WRITE ;
}
MI32 . mode . readingDone = 1 ;
break ;
case 3 :
if ( pChr - > canNotify ( ) ) {
if ( pChr - > subscribe ( true , MI32notifyCB , MI32 . conCtx - > response ) ) {
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: subscribe"));
}
}
else {
MI32 . conCtx - > error = MI32_CONN_CAN_NOT_NOTIFY ;
}
break ;
default :
break ;
}
2020-05-29 23:41:49 +01:00
}
2022-03-26 09:52:45 +00:00
else {
2022-04-07 16:53:01 +01:00
MI32 . conCtx - > error = MI32_CONN_NO_CHARACTERISTIC ;
2022-03-26 09:52:45 +00:00
}
timer = 0 ;
2020-07-12 17:17:27 +01:00
2022-04-07 16:53:01 +01:00
if ( MI32 . conCtx - > error = = MI32_CONN_NO_ERROR ) {
while ( timer < 150 ) {
if ( MI32 . mode . readingDone | | ! MI32 . conCtx - > oneOp ) {
break ;
}
else if ( timer > 148 ) {
if ( MI32 . conCtx - > operation = = 3 & & MI32 . conCtx - > oneOp ) {
MI32 . conCtx - > error = MI32_CONN_NOTIFY_TIMEOUT ; //did not read on notify - timeout only for one-shot op
}
}
timer + + ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
2022-03-26 09:52:45 +00:00
}
}
MI32 . mode . readingDone = 0 ;
if ( MI32 . conCtx - > oneOp ) {
MI32Client - > disconnect ( ) ;
keepConnectionAlive = false ;
2022-03-16 07:41:04 +00:00
}
else {
2022-03-26 09:52:45 +00:00
MI32 . mode . readyForNextConnJob = 1 ;
MI32 . mode . triggerBerryConnCB = 1 ;
2022-03-16 07:41:04 +00:00
}
2020-05-29 23:41:49 +01:00
}
2020-05-29 19:18:39 +01:00
}
2022-01-17 18:47:56 +00:00
else {
2022-04-07 16:53:01 +01:00
MI32 . mode . willConnect = 0 ;
MI32 . conCtx - > error = MI32_CONN_NO_CONNECT ; // could not connect (including op:5 in not connected state)
2020-04-21 08:58:33 +01:00
}
2022-04-07 16:53:01 +01:00
MI32 . mode . connected = 0 ;
2022-01-17 18:47:56 +00:00
MI32 . mode . triggerBerryConnCB = 1 ;
MI32StartTask ( MI32_TASK_SCAN ) ;
vTaskDelete ( NULL ) ;
2020-04-21 08:58:33 +01:00
}
/*********************************************************************************************\
* parse the response from advertisements
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-07-12 17:17:27 +01:00
void MI32parseMiBeacon ( char * _buf , uint32_t _slot , uint16_t _bufSize ) {
2022-01-17 18:47:56 +00:00
2020-04-21 08:58:33 +01:00
float _tempFloat ;
2022-01-17 18:47:56 +00:00
mi_beacon_t * _beacon = ( mi_beacon_t * ) _buf ;
mi_payload_t _payload ;
2020-07-12 17:17:27 +01:00
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . lastCnt = _beacon - > counter ;
2020-04-21 08:58:33 +01:00
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
bitSet ( MI32 . widgetSlot , _slot ) ;
# endif //USE_MI_EXT_GUI
if ( _beacon - > frame . includesObj = = 0 ) {
2022-01-21 19:01:15 +00:00
if ( _beacon - > capability = = 0x28 ) MIBLEsensors [ _slot ] . status . isUnbounded = 1 ;
2022-01-17 18:47:56 +00:00
return ; //nothing to parse
}
int decryptRet = 0 ;
if ( _beacon - > frame . isEncrypted ) {
2022-01-21 19:01:15 +00:00
MIBLEsensors [ _slot ] . feature . needsKey = 1 ;
2022-01-17 18:47:56 +00:00
decryptRet = MI32_decryptPacket ( _buf , _bufSize , ( uint8_t * ) & _payload , _slot ) ;
2022-01-21 19:01:15 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: decryptRet: %d"),decryptRet);
2022-01-17 18:47:56 +00:00
}
else {
uint32_t _offset = ( _beacon - > frame . includesCapability ) ? 0 : 1 ;
uint32_t _payloadSize = ( _beacon - > frame . includesCapability ) ? _beacon - > payload . size : _beacon - > payload . ten ;
if ( _beacon - > frame . includesMAC & & _beacon - > frame . includesObj ) {
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: offset %u, size: %u"),_offset,_payloadSize);
memcpy ( ( uint8_t * ) & _payload , ( uint8_t * ) ( & _beacon - > payload ) - _offset , _payloadSize + 3 ) ;
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)&_payload,_payloadSize + 3);
2020-07-12 17:17:27 +01:00
}
}
2022-01-21 19:01:15 +00:00
if ( decryptRet ! = 0 ) {
2021-01-23 16:10:06 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: Decryption failed with error: %d " ) , decryptRet ) ;
2022-01-21 19:01:15 +00:00
if ( decryptRet = = - 1 ) MIBLEsensors [ _slot ] . status . hasWrongKey = 1 ;
2020-10-20 13:49:10 +01:00
return ;
2020-07-12 17:17:27 +01:00
}
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u with payload type: %02x"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot,_payload.type);
MIBLEsensors [ _slot ] . lastTime = millis ( ) ;
switch ( _payload . type ) {
2020-07-12 17:17:27 +01:00
case 0x01 :
2022-02-11 17:03:22 +00:00
if ( _payload . Btn . type = = 4 ) { //dimmer knob rotation
MIBLEsensors [ _slot ] . eventType . knob = 1 ;
2022-01-17 18:47:56 +00:00
if ( _payload . Btn . num = = 0 ) {
2022-02-11 17:03:22 +00:00
MIBLEsensors [ _slot ] . pressed = 0 ;
MIBLEsensors [ _slot ] . dimmer = _payload . Btn . value ;
2022-01-17 18:47:56 +00:00
}
2022-02-11 17:03:22 +00:00
else {
MIBLEsensors [ _slot ] . pressed = 1 ;
MIBLEsensors [ _slot ] . dimmer = _payload . Btn . num ;
2022-01-17 18:47:56 +00:00
}
2022-02-11 17:03:22 +00:00
MI32 . mode . shallTriggerTele = 1 ;
break ; //To-Do: Map to HomeKit somehow or wait for real support of this device class in HomeKit
}
if ( _payload . Btn . num = = 1 & & MIBLEsensors [ _slot ] . feature . knob ) { //dimmer knob long press
MIBLEsensors [ _slot ] . longpress = _payload . Btn . value ;
MI32 . mode . shallTriggerTele = 1 ;
MIBLEsensors [ _slot ] . eventType . longpress = 1 ;
# ifdef USE_MI_HOMEKIT
if ( ( void * * ) MIBLEsensors [ _slot ] . button_hap_service [ 0 ] ! = nullptr ) {
mi_homekit_update_value ( MIBLEsensors [ _slot ] . button_hap_service [ 0 ] , ( float ) 2.0f , 0x01 ) ; // only one button, long press = 2
2022-01-17 18:47:56 +00:00
}
2022-02-11 17:03:22 +00:00
# endif //USE_MI_HOMEKIT
break ;
}
// single, double, long
MIBLEsensors [ _slot ] . Btn = _payload . Btn . num ;
if ( MIBLEsensors [ _slot ] . feature . knob ) {
MIBLEsensors [ _slot ] . BtnType = _payload . Btn . value - 1 ;
}
else {
MIBLEsensors [ _slot ] . BtnType = _payload . Btn . type ;
2022-01-17 18:47:56 +00:00
}
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . Btn = 1 ;
2020-10-20 13:49:10 +01:00
MI32 . mode . shallTriggerTele = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
2022-02-11 17:03:22 +00:00
if ( MIBLEsensors [ _slot ] . Btn > 5 ) break ; // hard coded limit for now
2022-01-17 18:47:56 +00:00
if ( ( void * * ) MIBLEsensors [ _slot ] . button_hap_service [ MIBLEsensors [ _slot ] . Btn ] ! = nullptr ) {
// AddLog(LOG_LEVEL_DEBUG,PSTR("Send Button %u: SingleLong:%u, pointer: %x"), MIBLEsensors[_slot].Btn,_singleLong,MIBLEsensors[_slot].button_hap_service[MIBLEsensors[_slot].Btn] );
2022-02-11 17:03:22 +00:00
mi_homekit_update_value ( MIBLEsensors [ _slot ] . button_hap_service [ MIBLEsensors [ _slot ] . Btn ] , ( float ) MIBLEsensors [ _slot ] . BtnType , 0x01 ) ;
}
2022-01-17 18:47:56 +00:00
# endif //USE_MI_HOMEKIT
2021-01-23 16:10:06 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 1: U16: %u Button"), MIBLEsensors[_slot].Btn );
2020-07-12 17:17:27 +01:00
break ;
2020-04-21 08:58:33 +01:00
case 0x04 :
2022-01-17 18:47:56 +00:00
_tempFloat = ( float ) ( _payload . temp ) / 10.0f ;
2020-07-12 17:17:27 +01:00
if ( _tempFloat < 60 ) {
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . temp = _tempFloat ;
MIBLEsensors [ _slot ] . eventType . temp = 1 ;
DEBUG_SENSOR_LOG ( PSTR ( " Mode 4: temp updated " ) ) ;
2020-07-12 17:17:27 +01:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . temp_hap_service , _tempFloat , 0x04 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . temp_history , _tempFloat , 0 ) ;
# endif //USE_MI_EXT_GUI
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 4: U16: %u Temp"), _payload.temp );
2020-04-21 08:58:33 +01:00
break ;
case 0x06 :
2022-01-17 18:47:56 +00:00
_tempFloat = ( float ) ( _payload . hum ) / 10.0f ;
2020-07-12 17:17:27 +01:00
if ( _tempFloat < 101 ) {
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . hum = _tempFloat ;
MIBLEsensors [ _slot ] . eventType . hum = 1 ;
DEBUG_SENSOR_LOG ( PSTR ( " Mode 6: hum updated " ) ) ;
2020-07-12 17:17:27 +01:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . hum_hap_service , _tempFloat , 0x06 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . hum_history , _tempFloat , 1 ) ;
# endif //USE_MI_EXT_GUI
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 6: U16: %u Hum"), _payload.hum);
2020-04-21 08:58:33 +01:00
break ;
case 0x07 :
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . lux = _payload . lux & 0x00ffffff ;
2020-07-12 17:17:27 +01:00
if ( MIBLEsensors [ _slot ] . type = = MJYD2S ) {
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . noMotion = 1 ;
2020-07-12 17:17:27 +01:00
}
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . lux = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . light_hap_service , ( float ) MIBLEsensors [ _slot ] . lux , 0x07 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . lux_history , ( float ) MIBLEsensors [ _slot ] . lux , 2 ) ;
# endif //USE_MI_EXT_GUI
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 7: U24: %u Lux"), _payload.lux & 0x00ffffff);
2020-04-21 10:06:30 +01:00
break ;
2020-04-21 08:58:33 +01:00
case 0x08 :
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . moisture = _payload . moist ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . moist = 1 ;
DEBUG_SENSOR_LOG ( PSTR ( " Mode 8: moisture updated " ) ) ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 8: U8: %u Moisture"), _payload.moist);
2020-04-21 08:58:33 +01:00
break ;
case 0x09 :
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . fertility = _payload . fert ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . fert = 1 ;
2020-07-12 17:17:27 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " Mode 9: fertility updated " ) ) ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 9: U16: %u Fertility"), _payload.fert);
2020-04-21 08:58:33 +01:00
break ;
case 0x0a :
2020-07-20 07:51:17 +01:00
if ( MI32 . option . ignoreBogusBattery ) {
if ( MIBLEsensors [ _slot ] . type = = LYWSD03MMC | | MIBLEsensors [ _slot ] . type = = MHOC401 ) {
break ;
}
}
2022-01-17 18:47:56 +00:00
if ( _payload . bat < 101 ) {
MIBLEsensors [ _slot ] . bat = _payload . bat ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . bat = 1 ;
2020-07-12 17:17:27 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " Mode a: bat updated " ) ) ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . bat_hap_service , ( float ) _payload . bat , 0xa ) ;
# endif //USE_MI_HOMEKIT
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode a: U8: %u %%"), _payload.bat);
2020-04-21 08:58:33 +01:00
break ;
case 0x0d :
2022-01-17 18:47:56 +00:00
_tempFloat = ( float ) ( _payload . HT . temp ) / 10.0f ;
2020-07-12 17:17:27 +01:00
if ( _tempFloat < 60 ) {
MIBLEsensors [ _slot ] . temp = _tempFloat ;
DEBUG_SENSOR_LOG ( PSTR ( " Mode d: temp updated " ) ) ;
}
2022-01-17 18:47:56 +00:00
_tempFloat = ( float ) ( _payload . HT . hum ) / 10.0f ;
2020-07-12 17:17:27 +01:00
if ( _tempFloat < 100 ) {
MIBLEsensors [ _slot ] . hum = _tempFloat ;
DEBUG_SENSOR_LOG ( PSTR ( " Mode d: hum updated " ) ) ;
}
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . tempHum = 1 ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode d: U16: %x Temp U16: %x Hum"), _payload.HT.temp, _payload.HT.hum);
2020-07-12 17:17:27 +01:00
break ;
2022-01-17 18:47:56 +00:00
2020-07-12 17:17:27 +01:00
case 0x0f :
2022-01-17 18:47:56 +00:00
if ( _payload . ten ! = 0 ) break ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . motion = 1 ;
2020-07-12 17:17:27 +01:00
MIBLEsensors [ _slot ] . events + + ;
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . lux = _payload . lux & 0x00ffffff ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . lux = 1 ;
2020-10-20 13:49:10 +01:00
MIBLEsensors [ _slot ] . NMT = 0 ;
MI32 . mode . shallTriggerTele = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . motion_hap_service , ( float ) 1 , 0x0f ) ;
mi_homekit_update_value ( MIBLEsensors [ _slot ] . light_hap_service , ( float ) _payload . lux , 0x07 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . lux_history , ( float ) MIBLEsensors [ _slot ] . lux , 2 ) ;
# endif //USE_MI_EXT_GUI
// AddLog(LOG_LEVEL_DEBUG,PSTR("motion: primary"),MIBLEsensors[_slot].lux );
2020-07-12 17:17:27 +01:00
break ;
2022-01-17 18:47:56 +00:00
case 0x14 :
MIBLEsensors [ _slot ] . leak = _payload . leak ;
MIBLEsensors [ _slot ] . eventType . leak = 1 ;
if ( _payload . leak > 0 ) MI32 . mode . shallTriggerTele = 1 ;
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . leak_hap_service , ( float ) _payload . leak , 0x14 ) ;
# endif //USE_MI_HOMEKIT
break ;
2020-07-12 17:17:27 +01:00
case 0x17 :
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . NMT = _payload . NMT ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . NMT = 1 ;
2020-10-20 13:49:10 +01:00
MI32 . mode . shallTriggerTele = 1 ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 17: NMT: %u seconds"), _payload.NMT);
2020-07-12 17:17:27 +01:00
break ;
2022-01-17 18:47:56 +00:00
case 0x19 :
MIBLEsensors [ _slot ] . door = _payload . door ;
MIBLEsensors [ _slot ] . eventType . door = 1 ;
MIBLEsensors [ _slot ] . events + + ;
MI32 . mode . shallTriggerTele = 1 ;
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . door_sensor_hap_service , ( float ) _payload . door , 0x19 ) ;
# endif //USE_MI_HOMEKIT
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 19: %u"), _payload.door);
break ;
2020-07-12 17:17:27 +01:00
default :
if ( MIBLEsensors [ _slot ] . type = = NLIGHT ) {
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . eventType . motion = 1 ; //motion
2020-07-12 17:17:27 +01:00
MIBLEsensors [ _slot ] . events + + ;
2020-10-30 11:29:48 +00:00
MIBLEsensors [ _slot ] . NMT = 0 ;
2020-10-20 13:49:10 +01:00
MI32 . mode . shallTriggerTele = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . motion_hap_service , ( float ) 1 , 0x0f ) ;
# endif //USE_MI_HOMEKIT
2020-07-12 17:17:27 +01:00
}
2020-10-20 13:49:10 +01:00
else {
2022-01-17 18:47:56 +00:00
//unknown payload
2020-10-20 13:49:10 +01:00
AddLogBuffer ( LOG_LEVEL_DEBUG , ( uint8_t * ) _buf , _bufSize ) ;
}
2020-04-21 08:58:33 +01:00
break ;
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ _slot ] . eventType . raw = = 0 ) return ;
MIBLEsensors [ _slot ] . shallSendMQTT = 1 ;
2020-10-20 13:49:10 +01:00
if ( MI32 . option . directBridgeMode ) MI32 . mode . shallTriggerTele = 1 ;
2020-04-21 08:58:33 +01:00
}
2020-10-23 09:18:57 +01:00
void MI32ParseATCPacket ( char * _buf , uint32_t length , uint8_t addr [ 6 ] , int RSSI ) {
2020-09-16 07:03:55 +01:00
ATCPacket_t * _packet = ( ATCPacket_t * ) _buf ;
2022-01-17 18:47:56 +00:00
bool isATC = ( length = = 0x0d ) ;
uint32_t _slot ;
if ( isATC ) _slot = MIBLEgetSensorSlot ( _packet - > MAC , 0x0a1c , _packet - > A . frameCnt ) ; // This must be a hard-coded fake ID
else {
MI32_ReverseMAC ( _packet - > MAC ) ;
_slot = MIBLEgetSensorSlot ( _packet - > MAC , 0x944a , _packet - > P . frameCnt ) ; // ... and again
}
2020-09-16 07:03:55 +01:00
if ( _slot = = 0xff ) return ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot);
2020-09-16 07:03:55 +01:00
2020-10-23 09:18:57 +01:00
MIBLEsensors [ _slot ] . RSSI = RSSI ;
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . lastTime = millis ( ) ;
if ( isATC ) {
MIBLEsensors [ _slot ] . temp = ( float ) ( int16_t ( __builtin_bswap16 ( _packet - > A . temp ) ) ) / 10.0f ;
MIBLEsensors [ _slot ] . hum = ( float ) _packet - > A . hum ;
MIBLEsensors [ _slot ] . bat = _packet - > A . batPer ;
}
else {
MIBLEsensors [ _slot ] . temp = ( float ) ( _packet - > P . temp ) / 100.0f ;
MIBLEsensors [ _slot ] . hum = ( float ) _packet - > P . hum / 100.0f ;
MIBLEsensors [ _slot ] . bat = _packet - > P . batPer ;
}
2020-09-16 07:03:55 +01:00
MIBLEsensors [ _slot ] . eventType . tempHum = 1 ;
MIBLEsensors [ _slot ] . eventType . bat = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . temp_hap_service , MIBLEsensors . at ( _slot ) . temp , 0x04 ) ;
mi_homekit_update_value ( MIBLEsensors [ _slot ] . hum_hap_service , MIBLEsensors . at ( _slot ) . hum , 0x06 ) ;
mi_homekit_update_value ( MIBLEsensors [ _slot ] . bat_hap_service , ( float ) MIBLEsensors . at ( _slot ) . bat , 0x0a ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
bitSet ( MI32 . widgetSlot , _slot ) ;
MI32addHistory ( MIBLEsensors [ _slot ] . temp_history , ( float ) MIBLEsensors [ _slot ] . temp , 0 ) ;
MI32addHistory ( MIBLEsensors [ _slot ] . hum_history , ( float ) MIBLEsensors [ _slot ] . hum , 1 ) ;
# endif //USE_MI_EXT_GUI
2020-09-16 07:03:55 +01:00
MIBLEsensors [ _slot ] . shallSendMQTT = 1 ;
2020-10-20 13:49:10 +01:00
if ( MI32 . option . directBridgeMode ) MI32 . mode . shallTriggerTele = 1 ;
2020-09-16 07:03:55 +01:00
}
2020-10-23 09:18:57 +01:00
void MI32parseCGD1Packet ( char * _buf , uint32_t length , uint8_t addr [ 6 ] , int RSSI ) { // no MiBeacon
2020-04-21 08:58:33 +01:00
uint8_t _addr [ 6 ] ;
memcpy ( _addr , addr , 6 ) ;
2020-07-12 17:17:27 +01:00
uint32_t _slot = MIBLEgetSensorSlot ( _addr , 0x0576 , 0 ) ; // This must be hard-coded, no object-id in Cleargrass-packet, we have no packet counter too
2020-04-21 08:58:33 +01:00
if ( _slot = = 0xff ) return ;
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot);
2020-10-23 09:18:57 +01:00
MIBLEsensors [ _slot ] . RSSI = RSSI ;
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . lastTime = millis ( ) ;
2020-04-21 08:58:33 +01:00
cg_packet_t _packet ;
memcpy ( ( char * ) & _packet , _buf , sizeof ( _packet ) ) ;
switch ( _packet . mode ) {
case 0x0401 :
float _tempFloat ;
_tempFloat = ( float ) ( _packet . temp ) / 10.0f ;
if ( _tempFloat < 60 ) {
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . temp = _tempFloat ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . temp = 1 ;
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " CGD1: temp updated " ) ) ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . temp_hap_service , _tempFloat , 0x04 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . temp_history , ( float ) MIBLEsensors [ _slot ] . temp , 0 ) ;
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
}
_tempFloat = ( float ) ( _packet . hum ) / 10.0f ;
if ( _tempFloat < 100 ) {
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . hum = _tempFloat ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . hum = 1 ;
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " CGD1: hum updated " ) ) ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
mi_homekit_update_value ( MIBLEsensors [ _slot ] . hum_hap_service , _tempFloat , 0x06 ) ;
# endif //USE_MI_HOMEKIT
# ifdef USE_MI_EXT_GUI
MI32addHistory ( MIBLEsensors [ _slot ] . hum_history , ( float ) MIBLEsensors [ _slot ] . hum , 1 ) ;
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
}
DEBUG_SENSOR_LOG ( PSTR ( " CGD1: U16: %x Temp U16: %x Hum " ) , _packet . temp , _packet . hum ) ;
break ;
case 0x0102 :
if ( _packet . bat < 101 ) {
2022-01-17 18:47:56 +00:00
MIBLEsensors [ _slot ] . bat = _packet . bat ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ _slot ] . eventType . bat = 1 ;
2020-04-21 08:58:33 +01:00
DEBUG_SENSOR_LOG ( PSTR ( " Mode a: bat updated " ) ) ;
}
break ;
default :
2021-01-18 10:33:13 +00:00
DEBUG_SENSOR_LOG ( PSTR ( " M32: Unexpected CGD1-packet " ) ) ;
2020-04-21 08:58:33 +01:00
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ _slot ] . eventType . raw = = 0 ) return ;
MIBLEsensors [ _slot ] . shallSendMQTT = 1 ;
2020-10-20 13:49:10 +01:00
if ( MI32 . option . directBridgeMode ) MI32 . mode . shallTriggerTele = 1 ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
bitSet ( MI32 . widgetSlot , _slot ) ;
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
}
2020-10-23 09:18:57 +01:00
void MI32ParseResponse ( char * buf , uint16_t bufsize , uint8_t addr [ 6 ] , int RSSI ) {
2020-07-12 17:17:27 +01:00
if ( bufsize < 9 ) { //9 is from the NLIGHT
2020-04-21 08:58:33 +01:00
return ;
}
2020-07-12 17:17:27 +01:00
uint16_t _type = buf [ 3 ] * 256 + buf [ 2 ] ;
2021-01-23 16:10:06 +00:00
// AddLog(LOG_LEVEL_INFO, PSTR("%02x %02x %02x %02x"),(uint8_t)buf[0], (uint8_t)buf[1],(uint8_t)buf[2],(uint8_t)buf[3]);
2020-04-21 08:58:33 +01:00
uint8_t _addr [ 6 ] ;
memcpy ( _addr , addr , 6 ) ;
2020-07-12 17:17:27 +01:00
uint16_t _slot = MIBLEgetSensorSlot ( _addr , _type , buf [ 4 ] ) ;
2020-07-10 17:03:07 +01:00
if ( _slot ! = 0xff ) {
2020-10-23 09:18:57 +01:00
MIBLEsensors [ _slot ] . RSSI = RSSI ;
2020-07-12 20:01:36 +01:00
MI32parseMiBeacon ( buf , _slot , bufsize ) ;
2020-07-10 17:03:07 +01:00
}
2020-04-21 08:58:33 +01:00
}
2020-07-20 07:51:17 +01:00
/**
* @ brief Launch functions from Core 1 to make race conditions less likely
2020-10-30 11:29:48 +00:00
*
2020-07-20 07:51:17 +01:00
*/
void MI32Every50mSecond ( ) {
if ( MI32 . mode . shallTriggerTele ) {
MI32 . mode . shallTriggerTele = 0 ;
MI32triggerTele ( ) ;
}
2022-01-17 18:47:56 +00:00
if ( MI32 . mode . triggerBerryAdvCB = = 1 ) {
if ( MI32 . beAdvCB ! = nullptr ) {
2022-03-16 07:41:04 +00:00
// AddLogBuffer(LOG_LEVEL_DEBUG,MI32.beAdvBuf,40);
uint8_t _index = 9 ; // is the first byte of payload in the advertisement buffer
int _svc = 0 ;
int _manu = 0 ;
while ( _index < 9 + MI32 . beAdvBuf [ 8 ] ) { //index of payload + _packet->length
if ( MI32 . beAdvBuf [ _index + 1 ] = = 0x16 ) {
_svc = _index + 2 ;
}
else if ( MI32 . beAdvBuf [ _index + 1 ] = = 0xff ) {
_manu = _index + 2 ;
}
_index + = MI32 . beAdvBuf [ _index ] + 1 ;
}
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: svc:%u , manu:%u"),_svc,_manu);
void ( * func_ptr ) ( int , int ) = ( void ( * ) ( int , int ) ) MI32 . beAdvCB ;
func_ptr ( _svc , _manu ) ;
}
2022-01-17 18:47:56 +00:00
MI32 . mode . triggerBerryAdvCB = 0 ;
}
if ( MI32 . mode . triggerBerryConnCB = = 1 ) {
if ( MI32 . beConnCB ! = nullptr ) {
2022-03-16 07:41:04 +00:00
void ( * func_ptr ) ( int , int , int ) = ( void ( * ) ( int , int , int ) ) MI32 . beConnCB ;
2022-01-17 18:47:56 +00:00
char _message [ 32 ] ;
GetTextIndexed ( _message , sizeof ( _message ) , MI32 . conCtx - > error , kMI32_ConnErrorMsg ) ;
2022-04-07 16:53:01 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: BryCbMsg: %s " ) , _message ) ;
2022-03-16 07:41:04 +00:00
func_ptr ( MI32 . conCtx - > error , MI32 . conCtx - > operation , MI32 . conCtx - > returnCharUUID ) ;
2022-04-07 16:53:01 +01:00
}
2022-01-17 18:47:56 +00:00
MI32 . mode . triggerBerryConnCB = 0 ;
}
if ( MI32 . infoMsg > 0 ) {
char _message [ 32 ] ;
GetTextIndexed ( _message , sizeof ( _message ) , MI32 . infoMsg - 1 , kMI32_BLEInfoMsg ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: %s " ) , _message ) ;
MI32 . infoMsg = 0 ;
}
# ifdef USE_MI_HOMEKIT
if ( MI32 . HKinfoMsg > 0 ) {
char _message [ 32 ] ;
GetTextIndexed ( _message , sizeof ( _message ) , MI32 . HKinfoMsg - 1 , kMI32_HKInfoMsg ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " M32: %s " ) , _message ) ;
MI32 . HKinfoMsg = 0 ;
}
# endif //USE_MI_HOMEKIT
2020-07-20 07:51:17 +01:00
}
2020-04-21 08:58:33 +01:00
/**
* @ brief Main loop of the driver , " high level " - loop
2020-04-21 10:06:30 +01:00
*
2020-04-21 08:58:33 +01:00
*/
void MI32EverySecond ( bool restart ) {
2020-07-12 17:17:27 +01:00
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_HOMEKIT
if ( TasmotaGlobal . devices_present > 0 ) {
for ( uint32_t i = 0 ; i < TasmotaGlobal . devices_present ; i + + ) {
power_t mask = 1 < < i ;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Power masl: %u"), (TasmotaGlobal.power & mask));
mi_homekit_update_value ( MI32 . outlet_hap_service [ i ] , ( TasmotaGlobal . power & mask ) ! = 0 , 0xf0 ) ;
2020-04-21 10:06:30 +01:00
}
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
# endif //USE_MI_HOMEKIT
2020-04-21 08:58:33 +01:00
2020-10-30 11:29:48 +00:00
2022-01-17 18:47:56 +00:00
for ( uint32_t i = 0 ; i < MIBLEsensors . size ( ) ; i + + ) {
if ( MIBLEsensors [ i ] . type = = NLIGHT | | MIBLEsensors [ i ] . type = = MJYD2S ) {
MIBLEsensors [ i ] . NMT + + ;
# ifdef USE_MI_HOMEKIT
if ( MIBLEsensors [ i ] . NMT > 20 ) { //TODO: Make a choosable timeout later
mi_homekit_update_value ( MIBLEsensors [ i ] . motion_hap_service , 0.0f , 0x0f ) ;
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
# endif //USE_MI_HOMEKIT
2020-04-21 08:58:33 +01:00
}
}
}
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-17 18:47:56 +00:00
void CmndMi32Key ( void ) {
if ( 44 = = XdrvMailbox . data_len | | 36 = = XdrvMailbox . data_len ) { // a KEY-MAC-string
mi_bindKey_t keyMAC ;
MI32HexStringToBytes ( XdrvMailbox . data , keyMAC . buf ) ;
if ( 36 = = XdrvMailbox . data_len ) {
memmove ( keyMAC . buf + 10 , keyMAC . buf + 6 , 12 ) ;
const uint8_t _fillbytes [ 4 ] = { 0x8d , 0x3d , 0x3c , 0x97 } ; // only valid for YLKG08 and YLKG07 ??
memcpy ( keyMAC . buf + 6 , _fillbytes , 4 ) ;
AddLogBuffer ( LOG_LEVEL_DEBUG , ( uint8_t * ) keyMAC . buf , 16 ) ;
}
MI32AddKey ( keyMAC ) ;
ResponseCmndDone ( ) ;
2020-11-13 16:00:44 +00:00
}
}
2022-01-17 18:47:56 +00:00
void CmndMi32Cfg ( void ) {
MI32saveConfig ( ) ;
ResponseCmndDone ( ) ;
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
void CmndMi32Option ( void ) {
bool onOff = atoi ( XdrvMailbox . data ) ;
switch ( XdrvMailbox . index ) {
case 0 :
2022-05-27 19:51:59 +01:00
if ( XdrvMailbox . data_len > 0 ) {
MI32 . option . allwaysAggregate = onOff ;
}
else {
onOff = MI32 . option . allwaysAggregate ;
}
2022-01-17 18:47:56 +00:00
break ;
case 1 :
2022-05-27 19:51:59 +01:00
if ( XdrvMailbox . data_len > 0 ) {
MI32 . option . noSummary = onOff ;
}
else {
onOff = MI32 . option . noSummary ;
}
2022-01-17 18:47:56 +00:00
break ;
case 2 :
2022-05-27 19:51:59 +01:00
if ( XdrvMailbox . data_len > 0 ) {
MI32 . option . directBridgeMode = onOff ;
}
else {
onOff = MI32 . option . directBridgeMode ;
}
2022-01-17 18:47:56 +00:00
break ;
case 3 :
2022-05-27 19:51:59 +01:00
if ( XdrvMailbox . data_len > 0 ) {
MI32 . mode . didGetConfig = onOff ;
}
else {
onOff = MI32 . mode . didGetConfig ;
}
2022-01-17 18:47:56 +00:00
break ;
2022-03-16 07:41:04 +00:00
case 4 :
2022-05-27 19:51:59 +01:00
if ( XdrvMailbox . data_len > 0 ) {
if ( MI32 . option . activeScan ! = onOff ) {
MI32 . option . activeScan = onOff ;
if ( MI32 . mode . runningScan ) {
MI32 . mode . updateScan = 1 ;
}
else {
MI32StartTask ( MI32_TASK_SCAN ) ;
}
}
}
else {
onOff = MI32 . option . activeScan ;
2022-03-16 07:41:04 +00:00
}
break ;
2020-11-13 16:00:44 +00:00
}
2022-05-27 19:51:59 +01:00
ResponseCmndIdxNumber ( onOff ? 1 : 0 ) ;
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
/*********************************************************************************************\
* Presentation
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef USE_MI_EXT_GUI
bool MI32HandleWebGUIResponse ( void ) {
char tmp [ 16 ] ;
WebGetArg ( PSTR ( " wi " ) , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
WSContentBegin ( 200 , CT_PLAIN ) ;
if ( MI32 . widgetSlot = = 0 ) { WSContentEnd ( ) ; return true ; }
for ( uint32_t i = 0 ; i < 32 ; i + + ) {
if ( bitRead ( MI32 . widgetSlot , i ) ) {
MI32sendWidget ( i ) ;
WSContentEnd ( ) ;
bitClear ( MI32 . widgetSlot , i ) ;
return true ;
2020-11-13 16:00:44 +00:00
}
}
2022-01-17 18:47:56 +00:00
WSContentEnd ( ) ;
return true ;
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
return false ;
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_ESP32_ENERGY
//https://gist.github.com/LingDong-/7e4c4cae5cbbc44400a05fba65f06f23
// used for logarithmic mapping of 0 - 3600 watts to 0-20 pixel - TaylorLog did not work as expected
float MI32ln ( float x ) {
unsigned int bx = * ( unsigned int * ) ( & x ) ;
unsigned int ex = bx > > 23 ;
signed int t = ( signed int ) ex - ( signed int ) 127 ;
unsigned int s = ( t < 0 ) ? ( - t ) : t ;
bx = 1065353216 | ( bx & 8388607 ) ;
x = * ( float * ) ( & bx ) ;
return - 1.49278 + ( 2.11263 + ( - 0.729104 + 0.10969 * x ) * x ) * x + 0.6931471806 * t ;
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
# endif //USE_MI_ESP32_ENERGY
void MI32createPolyline ( char * polyline , uint8_t * history ) {
uint32_t _pos = 0 ;
uint32_t _inc = 0 ;
for ( uint32_t i = 0 ; i < 24 ; i + + ) {
uint32_t y = 21 - MI32fetchHistory ( history , i ) ;
if ( y > 20 ) {
y = 150 ; //create a big gap in the graph to represent invalidated data
2020-11-13 16:00:44 +00:00
}
2022-01-17 18:47:56 +00:00
_inc = snprintf_P ( polyline + _pos , 10 , PSTR ( " %u,%u " ) , i * 6 , y ) ;
_pos + = _inc ;
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: polyline: %s"),polyline);
2020-04-21 08:58:33 +01:00
}
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_ESP32_ENERGY
void MI32sendEnergyWidget ( ) {
if ( Energy . current_available & & Energy . voltage_available ) {
WSContentSend_P ( HTTP_MI32_POWER_WIDGET , MIBLEsensors . size ( ) + 1 , Energy . voltage , Energy . current [ 1 ] ) ;
char _polyline [ 176 ] ;
MI32createPolyline ( _polyline , MI32 . energy_history ) ;
WSContentSend_P ( PSTR ( " <p> " D_POWERUSAGE " : %.1f " D_UNIT_WATT " " ) , Energy . active_power ) ;
WSContentSend_P ( HTTP_MI32_GRAPH , _polyline , 185 , 124 , 124 , _polyline , 1 ) ;
WSContentSend_P ( PSTR ( " </p></div> " ) ) ;
}
}
# endif //USE_MI_ESP32_ENERGY
void MI32sendWidget ( uint32_t slot ) {
auto _sensor = MIBLEsensors [ slot ] ;
char _MAC [ 13 ] ;
ToHex_P ( _sensor . MAC , 6 , _MAC , 13 ) ;
uint32_t _opacity = 1 ;
if ( _sensor . RSSI = = 0 ) {
_opacity = 0 ;
}
char _key [ 33 ] = { 0 } ;
if ( _sensor . key ! = nullptr ) {
ToHex_P ( _sensor . key , 16 , _key , 33 ) ;
}
2022-01-21 19:01:15 +00:00
else if ( _sensor . feature . needsKey = = 1 ) {
snprintf_P ( _key , 32 , PSTR ( " !! needs key !! " ) ) ;
_opacity = 0 ;
}
if ( _sensor . status . hasWrongKey = = 1 ) {
snprintf_P ( _key , 32 , PSTR ( " !! wrong key !! " ) ) ;
_opacity = 0 ;
}
if ( _sensor . status . isUnbounded = = 1 ) {
if ( _sensor . type ! = CGD1 ) { //only exception atm
snprintf_P ( _key , 32 , PSTR ( " !! not paired !! " ) ) ;
_opacity = 0 ;
}
}
2022-01-17 18:47:56 +00:00
char _bat [ 24 ] ;
snprintf_P ( _bat , 24 , PSTR ( " 🔋%u%% " ) , _sensor . bat ) ;
if ( ! _sensor . feature . bat ) _bat [ 0 ] = 0 ;
if ( _sensor . bat = = 0 ) _bat [ 9 ] = 0 ;
WSContentSend_P ( HTTP_MI32_WIDGET , slot + 1 , _opacity , _MAC , _sensor . RSSI , _bat , _key , kMI32DeviceType [ _sensor . type - 1 ] ) ;
2022-01-21 19:01:15 +00:00
2022-01-17 18:47:56 +00:00
if ( _sensor . feature . tempHum ) {
if ( ! isnan ( _sensor . temp ) ) {
char _polyline [ 176 ] ;
MI32createPolyline ( _polyline , _sensor . temp_history ) ;
WSContentSend_P ( PSTR ( " <p> " D_JSON_TEMPERATURE " : %.1f °C " ) , _sensor . temp ) ;
WSContentSend_P ( HTTP_MI32_GRAPH , _polyline , 185 , 124 , 124 , _polyline , 1 ) ;
WSContentSend_P ( PSTR ( " </p> " ) ) ;
}
if ( ! isnan ( _sensor . hum ) ) {
char _polyline [ 176 ] ;
MI32createPolyline ( _polyline , _sensor . hum_history ) ;
WSContentSend_P ( PSTR ( " <p> " D_JSON_HUMIDITY " : %.1f %% " ) , _sensor . hum ) ;
WSContentSend_P ( HTTP_MI32_GRAPH , _polyline , 151 , 190 , 216 , _polyline , 2 ) ;
WSContentSend_P ( PSTR ( " </p> " ) ) ;
}
if ( ! isnan ( _sensor . temp ) & & ! isnan ( _sensor . hum ) ) {
WSContentSend_P ( PSTR ( " " D_JSON_DEWPOINT " : %.1f °C " ) , CalcTempHumToDew ( _sensor . temp , _sensor . hum ) ) ;
}
}
else if ( _sensor . feature . temp ) {
if ( ! isnan ( _sensor . temp ) ) {
char _polyline [ 176 ] ;
MI32createPolyline ( _polyline , _sensor . temp_history ) ;
WSContentSend_P ( PSTR ( " <p> " D_JSON_TEMPERATURE " : %.1f °C " ) , _sensor . temp ) ;
WSContentSend_P ( HTTP_MI32_GRAPH , _polyline , 185 , 124 , 124 , _polyline , 1 ) ;
WSContentSend_P ( PSTR ( " </p> " ) ) ;
}
}
if ( _sensor . feature . lux ) {
if ( _sensor . lux ! = 0x00ffffff ) {
char _polyline [ 176 ] ;
MI32createPolyline ( _polyline , _sensor . lux_history ) ;
WSContentSend_P ( PSTR ( " <p> " D_JSON_ILLUMINANCE " : %d Lux " ) , _sensor . lux ) ;
WSContentSend_P ( HTTP_MI32_GRAPH , _polyline , 242 , 240 , 176 , _polyline , 3 ) ;
WSContentSend_P ( PSTR ( " </p> " ) ) ;
}
}
2022-02-11 17:03:22 +00:00
if ( _sensor . feature . knob ) {
if ( _sensor . pressed = = 0 ) {
WSContentSend_P ( PSTR ( " <p>Dimmer Steps: %d</p> " ) , _sensor . dimmer ) ;
}
else {
WSContentSend_P ( PSTR ( " <p>Dimmer Steps pressed: %d</p> " ) , _sensor . dimmer ) ;
}
2022-03-16 07:41:04 +00:00
WSContentSend_P ( PSTR ( " <p>Hold: %u</p> " ) , _sensor . longpress ) ;
2022-02-11 17:03:22 +00:00
}
2022-01-17 18:47:56 +00:00
if ( _sensor . feature . Btn ) {
2022-02-11 17:03:22 +00:00
char _message [ 16 ] ;
GetTextIndexed ( _message , sizeof ( _message ) , _sensor . BtnType , kMI32_ButtonMsg ) ;
if ( _sensor . Btn < 12 ) WSContentSend_P ( PSTR ( " <p>Button%u: %s</p> " ) , _sensor . Btn , _message ) ;
2022-01-17 18:47:56 +00:00
}
if ( _sensor . feature . motion ) {
WSContentSend_P ( PSTR ( " <p>Events: %u</p> " ) , _sensor . events ) ;
WSContentSend_P ( PSTR ( " <p>No motion for > <span class='Ti'>%u</span> seconds</p> " ) , _sensor . NMT ) ;
}
if ( _sensor . feature . door ) {
if ( _sensor . door ! = 255 ) {
if ( _sensor . door = = 1 ) {
WSContentSend_P ( PSTR ( " <p>Contact open</p> " ) ) ;
}
else {
WSContentSend_P ( PSTR ( " <p>Contact closed</p> " ) ) ;
}
WSContentSend_P ( PSTR ( " <p>Events: %u</p> " ) , _sensor . events ) ;
2020-11-17 08:30:59 +00:00
}
}
2022-01-17 18:47:56 +00:00
if ( _sensor . feature . leak ) {
if ( _sensor . leak = = 1 ) {
WSContentSend_P ( PSTR ( " <p>Leak !!!</p> " ) ) ;
}
else {
2022-02-11 17:03:22 +00:00
WSContentSend_P ( PSTR ( " <p>No leak</p> " ) ) ;
2020-11-17 08:30:59 +00:00
}
}
2022-01-17 18:47:56 +00:00
WSContentSend_P ( PSTR ( " </div> " ) ) ;
2020-11-17 08:30:59 +00:00
}
2022-01-17 18:47:56 +00:00
void MI32InitGUI ( void ) {
MI32suspendScanTask ( ) ;
MI32 . widgetSlot = 0 ;
WSContentStart_P ( " m32 " ) ;
WSContentSend_P ( HTTP_MI32_SCRIPT_1 ) ;
// WSContentSend_P(HTTP_MI32_SCRIPT_1);
WSContentSendStyle ( ) ;
WSContentSend_P ( HTTP_MI32_STYLE ) ;
WSContentSend_P ( HTTP_MI32_STYLE_SVG , 1 , 185 , 124 , 124 , 185 , 124 , 124 ) ;
WSContentSend_P ( HTTP_MI32_STYLE_SVG , 2 , 151 , 190 , 216 , 151 , 190 , 216 ) ;
WSContentSend_P ( HTTP_MI32_STYLE_SVG , 3 , 242 , 240 , 176 , 242 , 240 , 176 ) ;
# ifdef USE_MI_HOMEKIT
WSContentSend_P ( ( HTTP_MI32_PARENT_START ) , MIBLEsensors . size ( ) , UpTime ( ) , MI32 . hk_setup_code , MI32 . HKconnectedControllers , ESP . getFreeHeap ( ) / 1024 ) ;
# else
const char _setupCode [ 1 ] = { 0 } ;
WSContentSend_P ( ( HTTP_MI32_PARENT_START ) , MIBLEsensors . size ( ) , UpTime ( ) , _setupCode , ESP . getFreeHeap ( ) / 1024 ) ;
# endif //USE_MI_HOMEKIT
for ( uint32_t _slot = 0 ; _slot < MIBLEsensors . size ( ) ; _slot + + ) {
MI32sendWidget ( _slot ) ;
}
# ifdef USE_MI_ESP32_ENERGY
MI32sendEnergyWidget ( ) ;
# endif //USE_MI_ESP32_ENERGY
WSContentSend_P ( PSTR ( " </div> " ) ) ;
WSContentSpaceButton ( BUTTON_MAIN ) ;
WSContentStop ( ) ;
vTaskResume ( MI32 . ScanTask ) ;
2020-11-17 08:30:59 +00:00
}
2022-01-17 18:47:56 +00:00
void MI32HandleWebGUI ( void ) {
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
if ( MI32HandleWebGUIResponse ( ) ) { return ; }
MI32InitGUI ( ) ;
}
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
2022-01-17 18:47:56 +00:00
const char HTTP_MI32 [ ] PROGMEM = " {s}Mi ESP32 {m} %u devices{e} " ;
# ifndef USE_MI_EXT_GUI
2020-07-09 19:47:01 +01:00
const char HTTP_BATTERY [ ] PROGMEM = " {s}%s " " Battery " " {m}%u %%{e} " ;
2020-07-12 17:17:27 +01:00
const char HTTP_LASTBUTTON [ ] PROGMEM = " {s}%s Last Button{m}%u {e} " ;
const char HTTP_EVENTS [ ] PROGMEM = " {s}%s Events{m}%u {e} " ;
const char HTTP_NMT [ ] PROGMEM = " {s}%s No motion{m}> %u seconds{e} " ;
2022-01-17 18:47:56 +00:00
const char HTTP_DOOR [ ] PROGMEM = " {s}%s Door{m}> %u open/closed{e} " ;
2020-07-09 19:47:01 +01:00
const char HTTP_MI32_FLORA_DATA [ ] PROGMEM = " {s}%s " " Fertility " " {m}%u us/cm{e} " ;
2022-01-17 18:47:56 +00:00
# endif //USE_MI_EXT_GUI
const char HTTP_MI32_MAC [ ] PROGMEM = " {s}%s %s{m}%s{e} " ;
2020-04-21 08:58:33 +01:00
const char HTTP_MI32_HL [ ] PROGMEM = " {s}<hr>{m}<hr>{e} " ;
2022-01-17 18:47:56 +00:00
const char HTTP_RSSI [ ] PROGMEM = " {s}%s " D_RSSI " {m}%d dBm{e} " ;
2020-04-21 08:58:33 +01:00
2021-06-06 15:08:01 +01:00
void MI32ShowContinuation ( bool * commaflg ) {
if ( * commaflg ) {
ResponseAppend_P ( PSTR ( " , " ) ) ;
} else {
* commaflg = true ;
}
}
2020-04-21 08:58:33 +01:00
void MI32Show ( bool json )
{
if ( json ) {
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
bool _noSummarySave = MI32 . option . noSummary ;
bool _minimalSummarySave = MI32 . option . minimalSummary ;
if ( hass_mode = = 2 ) {
MI32 . option . noSummary = false ;
MI32 . option . minimalSummary = false ;
}
# endif //USE_HOME_ASSISTANT
2020-07-12 17:17:27 +01:00
if ( ! MI32 . mode . triggeredTele ) {
2020-07-20 07:51:17 +01:00
if ( MI32 . option . noSummary ) return ; // no message at TELEPERIOD
2020-07-12 17:17:27 +01:00
}
2022-01-17 18:47:56 +00:00
MI32suspendScanTask ( ) ;
2020-07-20 07:51:17 +01:00
for ( uint32_t i = 0 ; i < MIBLEsensors . size ( ) ; i + + ) {
if ( MI32 . mode . triggeredTele & & MIBLEsensors [ i ] . eventType . raw = = 0 ) continue ;
if ( MI32 . mode . triggeredTele & & MIBLEsensors [ i ] . shallSendMQTT = = 0 ) continue ;
2020-10-30 11:29:48 +00:00
2021-06-06 15:08:01 +01:00
bool commaflg = false ;
ResponseAppend_P ( PSTR ( " , \" %s-%02x%02x%02x \" :{ " ) ,
2020-07-12 17:17:27 +01:00
kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] ,
MIBLEsensors [ i ] . MAC [ 3 ] , MIBLEsensors [ i ] . MAC [ 4 ] , MIBLEsensors [ i ] . MAC [ 5 ] ) ;
2020-04-21 10:46:41 +01:00
2020-07-20 07:51:17 +01:00
if ( ( ! MI32 . mode . triggeredTele & & ! MI32 . option . minimalSummary ) | | MI32 . mode . triggeredTele ) {
bool tempHumSended = false ;
if ( MIBLEsensors [ i ] . feature . tempHum ) {
if ( MIBLEsensors [ i ] . eventType . tempHum | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
if ( ! isnan ( MIBLEsensors [ i ] . hum ) & & ! isnan ( MIBLEsensors [ i ] . temp )
# ifdef USE_HOME_ASSISTANT
2020-10-21 07:26:38 +01:00
| | ( hass_mode ! = - 1 )
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
) {
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
2020-07-20 07:51:17 +01:00
ResponseAppendTHD ( MIBLEsensors [ i ] . temp , MIBLEsensors [ i ] . hum ) ;
tempHumSended = true ;
}
}
}
if ( MIBLEsensors [ i ] . feature . temp & & ! tempHumSended ) {
if ( MIBLEsensors [ i ] . eventType . temp | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
if ( ! isnan ( MIBLEsensors [ i ] . temp )
# ifdef USE_HOME_ASSISTANT
2020-10-21 07:26:38 +01:00
| | ( hass_mode ! = - 1 )
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
) {
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_TEMPERATURE " \" :%*_f " ) ,
2021-06-11 17:14:12 +01:00
Settings - > flag2 . temperature_resolution , & MIBLEsensors [ i ] . temp ) ;
2020-07-20 07:51:17 +01:00
}
}
}
if ( MIBLEsensors [ i ] . feature . hum & & ! tempHumSended ) {
if ( MIBLEsensors [ i ] . eventType . hum | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
if ( ! isnan ( MIBLEsensors [ i ] . hum )
# ifdef USE_HOME_ASSISTANT
2020-10-21 07:26:38 +01:00
| | ( hass_mode ! = - 1 )
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
) {
2020-07-20 07:51:17 +01:00
char hum [ FLOATSZ ] ;
2021-06-11 17:14:12 +01:00
dtostrfd ( MIBLEsensors [ i ] . hum , Settings - > flag2 . humidity_resolution , hum ) ;
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_HUMIDITY " \" :%s " ) , hum ) ;
2020-07-20 07:51:17 +01:00
}
}
}
if ( MIBLEsensors [ i ] . feature . lux ) {
if ( MIBLEsensors [ i ] . eventType . lux | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( hass_mode ! = - 1 ) & & ( MIBLEsensors [ i ] . lux = = 0x0ffffff ) ) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_ILLUMINANCE " \" :null " ) ) ;
} else
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( MIBLEsensors [ i ] . lux ! = 0x0ffffff )
2020-10-21 07:26:38 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
| | ( hass_mode ! = - 1 )
2020-10-21 07:26:38 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
) { // this is the error code -> no lux
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_ILLUMINANCE " \" :%u " ) , MIBLEsensors [ i ] . lux ) ;
2020-07-20 07:51:17 +01:00
}
}
}
if ( MIBLEsensors [ i ] . feature . moist ) {
if ( MIBLEsensors [ i ] . eventType . moist | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( hass_mode ! = - 1 ) & & ( MIBLEsensors [ i ] . moisture = = 0xff ) ) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_MOISTURE " \" :null " ) ) ;
} else
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( MIBLEsensors [ i ] . moisture ! = 0xff )
2020-10-21 07:26:38 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
| | ( hass_mode ! = - 1 )
2020-10-21 07:26:38 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" " D_JSON_MOISTURE " \" :%u " ) , MIBLEsensors [ i ] . moisture ) ;
2020-07-20 07:51:17 +01:00
}
}
2020-04-21 08:58:33 +01:00
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ i ] . feature . fert ) {
if ( MIBLEsensors [ i ] . eventType . fert | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( hass_mode ! = - 1 ) & & ( MIBLEsensors [ i ] . fertility = = 0xffff ) ) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Fertility \" :null " ) ) ;
} else
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( MIBLEsensors [ i ] . fertility ! = 0xffff )
2020-10-21 07:26:38 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
| | ( hass_mode ! = - 1 )
2020-10-21 07:26:38 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Fertility \" :%u " ) , MIBLEsensors [ i ] . fertility ) ;
2020-07-20 07:51:17 +01:00
}
}
2020-04-21 08:58:33 +01:00
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ i ] . feature . Btn ) {
2020-09-26 18:24:58 +01:00
if ( MIBLEsensors [ i ] . eventType . Btn
# ifdef USE_HOME_ASSISTANT
| | ( hass_mode = = 2 )
# endif //USE_HOME_ASSISTANT
) {
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
2022-02-11 17:03:22 +00:00
ResponseAppend_P ( PSTR ( " \" Button%u \" :%u " ) , MIBLEsensors [ i ] . Btn , MIBLEsensors [ i ] . BtnType + 1 ) ; //internal type is Xiaomi/Homekit 0,1,2 -> Tasmota 1,2,3
}
}
if ( MIBLEsensors [ i ] . feature . knob ) {
if ( MIBLEsensors [ i ] . eventType . knob
# ifdef USE_HOME_ASSISTANT
| | ( hass_mode = = 2 )
# endif //USE_HOME_ASSISTANT
) {
MI32ShowContinuation ( & commaflg ) ;
char _pressed [ 3 ] = { ' _ ' , ' P ' , 0 } ;
if ( MIBLEsensors [ i ] . pressed = = 0 ) {
_pressed [ 0 ] = 0 ;
}
ResponseAppend_P ( PSTR ( " \" Dimmer%s \" :%d " ) , _pressed , MIBLEsensors [ i ] . dimmer ) ;
}
if ( MIBLEsensors [ i ] . eventType . longpress
# ifdef USE_HOME_ASSISTANT
| | ( hass_mode = = 2 )
# endif //USE_HOME_ASSISTANT
) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Hold \" :%d " ) , MIBLEsensors [ i ] . longpress ) ;
2020-07-20 07:51:17 +01:00
}
2020-04-21 10:46:41 +01:00
}
2020-07-20 07:51:17 +01:00
} // minimal summary
2022-01-17 18:47:56 +00:00
if ( MIBLEsensors [ i ] . feature . motion ) {
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ i ] . eventType . motion | | ! MI32 . mode . triggeredTele ) {
2021-06-06 15:08:01 +01:00
if ( MI32 . mode . triggeredTele ) {
MI32ShowContinuation ( & commaflg ) ;
2022-02-11 17:03:22 +00:00
ResponseAppend_P ( PSTR ( " \" Motion \" :1 " ) ) ; // only real-time
2021-06-06 15:08:01 +01:00
}
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Events \" :%u " ) , MIBLEsensors [ i ] . events ) ;
2020-04-21 10:46:41 +01:00
}
2020-07-20 07:51:17 +01:00
else if ( MIBLEsensors [ i ] . eventType . noMotion & & MI32 . mode . triggeredTele ) {
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
2022-02-11 17:03:22 +00:00
ResponseAppend_P ( PSTR ( " \" Motion \" :0 " ) ) ;
2022-01-17 18:47:56 +00:00
}
}
if ( MIBLEsensors [ i ] . feature . door ) {
if ( MIBLEsensors [ i ] . eventType . door | | ! MI32 . mode . triggeredTele ) {
if ( MI32 . mode . triggeredTele ) {
MI32ShowContinuation ( & commaflg ) ;
2022-02-11 17:03:22 +00:00
ResponseAppend_P ( PSTR ( " \" Door \" :%u " ) , MIBLEsensors [ i ] . door ) ;
2022-01-17 18:47:56 +00:00
}
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Events \" :%u " ) , MIBLEsensors [ i ] . events ) ;
2020-07-20 07:51:17 +01:00
}
}
if ( MIBLEsensors [ i ] . type = = FLORA & & ! MI32 . mode . triggeredTele ) {
2020-07-13 20:24:38 +01:00
if ( MIBLEsensors [ i ] . firmware [ 0 ] ! = ' \0 ' ) { // this is the error code -> no firmware
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Firmware \" : \" %s \" " ) , MIBLEsensors [ i ] . firmware ) ;
2020-07-13 20:08:10 +01:00
}
2020-04-21 10:46:41 +01:00
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ i ] . feature . NMT | | ! MI32 . mode . triggeredTele ) {
if ( MIBLEsensors [ i ] . eventType . NMT ) {
2021-06-06 15:08:01 +01:00
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" NMT \" :%u " ) , MIBLEsensors [ i ] . NMT ) ;
2020-04-21 08:58:33 +01:00
}
2020-04-21 10:46:41 +01:00
}
2020-07-20 07:51:17 +01:00
if ( MIBLEsensors [ i ] . feature . bat ) {
if ( MIBLEsensors [ i ] . eventType . bat | | ! MI32 . mode . triggeredTele | | MI32 . option . allwaysAggregate ) {
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( hass_mode ! = - 1 ) & & ( MIBLEsensors [ i ] . bat = = 0x00 ) ) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Battery \" :null " ) ) ;
} else
2020-09-26 18:24:58 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
if ( ( MIBLEsensors [ i ] . bat ! = 0x00 )
2020-10-21 07:26:38 +01:00
# ifdef USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
| | ( hass_mode ! = - 1 )
2020-10-21 07:26:38 +01:00
# endif //USE_HOME_ASSISTANT
2021-06-06 15:08:01 +01:00
) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" Battery \" :%u " ) , MIBLEsensors [ i ] . bat ) ;
2020-07-20 07:51:17 +01:00
}
}
2020-04-21 10:46:41 +01:00
}
2021-06-06 15:08:01 +01:00
if ( MI32 . option . showRSSI ) {
MI32ShowContinuation ( & commaflg ) ;
ResponseAppend_P ( PSTR ( " \" RSSI \" :%d " ) , MIBLEsensors [ i ] . RSSI ) ;
}
ResponseJsonEnd ( ) ;
2020-07-20 07:51:17 +01:00
MIBLEsensors [ i ] . eventType . raw = 0 ;
if ( MIBLEsensors [ i ] . shallSendMQTT = = 1 ) {
MIBLEsensors [ i ] . shallSendMQTT = 0 ;
2020-09-26 18:24:58 +01:00
continue ;
2020-07-20 07:51:17 +01:00
}
2020-04-21 08:58:33 +01:00
}
2020-07-20 07:51:17 +01:00
MI32 . mode . triggeredTele = 0 ;
2020-09-26 18:24:58 +01:00
# ifdef USE_HOME_ASSISTANT
if ( hass_mode = = 2 ) {
MI32 . option . noSummary = _noSummarySave ;
MI32 . option . minimalSummary = _minimalSummarySave ;
}
# endif //USE_HOME_ASSISTANT
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
Mi32invalidateOldHistory ( ) ;
# ifdef USE_MI_ESP32_ENERGY
MI32addHistory ( MI32 . energy_history , Energy . active_power [ 0 ] , 100 ) ; //TODO: which value??
# endif //USE_MI_ESP32_ENERGY
# endif //USE_MI_EXT_GUI
vTaskResume ( MI32 . ScanTask ) ;
2020-04-21 08:58:33 +01:00
# ifdef USE_WEBSERVER
} else {
2022-01-17 18:47:56 +00:00
MI32suspendScanTask ( ) ;
2020-04-21 08:58:33 +01:00
2022-01-17 18:47:56 +00:00
WSContentSend_P ( HTTP_MI32 , MIBLEsensors . size ( ) ) ;
# ifdef USE_MI_HOMEKIT
if ( MI32 . mode . didStartHAP ) {
WSContentSend_PD ( PSTR ( " {s}HomeKit Code{m} %s{e} " ) , MI32 . hk_setup_code ) ;
}
# endif //USE_MI_HOMEKIT
# ifndef USE_MI_EXT_GUI
for ( uint32_t i = 0 ; i < MIBLEsensors . size ( ) ; i + + ) {
2020-04-21 08:58:33 +01:00
WSContentSend_PD ( HTTP_MI32_HL ) ;
2020-09-26 18:24:58 +01:00
char _MAC [ 18 ] ;
ToHex_P ( MIBLEsensors [ i ] . MAC , 6 , _MAC , 18 , ' : ' ) ;
WSContentSend_PD ( HTTP_MI32_MAC , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , D_MAC_ADDRESS , _MAC ) ;
2020-10-23 09:18:57 +01:00
WSContentSend_PD ( HTTP_RSSI , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . RSSI ) ;
2020-04-21 10:46:41 +01:00
if ( MIBLEsensors [ i ] . type = = FLORA ) {
if ( ! isnan ( MIBLEsensors [ i ] . temp ) ) {
2021-01-26 16:12:08 +00:00
WSContentSend_Temp ( kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . temp ) ;
2020-04-21 08:58:33 +01:00
}
2020-07-15 16:41:12 +01:00
if ( MIBLEsensors [ i ] . moisture ! = 0xff ) {
WSContentSend_PD ( HTTP_SNS_MOISTURE , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . moisture ) ;
2020-04-21 08:58:33 +01:00
}
2020-07-15 16:41:12 +01:00
if ( MIBLEsensors [ i ] . fertility ! = 0xffff ) {
WSContentSend_PD ( HTTP_MI32_FLORA_DATA , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . fertility ) ;
2020-04-21 08:58:33 +01:00
}
}
2020-04-21 10:46:41 +01:00
if ( MIBLEsensors [ i ] . type > FLORA ) { // everything "above" Flora
if ( ! isnan ( MIBLEsensors [ i ] . hum ) & & ! isnan ( MIBLEsensors [ i ] . temp ) ) {
2020-07-12 17:17:27 +01:00
WSContentSend_THD ( kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . temp , MIBLEsensors [ i ] . hum ) ;
2020-04-21 08:58:33 +01:00
}
2020-04-21 10:06:30 +01:00
}
2022-01-17 18:47:56 +00:00
if ( MIBLEsensors [ i ] . feature . needsKey ) {
if ( MIBLEsensors [ i ] . key = = nullptr ) {
WSContentSend_PD ( PSTR ( " {s}No known Key!!{m} can not decrypt messages{e} " ) ) ;
}
2022-01-21 19:01:15 +00:00
else if ( MIBLEsensors [ i ] . status . hasWrongKey ) {
2022-01-17 18:47:56 +00:00
WSContentSend_PD ( PSTR ( " {s}Wrong Key!!{m} can not decrypt messages{e} " ) ) ;
}
}
2020-07-12 17:17:27 +01:00
if ( MIBLEsensors [ i ] . type = = NLIGHT | | MIBLEsensors [ i ] . type = = MJYD2S ) {
WSContentSend_PD ( HTTP_EVENTS , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . events ) ;
if ( MIBLEsensors [ i ] . NMT > 0 ) WSContentSend_PD ( HTTP_NMT , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . NMT ) ;
}
2022-01-17 18:47:56 +00:00
if ( MIBLEsensors [ i ] . door ! = 255 & & MIBLEsensors [ i ] . type = = MCCGQ02 ) {
WSContentSend_PD ( HTTP_DOOR , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . door ) ;
}
2020-07-12 17:17:27 +01:00
if ( MIBLEsensors [ i ] . lux ! = 0x00ffffff ) { // this is the error code -> no valid value
WSContentSend_PD ( HTTP_SNS_ILLUMINANCE , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . lux ) ;
}
2020-04-21 08:58:33 +01:00
if ( MIBLEsensors [ i ] . bat ! = 0x00 ) {
2020-07-12 17:17:27 +01:00
WSContentSend_PD ( HTTP_BATTERY , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . bat ) ;
}
2022-02-11 17:03:22 +00:00
if ( MIBLEsensors [ i ] . type = = YLYK01 ) {
2020-07-12 17:17:27 +01:00
WSContentSend_PD ( HTTP_LASTBUTTON , kMI32DeviceType [ MIBLEsensors [ i ] . type - 1 ] , MIBLEsensors [ i ] . Btn ) ;
2020-04-21 08:58:33 +01:00
}
}
2022-01-17 18:47:56 +00:00
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
# endif // USE_WEBSERVER
}
2022-01-17 18:47:56 +00:00
vTaskResume ( MI32 . ScanTask ) ;
}
int ExtStopBLE ( ) {
if ( Settings - > flag5 . mi32_enable = = 0 ) return 0 ;
if ( MI32 . ScanTask ! = nullptr ) {
MI32Scan - > stop ( ) ;
2022-05-27 19:51:59 +01:00
MI32 . mode . deleteScanTask = 1 ;
2022-01-17 18:47:56 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: stop BLE " ) ) ;
}
# ifdef USE_MI_HOMEKIT
if ( MI32 . mode . didStartHAP ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " M32: stop Homebridge " ) ) ;
mi_homekit_stop ( ) ;
}
# endif //USE_MI_HOMEKIT
return 0 ;
2020-04-21 08:58:33 +01:00
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool Xsns62 ( uint8_t function )
{
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag5 . mi32_enable ) { return false ; } // SetOption115 - Enable ESP32 MI32 BLE
2020-11-13 16:00:44 +00:00
2020-04-21 08:58:33 +01:00
bool result = false ;
2020-11-13 16:00:44 +00:00
2020-04-21 08:58:33 +01:00
if ( FUNC_INIT = = function ) {
2020-11-09 19:27:11 +00:00
MI32PreInit ( ) ;
2020-04-21 08:58:33 +01:00
}
2020-11-13 16:00:44 +00:00
if ( ! MI32 . mode . init ) {
if ( function = = FUNC_EVERY_250_MSECOND ) {
2020-11-09 19:27:11 +00:00
MI32Init ( ) ;
}
return result ;
}
switch ( function ) {
case FUNC_EVERY_50_MSECOND :
MI32Every50mSecond ( ) ;
break ;
case FUNC_EVERY_SECOND :
MI32EverySecond ( false ) ;
break ;
2022-01-17 18:47:56 +00:00
case FUNC_SAVE_BEFORE_RESTART :
ExtStopBLE ( ) ;
break ;
2020-11-09 19:27:11 +00:00
case FUNC_COMMAND :
2020-11-13 16:00:44 +00:00
result = DecodeCommand ( kMI32_Commands , MI32_Commands ) ;
2020-11-09 19:27:11 +00:00
break ;
case FUNC_JSON_APPEND :
MI32Show ( 1 ) ;
break ;
2020-04-21 08:58:33 +01:00
# ifdef USE_WEBSERVER
2020-11-09 19:27:11 +00:00
case FUNC_WEB_SENSOR :
MI32Show ( 0 ) ;
break ;
2022-01-17 18:47:56 +00:00
# ifdef USE_MI_EXT_GUI
case FUNC_WEB_ADD_MAIN_BUTTON :
if ( MI32 . mode . didGetConfig ) WSContentSend_P ( HTTP_BTN_MENU_MI32 ) ;
break ;
case FUNC_WEB_ADD_HANDLER :
WebServer_on ( PSTR ( " /m32 " ) , MI32HandleWebGUI ) ;
break ;
# endif //USE_MI_EXT_GUI
2020-04-21 08:58:33 +01:00
# endif // USE_WEBSERVER
2020-11-09 19:27:11 +00:00
}
2020-04-21 08:58:33 +01:00
return result ;
}
2020-04-21 10:06:30 +01:00
# endif // USE_MI_ESP32
2021-08-22 14:52:00 +01:00
# endif // CONFIG_IDF_TARGET_ESP32 or CONFIG_IDF_TARGET_ESP32C3
2020-07-12 17:17:27 +01:00
# endif // ESP32
2022-03-25 09:15:58 +00:00
# endif // USE_BLE_ESP32