mirror of https://github.com/arendst/Tasmota.git
Align protocol interpretation with MI docs (16 bit payload type).
Add ref to MI docs. Add light sense for DOOR. Add HASS discovery for MOST sensor types.
This commit is contained in:
parent
f91ca66a69
commit
3a3e77215b
|
@ -182,8 +182,7 @@ struct mi_beacon_mac_data_t{ // e.g. 28/08
|
|||
uint8_t mac[6];
|
||||
};
|
||||
struct mi_beacon_payload_data_t{ //
|
||||
uint8_t type;
|
||||
uint8_t ten;
|
||||
uint16_t type;
|
||||
uint8_t size;
|
||||
uint8_t data[16];
|
||||
};
|
||||
|
@ -286,6 +285,7 @@ struct mi_sensor_t{
|
|||
uint32_t Btn:1;
|
||||
uint32_t events:1;
|
||||
uint32_t pairing:1;
|
||||
uint32_t light:1; // binary light sensor
|
||||
};
|
||||
uint32_t raw;
|
||||
} feature;
|
||||
|
@ -303,12 +303,16 @@ struct mi_sensor_t{
|
|||
uint32_t noMotion:1;
|
||||
uint32_t Btn:1;
|
||||
uint32_t PairBtn:1;
|
||||
uint32_t light:1; // binary light sensor
|
||||
};
|
||||
uint32_t raw;
|
||||
} eventType;
|
||||
|
||||
int RSSI;
|
||||
uint8_t pairing;
|
||||
int8_t light; // binary light sensor - initialise to -1
|
||||
int16_t Btn; // moved so we can initialise to -1
|
||||
|
||||
uint32_t lastTime;
|
||||
uint32_t lux;
|
||||
float temp; //Flora, MJ_HT_V1, LYWSD0x, CGx
|
||||
|
@ -325,7 +329,6 @@ struct mi_sensor_t{
|
|||
uint16_t events; //"alarms" since boot
|
||||
uint32_t NMT; // no motion time in seconds for the MJYD2S
|
||||
};
|
||||
uint16_t Btn;
|
||||
};
|
||||
union {
|
||||
uint8_t bat; // many values seem to be hard-coded garbage (LYWSD0x, GCD1)
|
||||
|
@ -1152,6 +1155,21 @@ int MIDecryptPayload(const uint8_t *macin, const uint8_t *nonce, uint32_t tag, u
|
|||
// xxyy FFEEDDCCBBAA 0104 TTTTHHHH
|
||||
// xxyy FFEEDDCCBBAA 0201 BB
|
||||
|
||||
const char *MIaddrStr(const uint8_t *addr, int useAlias = 0){
|
||||
static char addrstr[32];
|
||||
|
||||
const char *id = nullptr;
|
||||
if (useAlias){
|
||||
id = BLE_ESP32::getAlias(addr);
|
||||
}
|
||||
if (!id || !(*id)){
|
||||
id = addrstr;
|
||||
BLE_ESP32::dump(addrstr, 13, addr, 6);
|
||||
} else {
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const uint8_t *datain, int len){
|
||||
uint8_t data[32];
|
||||
|
@ -1189,6 +1207,10 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
|
|||
parsed->framedata.bindingvalidreq = (data[byteindex] & 0x02)>>1; //Byte 0: ......x.
|
||||
parsed->framedata.registeredflag = (data[byteindex] & 0x01); //Byte 0: .......x
|
||||
|
||||
// note:
|
||||
// if bindingvalidreq, we should connect and establish a key.
|
||||
// However, how do we determine WHICH TAS should do this?
|
||||
|
||||
byteindex++;
|
||||
|
||||
parsed->devicetype = *((uint16_t *)(data + byteindex));
|
||||
|
@ -1243,17 +1265,17 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
|
|||
break;
|
||||
case 0: // suceeded
|
||||
parsed->needkey = KEY_REQUIRED_AND_FOUND;
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload decrypted"));
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload decrypted"), MIaddrStr(slotmac));
|
||||
break;
|
||||
case -1: // key failed to work
|
||||
parsed->needkey = KEY_REQUIRED_AND_INVALID;
|
||||
AddLog(LOG_LEVEL_ERROR,PSTR("M32: Payload decrypt failed"));
|
||||
AddLog(LOG_LEVEL_ERROR,PSTR("M32 %s: Payload decrypt failed"), MIaddrStr(slotmac));
|
||||
parsed->payloadpresent = 0;
|
||||
return 0;
|
||||
break;
|
||||
case -2: // key not present
|
||||
parsed->needkey = KEY_REQUIRED_BUT_NOT_FOUND;
|
||||
AddLog(LOG_LEVEL_ERROR,PSTR("M32: Payload encrypted but no key"));
|
||||
AddLog(LOG_LEVEL_ERROR,PSTR("M32 %s: Payload encrypted but no key"), MIaddrStr(slotmac));
|
||||
parsed->payloadpresent = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
@ -1288,7 +1310,7 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
|
|||
}
|
||||
|
||||
if ((len - byteindex) == 0){
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: No payload"));
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: No payload"), MIaddrStr(slotmac));
|
||||
parsed->payload.size = 0;
|
||||
parsed->payloadpresent = 0;
|
||||
return 0;
|
||||
|
@ -1297,14 +1319,14 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const
|
|||
// we have payload which did not need decrypt.
|
||||
if (decres == 1){
|
||||
parsed->needkey = KEY_NOT_REQUIRED;
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload unencrypted"));
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload unencrypted"), MIaddrStr(slotmac));
|
||||
}
|
||||
|
||||
// already decrypted if required
|
||||
parsed->payloadpresent = 1;
|
||||
memcpy(&parsed->payload, (data + byteindex), (len - byteindex));
|
||||
if (parsed->payload.size != (len - byteindex) - 3){
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Payload length mismatch"));
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32 %s: Payload length mismatch"), MIaddrStr(slotmac));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -1399,6 +1421,8 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
|
|||
_newSensor.bat = 0x00;
|
||||
_newSensor.RSSI = 0xffff;
|
||||
_newSensor.lux = 0x00ffffff;
|
||||
_newSensor.light = -1;
|
||||
_newSensor.Btn = -1;
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
|
@ -1428,9 +1452,13 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
|
|||
_newSensor.feature.events=1;
|
||||
break;
|
||||
case MI_YEERC:
|
||||
case MI_DOOR:
|
||||
_newSensor.feature.Btn=1;
|
||||
break;
|
||||
case MI_DOOR: // MCCGQ02HL
|
||||
_newSensor.feature.Btn=1;
|
||||
_newSensor.feature.light=1;
|
||||
_newSensor.feature.bat=1;
|
||||
break;
|
||||
default:
|
||||
_newSensor.hum=NAN;
|
||||
_newSensor.feature.temp=1;
|
||||
|
@ -1651,26 +1679,49 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
MIBLEsensors[_slot].pairing = 0;
|
||||
MIBLEsensors[_slot].eventType.PairBtn = 0;
|
||||
|
||||
//https://iot.mi.com/new/doc/embedded-development/ble/object-definition
|
||||
|
||||
switch(parsed->payload.type){
|
||||
case 0x01: // button press
|
||||
MIBLEsensors[_slot].Btn = pld->Btn.num + (pld->Btn.longPress/2)*6;
|
||||
MIBLEsensors[_slot].feature.Btn = 1;
|
||||
MIBLEsensors[_slot].eventType.Btn = 1;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
break;
|
||||
case 0x02: // related to pair button?
|
||||
case 0x0002: // related to pair button? 'easypairing'
|
||||
MIBLEsensors[_slot].pairing = 1;
|
||||
MIBLEsensors[_slot].eventType.PairBtn = 1;
|
||||
MIBLEsensors[_slot].feature.pairing = 1;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
break;
|
||||
case 0x03: {// motion? 1 byte
|
||||
case 0x0003: {// motion? 1 byte 'near'
|
||||
uint8_t motion = parsed->payload.data[0];
|
||||
res = 0;
|
||||
}break;
|
||||
case 0x04:{
|
||||
case 0x000f: // 'Someone is moving (with light)'
|
||||
MIBLEsensors[_slot].eventType.motion = 1;
|
||||
MIBLEsensors[_slot].lastTime = millis();
|
||||
MIBLEsensors[_slot].events++;
|
||||
MIBLEsensors[_slot].lux = pld->lux;
|
||||
MIBLEsensors[_slot].eventType.lux = 1;
|
||||
MIBLEsensors[_slot].NMT = 0;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
MIBLEsensors[_slot].feature.lux = 1;
|
||||
MIBLEsensors[_slot].feature.NMT = 1;
|
||||
MIBLEsensors[_slot].feature.events=1;
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: PIR: primary"),MIBLEsensors[_slot].lux );
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 0x1001: // button press
|
||||
MIBLEsensors[_slot].Btn = pld->Btn.num + (pld->Btn.longPress/2)*6;
|
||||
MIBLEsensors[_slot].feature.Btn = 1;
|
||||
MIBLEsensors[_slot].eventType.Btn = 1;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
break;
|
||||
//case 0x1002: // 'sleep'
|
||||
//case 0x1003: // 'RSSI'
|
||||
|
||||
case 0x1004:{ // 'temperature'
|
||||
float _tempFloat=(float)(pld->temp)/10.0f;
|
||||
if(_tempFloat<60){
|
||||
MIBLEsensors[_slot].temp=_tempFloat;
|
||||
|
@ -1682,7 +1733,8 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 4: U16: %u Temp"), _beacon.temp );
|
||||
} break;
|
||||
case 0x06: {
|
||||
// 0x1005 - not documented
|
||||
case 0x1006: { // 'humidity'
|
||||
float _tempFloat=(float)(pld->hum)/10.0f;
|
||||
if(_tempFloat<101){
|
||||
MIBLEsensors[_slot].hum=_tempFloat;
|
||||
|
@ -1694,7 +1746,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 6: U16: %u Hum"), _beacon.hum);
|
||||
} break;
|
||||
case 0x07:
|
||||
case 0x1007: // 'Light illuminance'
|
||||
MIBLEsensors[_slot].lux=pld->lux & 0x00ffffff;
|
||||
if(MIBLEsensors[_slot].type==MI_MJYD2S){
|
||||
MIBLEsensors[_slot].eventType.noMotion = 1;
|
||||
|
@ -1703,21 +1755,21 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
MIBLEsensors[_slot].feature.lux = 1;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x1008: //'Soil moisture'
|
||||
MIBLEsensors[_slot].moisture=pld->moist;
|
||||
MIBLEsensors[_slot].eventType.moist = 1;
|
||||
MIBLEsensors[_slot].feature.moist = 1;
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 8: moisture updated"));
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 8: U8: %u Moisture"), _beacon.moist);
|
||||
break;
|
||||
case 0x09: // 'conductivity'
|
||||
case 0x1009: // 'conductivity' / 'Soil EC value'
|
||||
MIBLEsensors[_slot].fertility=pld->fert;
|
||||
MIBLEsensors[_slot].eventType.fert = 1;
|
||||
MIBLEsensors[_slot].feature.fert = 1;
|
||||
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 9: fertility updated"));
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 9: U16: %u Fertility"), _beacon.fert);
|
||||
break;
|
||||
case 0x0a:
|
||||
case 0x100a:// 'Electricity'
|
||||
if(MI32.option.ignoreBogusBattery){
|
||||
if(MIBLEsensors[_slot].type==MI_LYWSD03MMC || MIBLEsensors[_slot].type==MI_MHOC401){
|
||||
res = 0;
|
||||
|
@ -1736,7 +1788,8 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode a: U8: %u %%"), _beacon.bat);
|
||||
break;
|
||||
case 0x0d:{
|
||||
// 100b-100d -> undefioend in docs.
|
||||
case 0x100d:{ // is this right????
|
||||
MIBLEsensors[_slot].feature.tempHum = 1;
|
||||
float _tempFloat=(float)(pld->HT.temp)/10.0f;
|
||||
if(_tempFloat < 60){
|
||||
|
@ -1755,36 +1808,26 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
MIBLEsensors[_slot].eventType.tempHum = 1;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode d: U16: %x Temp U16: %x Hum"), _beacon.HT.temp, _beacon.HT.hum);
|
||||
} break;
|
||||
case 0x0f:
|
||||
if (parsed->payload.ten != 0) break;
|
||||
MIBLEsensors[_slot].eventType.motion = 1;
|
||||
MIBLEsensors[_slot].lastTime = millis();
|
||||
MIBLEsensors[_slot].events++;
|
||||
MIBLEsensors[_slot].lux = pld->lux;
|
||||
MIBLEsensors[_slot].eventType.lux = 1;
|
||||
MIBLEsensors[_slot].NMT = 0;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
MIBLEsensors[_slot].feature.lux = 1;
|
||||
MIBLEsensors[_slot].feature.NMT = 1;
|
||||
MIBLEsensors[_slot].feature.events=1;
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: PIR: primary"),MIBLEsensors[_slot].lux );
|
||||
break;
|
||||
case 0x10:{ // 'formaldehide'
|
||||
// 100e = 'lock'
|
||||
// 100f = 'door'
|
||||
case 0x1010:{ // 'formaldehide'
|
||||
const uint16_t f = uint16_t(parsed->payload.data[0]) | (uint16_t(parsed->payload.data[1]) << 8);
|
||||
float formaldehyde = (float)f / 100.0f;
|
||||
res = 0;
|
||||
} break;
|
||||
case 0x12:{ // 'active'
|
||||
// 1011 = 'bind'
|
||||
case 0x1012:{ // 'switch'
|
||||
int active = parsed->payload.data[0];
|
||||
res = 0;
|
||||
} break;
|
||||
case 0x13:{ //mosquito tablet
|
||||
case 0x1013:{ // 'Remaining amount of consumables' - mosquito tablet
|
||||
int tablet = parsed->payload.data[0];
|
||||
res = 0;
|
||||
} break;
|
||||
case 0x17:{
|
||||
//Flooding 0x1014 1 1
|
||||
//smoke 0x1015 1 1
|
||||
//Gas 0x1016
|
||||
case 0x1017:{ // 'No one moves'
|
||||
const uint32_t idle_time =
|
||||
uint32_t(parsed->payload.data[0]) | (uint32_t(parsed->payload.data[1]) << 8) | (uint32_t(parsed->payload.data[2]) << 16) | (uint32_t(parsed->payload.data[2]) << 24);
|
||||
float idlemins = (float)idle_time / 60.0f;
|
||||
|
@ -1798,17 +1841,29 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
|
|||
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 17: NMT: %u seconds"), _beacon.NMT);
|
||||
} break;
|
||||
|
||||
case 0x19:{
|
||||
MIBLEsensors[_slot].Btn = uint8_t(parsed->payload.data[0]); // just an 8 bit value in a union.
|
||||
//Light intensity 0x1018
|
||||
case 0x1018:{ //'Light intensity' - 0=dark, 1=light? - MCCGQ02HL
|
||||
MIBLEsensors[_slot].light = parsed->payload.data[0];
|
||||
MIBLEsensors[_slot].eventType.light = 1;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
MIBLEsensors[_slot].feature.light = 1;
|
||||
} break;
|
||||
case 0x1019:{ //'Door sensor' - 0=open, 1=closed, 2=timeout? - MCCGQ02HL
|
||||
MIBLEsensors[_slot].Btn = (uint8_t) parsed->payload.data[0]; // just an 8 bit value in a union.
|
||||
MIBLEsensors[_slot].eventType.Btn = 1;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
MIBLEsensors[_slot].feature.Btn = 1;
|
||||
} break;
|
||||
|
||||
//Weight attributes 0x101A 600 0
|
||||
//No one moves over time 0x101B 1 1
|
||||
//Smart pillow 0x101C 60 1
|
||||
//Formaldehyde (new) 0x101D
|
||||
|
||||
default: {
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Unknown MI pld"));
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Unknown MI pld type %x %s"), parsed->payload.type, tmp);
|
||||
res = 0;
|
||||
} break;
|
||||
}
|
||||
|
@ -2179,45 +2234,65 @@ void CmndMi32Block(void){
|
|||
}
|
||||
|
||||
void CmndMi32Option(void){
|
||||
bool onOff = atoi(XdrvMailbox.data);
|
||||
bool set = false;
|
||||
if (strlen(XdrvMailbox.data)){
|
||||
set = true;
|
||||
}
|
||||
int onOff = atoi(XdrvMailbox.data);
|
||||
switch(XdrvMailbox.index) {
|
||||
case 0:
|
||||
MI32.option.allwaysAggregate = onOff;
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
if (set){
|
||||
MI32.option.allwaysAggregate = onOff;
|
||||
} else {
|
||||
onOff = MI32.option.allwaysAggregate;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
MI32.option.noSummary = onOff;
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
if (set){
|
||||
MI32.option.noSummary = onOff;
|
||||
} else {
|
||||
onOff = MI32.option.noSummary;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
MI32.option.directBridgeMode = onOff;
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
if (set){
|
||||
MI32.option.directBridgeMode = onOff;
|
||||
} else {
|
||||
onOff = MI32.option.directBridgeMode;
|
||||
}
|
||||
break;
|
||||
case 4:{
|
||||
MI32.option.ignoreBogusBattery = onOff;
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
if (set){
|
||||
MI32.option.ignoreBogusBattery = onOff;
|
||||
} else {
|
||||
onOff = MI32.option.ignoreBogusBattery;
|
||||
}
|
||||
} break;
|
||||
case 5:{
|
||||
MI32.option.onlyAliased = onOff;
|
||||
if (MI32.option.onlyAliased){
|
||||
// discard all sensors for a restart
|
||||
MIBLEsensors.clear();
|
||||
if (set){
|
||||
MI32.option.onlyAliased = onOff;
|
||||
if (MI32.option.onlyAliased){
|
||||
// discard all sensors for a restart
|
||||
MIBLEsensors.clear();
|
||||
}
|
||||
} else {
|
||||
onOff = MI32.option.onlyAliased;
|
||||
}
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
} break;
|
||||
case 6:{
|
||||
MI32.option.MQTTType = onOff;
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
if (set){
|
||||
MI32.option.MQTTType = onOff;
|
||||
} else {
|
||||
onOff = MI32.option.MQTTType;
|
||||
}
|
||||
} break;
|
||||
default:{
|
||||
ResponseCmndIdxError();
|
||||
return;
|
||||
} break;
|
||||
|
||||
}
|
||||
ResponseCmndIdxError();
|
||||
ResponseCmndIdxNumber(onOff);
|
||||
return;
|
||||
}
|
||||
|
||||
void MI32KeyListResp(){
|
||||
|
@ -2325,6 +2400,7 @@ const char HTTP_EVENTS[] PROGMEM = "{s}%s Events{m}%u {e}";
|
|||
const char HTTP_NMT[] PROGMEM = "{s}%s No motion{m}> %u seconds{e}";
|
||||
const char HTTP_MI32_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%u us/cm{e}";
|
||||
const char HTTP_MI32_HL[] PROGMEM = "{s}<hr>{m}<hr>{e}";
|
||||
const char HTTP_MI32_LIGHT[] PROGMEM = "{s}%s" " Light" "{m}%d{e}";
|
||||
|
||||
//const char HTTP_NEEDKEY[] PROGMEM = "{s}%s <a target=\"_blank\" href=\""
|
||||
// "https://atc1441.github.io/TelinkFlasher.html?mac=%s&cb=http%%3A%%2F%%2F%s%%2Fmikey"
|
||||
|
@ -2417,6 +2493,12 @@ void MI32GetOneSensorJson(int slot, int hidename){
|
|||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
|
||||
const char *alias = BLE_ESP32::getAlias(p->MAC);
|
||||
if (alias && alias[0]){
|
||||
ResponseAppend_P(PSTR("\"alias\":\"%s\","),
|
||||
alias);
|
||||
}
|
||||
|
||||
ResponseAppend_P(PSTR("\"mac\":\"%02x%02x%02x%02x%02x%02x\""),
|
||||
p->MAC[0], p->MAC[1], p->MAC[2],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
|
@ -2475,6 +2557,15 @@ void MI32GetOneSensorJson(int slot, int hidename){
|
|||
}
|
||||
}
|
||||
}
|
||||
if (p->feature.light){
|
||||
if(p->eventType.light || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
||(hass_mode==2)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
){
|
||||
ResponseAppend_P(PSTR(",\"Light\":%d"), p->light);
|
||||
}
|
||||
}
|
||||
if (p->feature.moist){
|
||||
if(p->eventType.moist || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){
|
||||
if (p->moisture!=0xff
|
||||
|
@ -2504,12 +2595,12 @@ void MI32GetOneSensorJson(int slot, int hidename){
|
|||
}
|
||||
}
|
||||
if (p->feature.Btn){
|
||||
if(p->eventType.Btn
|
||||
if(p->eventType.Btn || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
||(hass_mode==2)
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
){
|
||||
ResponseAppend_P(PSTR(",\"Btn\":%u"),p->Btn);
|
||||
ResponseAppend_P(PSTR(",\"Btn\":%d"),p->Btn);
|
||||
}
|
||||
}
|
||||
if(p->eventType.PairBtn && p->pairing){
|
||||
|
@ -2685,14 +2776,74 @@ const char MI_HA_DISCOVERY_TEMPLATE[] PROGMEM =
|
|||
"\"model\":\"%s\","
|
||||
"\"via_device\":\"%s\""
|
||||
"},"
|
||||
"\"dev_cla\":\"%s\","
|
||||
"%s%s%s"
|
||||
"\"expire_after\":600,"
|
||||
"\"json_attr_t\":\"%s\","
|
||||
"\"name\":\"%s_%s\","
|
||||
"\"state_topic\":\"%s\","
|
||||
"\"uniq_id\":\"%s_%s\","
|
||||
"\"unit_of_meas\":\"%s\","
|
||||
"\"val_tpl\":\"{{ value_json.%s }}\"}";
|
||||
"%s%s%s"
|
||||
"\"val_tpl\":\"{{ %s%s%s }}\"}";
|
||||
|
||||
// careful - a missing comma causes a crash!!!!
|
||||
// because of the way we loop?
|
||||
const char *classes[] = {
|
||||
// 0
|
||||
"temperature",
|
||||
"Temperature",
|
||||
"°C",
|
||||
|
||||
// 1
|
||||
"humidity",
|
||||
"Humidity",
|
||||
"%",
|
||||
|
||||
// 2
|
||||
"temperature",
|
||||
"DewPoint",
|
||||
"°C",
|
||||
|
||||
// 3
|
||||
"battery",
|
||||
"Battery",
|
||||
"%",
|
||||
|
||||
// 4
|
||||
"signal_strength",
|
||||
"RSSI",
|
||||
"dB",
|
||||
|
||||
// 5
|
||||
"",//- empty device class
|
||||
"Btn",
|
||||
"",
|
||||
|
||||
// 6
|
||||
"", //- empty device class
|
||||
"Light",
|
||||
"",
|
||||
|
||||
// 7
|
||||
"", //- empty device class
|
||||
"Moisture",
|
||||
"",
|
||||
|
||||
// 8
|
||||
"", //- empty device class
|
||||
"Illuminance",
|
||||
"",
|
||||
|
||||
// 9
|
||||
"", //- empty device class
|
||||
"Fertility",
|
||||
"",
|
||||
|
||||
// 10
|
||||
"", //- empty device class
|
||||
"Firmware",
|
||||
"",
|
||||
};
|
||||
|
||||
|
||||
void MI32DiscoveryOneMISensor(){
|
||||
// don't detect half-added ones here
|
||||
|
@ -2708,25 +2859,7 @@ void MI32DiscoveryOneMISensor(){
|
|||
p = &MIBLEsensors[MI32.mqttCurrentSingleSlot];
|
||||
|
||||
|
||||
// careful - a missing comma causes a crash!!!!
|
||||
// because of the way we loop?
|
||||
const char *classes[] = {
|
||||
"temperature",
|
||||
"Temperature",
|
||||
"°C",
|
||||
"humidity",
|
||||
"Humidity",
|
||||
"%",
|
||||
"temperature",
|
||||
"DewPoint",
|
||||
"°C",
|
||||
"battery",
|
||||
"Battery",
|
||||
"%",
|
||||
"signal_strength",
|
||||
"RSSI",
|
||||
"dB"
|
||||
};
|
||||
|
||||
|
||||
int datacount = (sizeof(classes)/sizeof(*classes))/3;
|
||||
|
||||
|
@ -2758,9 +2891,72 @@ void MI32DiscoveryOneMISensor(){
|
|||
if (!classes[i] || !classes[i+1] || !classes[i+2]){
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t isBinary = 0;
|
||||
|
||||
ResponseClear();
|
||||
|
||||
switch(i/3){
|
||||
case 0: // temp
|
||||
if (!p->feature.temp && !p->feature.tempHum){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 1:// hum
|
||||
if (!p->feature.hum && !p->feature.tempHum){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2: //dew
|
||||
if (!p->feature.tempHum && !(p->feature.temp && p->feature.hum)){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: //bat
|
||||
if (!p->feature.bat){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: //rssi - all
|
||||
break;
|
||||
|
||||
case 5: // button
|
||||
if (!p->feature.Btn){
|
||||
continue;
|
||||
}
|
||||
//isBinary = 2; // invert payload
|
||||
break;
|
||||
|
||||
case 6: // binary light sense
|
||||
if (!p->feature.light){
|
||||
continue;
|
||||
}
|
||||
//isBinary = 1;
|
||||
break;
|
||||
case 7: // moisture
|
||||
if (!p->feature.moist){
|
||||
continue;
|
||||
}
|
||||
//isBinary = 1;
|
||||
break;
|
||||
case 8: // lux
|
||||
if (!p->feature.lux){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 9: // fertility
|
||||
if (!p->feature.fert){
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 10: // firmware
|
||||
if (!p->feature.fert){ // Flora only
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],"manufacturer":"simon","model":"someBLEsensor","name":"TASBLEa4c1387fc1e1","sw_version":"0.0.0"},"dev_cla":"temperature","json_attr_t":"tele/tasmota_esp32/SENSOR","name":"TASLYWSD037fc1e1Temp","state_topic":"tele/tasmota_esp32/SENSOR","uniq_id":"Tasmotaa4c1387fc1e1temp","unit_of_meas":"°C","val_tpl":"{{ value_json.LYWSD037fc1e1.Temperature }}"}
|
||||
{"availability":[],"device":{"identifiers":["TasmotaBLEa4c1387fc1e1"],
|
||||
|
@ -2781,7 +2977,9 @@ void MI32DiscoveryOneMISensor(){
|
|||
//\"via_device\":\"%s\"
|
||||
host,
|
||||
//"\"dev_cla\":\"%s\","
|
||||
(classes[i][0]?"\"dev_cla\":\"":""),
|
||||
classes[i],
|
||||
(classes[i][0]?"\",":""),
|
||||
//"\"json_attr_t\":\"%s\"," - the topic the sensor publishes on
|
||||
SensorTopic,
|
||||
//"\"name\":\"%s_%s\"," - the name of this DATA
|
||||
|
@ -2791,14 +2989,26 @@ void MI32DiscoveryOneMISensor(){
|
|||
//"\"uniq_id\":\"%s_%s\"," - unique for this data,
|
||||
id, classes[i+1],
|
||||
//"\"unit_of_meas\":\"%s\"," - the measure of this type of data
|
||||
(classes[i+2][0]?"\"unit_of_meas\":\"":""),
|
||||
classes[i+2],
|
||||
//"\"val_tpl\":\"{{ value_json.%s }}") // e.g. Temperature
|
||||
classes[i+1]
|
||||
(classes[i+2][0]?"\",":""),
|
||||
//"\"val_tpl\":\"{{ %s%s }}") // e.g. Temperature
|
||||
// inverted binary - {{ 'off' if value_json.posn else 'on' }}
|
||||
// binary - {{ 'on' if value_json.posn else 'off' }}
|
||||
|
||||
((isBinary < 1)?"value_json.":
|
||||
((isBinary < 2)?"value_json.":"'off' if value_json.")
|
||||
),
|
||||
classes[i+1],
|
||||
((isBinary < 1)?"":
|
||||
((isBinary < 2)?"":" else 'on'")
|
||||
)
|
||||
|
||||
//
|
||||
);
|
||||
|
||||
sprintf(DiscoveryTopic, "homeassistant/sensor/%s/%s/config",
|
||||
id, classes[i+1]);
|
||||
sprintf(DiscoveryTopic, "homeassistant/%ssensor/%s/%s/config",
|
||||
(isBinary? "binary_":""), id, classes[i+1]);
|
||||
|
||||
MqttPublish(DiscoveryTopic);
|
||||
p->nextDiscoveryData++;
|
||||
|
@ -3013,6 +3223,10 @@ void MI32Show(bool json)
|
|||
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, typeName, p->lux);
|
||||
}
|
||||
}
|
||||
if (p->feature.light){
|
||||
WSContentSend_PD(HTTP_MI32_LIGHT, typeName, p->light);
|
||||
}
|
||||
|
||||
if(p->bat!=0x00){
|
||||
WSContentSend_PD(HTTP_BATTERY, typeName, p->bat);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue