Merge pull request #11161 from btsimonh/MI_Updates2021

Align protocol interpretation with MI docs (16 bit payload type).
This commit is contained in:
Theo Arends 2021-03-01 11:10:59 +01:00 committed by GitHub
commit e83481721e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 316 additions and 102 deletions

View File

@ -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);
}