Rename set commands to config correct json buffer size and gateway name replace state to cmd replace set by config add restart and erase command add unicity to gateway command switches BLE devices shouldn't be child of the gateway make the BTtoMQTT topic consistent with other definitions
1245 lines
42 KiB
Arduino
1245 lines
42 KiB
Arduino
/*
|
|
OpenMQTTGateway - ESP8266 or Arduino program for home automation
|
|
|
|
Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal/BLE and a MQTT broker
|
|
Send and receiving command by MQTT
|
|
|
|
This gateway enables to:
|
|
- publish MQTT data to a different topic related to BLE devices rssi signal
|
|
- publish MQTT data related to mi flora temperature, moisture, fertility and lux
|
|
- publish MQTT data related to mi jia indoor temperature & humidity sensor
|
|
|
|
Copyright: (c)Florian ROBERT
|
|
|
|
This file is part of OpenMQTTGateway.
|
|
|
|
OpenMQTTGateway 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.
|
|
|
|
OpenMQTTGateway 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/>.
|
|
|
|
Thanks to wolass https://github.com/wolass for suggesting me HM 10 and dinosd https://github.com/dinosd/BLE_PROXIMITY for inspiring me how to implement the gateway
|
|
*/
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayBT
|
|
|
|
#include <vector>
|
|
using namespace std;
|
|
vector<BLEdevice> devices;
|
|
|
|
void setWorBMac(char *mac, bool isWhite)
|
|
{
|
|
bool foundMac = false;
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
if ((strcmp(p->macAdr, mac) == 0))
|
|
{
|
|
p->isWhtL = isWhite;
|
|
p->isBlkL = !isWhite;
|
|
foundMac = true;
|
|
}
|
|
}
|
|
if (!foundMac)
|
|
{
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = false;
|
|
device.isWhtL = isWhite;
|
|
device.isBlkL = !isWhite;
|
|
devices.push_back(device);
|
|
}
|
|
}
|
|
|
|
bool oneWhite()
|
|
{
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
if (p->isWhtL)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isWhite(char *mac)
|
|
{
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
if ((strcmp(p->macAdr, mac) == 0))
|
|
{
|
|
return p->isWhtL;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isBlack(char *mac)
|
|
{
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
if ((strcmp(p->macAdr, mac) == 0))
|
|
{
|
|
return p->isBlkL;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isDiscovered(char *mac)
|
|
{
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
if ((strcmp(p->macAdr, mac) == 0))
|
|
{
|
|
return p->isDisc;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void dumpDevices()
|
|
{
|
|
for (vector<BLEdevice>::iterator p = devices.begin(); p != devices.end(); ++p)
|
|
{
|
|
trc(p->macAdr);
|
|
trc(p->isDisc);
|
|
trc(p->isWhtL);
|
|
trc(p->isBlkL);
|
|
}
|
|
}
|
|
|
|
void strupp(char *beg)
|
|
{
|
|
while (*beg = toupper(*beg))
|
|
++beg;
|
|
}
|
|
|
|
#ifdef ZmqttDiscovery
|
|
void MiFloraDiscovery(char *mac)
|
|
{
|
|
#define MiFloraparametersCount 4
|
|
trc(F("MiFloraDiscovery"));
|
|
char *MiFlorasensor[MiFloraparametersCount][8] = {
|
|
{"sensor", "MiFlora-lux", mac, "illuminance", "{{ value_json.lux | is_defined }}", "", "", "lu"},
|
|
{"sensor", "MiFlora-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "MiFlora-fer", mac, "", "{{ value_json.fer | is_defined }}", "", "", "µS/cm"},
|
|
{"sensor", "MiFlora-moi", mac, "", "{{ value_json.moi | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < MiFloraparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(MiFlorasensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + MiFlorasensor[i][1];
|
|
createDiscovery(MiFlorasensor[i][0],
|
|
(char *)discovery_topic.c_str(), MiFlorasensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, MiFlorasensor[i][3], MiFlorasensor[i][4],
|
|
MiFlorasensor[i][5], MiFlorasensor[i][6], MiFlorasensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void VegTrugDiscovery(char *mac)
|
|
{
|
|
#define VegTrugparametersCount 4
|
|
trc(F("VegTrugDiscovery"));
|
|
char *VegTrugsensor[VegTrugparametersCount][8] = {
|
|
{"sensor", "VegTrug-lux", mac, "illuminance", "{{ value_json.lux | is_defined }}", "", "", "lu"},
|
|
{"sensor", "VegTrug-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "VegTrug-fer", mac, "", "{{ value_json.fer | is_defined }}", "", "", "µS/cm"},
|
|
{"sensor", "VegTrug-moi", mac, "", "{{ value_json.moi | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < VegTrugparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(VegTrugsensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + VegTrugsensor[i][1];
|
|
createDiscovery(VegTrugsensor[i][0],
|
|
(char *)discovery_topic.c_str(), VegTrugsensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, VegTrugsensor[i][3], VegTrugsensor[i][4],
|
|
VegTrugsensor[i][5], VegTrugsensor[i][6], VegTrugsensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void MiJiaDiscovery(char *mac)
|
|
{
|
|
#define MiJiaparametersCount 3
|
|
trc(F("MiJiaDiscovery"));
|
|
char *MiJiasensor[MiJiaparametersCount][8] = {
|
|
{"sensor", "MiJia-batt", mac, "battery", "{{ value_json.batt | is_defined }}", "", "", "%"},
|
|
{"sensor", "MiJia-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "MiJia-hum", mac, "humidity", "{{ value_json.hum | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < MiJiaparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(MiJiasensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + MiJiasensor[i][1];
|
|
createDiscovery(MiJiasensor[i][0],
|
|
(char *)discovery_topic.c_str(), MiJiasensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, MiJiasensor[i][3], MiJiasensor[i][4],
|
|
MiJiasensor[i][5], MiJiasensor[i][6], MiJiasensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void LYWSD02Discovery(char *mac)
|
|
{
|
|
#define LYWSD02parametersCount 3
|
|
trc(F("LYWSD02Discovery"));
|
|
char *LYWSD02sensor[LYWSD02parametersCount][8] = {
|
|
{"sensor", "LYWSD02-batt", mac, "battery", "{{ value_json.batt | is_defined }}", "", "", "V"},
|
|
{"sensor", "LYWSD02-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "LYWSD02-hum", mac, "humidity", "{{ value_json.hum | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < LYWSD02parametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(LYWSD02sensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + LYWSD02sensor[i][1];
|
|
createDiscovery(LYWSD02sensor[i][0],
|
|
(char *)discovery_topic.c_str(), LYWSD02sensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, LYWSD02sensor[i][3], LYWSD02sensor[i][4],
|
|
LYWSD02sensor[i][5], LYWSD02sensor[i][6], LYWSD02sensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void CLEARGRASSTRHDiscovery(char *mac)
|
|
{
|
|
#define CLEARGRASSTRHparametersCount 3
|
|
trc(F("CLEARGRASSTRHDiscovery"));
|
|
char *CLEARGRASSTRHsensor[CLEARGRASSTRHparametersCount][8] = {
|
|
{"sensor", "CLEARGRASSTRH-batt", mac, "battery", "{{ value_json.batt | is_defined }}", "", "", "V"},
|
|
{"sensor", "CLEARGRASSTRH-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "CLEARGRASSTRH-hum", mac, "humidity", "{{ value_json.hum | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < CLEARGRASSTRHparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(CLEARGRASSTRHsensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + CLEARGRASSTRHsensor[i][1];
|
|
createDiscovery(CLEARGRASSTRHsensor[i][0],
|
|
(char *)discovery_topic.c_str(), CLEARGRASSTRHsensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, CLEARGRASSTRHsensor[i][3], CLEARGRASSTRHsensor[i][4],
|
|
CLEARGRASSTRHsensor[i][5], CLEARGRASSTRHsensor[i][6], CLEARGRASSTRHsensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void CLEARGRASSTRHKPADiscovery(char *mac)
|
|
{
|
|
#define CLEARGRASSTRHKPAparametersCount 3
|
|
trc(F("CLEARGRASSTRHKPADiscovery"));
|
|
char *CLEARGRASSTRHKPAsensor[CLEARGRASSTRHKPAparametersCount][8] = {
|
|
{"sensor", "CLEARGRASSTRHKPA-pres", mac, "pressure", "{{ value_json.pres | is_defined }}", "", "", "kPa"},
|
|
{"sensor", "CLEARGRASSTRHKPA-tem", mac, "temperature", "{{ value_json.tem | is_defined }}", "", "", "°C"},
|
|
{"sensor", "CLEARGRASSTRHKPA-hum", mac, "humidity", "{{ value_json.hum | is_defined }}", "", "", "%"}
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < CLEARGRASSTRHKPAparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(CLEARGRASSTRHKPAsensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + CLEARGRASSTRHKPAsensor[i][1];
|
|
createDiscovery(CLEARGRASSTRHKPAsensor[i][0],
|
|
(char *)discovery_topic.c_str(), CLEARGRASSTRHKPAsensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, CLEARGRASSTRHKPAsensor[i][3], CLEARGRASSTRHKPAsensor[i][4],
|
|
CLEARGRASSTRHKPAsensor[i][5], CLEARGRASSTRHKPAsensor[i][6], CLEARGRASSTRHKPAsensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void MiScaleDiscovery(char *mac)
|
|
{
|
|
#define MiScaleparametersCount 1
|
|
trc(F("MiScaleDiscovery"));
|
|
char *MiScalesensor[MiScaleparametersCount][8] = {
|
|
{"sensor", "MiScale-weight", mac, "weight", "{{ value_json.weight | is_defined }}", "", "", "kg"},
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < MiScaleparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(MiScalesensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + MiScalesensor[i][1];
|
|
createDiscovery(MiScalesensor[i][0],
|
|
(char *)discovery_topic.c_str(), MiScalesensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, MiScalesensor[i][3], MiScalesensor[i][4],
|
|
MiScalesensor[i][5], MiScalesensor[i][6], MiScalesensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void MiLampDiscovery(char *mac)
|
|
{
|
|
#define MiLampparametersCount 1
|
|
trc(F("MiLampDiscovery"));
|
|
char *MiLampsensor[MiLampparametersCount][8] = {
|
|
{"sensor", "MiLamp-presence", mac, "presence", "{{ value_json.presence}}", "", "", "d"},
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < MiLampparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(MiLampsensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + MiLampsensor[i][1];
|
|
createDiscovery(MiLampsensor[i][0],
|
|
(char *)discovery_topic.c_str(), MiLampsensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, MiLampsensor[i][3], MiLampsensor[i][4],
|
|
MiLampsensor[i][5], MiLampsensor[i][6], MiLampsensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
void MiBandDiscovery(char *mac)
|
|
{
|
|
#define MiBandparametersCount 1
|
|
trc(F("MiBandDiscovery"));
|
|
char *MiBandsensor[MiBandparametersCount][8] = {
|
|
{"sensor", "MiBand-steps", mac, "steps", "{{ value_json.steps | is_defined }}", "", "", "nb"},
|
|
//component type,name,availability topic,device class,value template,payload on, payload off, unit of measurement
|
|
};
|
|
|
|
for (int i = 0; i < MiBandparametersCount; i++)
|
|
{
|
|
trc(F("CreateDiscoverySensor"));
|
|
trc(MiBandsensor[i][1]);
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + MiBandsensor[i][1];
|
|
createDiscovery(MiBandsensor[i][0],
|
|
(char *)discovery_topic.c_str(), MiBandsensor[i][1], (char *)unique_id.c_str(),
|
|
will_Topic, MiBandsensor[i][3], MiBandsensor[i][4],
|
|
MiBandsensor[i][5], MiBandsensor[i][6], MiBandsensor[i][7],
|
|
0, "", "", false, "");
|
|
}
|
|
BLEdevice device;
|
|
strcpy(device.macAdr, mac);
|
|
device.isDisc = true;
|
|
device.isWhtL = false;
|
|
device.isBlkL = false;
|
|
devices.push_back(device);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef ESP32
|
|
/*
|
|
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
|
Ported to Arduino ESP32 by Evandro Copercini
|
|
*/
|
|
// core task implementation thanks to https://techtutorialsx.com/2017/05/09/esp32-running-code-on-a-specific-core/
|
|
|
|
#include <BLEDevice.h>
|
|
#include <BLEUtils.h>
|
|
#include <BLEScan.h>
|
|
#include <BLEAdvertisedDevice.h>
|
|
#include "soc/timer_group_struct.h"
|
|
#include "soc/timer_group_reg.h"
|
|
|
|
//core on which the BLE detection task will run
|
|
static int taskCore = 0;
|
|
|
|
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
|
{
|
|
void onResult(BLEAdvertisedDevice advertisedDevice)
|
|
{
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
String mac_adress = advertisedDevice.getAddress().toString().c_str();
|
|
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);
|
|
trc("device detected");
|
|
trc(mac);
|
|
if ((!oneWhite() || isWhite(mac)) && !isBlack(mac))
|
|
{ //if not black listed mac we go AND if we have no white mac or this mac is white we go out
|
|
if (advertisedDevice.haveName())
|
|
BLEdata.set("name", (char *)advertisedDevice.getName().c_str());
|
|
if (advertisedDevice.haveManufacturerData())
|
|
BLEdata.set("manufacturerdata", (char *)advertisedDevice.getManufacturerData().c_str());
|
|
if (advertisedDevice.haveRSSI())
|
|
BLEdata.set("rssi", (int)advertisedDevice.getRSSI());
|
|
if (advertisedDevice.haveTXPower())
|
|
BLEdata.set("txpower", (int8_t)advertisedDevice.getTXPower());
|
|
#ifdef subjectHomePresence
|
|
if (advertisedDevice.haveRSSI())
|
|
haRoomPresence(BLEdata); // this device has an rssi in consequence we can use it for home assistant room presence component
|
|
#endif
|
|
if (advertisedDevice.haveServiceData())
|
|
{
|
|
trc(F("Get services data :"));
|
|
int serviceDataCount = advertisedDevice.getServiceDataCount();
|
|
trc(serviceDataCount);
|
|
for (int j = 0; j < serviceDataCount; j++)
|
|
{
|
|
std::string serviceData = advertisedDevice.getServiceData(j);
|
|
int serviceDataLength = serviceData.length();
|
|
String returnedString = "";
|
|
for (int i = 0; i < serviceDataLength; i++)
|
|
{
|
|
int a = serviceData[i];
|
|
if (a < 16)
|
|
{
|
|
returnedString = returnedString + "0";
|
|
}
|
|
returnedString = returnedString + String(a, HEX);
|
|
}
|
|
char service_data[returnedString.length() + 1];
|
|
returnedString.toCharArray(service_data, returnedString.length() + 1);
|
|
service_data[returnedString.length()] = '\0';
|
|
#ifdef pubBLEServiceData
|
|
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, LYWDS02, VegTrug
|
|
trc("Processing BLE device data");
|
|
int pos = -1;
|
|
pos = strpos(service_data, "209800");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("mi flora data reading"));
|
|
//example "servicedata":"71209800bc63b6658d7cc40d0910023200"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiFloraDiscovery(mac);
|
|
#endif
|
|
process_sensors(pos - 24, service_data, mac);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(service_data, "20bc03");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("vegtrug data reading"));
|
|
//example "servicedata":"7120bc0399c309688d7cc40d0910020000"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
VegTrugDiscovery(mac);
|
|
#endif
|
|
process_sensors(pos - 24, service_data, mac);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(service_data, "20aa01");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("mi jia data reading"));
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiJiaDiscovery(mac);
|
|
#endif
|
|
process_sensors(pos - 26, service_data, mac);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(service_data, "205b04");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("LYWSD02 data reading"));
|
|
//example "servicedata":"70205b04b96ab883c8593f09041002e000"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
LYWSD02Discovery(mac);
|
|
#endif
|
|
process_sensors(pos - 24, service_data, mac);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(service_data, "304703");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("ClearGrass T RH data reading method 1"));
|
|
//example "servicedata":"5030470340743e10342d58041002d6000a100164"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
CLEARGRASSTRHDiscovery(mac);
|
|
#endif
|
|
process_sensors(pos - 26, service_data, mac);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(service_data, "4030dd");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("Mi Lamp data reading"));
|
|
//example "servicedata":4030DD031D0300010100
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiLampDiscovery(mac);
|
|
#endif
|
|
process_milamp(service_data, mac);
|
|
}
|
|
}
|
|
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "181d") != NULL)
|
|
{ // Mi Scale V1
|
|
trc(F("Mi Scale V1 data reading"));
|
|
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiScaleDiscovery(mac);
|
|
#endif
|
|
process_scale_v1(service_data, mac);
|
|
}
|
|
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "181b") != NULL)
|
|
{ // Mi Scale V2
|
|
trc(F("Mi Scale V2 data reading"));
|
|
//example "servicedata":02c4e1070b1e13050c00002607 / 02a6e20705150a251df401443e /02a6e20705180c0d04d701943e
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiScaleDiscovery(mac);
|
|
#endif
|
|
process_scale_v2(service_data, mac);
|
|
}
|
|
if (strstr(BLEdata["servicedatauuid"].as<char *>(), "fee0") != NULL)
|
|
{ // Mi Band //0000fee0-0000-1000-8000-00805f9b34fb // ESP32 only
|
|
trc(F("Mi Band data reading"));
|
|
//example "servicedata":a21e0000
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
MiBandDiscovery(mac);
|
|
#endif
|
|
process_miband(service_data, mac);
|
|
}
|
|
if (strstr(BLEdata["servicedata"].as<char *>(), "08094c") != NULL)
|
|
{ // Clear grass with air pressure//08094c0140342d580104d8000c020702612702015a
|
|
trc(F("Clear grass data with air pressure reading"));
|
|
//example "servicedata":08094c0140342d580104 c400 2402 0702 5d27 02015a
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(mac))
|
|
CLEARGRASSTRHKPADiscovery(mac);
|
|
#endif
|
|
process_cleargrass_air(service_data, mac);
|
|
}
|
|
if (strstr(BLEdata["servicedata"].as<char *>(), "080774") != NULL)
|
|
{ // Clear grass standard method 2/0807743e10342d580104c3002c0202012a
|
|
trc(F("Clear grass data reading method 2"));
|
|
//example "servicedata":0807743e10342d580104 c300 2c02 02012a
|
|
// no discovery as it is already available with method 1
|
|
process_cleargrass(service_data, mac);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trc("Low rssi, device filtered");
|
|
}
|
|
}
|
|
}
|
|
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
|
|
{
|
|
trc("Low rssi, device filtered");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trc(F("Filtered mac device"));
|
|
}
|
|
}
|
|
};
|
|
|
|
void BLEscan()
|
|
{
|
|
|
|
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
|
TIMERG0.wdt_feed = 1;
|
|
TIMERG0.wdt_wprotect = 0;
|
|
trc(F("Scan begin"));
|
|
BLEDevice::init("");
|
|
BLEScan *pBLEScan = BLEDevice::getScan(); //create new scan
|
|
MyAdvertisedDeviceCallbacks myCallbacks;
|
|
pBLEScan->setAdvertisedDeviceCallbacks(&myCallbacks);
|
|
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
|
BLEScanResults foundDevices = pBLEScan->start(Scan_duration);
|
|
trc(F("Scan end, deinit controller"));
|
|
esp_bt_controller_deinit();
|
|
}
|
|
|
|
void coreTask(void *pvParameters)
|
|
{
|
|
|
|
String taskMessage = "BT Task running on core ";
|
|
taskMessage = taskMessage + xPortGetCoreID();
|
|
|
|
while (true)
|
|
{
|
|
trc(taskMessage);
|
|
delay(BLEinterval);
|
|
if (client.state() == 0)
|
|
{
|
|
BLEscan();
|
|
}
|
|
else
|
|
{
|
|
trc("MQTT client disconnected no BLE scan");
|
|
delay(1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void setupBT()
|
|
{
|
|
BLEinterval = TimeBtw_Read;
|
|
Minrssi = MinimumRSSI;
|
|
trc(F("BLEinterval btw scans"));
|
|
trc(BLEinterval);
|
|
trc(F("Minrssi"));
|
|
trc(Minrssi);
|
|
// we setup a task with priority one to avoid conflict with other gateways
|
|
xTaskCreatePinnedToCore(
|
|
coreTask, /* Function to implement the task */
|
|
"coreTask", /* Name of the task */
|
|
10000, /* Stack size in words */
|
|
NULL, /* Task input parameter */
|
|
1, /* Priority of the task */
|
|
NULL, /* Task handle. */
|
|
taskCore); /* Core where the task should run */
|
|
trc(F("ZgatewayBT multicore ESP32 setup done "));
|
|
}
|
|
|
|
bool BTtoMQTT()
|
|
{ // for on demand BLE scans
|
|
BLEscan();
|
|
}
|
|
#else // arduino or ESP8266 working with HM10/11
|
|
|
|
#include <SoftwareSerial.h>
|
|
|
|
#define STRING_MSG "OK+DISC:"
|
|
#define QUESTION_MSG "AT+DISA?"
|
|
#define RESPONSE_MSG "OK+DISIS"
|
|
#define RESP_END_MSG "OK+DISCE"
|
|
#define SETUP_MSG "OK+RESET"
|
|
|
|
SoftwareSerial softserial(BT_RX, BT_TX);
|
|
|
|
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}};
|
|
|
|
void setupBT()
|
|
{
|
|
BLEinterval = TimeBtw_Read;
|
|
Minrssi = MinimumRSSI;
|
|
trc(F("BLEinterval btw scans"));
|
|
trc(BLEinterval);
|
|
trc(F("Minrssi"));
|
|
trc(Minrssi);
|
|
softserial.begin(9600);
|
|
softserial.print(F("AT+ROLE1"));
|
|
delay(100);
|
|
softserial.print(F("AT+IMME1"));
|
|
delay(100);
|
|
softserial.print(F("AT+RESET"));
|
|
delay(100);
|
|
#ifdef HM_BLUE_LED_STOP
|
|
softserial.print(F("AT+PIO11")); // When not connected (as in BLE mode) the LED is off. When connected the LED is solid on.
|
|
#endif
|
|
delay(100);
|
|
trc(F("ZgatewayBT HM1X setup done "));
|
|
}
|
|
|
|
bool BTtoMQTT()
|
|
{
|
|
|
|
//extract serial data from module in hexa format
|
|
while (softserial.available() > 0)
|
|
{
|
|
int a = softserial.read();
|
|
if (a < 16)
|
|
{
|
|
returnedString = returnedString + "0";
|
|
}
|
|
returnedString = returnedString + String(a, HEX);
|
|
}
|
|
|
|
if (millis() > (timebt + BLEinterval))
|
|
{ //retriving data
|
|
timebt = millis();
|
|
#if defined(ESP8266)
|
|
yield();
|
|
#endif
|
|
if (returnedString != "")
|
|
{
|
|
size_t pos = 0;
|
|
while ((pos = returnedString.lastIndexOf(BLEdelimiter)) != -1)
|
|
{
|
|
#if defined(ESP8266)
|
|
yield();
|
|
#endif
|
|
String token = returnedString.substring(pos);
|
|
returnedString.remove(pos, returnedString.length());
|
|
char token_char[token.length() + 1];
|
|
token.toCharArray(token_char, token.length() + 1);
|
|
trc(token);
|
|
if (token.length() > 60)
|
|
{ // we extract data only if we have detailled infos
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
extract_char(token_char, d[i].extract, d[i].start, d[i].len, d[i].reverse, false);
|
|
if (i == 3)
|
|
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
|
|
{
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
strupp(d[0].extract);
|
|
if (isBlack(d[0].extract))
|
|
return false; //if black listed mac we go out
|
|
if (oneWhite() && !isWhite(d[0].extract))
|
|
return false; //if we have at least one white mac and this mac is not white we go out
|
|
#ifdef subjectHomePresence
|
|
String HomePresenceId;
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
HomePresenceId += String(d[0].extract[i]);
|
|
if (((i - 1) % 2 == 0) && (i != 11))
|
|
HomePresenceId += ":";
|
|
}
|
|
trc(F("HomePresenceId"));
|
|
trc(HomePresenceId);
|
|
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);
|
|
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)
|
|
{
|
|
trc("mi flora data reading");
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
MiFloraDiscovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc("mi jia data reading");
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
MiJiaDiscovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc("LYWSD02 data reading");
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
LYWSD02Discovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc("CLEARGRASSTRH data reading method 1");
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
CLEARGRASSTRHDiscovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc("Mi Scale data reading");
|
|
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
MiScaleDiscovery(d[0].extract);
|
|
#endif
|
|
bool result = process_scale_v1((char *)service_data.c_str(), d[0].extract);
|
|
}
|
|
pos = -1;
|
|
pos = strpos(d[5].extract, "4030dd");
|
|
if (pos != -1)
|
|
{
|
|
trc(F("Mi Lamp data reading"));
|
|
//example "servicedata":4030dd31d0300010100
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
MiLampDiscovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc(F("Clear grass data with air pressure reading"));
|
|
//example "servicedata":08094c0140342d580104 c400 2402 0702 5d27 02015a
|
|
#ifdef ZmqttDiscovery
|
|
if (!isDiscovered(d[0].extract))
|
|
CLEARGRASSTRHKPADiscovery(d[0].extract);
|
|
#endif
|
|
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)
|
|
{
|
|
trc(F("Clear grass data reading method 2"));
|
|
//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);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
trc("Low rssi, device filtered");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
returnedString = ""; //init data string
|
|
return false;
|
|
}
|
|
softserial.print(F(QUESTION_MSG));
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
double value_from_service_data(char *service_data, int offset, int data_length)
|
|
{
|
|
char rev_data[data_length + 1];
|
|
char data[data_length + 1];
|
|
memcpy(rev_data, &service_data[offset], data_length);
|
|
rev_data[data_length] = '\0';
|
|
|
|
// reverse data order
|
|
revert_hex_data(rev_data, data, data_length + 1);
|
|
double value = strtol(data, NULL, 16);
|
|
if (value > 65000 && data_length <= 4)
|
|
value = value - 65535;
|
|
trc(value);
|
|
return value;
|
|
}
|
|
|
|
bool process_sensors(int offset, char *rest_data, char *mac_adress)
|
|
{
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
int data_length = 0;
|
|
trc("data_length");
|
|
trc(rest_data[51 + offset]);
|
|
switch (rest_data[51 + offset])
|
|
{
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
data_length = ((rest_data[51 + offset] - '0') * 2);
|
|
trc("valid data_length");
|
|
break;
|
|
default:
|
|
trc("invalid data_length");
|
|
return false;
|
|
}
|
|
|
|
double value = 9999;
|
|
value = value_from_service_data(rest_data, 52 + 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])
|
|
{
|
|
case '9':
|
|
BLEdata.set("fer", (double)value);
|
|
break;
|
|
case '4':
|
|
BLEdata.set("tem", (double)value / 10);
|
|
break;
|
|
case '6':
|
|
BLEdata.set("hum", (double)value / 10);
|
|
break;
|
|
case '7':
|
|
BLEdata.set("lux", (double)value);
|
|
break;
|
|
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);
|
|
BLEdata.set("tem", (double)value / 10);
|
|
// temperature
|
|
value = value_from_service_data(rest_data, 56 + offset, 4);
|
|
BLEdata.set("hum", (double)value / 10);
|
|
break;
|
|
default:
|
|
trc("can't read values");
|
|
return false;
|
|
}
|
|
String mactopic(mac_adress);
|
|
mactopic = subjectBTtoMQTT + String("/") + mactopic;
|
|
pub((char *)mactopic.c_str(), BLEdata);
|
|
return true;
|
|
}
|
|
|
|
bool process_scale_v1(char *rest_data, char *mac_adress)
|
|
{
|
|
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
|
|
double weight = value_from_service_data(rest_data, 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;
|
|
}
|
|
|
|
bool process_scale_v2(char *rest_data, char *mac_adress)
|
|
{
|
|
//example "servicedata":"a2ac2be307060207122b" /"a28039e3070602070e28"
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
|
|
double weight = value_from_service_data(rest_data, 22, 4) / 200;
|
|
double impedance = value_from_service_data(rest_data, 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;
|
|
}
|
|
|
|
bool process_miband(char *rest_data, char *mac_adress)
|
|
{
|
|
//example "servicedata":"a21e0000"
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
|
|
double steps = value_from_service_data(rest_data, 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;
|
|
}
|
|
|
|
bool process_milamp(char *rest_data, char *mac_adress)
|
|
{
|
|
//example "servicedata":"4030dd31d0300010100"
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
StaticJsonBuffer<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject &BLEdata = jsonBuffer.createObject();
|
|
|
|
long darkness = value_from_service_data(rest_data, 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;
|
|
}
|
|
|
|
bool process_cleargrass_air(char *rest_data, char *mac_adress)
|
|
{
|
|
//example "servicedata":"08094c0140342d580104c400240207025d2702015a"
|
|
//decoding "08094c0140342d580104 temp:c400 hum:2402 0702 pressure:5d27 02015a"
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
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);
|
|
// air pressure
|
|
value = value_from_service_data(rest_data, 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
|
|
trc("rest_data");
|
|
trc(rest_data);
|
|
|
|
trc(F("Creating BLE buffer"));
|
|
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;
|
|
}
|
|
|
|
#ifdef subjectHomePresence
|
|
void haRoomPresence(JsonObject &HomePresence)
|
|
{
|
|
int BLErssi = HomePresence["rssi"];
|
|
trc(F("BLErssi"));
|
|
trc(BLErssi);
|
|
int txPower = HomePresence["txpower"] | 0;
|
|
if (txPower >= 0)
|
|
txPower = -59; //if tx power is not found we set a default calibration value
|
|
trc(F("txPower"));
|
|
trc(txPower);
|
|
double ratio = BLErssi * 1.0 / txPower;
|
|
double distance;
|
|
if (ratio < 1.0)
|
|
{
|
|
distance = pow(ratio, 10);
|
|
}
|
|
else
|
|
{
|
|
distance = (0.89976) * pow(ratio, 7.7095) + 0.111;
|
|
}
|
|
HomePresence["distance"] = distance;
|
|
trc(F("BLE DISTANCE :"));
|
|
trc(distance);
|
|
String topic = String(Base_Topic) + "home_presence/" + String(gateway_name);
|
|
pub_custom_topic((char *)topic.c_str(), HomePresence, false);
|
|
}
|
|
#endif
|
|
|
|
void MQTTtoBT(char *topicOri, JsonObject &BTdata)
|
|
{ // json object decoding
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoBTset))
|
|
{
|
|
trc(F("MQTTtoBT json set"));
|
|
|
|
// Black list & white list set
|
|
int WLsize = BTdata["white-list"].size();
|
|
if (WLsize > 0)
|
|
{
|
|
trc(F("WL set"));
|
|
for (int i = 0; i < WLsize; i++)
|
|
{
|
|
const char *whiteMac = BTdata["white-list"][i];
|
|
setWorBMac((char *)whiteMac, true);
|
|
}
|
|
}
|
|
int BLsize = BTdata["black-list"].size();
|
|
if (BLsize > 0)
|
|
{
|
|
trc(F("BL set"));
|
|
for (int i = 0; i < BLsize; i++)
|
|
{
|
|
const char *blackMac = BTdata["black-list"][i];
|
|
setWorBMac((char *)blackMac, false);
|
|
}
|
|
}
|
|
if (BLsize > 0 || WLsize > 0)
|
|
dumpDevices();
|
|
|
|
// Scan interval set
|
|
if (BTdata.containsKey("interval"))
|
|
{
|
|
trc(F("BLE interval"));
|
|
// storing BLE interval for further use if needed
|
|
unsigned int prevBLEinterval = BLEinterval;
|
|
trc("previous interval");
|
|
trc(BLEinterval);
|
|
// set BLE interval if present if not setting default value
|
|
BLEinterval = (unsigned int)BTdata["interval"];
|
|
trc("new interval");
|
|
trc(BLEinterval);
|
|
if (BLEinterval == 0)
|
|
{
|
|
if (BTtoMQTT()) // as BLEinterval is = to 0 we can launch the loop and the scan will execute immediately
|
|
trc(F("Scan done"));
|
|
BLEinterval = prevBLEinterval; // as 0 was just used as a command we recover previous scan duration
|
|
}
|
|
}
|
|
// MinRSSI set
|
|
if (BTdata.containsKey("minrssi"))
|
|
{
|
|
trc(F("Min RSSI"));
|
|
// storing Min RSSI for further use if needed
|
|
trc("previous Minrssi");
|
|
trc(Minrssi);
|
|
// set Min RSSI if present if not setting default value
|
|
Minrssi = (unsigned int)BTdata["minrssi"];
|
|
trc("new Minrssi");
|
|
trc(Minrssi);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|