Refactor BLE gateways (#617)

* Refactor BLE gateways:
-merge HM10 and ESP32 code
-publish sensor values with the other BLE device parameters to avoid MQTT multiple publication
-make uniform the case of mac adress id between HM10 and ESP32
-add the possibility to remove service data publishing either when sensors is recognised or not
-correct manufacturing data display
-merge process cleargrass methods
-check service data validity before processing
This commit is contained in:
Florian authored and GitHub committed 2020-06-05 08:09:49 -05:00
1 parent ac4f6b74c2
commit 661ef9c55e
5 files changed
+290 -401

No files matched your search

+5 -2
View File
@@ -17,13 +17,16 @@ OpenMQTTGateway is able to scan all the BLE devices that advertise their data so
|-|:-:|:-:|
| BLE watches with fixed mac||rssi for presence detection|
| BLE beacons keychains||rssi for presence detection|
| XIAOMI Mi Flora ||temperature/moisture/luminance/fertility|
| Vegtrug ||temperature/moisture/luminance/fertility|
| XIAOMI Mi Flora |HHCCJCY01HHCC|temperature/moisture/luminance/fertility|
| XIAOMI Mi Jia |LYWSDCGO|temperature/humidity/battery|
| XIAOMI Mi Lamp |MUE4094RT|presence|
| ClearGrass |CGG1|temperature/humidity/battery|
| ClearGrass alarm clock|CGD1|temperature/humidity|
| ClearGrass with atmospheric pressure |CGP1W|temperature/humidity/air pressure|
| Clock |LYWDS02|temperature/humidity|
| XIAOMI Mi Scale ||weight|
| XIAOMI Mi Scale v1|XMTZC04HM|weight|
| XIAOMI Mi Scale v2|XMTZC05HM|weight|
| XIAOMI Mi band ||steps|
+8
View File
@@ -39,6 +39,9 @@ Note that the gateway return one or two measurement value each time. The differe
* Temperature
* Moisture
* Fertilization
* Humidity
* Pressure
* Steps
* Weight
* Impedance
* Battery (mi jia only)
@@ -49,6 +52,11 @@ The infos will appear like this on your MQTT broker:
More info are available on [my blog](https://1technophile.blogspot.fr/2017/11/mi-flora-integration-to-openmqttgateway.html) (especially about how it was implemented with HM10)
::: tip
The HM10 module doesn't read enough information (servicedata UUID is missing) to support Mi Scale and Mi Band. They are supported nevertheless with ESP32.
OpenMQTTGateway publish the servicedata field of your BLE devices, with HM10 this field can be longer compared to ESP32 if the device is not recognised.
:::
## Setting a white or black list
A black list is a list of mac adresses that will never be published by OMG
to set black list
+265 -388
View File
@@ -51,6 +51,8 @@ static bool oneWhite = false;
BLEdevice * getDeviceByMac(const char *mac)
{
Log.trace(F("getDeviceByMac %s" CR), mac);
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
{
if ((strcmp(p->macAdr, mac) == 0))
@@ -63,6 +65,7 @@ BLEdevice * getDeviceByMac(const char *mac)
bool updateWorB(JsonObject &BTdata, bool isWhite)
{
Log.trace(F("update WorB" CR));
const char* jsonKey = isWhite ? "white-list" : "black-list";
int size = BTdata[jsonKey].size();
@@ -327,14 +330,13 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
String mac_adress = advertisedDevice.getAddress().toString().c_str();
mac_adress.toUpperCase();
BLEdata.set("id", (char *)mac_adress.c_str());
mac_adress.replace(":", "");
mac_adress.toUpperCase();
String mactopic = subjectBTtoMQTT + String("/") + mac_adress;
char mac[mac_adress.length() + 1];
mac_adress.toCharArray(mac, mac_adress.length() + 1);
Log.notice(F("Device detected: %s" CR),mac);
Log.notice(F("Device detected: %s" CR), mac);
BLEdevice *device = getDeviceByMac(mac);
if ((!oneWhite || isWhite(device)) && !isBlack(device))
@@ -343,7 +345,11 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
BLEdata.set("name", (char *)advertisedDevice.getName().c_str());
#if pubBLEManufacturerData
if (advertisedDevice.haveManufacturerData())
BLEdata.set("manufacturerdata", (char *)advertisedDevice.getManufacturerData().c_str());
{
char* manufacturerdata = BLEUtils::buildHexData(NULL, (uint8_t*)advertisedDevice.getManufacturerData().data(), advertisedDevice.getManufacturerData().length());
Log.trace(F("Manufacturer Data: %s" CR), manufacturerdata);
BLEdata.set("manufacturerdata", manufacturerdata);
}
#endif
if (advertisedDevice.haveRSSI())
BLEdata.set("rssi", (int)advertisedDevice.getRSSI());
@@ -356,7 +362,7 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
if (advertisedDevice.haveServiceData())
{
int serviceDataCount = advertisedDevice.getServiceDataCount();
Log.trace(F("Get services data number: %d" CR),serviceDataCount);
Log.trace(F("Get services data number: %d" CR), serviceDataCount);
for (int j = 0; j < serviceDataCount; j++)
{
std::string serviceData = advertisedDevice.getServiceData(j);
@@ -374,163 +380,17 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
char service_data[returnedString.length() + 1];
returnedString.toCharArray(service_data, returnedString.length() + 1);
service_data[returnedString.length()] = '\0';
Log.notice(F("Service data: %s" CR),service_data);
#ifdef pubBLEServiceData
Log.trace(F("Service data: %s" CR), service_data);
BLEdata.set("servicedata", service_data);
#endif
BLEdata.set("servicedatauuid", (char *)advertisedDevice.getServiceDataUUID(j).toString().c_str());
if (abs((int)BLEdata["rssi"] | 0) < abs(Minrssi))
{ // publish only the devices close enough
pub((char *)mactopic.c_str(), BLEdata);
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "fe95") != NULL)
{ //Mi FLora, Mi jia, Cleargrass Method 1, LYWSD02, VegTrug
Log.trace(F("Processing BLE device data" CR));
int pos = -1;
pos = strpos(service_data, "209800");
if (pos != -1)
{
Log.trace(F("mi flora data reading" CR));
//example "servicedata":"71209800bc63b6658d7cc40d0910023200"
if (!isDiscovered(device))
MiFloraDiscovery(mac);
process_sensors(pos - 24, service_data, mac);
}
pos = -1;
pos = strpos(service_data, "20bc03");
if (pos != -1)
{
Log.trace(F("vegtrug data reading" CR));
//example "servicedata":"7120bc0399c309688d7cc40d0910020000"
if (!isDiscovered(device))
VegTrugDiscovery(mac);
process_sensors(pos - 24, service_data, mac);
}
pos = -1;
pos = strpos(service_data, "20aa01");
if (pos != -1)
{
Log.trace(F("mi jia data reading" CR));
if (!isDiscovered(device))
MiJiaDiscovery(mac);
process_sensors(pos - 26, service_data, mac);
}
pos = -1;
pos = strpos(service_data, "205b04");
if (pos != -1)
{
Log.trace(F("LYWSD02 data reading" CR));
//example "servicedata":"70205b04b96ab883c8593f09041002e000"
if (!isDiscovered(device))
LYWSD02Discovery(mac);
process_sensors(pos - 24, service_data, mac);
}
pos = -1;
pos = strpos(service_data, "304703");
if (pos != -1)
{
Log.trace(F("ClearGrass T RH data reading method 1" CR));
//example "servicedata":"5030470340743e10342d58041002d6000a100164"
if (!isDiscovered(device))
CLEARGRASSTRHDiscovery(mac);
process_sensors(pos - 26, service_data, mac);
}
pos = -1;
pos = strpos(service_data, "4030dd");
if (pos != -1)
{
Log.trace(F("Mi Lamp data reading" CR));
//example "servicedata":4030DD031D0300010100
if (!isDiscovered(device))
MiLampDiscovery(mac);
process_milamp(service_data, mac);
}
}
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "181d") != NULL)
{ // Mi Scale V1
Log.trace(F("Mi Scale V1 data reading" CR));
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
if (!isDiscovered(device))
MiScaleDiscovery(mac);
process_scale_v1(service_data, mac);
}
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "181b") != NULL)
{ // Mi Scale V2
Log.trace(F("Mi Scale V2 data reading" CR));
//example "servicedata":02c4e1070b1e13050c00002607 / 02a6e20705150a251df401443e /02a6e20705180c0d04d701943e
if (!isDiscovered(device))
MiScaleDiscovery(mac);
process_scale_v2(service_data, mac);
}
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "fee0") != NULL)
{ // Mi Band //0000fee0-0000-1000-8000-00805f9b34fb // ESP32 only
Log.trace(F("Mi Band data reading" CR));
//example "servicedata":a21e0000
if (!isDiscovered(device))
MiBandDiscovery(mac);
process_miband(service_data, mac);
}
if (strstr(BLEdata["servicedata"].as<char *>(), "08094c") != NULL)
{ // Clear grass with air pressure//08094c0140342d580104d8000c020702612702015a
Log.trace(F("Clear grass data with air pressure reading" CR));
//example "servicedata":08094c0140342d580104 c400 2402 0702 5d27 02015a
if (!isDiscovered(device))
CLEARGRASSTRHKPADiscovery(mac);
process_cleargrass_air(service_data, mac);
}
if (strstr(BLEdata["servicedata"].as<char *>(), "080774") != NULL)
{ // Clear grass standard method 2/0807743e10342d580104c3002c0202012a
Log.trace(F("Clear grass data reading method 2" CR));
//example "servicedata":0807743e10342d580104 c300 2c02 02012a
// no discovery as it is already available with method 1
process_cleargrass(service_data, mac);
}
if (strstr(BLEdata["servicedata"].as<char *>(), "080caf") != NULL)
{ // Clear grass CGD1 080caffd50342d580104c900a102
Log.trace(F("Clear grass CGD1 data reading" CR));
//example "servicedata":080caffd50342d580104 c900 a102
if (!isDiscovered(device))
CLEARGRASSCGD1Discovery(mac);
process_cleargrass(service_data, mac);
}
}
else
{
Log.trace(F("Low rssi, device filtered" CR));
}
std::string serviceDatauuid = advertisedDevice.getServiceDataUUID(j).toString();
Log.trace(F("Service data UUID: %s" CR), (char *)serviceDatauuid.c_str());
BLEdata.set("servicedatauuid", (char *)serviceDatauuid.c_str());
PublishDeviceData(BLEdata);
}
}
else
{
if (abs((int)BLEdata["rssi"] | 0) < abs(Minrssi))
{ // publish only the devices close enough
pub((char *)mactopic.c_str(), BLEdata); // publish device even if there is no service data
}
else
{
Log.trace(F("Low rssi, device filtered" CR));
}
PublishDeviceData(BLEdata); // publish device even if there is no service data
}
}
else
@@ -542,7 +402,6 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
void BLEscan()
{
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed = 1;
TIMERG0.wdt_wprotect = 0;
@@ -673,14 +532,14 @@ String returnedString = "";
unsigned long timebt = 0;
// this struct define which parts of the hexadecimal chain we extract and what to do with these parts
struct decompose d[6] = {{"mac", 16, 12, true}, {"typ", 28, 2, false}, {"rsi", 30, 2, false}, {"rdl", 32, 2, false}, {"sty", 44, 4, true}, {"rda", 34, 60, false}};
struct decompose d[6] = {{"mac", 16, 12, true}, {"typ", 28, 2, false}, {"rsi", 30, 2, false}, {"rdl", 32, 2, false}, {"sty", 44, 4, true}, {"rda", 56, 60, false}};
void setupBT()
{
BLEinterval = TimeBtw_Read;
Minrssi = MinimumRSSI;
Log.notice(F("BLEinterval: %d" CR),BLEinterval);
Log.notice(F("Minrssi: %d" CR),Minrssi);
Log.notice(F("BLEinterval: %d" CR), BLEinterval);
Log.notice(F("Minrssi: %d" CR), Minrssi);
softserial.begin(HMSerialSpeed);
softserial.print(F("AT+ROLE1" CR));
delay(100);
@@ -709,13 +568,14 @@ bool BTtoMQTT()
}
if (millis() > (timebt + BLEinterval))
{ //retriving data
{ //retrieving data
timebt = millis();
#if defined(ESP8266)
yield();
#endif
if (returnedString != "")
{
Log.verbose(F("returnedString: %s" CR), (char *)returnedString.c_str());
size_t pos = 0;
while ((pos = returnedString.lastIndexOf(BLEdelimiter)) != -1)
{
@@ -726,9 +586,9 @@ bool BTtoMQTT()
returnedString.remove(pos, returnedString.length());
char token_char[token.length() + 1];
token.toCharArray(token_char, token.length() + 1);
Log.trace(F("Token: %s" CR),token_char);
Log.trace(F("Token: %s" CR), token_char);
if (token.length() > 60)
{ // we extract data only if we have detailled infos
{ // we extract data only if we have infos (BLEdelimiter length + 4)
for (int i = 0; i < 6; i++)
{
extract_char(token_char, d[i].extract, d[i].start, d[i].len, d[i].reverse, false);
@@ -736,7 +596,7 @@ bool BTtoMQTT()
d[5].len = (int)strtol(d[i].extract, NULL, 16) * 2; // extracting the length of the rest data
}
if ((strlen(d[0].extract)) == 12) // if a mac adress is detected we publish it
if ((strlen(d[0].extract)) == 12) // if a BLE device is detected we analyse it
{
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
@@ -760,130 +620,14 @@ bool BTtoMQTT()
Log.trace(F("HomePresenceId %s" CR),(char *)HomePresenceId.c_str());
BLEdata.set("id", (char *)HomePresenceId.c_str());
#endif
String topic = subjectBTtoMQTT + String("/") + String(d[0].extract);
int rssi = (int)strtol(d[2].extract, NULL, 16) - 256;
BLEdata.set("rssi", (int)rssi);
#ifdef subjectHomePresence
haRoomPresence(BLEdata); // this device has an rssi in consequence we can use it for home assistant room presence component
#endif
String service_data(d[5].extract);
Log.notice(F("Service data: %s" CR),d[5].extract);
service_data = service_data.substring(14);
#ifdef pubBLEServiceData
BLEdata.set("servicedata", (char *)service_data.c_str());
#endif
if (abs((int)BLEdata["rssi"] | 0) < abs(Minrssi))
{ // publish only the devices close enough
pub((char *)topic.c_str(), BLEdata);
int pos = -1;
pos = strpos(d[5].extract, "209800");
if (pos != -1)
{
Log.trace(F("mi flora data reading" CR));
if (!isDiscovered(device))
MiFloraDiscovery(d[0].extract);
bool result = process_sensors(pos - 38, (char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "20aa01");
//example "servicedata":"5020aa0194dfaa33342d580d1004e3002c02"
if (pos != -1)
{
Log.trace(F("mi jia data reading" CR));
if (!isDiscovered(device))
MiJiaDiscovery(d[0].extract);
bool result = process_sensors(pos - 40, (char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "205b04");
//example "servicedata":"141695fe70205b0461298882c8593f09061002d002"
if (pos != -1)
{
Log.trace(F("LYWSD02 data reading" CR));
if (!isDiscovered(device))
LYWSD02Discovery(d[0].extract);
bool result = process_sensors(pos - 38, (char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "304703");
if (pos != -1)
{
Log.trace(F("CLEARGRASSTRH data reading method 1" CR));
if (!isDiscovered(device))
CLEARGRASSTRHDiscovery(d[0].extract);
bool result = process_sensors(pos - 40, (char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "e30706");
if (pos != -1)
{
Log.trace(F("Mi Scale data reading" CR));
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
if (!isDiscovered(device))
MiScaleDiscovery(d[0].extract);
bool result = process_scale_v1((char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "4030dd");
if (pos != -1)
{
Log.trace(F("Mi Lamp data reading" CR));
//example "servicedata":4030dd31d0300010100
if (!isDiscovered(device))
MiLampDiscovery(d[0].extract);
process_milamp((char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "08094c"); // Clear grass with air pressure//08094c0140342d580104d8000c020702612702015a
if (pos != -1)
{
Log.trace(F("Clear grass data with air pressure reading" CR));
//example "servicedata":08094c0140342d580104 c400 2402 0702 5d27 02015a
if (!isDiscovered(device))
CLEARGRASSTRHKPADiscovery(d[0].extract);
process_cleargrass_air((char *)service_data.c_str(), d[0].extract);
}
pos = -1;
pos = strpos(d[5].extract, "080774"); // Clear grass standard method 2/0807743e10342d580104c3002c0202012a
if (pos != -1)
{
Log.trace(F("Clear grass data reading method 2" CR));
//example "servicedata":0807743e10342d580104 c300 2c02 02012a
// no discovery as it is already available with method 1
process_cleargrass((char *)service_data.c_str(), d[0].extract);
}
pos = strpos(d[5].extract, "080caf"); // Clear grass CGD1 08094c0140342d580104d8000c020702612702015a
if (pos != -1)
{
Log.trace(F("Clear grass data CGD1" CR));
//example "servicedata":080caffd50342d580104 c900 a102
if (!isDiscovered(device))
CLEARGRASSCGD1Discovery(d[0].extract);
process_cleargrass((char *)service_data.c_str(), d[0].extract);
}
return true;
}
else
{
Log.trace(F("Low rssi, device filtered" CR));
}
Log.trace(F("Service data: %s" CR), d[5].extract);
BLEdata.set("servicedata", d[5].extract);
PublishDeviceData(BLEdata);
}
}
}
@@ -900,7 +644,15 @@ bool BTtoMQTT()
}
#endif
double value_from_service_data(char *service_data, int offset, int data_length)
void RemoveJsonPropertyIf(JsonObject &obj, char* key, bool condition)
{
if(condition){
Log.trace(F("Removing %s" CR), key);
obj.remove(key);
}
}
double value_from_service_data(const char *service_data, int offset, int data_length)
{
char rev_data[data_length + 1];
char data[data_length + 1];
@@ -916,35 +668,219 @@ double value_from_service_data(char *service_data, int offset, int data_length)
return value;
}
bool process_sensors(int offset, char *rest_data, char *mac_adress)
boolean valid_service_data(const char * data)
{
int size = strlen(data);
for (int i = 0; i < size; ++i) {
if(data[i] != 48) // 48 correspond to 0 in ASCII table
return true;
}
return false;
}
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
void launch_discovery(JsonObject &BLEdata, char * mac){
BLEdevice *device = getDeviceByMac(mac);
if (!isDiscovered(device) && BLEdata.containsKey("model"))
{
Log.trace(F("Launching discovery of %s" CR), mac);
if(strcmp(BLEdata["model"].as<const char*>(), "HHCCJCY01HHCC") == 0) MiFloraDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "VegTrug") == 0) VegTrugDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "LYWSDCGQ") == 0) MiJiaDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "LYWSD02") == 0) LYWSD02Discovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "CGG1") == 0) CLEARGRASSTRHDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "CGP1W") == 0) CLEARGRASSTRHKPADiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "MUE4094RT") == 0) MiLampDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "CGD1") == 0) CLEARGRASSCGD1Discovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "MiBand") == 0) MiBandDiscovery(mac);
if(strcmp(BLEdata["model"].as<const char*>(), "XMTZC04HM") == 0 ||
strcmp(BLEdata["model"].as<const char*>(), "XMTZC05HM") == 0) MiScaleDiscovery(mac);
}
else
{
Log.trace(F("Device already discovered or model not detected" CR));
}
}
void PublishDeviceData(JsonObject &BLEdata)
{
if (abs((int)BLEdata["rssi"] | 0) < abs(Minrssi))
{ // process only the devices close enough
JsonObject &BLEdataOut = process_bledata(BLEdata);
String mac_adress = BLEdataOut["id"].as<const char*>();
mac_adress.replace(":", "");
char mac[mac_adress.length() + 1];
mac_adress.toCharArray(mac, mac_adress.length() + 1);
#ifdef ZmqttDiscovery
launch_discovery(BLEdataOut, mac);
#endif
#if !pubBLEServiceUUID
RemoveJsonPropertyIf(BLEdataOut, "servicedatauuid", BLEdataOut.containsKey("servicedatauuid"));
#endif
#if !pubKnownBLEServiceData
RemoveJsonPropertyIf(BLEdataOut, "servicedata", BLEdataOut.containsKey("model") && BLEdataOut.containsKey("servicedata"));
#endif
String mactopic(mac);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdataOut);
}
else
{
Log.trace(F("Low rssi, device filtered" CR));
}
}
JsonObject& process_bledata(JsonObject &BLEdata){
if(BLEdata.containsKey("servicedata"))
{
Log.trace(F("Checking BLE service data validity" CR));
const char * service_data = (const char *)(BLEdata["servicedata"]|"");
if(valid_service_data(service_data))
{
Log.trace(F("Searching BLE device data %s size %d" CR), service_data, strlen(service_data));
Log.trace(F("Is it a mi flora ?" CR));
if (strstr(service_data, "209800") != NULL)
{
Log.trace(F("mi flora data reading" CR));
BLEdata.set("model", "HHCCJCY01HHCC");
return process_sensors(2, BLEdata);
}
Log.trace(F("Is it a vegtrug ?" CR));
if (strstr(service_data, "20bc03") != NULL && strlen(service_data) > ServicedataMinLength)
{
Log.trace(F("vegtrug data reading" CR));
BLEdata.set("model", "VegTrug");
return process_sensors(2, BLEdata);
}
Log.trace(F("Is it a LYWSDCGQ?" CR));
if (strstr(service_data, "20aa01") != NULL && strlen(service_data) > ServicedataMinLength)
{
Log.trace(F("LYWSDCGQ data reading" CR));
BLEdata.set("model", "LYWSDCGQ");
return process_sensors(0, BLEdata);
}
Log.trace(F("Is it a LYWSD02?" CR));
if (strstr(service_data, "205b04") != NULL && strlen(service_data) > ServicedataMinLength)
{
Log.trace(F("LYWSD02 data reading" CR));
BLEdata.set("model", "LYWSD02");
return process_sensors(2, BLEdata);
}
Log.trace(F("Is it a CGG1?" CR));
if (strstr(service_data, "304703") != NULL && strlen(service_data) > ServicedataMinLength)
{
Log.trace(F("CGG1 data reading method 1" CR));
BLEdata.set("model", "CGG1");
return process_sensors(0, BLEdata);
}
Log.trace(F("Is it a MUE4094RT?" CR));
if (strstr(service_data, "4030dd") != NULL)
{
Log.trace(F("MUE4094RT data reading" CR));
BLEdata.set("model", "MUE4094RT");
return process_milamp(BLEdata);
}
Log.trace(F("Is it a CGP1W?" CR));
if (strstr(service_data, "08094c") != NULL && strlen(service_data) > ServicedataMinLength)
{
Log.trace(F("CGP1W data reading" CR));
BLEdata.set("model", "CGP1W");
return process_cleargrass(BLEdata, true);
}
Log.trace(F("Is it a CGG1" CR));
if (strstr(service_data, "080774") != NULL)
{
Log.trace(F("CGG1 method 2" CR));
BLEdata.set("model", "CGG1");
// no discovery as it is already available with method 1
return process_cleargrass(BLEdata, false);
}
Log.trace(F("Is it a CGD1?" CR));
if ((strstr(service_data, "080caf") != NULL || strstr(service_data, "080c09") != NULL)
&& (strlen(service_data) > ServicedataMinLength))
{
Log.trace(F("CGD1 data reading" CR));
BLEdata.set("model", "CGD1");
return process_cleargrass(BLEdata, false);
}
if(BLEdata.containsKey("servicedatauuid"))
{
const char * service_datauuid = (const char *)(BLEdata["servicedatauuid"]|"");
Log.trace(F("servicedatauuid %s" CR), service_datauuid);
Log.trace(F("Is it a MiBand?" CR));
if (strstr(service_datauuid, "fee0") != NULL)
{
Log.trace(F("Mi Band data reading" CR));
BLEdata.set("model", "MiBand");
return process_miband(BLEdata);
}
Log.trace(F("Is it a XMTZC04HM?" CR));
if (strstr(service_datauuid, "181d") != NULL)
{
Log.trace(F("XMTZC04HM data reading" CR));
BLEdata.set("model", "XMTZC04HM");
return process_scale_v1(BLEdata);
}
Log.trace(F("Is it a XMTZC05HM?" CR));
if (strstr(service_datauuid, "181b") != NULL)
{
Log.trace(F("XMTZC05HM data reading" CR));
BLEdata.set("model", "XMTZC05HM");;
return process_scale_v2(BLEdata);
}
}
}
else
{
Log.trace(F("Non valid service data, removing it" CR));
BLEdata.remove("servicedata");
}
#if !pubUnknownBLEServiceData
Log.trace(F("Unknown service data, removing it" CR));
BLEdata.remove("servicedata");
#endif
}
return BLEdata;
}
JsonObject& process_sensors(int offset, JsonObject &BLEdata)
{
const char * servicedata = BLEdata["servicedata"].as<const char *>();
int data_length = 0;
switch (rest_data[51 + offset])
switch (servicedata[27 + offset])
{
case '1':
case '2':
case '3':
case '4':
data_length = ((rest_data[51 + offset] - '0') * 2);
data_length = ((servicedata[27 + offset] - '0') * 2);
Log.trace(F("Valid data_length: %d" CR), data_length);
break;
default:
Log.trace(F("Invalid data_length" CR));
return false;
Log.trace(F("Invalid data_length, not enriching the device data" CR));
return BLEdata;
}
double value = 9999;
value = value_from_service_data(rest_data, 52 + offset, data_length);
value = value_from_service_data(servicedata, 28 + offset, data_length);
// Mi flora provides tem(perature), (earth) moi(sture), fer(tility) and lux (illuminance)
// Mi Jia provides tem(perature), batt(erry) and hum(idity)
// following the value of digit 47 we determine the type of data we get from the sensor
switch (rest_data[47 + offset])
// following the value of digit 23 + offset we determine the type of data we get from the sensor
switch (servicedata[23 + offset])
{
case '9':
BLEdata.set("fer", (double)value);
@@ -961,152 +897,94 @@ bool process_sensors(int offset, char *rest_data, char *mac_adress)
case '8':
BLEdata.set("moi", (double)value);
break;
case 'a':
BLEdata.set("batt", (double)value);
break;
case 'd':
// humidity
value = value_from_service_data(rest_data, 52 + offset, 4);
value = value_from_service_data(servicedata, 28 + offset, 4);
BLEdata.set("tem", (double)value / 10);
// temperature
value = value_from_service_data(rest_data, 56 + offset, 4);
value = value_from_service_data(servicedata, 32 + offset, 4);
BLEdata.set("hum", (double)value / 10);
break;
default:
Log.trace(F("can't read values" CR));
return false;
}
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
bool process_scale_v1(char *rest_data, char *mac_adress)
JsonObject& process_scale_v1(JsonObject &BLEdata)
{
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
const char * servicedata = BLEdata["servicedata"].as<const char *>();
double weight = value_from_service_data(rest_data, 2, 4) / 200;
double weight = value_from_service_data(servicedata, 2, 4) / 200;
//Set Json value
BLEdata.set("weight", (double)weight);
// Publish weight
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
bool process_scale_v2(char *rest_data, char *mac_adress)
JsonObject& process_scale_v2(JsonObject &BLEdata)
{
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
const char * servicedata = BLEdata["servicedata"].as<const char *>();
double weight = value_from_service_data(rest_data, 22, 4) / 200;
double impedance = value_from_service_data(rest_data, 18, 4);
double weight = value_from_service_data(servicedata, 22, 4) / 200;
double impedance = value_from_service_data(servicedata, 18, 4);
//Set Json values
BLEdata.set("weight", (double)weight);
BLEdata.set("impedance", (double)impedance);
// Publish weight
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
bool process_miband(char *rest_data, char *mac_adress)
JsonObject& process_miband(JsonObject &BLEdata)
{
//example "servicedata":"a21e0000"
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
const char * servicedata = BLEdata["servicedata"].as<const char *>();
double steps = value_from_service_data(rest_data, 0, 4);
double steps = value_from_service_data(servicedata, 0, 4);
//Set Json value
BLEdata.set("steps", (double)steps);
// Publish weight
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
bool process_milamp(char *rest_data, char *mac_adress)
JsonObject& process_milamp(JsonObject &BLEdata)
{
//example "servicedata":"4030dd31d0300010100"
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
const char * servicedata = BLEdata["servicedata"].as<const char *>();
long darkness = value_from_service_data(rest_data, 8, 2);
long darkness = value_from_service_data(servicedata, 8, 2);
//Set Json value
BLEdata.set("presence", (bool)"true");
BLEdata.set("darkness", (long)darkness);
// Publish
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
bool process_cleargrass_air(char *rest_data, char *mac_adress)
JsonObject& process_cleargrass(JsonObject &BLEdata, boolean air)
{
//example "servicedata":"08094c0140342d580104c400240207025d2702015a"
//decoding "08094c0140342d580104 temp:c400 hum:2402 0702 pressure:5d27 02015a"
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
const char * servicedata = BLEdata["servicedata"].as<const char *>();
double value = 9999;
// humidity
value = value_from_service_data(rest_data, 20, 4);
value = value_from_service_data(servicedata, 20, 4);
BLEdata.set("tem", (double)value / 10);
// temperature
value = value_from_service_data(rest_data, 24, 4);
value = value_from_service_data(servicedata, 24, 4);
BLEdata.set("hum", (double)value / 10);
// air pressure
value = value_from_service_data(rest_data, 32, 4);
BLEdata.set("pres", (double)value / 100);
if (air)
{
// air pressure
value = value_from_service_data(servicedata, 32, 4);
BLEdata.set("pres", (double)value / 100);
}
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
}
bool process_cleargrass(char *rest_data, char *mac_adress)
{
//example "servicedata":0807743e10342d580104 c300 2c02 02012a
Log.trace(F("Creating BLE buffer" CR));
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
JsonObject &BLEdata = jsonBuffer.createObject();
double value = 9999;
// humidity
value = value_from_service_data(rest_data, 20, 4);
BLEdata.set("tem", (double)value / 10);
// temperature
value = value_from_service_data(rest_data, 24, 4);
BLEdata.set("hum", (double)value / 10);
String mactopic(mac_adress);
mactopic = subjectBTtoMQTT + String("/") + mactopic;
pub((char *)mactopic.c_str(), BLEdata);
return true;
return BLEdata;
}
#ifdef subjectHomePresence
@@ -1183,5 +1061,4 @@ void MQTTtoBT(char *topicOri, JsonObject &BTdata)
#endif
}
}
#endif
#endif
+12 -3
View File
@@ -38,20 +38,29 @@ extern void MQTTtoBT(char * topicOri, JsonObject& RFdata);
#define HMSerialSpeed 9600 // Communication speed with the HM module, softwareserial doesn't support 115200
//#define HM-11 // uncomment this line if you use HM-11 and comment the line above
//#define HM_BLUE_LED_STOP true //uncomment to stop the blue led light of HM1X
#define BLEdelimiter "4f4b2b444953413a"
#define BLEdelimiter "4f4b2b444953413a" // OK+DISA:
#define ServicedataMinLength 30
#ifndef TimeBtw_Read
#define TimeBtw_Read 55555 //define default time between 2 scans
#endif
#ifndef pubBLEServiceData
#define pubBLEServiceData true // comment if you don't want to publish service data (in case you are having too heavy service data) https://github.com/1technophile/OpenMQTTGateway/issues/318#issuecomment-446064707
#ifndef pubKnownBLEServiceData
#define pubKnownBLEServiceData false // define true if you want to publish service data belonging to recognised sensors
#endif
#ifndef pubUnknownBLEServiceData
#define pubUnknownBLEServiceData true // define false if you don't want to publish service data to unrecognised sensors (in case you are having too heavy service data) https://github.com/1technophile/OpenMQTTGateway/issues/318#issuecomment-446064707
#endif
#ifndef pubBLEManufacturerData
#define pubBLEManufacturerData false // define true if you want to publish the manufacturer's data (sometimes contains characters that aren't valid with receiving client)
#endif
#ifndef pubBLEServiceUUID
#define pubBLEServiceUUID false // define true if you want to publish the service UUID data
#endif
/*-------------------HOME ASSISTANT ROOM PRESENCE ----------------------*/
// if not commented Home presence integration with HOME ASSISTANT is activated
#define subjectHomePresence "home_presence/" // will send Home Assistant room presence message to this topic (first part is same for all rooms, second is room name)
-8
View File
@@ -202,14 +202,6 @@ void extract_char(char *token_char, char *subset, int start, int l, bool reverse
subset[l] = '\0';
}
int strpos(char *haystack, char *needle) //from @miere https://stackoverflow.com/users/548685/miere
{
char *p = strstr(haystack, needle);
if (p)
return p - haystack;
return -1;
}
char *ip2CharArray(IPAddress ip)
{ //from Nick Lee https://stackoverflow.com/questions/28119653/arduino-display-ethernet-localip
static char a[16];