#include <string>
#include <Wire.h>
#include "DHTesp.h"
#include <esp_bt.h>
#include "BLEDevice.h"
#include "Ticker.h"
static BLEUUID thermo_service_uuid("11111111-2222-3333-4444-000000000000");
static BLEUUID thermo_temp_uuid("11111111-2222-3333-4444-000000000001");
static BLEUUID thermo_time_uuid("11111111-2222-3333-4444-000000000002");
#define NO_SERVER_SLEEP_TIME 60
#define ON_ERROR_SLEEP_TIME 30
#define WATCHDOG_SECONDS 30
#define uS_TO_S_FACTOR 1000000
#define BLE_POWER ESP_PWR_LVL_P7
#define SENSOR_POWER_PIN A3
#define SENSOR_DATA_PIN A2
#define VBAT_PIN A13
DHTesp dht;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
public:
BLEAddress* pServerAddress;
MyAdvertisedDeviceCallbacks() :
BLEAdvertisedDeviceCallbacks(),
pServerAddress(0)
{}
~MyAdvertisedDeviceCallbacks() { if (pServerAddress) delete pServerAddress; }
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.haveName() && advertisedDevice.getName() == "termostore") {
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
}
}
};
void enable_sensor(bool enable) {
pinMode(SENSOR_POWER_PIN,OUTPUT);
digitalWrite(SENSOR_POWER_PIN,enable ? HIGH : LOW);
delay(500);
}
bool read_sensor(float* humidity, float* temperature) {
dht.setup(SENSOR_DATA_PIN,DHTesp::DHT11);
int tries=0;bool ret=false;
while (!ret && ++tries<10) {
delay(dht.getMinimumSamplingPeriod());
*humidity = dht.getHumidity();
*temperature = dht.getTemperature();
if (dht.getStatus() != DHTesp::ERROR_TIMEOUT) ret = true;
}
return ret;
}
uint32_t send_data_and_get_time(BLEAddress* pAddress,String* data) {
BLEClient* pClient = BLEDevice::createClient();
bool ok = pClient->connect(*pAddress);
if (!ok) {
return ON_ERROR_SLEEP_TIME;
}
try {
BLERemoteService* pThermoService = pClient->getService(thermo_service_uuid);
if (!pThermoService) {
return 60;
}
BLERemoteCharacteristic* pTemp = pThermoService->getCharacteristic(thermo_temp_uuid);
if (!pTemp) {
return 60;
}
pTemp->writeValue(data->c_str(),data->length());
BLERemoteCharacteristic* pTime = pThermoService->getCharacteristic(thermo_time_uuid);
if (!pTime) {
return 60;
}
std::string next_time = pTime->readValue();
pClient->disconnect();
return String(next_time.c_str()).toInt();
}
catch (...) {
pClient->disconnect();
return ON_ERROR_SLEEP_TIME;
}
}
void setup() {
BLEDevice::init("");
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, BLE_POWER);
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, BLE_POWER);
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, BLE_POWER);
enable_sensor(true);
}
void teardown_and_sleep(int next_time) {
enable_sensor(false);
BLEDevice::uninit();
delay(2000);
esp_sleep_enable_timer_wakeup(next_time * uS_TO_S_FACTOR);
esp_deep_sleep_start();
}
void watchdog_cb() {
teardown_and_sleep(ON_ERROR_SLEEP_TIME);
}
void loop() {
Ticker watchdog_timer;
watchdog_timer.attach(WATCHDOG_SECONDS,watchdog_cb);
BLEScan* pBLEScan = BLEDevice::getScan();
MyAdvertisedDeviceCallbacks* cb = new MyAdvertisedDeviceCallbacks();
pBLEScan->setAdvertisedDeviceCallbacks(cb);
pBLEScan->setActiveScan(true);
BLEScanResults foundDevices = pBLEScan->start(30);
int next_time;
if (cb->pServerAddress) {
float humidity, temperature;
bool ok = read_sensor(&humidity,&temperature);
int batteryLevel = analogRead(VBAT_PIN);
batteryLevel *= 2;
if (ok) {
String data = String(BLEDevice::getAddress().toString().c_str()) + " "
+ String(humidity) + " "
+ String(temperature) + " "
+ String(batteryLevel) + "\n";
next_time = send_data_and_get_time(cb->pServerAddress,&data);
}
else {
next_time=ON_ERROR_SLEEP_TIME;
}
}
else {
next_time = NO_SERVER_SLEEP_TIME;
}
delete cb;
teardown_and_sleep(next_time);
delay(2000);
}