mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-29 05:36:39 +00:00
HA discovery via MQTT for BLE MI sensor devices
This commit is contained in:
parent
688c0b1a9f
commit
f69f000354
@ -320,7 +320,7 @@ static void BLEGenNotifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, ui
|
||||
void BLEPostAdvert(ble_advertisment_t *Advertisment);
|
||||
static void BLEPostMQTTSeenDevices(int type);
|
||||
|
||||
static void BLEShow(bool json);
|
||||
static void BLEShowStats();
|
||||
static void BLEPostMQTT(bool json);
|
||||
static void BLEStartOperationTask();
|
||||
|
||||
@ -390,7 +390,7 @@ uint8_t BLEAliasListTrigger = 0;
|
||||
// triggers send for ALL operations known about
|
||||
uint8_t BLEPostMQTTTrigger = 0;
|
||||
int BLEMaxAge = 60*10; // 10 minutes
|
||||
int BLEAddressFilter = 3;
|
||||
int BLEAddressFilter = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
@ -2181,6 +2181,7 @@ static void BLEEverySecond(bool restart){
|
||||
|
||||
if (BLEPublishDevices){
|
||||
BLEPostMQTTSeenDevices(BLEPublishDevices);
|
||||
BLEShowStats();
|
||||
BLEPublishDevices = 0;
|
||||
}
|
||||
|
||||
@ -3209,26 +3210,15 @@ static void mainThreadOpCallbacks() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void BLEShow(bool json)
|
||||
{
|
||||
if (json){
|
||||
#ifdef BLE_ESP32_DEBUG
|
||||
if (BLEDebugMode > 0) AddLog_P(LOG_LEVEL_INFO,PSTR("BLE: show json %d"),json);
|
||||
#endif
|
||||
uint32_t totalCount = BLEAdvertisment.totalCount;
|
||||
uint32_t deviceCount = seenDevices.size();
|
||||
|
||||
ResponseAppend_P(PSTR(",\"BLE\":{\"scans\":%u,\"adverts\":%u,\"devices\":%u,\"resets\":%u}"), BLEScanCount, totalCount, deviceCount, BLEResets);
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
else {
|
||||
//WSContentSend_PD(HTTP_MI32, i+1,stemp,MIBLEsensors.size());
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
static void BLEShowStats(){
|
||||
uint32_t totalCount = BLEAdvertisment.totalCount;
|
||||
uint32_t deviceCount = seenDevices.size();
|
||||
ResponseTime_P(PSTR(""));
|
||||
ResponseAppend_P(PSTR(",\"BLE\":{\"scans\":%u,\"adverts\":%u,\"devices\":%u,\"resets\":%u}}"), BLEScanCount, totalCount, deviceCount, BLEResets);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR("BLE"), 0);
|
||||
}
|
||||
|
||||
|
||||
/*void BLEAliasMqttList(){
|
||||
ResponseTime_P(PSTR(",\"BLEAlias\":["));
|
||||
for (int i = 0; i < aliases.size(); i++){
|
||||
@ -3495,7 +3485,6 @@ bool Xdrv52(uint8_t function)
|
||||
result = DecodeCommand(BLE_ESP32::kBLE_Commands, BLE_ESP32::BLE_Commands);
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
BLE_ESP32::BLEShow(1);
|
||||
break;
|
||||
|
||||
// next second, we will publish to our MQTT topic.
|
||||
@ -3510,10 +3499,6 @@ bool Xdrv52(uint8_t function)
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer_on(PSTR("/" WEB_HANDLE_BLE), BLE_ESP32::HandleBleConfiguration);
|
||||
break;
|
||||
|
||||
case FUNC_WEB_SENSOR:
|
||||
BLE_ESP32::BLEShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
return result;
|
||||
|
@ -79,6 +79,7 @@ void MI32notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pD
|
||||
struct {
|
||||
uint16_t perPage = 4;
|
||||
uint8_t mqttCurrentSlot = 0;
|
||||
uint8_t mqttCurrentSingleSlot = 0;
|
||||
uint32_t period; // set manually in addition to TELE-period, is set to TELE-period after start
|
||||
int secondsCounter = 0; // counts up in MI32EverySecond to period
|
||||
int secondsCounter2 = 0; // counts up in MI32EverySecond to period
|
||||
@ -255,6 +256,8 @@ struct mi_sensor_t{
|
||||
uint8_t type; //MI_Flora = 1; MI_MI-HT_V1=2; MI_LYWSD02=3; MI_LYWSD03=4; MI_CGG1=5; MI_CGD1=6
|
||||
uint8_t needkey; // tells http to display needkey message with link
|
||||
uint8_t lastCnt; //device generated counter of the packet
|
||||
uint8_t nextDiscoveryData; // used to lkimit discovery to one MQTT per sec
|
||||
|
||||
uint8_t shallSendMQTT;
|
||||
uint8_t MAC[6];
|
||||
union {
|
||||
@ -1880,6 +1883,9 @@ void MI32EverySecond(bool restart){
|
||||
|
||||
MI32ShowSomeSensors();
|
||||
|
||||
MI32DiscoveryOneMISensor();
|
||||
MI32ShowOneMISensor();
|
||||
|
||||
// read a battery if
|
||||
// MI32.batteryreader.slot < filled and !MI32.batteryreader.active
|
||||
readOneBat();
|
||||
@ -1906,10 +1912,12 @@ void MI32EverySecond(bool restart){
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Kick off tele sending"));
|
||||
MI32.mqttCurrentSlot = 0;
|
||||
MI32.secondsCounter2 = 0;
|
||||
MI32.mqttCurrentSingleSlot = 0;
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: Hit tele time, restarted but not finished last - lost from slot %d")+MI32.mqttCurrentSlot);
|
||||
MI32.mqttCurrentSlot = 0;
|
||||
MI32.secondsCounter2 = 0;
|
||||
MI32.mqttCurrentSingleSlot = 0;
|
||||
}
|
||||
}
|
||||
MI32.secondsCounter2++;
|
||||
@ -2302,15 +2310,18 @@ void MI32TimeoutSensors(){
|
||||
|
||||
|
||||
// this assumes that we're adding to a ResponseTime_P
|
||||
void MI32GetOneSensorJson(int slot){
|
||||
void MI32GetOneSensorJson(int slot, int hidename){
|
||||
mi_sensor_t *p;
|
||||
p = &MIBLEsensors[slot];
|
||||
|
||||
ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
// remove hyphen - make it difficult to configure HASS
|
||||
if (!hidename) {
|
||||
ResponseAppend_P(PSTR("\"%s%02x%02x%02x\":{"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
|
||||
ResponseAppend_P(PSTR("\"MAC\":\"%02x%02x%02x%02x%02x%02x\""),
|
||||
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]);
|
||||
|
||||
@ -2449,7 +2460,9 @@ void MI32GetOneSensorJson(int slot){
|
||||
}
|
||||
if (MI32.option.showRSSI) ResponseAppend_P(PSTR(",\"RSSI\":%d"), p->RSSI);
|
||||
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
if (!hidename) {
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
}
|
||||
p->eventType.raw = 0;
|
||||
p->shallSendMQTT = 0;
|
||||
|
||||
@ -2486,7 +2499,8 @@ void MI32ShowSomeSensors(){
|
||||
ResponseTime_P(PSTR(""));
|
||||
int cnt = 0;
|
||||
for (; (MI32.mqttCurrentSlot < numsensors) && (cnt < 4); MI32.mqttCurrentSlot++, cnt++) {
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSlot);
|
||||
ResponseAppend_P(PSTR(","));
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSlot, 0);
|
||||
int mlen = strlen(TasmotaGlobal.mqtt_data);
|
||||
|
||||
// if we ran out of room, leave here.
|
||||
@ -2511,6 +2525,183 @@ void MI32ShowSomeSensors(){
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends ONE sensor on a dedicated topic NOT related to this TAS
|
||||
// triggered by setting MI32.mqttCurrentSingleSlot = 0
|
||||
void MI32ShowOneMISensor(){
|
||||
// don't detect half-added ones here
|
||||
int numsensors = MIBLEsensors.size();
|
||||
if (MI32.mqttCurrentSingleSlot >= numsensors){
|
||||
// if we got to the end of the sensors, then don't send more
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
if(Settings.flag.hass_discovery){
|
||||
|
||||
ResponseTime_P(PSTR(","));
|
||||
MI32GetOneSensorJson(MI32.mqttCurrentSingleSlot, 1);
|
||||
mi_sensor_t *p;
|
||||
p = &MIBLEsensors[MI32.mqttCurrentSingleSlot];
|
||||
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
|
||||
char idstr[32];
|
||||
const char *alias = BLE_ESP32::getAlias(p->MAC);
|
||||
const char *id = idstr;
|
||||
if (alias && *alias){
|
||||
id = alias;
|
||||
} else {
|
||||
sprintf(idstr, PSTR("%s%02x%02x%02x"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
char SensorTopic[60];
|
||||
sprintf(SensorTopic, "tele/tasmota_ble/%s",
|
||||
id);
|
||||
|
||||
MqttPublish(SensorTopic);
|
||||
//AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: %s: show some %d %s"),D_CMND_MI32, MI32.mqttCurrentSlot, TasmotaGlobal.mqtt_data);
|
||||
}
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
MI32.mqttCurrentSingleSlot++;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends ONE sensor's worth of HA discovery msg
|
||||
#define MI_HA_DISCOVERY_TEMPLATE PSTR("{\"availability\":[],\"device\": \
|
||||
{\"identifiers\":[\"BLE%s\"],\
|
||||
\"name\":\"%s\",\
|
||||
\"manufacturer\":\"tas\",\
|
||||
\"model\":\"%s\",\
|
||||
\"via_device\":\"%s\"\
|
||||
}, \
|
||||
\"dev_cla\":\"%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 }}\"}")
|
||||
void MI32DiscoveryOneMISensor(){
|
||||
// don't detect half-added ones here
|
||||
int numsensors = MIBLEsensors.size();
|
||||
if (MI32.mqttCurrentSingleSlot >= numsensors){
|
||||
// if we got to the end of the sensors, then don't send more
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_HOME_ASSISTANT
|
||||
if(Settings.flag.hass_discovery){
|
||||
mi_sensor_t *p;
|
||||
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;
|
||||
|
||||
if (p->nextDiscoveryData >= datacount){
|
||||
p->nextDiscoveryData = 0;
|
||||
}
|
||||
|
||||
//int i = p->nextDiscoveryData*3;
|
||||
for (int i = 0; i < datacount*3; i += 3){
|
||||
if (!classes[i] || !classes[i+1] || !classes[i+2]){
|
||||
return;
|
||||
}
|
||||
|
||||
char idstr[32];
|
||||
const char *alias = BLE_ESP32::getAlias(p->MAC);
|
||||
const char *id = idstr;
|
||||
if (alias && *alias){
|
||||
id = alias;
|
||||
} else {
|
||||
sprintf(idstr, PSTR("%s%02x%02x%02x"),
|
||||
kMI32DeviceType[p->type-1],
|
||||
p->MAC[3], p->MAC[4], p->MAC[5]);
|
||||
}
|
||||
|
||||
char SensorTopic[60];
|
||||
sprintf(SensorTopic, "tele/tasmota_ble/%s",
|
||||
id);
|
||||
|
||||
|
||||
ResponseClear();
|
||||
|
||||
/*
|
||||
{"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"],
|
||||
"name":"TASBLEa4c1387fc1e1"},"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 }}"}
|
||||
*/
|
||||
|
||||
ResponseAppend_P(MI_HA_DISCOVERY_TEMPLATE,
|
||||
//"{\"identifiers\":[\"BLE%s\"],"
|
||||
id,
|
||||
//"\"name\":\"%s\"},"
|
||||
id,
|
||||
//\"model\":\"%s\",
|
||||
kMI32DeviceType[p->type-1],
|
||||
//\"via_device\":\"%s\"
|
||||
NetworkHostname(),
|
||||
//"\"dev_cla\":\"%s\","
|
||||
classes[i],
|
||||
//"\"json_attr_t\":\"%s\"," - the topic the sensor publishes on
|
||||
SensorTopic,
|
||||
//"\"name\":\"%s_%s\"," - the name of this DATA
|
||||
id, classes[i+1],
|
||||
//"\"state_topic\":\"%s\"," - the topic the sensor publishes on?
|
||||
SensorTopic,
|
||||
//"\"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],
|
||||
//"\"val_tpl\":\"{{ value_json.%s }}") // e.g. Temperature
|
||||
classes[i+1]
|
||||
//
|
||||
);
|
||||
|
||||
char DiscoveryTopic[80];
|
||||
sprintf(DiscoveryTopic, "homeassistant/sensor/%s/%s/config",
|
||||
id, classes[i+1]);
|
||||
|
||||
MqttPublish(DiscoveryTopic);
|
||||
p->nextDiscoveryData++;
|
||||
//vTaskDelay(100/ portTICK_PERIOD_MS);
|
||||
}
|
||||
} // end if hass discovery
|
||||
//AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: %s: show some %d %s"),D_CMND_MI32, MI32.mqttCurrentSlot, TasmotaGlobal.mqtt_data);
|
||||
#endif //USE_HOME_ASSISTANT
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// starts a completely fresh MQTT message.
|
||||
// sends up to 4 sensors pe5r msg
|
||||
@ -2535,7 +2726,8 @@ void MI32ShowTriggeredSensors(){
|
||||
if(p->shallSendMQTT==0) continue;
|
||||
|
||||
cnt++;
|
||||
MI32GetOneSensorJson(sensor);
|
||||
ResponseAppend_P(PSTR(","));
|
||||
MI32GetOneSensorJson(sensor, 0);
|
||||
int mlen = strlen(TasmotaGlobal.mqtt_data);
|
||||
|
||||
// if we ran out of room, leave here.
|
||||
|
Loading…
x
Reference in New Issue
Block a user