WIP
This commit is contained in:
parent
797ce586aa
commit
c66afc53be
|
@ -0,0 +1,106 @@
|
|||
#include "ble_fingerprint.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#include <cmath>
|
||||
|
||||
static const char* TAG = "BLE_FINGER";
|
||||
|
||||
// Static member initialization
|
||||
float BleFingerprint::maxDistance = 10.0f;
|
||||
float BleFingerprint::absorption = 2.0f;
|
||||
int8_t BleFingerprint::txRefRssi = -59;
|
||||
int8_t BleFingerprint::rxAdjRssi = 0;
|
||||
std::string BleFingerprint::query;
|
||||
std::string BleFingerprint::include;
|
||||
std::string BleFingerprint::exclude;
|
||||
std::string BleFingerprint::knownMacs;
|
||||
std::string BleFingerprint::knownIrks;
|
||||
std::string BleFingerprint::countIds;
|
||||
|
||||
void BleFingerprint::init() {
|
||||
// Configure scan parameters
|
||||
esp_ble_scan_params_t scan_params = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x50,
|
||||
.scan_window = 0x30,
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
||||
};
|
||||
|
||||
esp_err_t status = esp_ble_gap_set_scan_params(&scan_params);
|
||||
if (status != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set scan parameters: %s", esp_err_to_name(status));
|
||||
return;
|
||||
}
|
||||
|
||||
// Register GAP callback
|
||||
esp_ble_gap_register_callback(gap_callback);
|
||||
}
|
||||
|
||||
void BleFingerprint::start_scan() {
|
||||
esp_err_t status = esp_ble_gap_start_scanning(0); // Scan indefinitely
|
||||
if (status != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start scanning: %s", esp_err_to_name(status));
|
||||
}
|
||||
}
|
||||
|
||||
void BleFingerprint::stop_scan() {
|
||||
esp_err_t status = esp_ble_gap_stop_scanning();
|
||||
if (status != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to stop scanning: %s", esp_err_to_name(status));
|
||||
}
|
||||
}
|
||||
|
||||
void BleFingerprint::gap_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param) {
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "Scan parameters set");
|
||||
break;
|
||||
|
||||
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
|
||||
if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Scan start failed");
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
||||
if (param->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
|
||||
process_advertisement(param);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BleFingerprint::process_advertisement(esp_ble_gap_cb_param_t* scan_result) {
|
||||
// Calculate distance based on RSSI
|
||||
float distance = calculate_distance(scan_result->scan_rst.rssi);
|
||||
|
||||
if (distance > maxDistance) {
|
||||
return; // Device too far away
|
||||
}
|
||||
|
||||
// Convert BDA to string for MAC address
|
||||
char bda_str[18];
|
||||
sprintf(bda_str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
scan_result->scan_rst.bda[0], scan_result->scan_rst.bda[1],
|
||||
scan_result->scan_rst.bda[2], scan_result->scan_rst.bda[3],
|
||||
scan_result->scan_rst.bda[4], scan_result->scan_rst.bda[5]);
|
||||
|
||||
ESP_LOGI(TAG, "Device found - MAC: %s, RSSI: %d, Distance: %.2f",
|
||||
bda_str, scan_result->scan_rst.rssi, distance);
|
||||
|
||||
// TODO: Implement filtering based on query, include, exclude patterns
|
||||
// TODO: Implement device tracking and MQTT reporting
|
||||
}
|
||||
|
||||
float BleFingerprint::calculate_distance(int rssi) {
|
||||
// Calculate distance using the log-distance path loss model
|
||||
float ratio = (txRefRssi - (rssi + rxAdjRssi)) / (10.0 * absorption);
|
||||
return pow(10, ratio);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_bt_defs.h"
|
||||
|
||||
class BleFingerprint {
|
||||
public:
|
||||
static void init();
|
||||
static void start_scan();
|
||||
static void stop_scan();
|
||||
|
||||
// Configuration
|
||||
static float maxDistance;
|
||||
static float absorption;
|
||||
static int8_t txRefRssi;
|
||||
static int8_t rxAdjRssi;
|
||||
|
||||
// Filters
|
||||
static std::string query;
|
||||
static std::string include;
|
||||
static std::string exclude;
|
||||
static std::string knownMacs;
|
||||
static std::string knownIrks;
|
||||
static std::string countIds;
|
||||
|
||||
private:
|
||||
static void gap_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param);
|
||||
static void process_advertisement(esp_ble_gap_cb_param_t* scan_result);
|
||||
static float calculate_distance(int rssi);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "mqtt_client.h"
|
||||
|
||||
class MqttHandler {
|
||||
public:
|
||||
static void init(const std::string& host, uint16_t port,
|
||||
const std::string& username, const std::string& password);
|
||||
static bool publish(const char* topic, int qos, bool retain, const char* payload);
|
||||
static bool is_connected();
|
||||
|
||||
// Discovery related functions
|
||||
static bool send_discovery(const char* component, const char* name, const char* config);
|
||||
static bool send_telemetry(const char* payload);
|
||||
|
||||
private:
|
||||
static esp_mqtt_client_handle_t client;
|
||||
static bool connected;
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
static void connect();
|
||||
static void disconnect();
|
||||
};
|
|
@ -0,0 +1,101 @@
|
|||
#include "mqtt_handler.h"
|
||||
#include "esp_log.h"
|
||||
#include <cstring>
|
||||
|
||||
static const char* TAG = "MQTT";
|
||||
|
||||
// Static member initialization
|
||||
esp_mqtt_client_handle_t MqttHandler::client = nullptr;
|
||||
bool MqttHandler::connected = false;
|
||||
|
||||
void MqttHandler::init(const std::string& host, uint16_t port,
|
||||
const std::string& username, const std::string& password) {
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = host.c_str(),
|
||||
.broker.address.port = port,
|
||||
.credentials.username = username.c_str(),
|
||||
.credentials.authentication.password = password.c_str(),
|
||||
};
|
||||
|
||||
client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Failed to initialize MQTT client");
|
||||
return;
|
||||
}
|
||||
|
||||
// Register event handler
|
||||
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, NULL);
|
||||
|
||||
// Start client
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void MqttHandler::mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data) {
|
||||
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
|
||||
|
||||
switch (event->event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT Connected");
|
||||
connected = true;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT Disconnected");
|
||||
connected = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGE(TAG, "MQTT Error");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MqttHandler::publish(const char* topic, int qos, bool retain, const char* payload) {
|
||||
if (!connected || !client) {
|
||||
ESP_LOGW(TAG, "MQTT not connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
int msg_id = esp_mqtt_client_publish(client, topic, payload,
|
||||
strlen(payload), qos, retain);
|
||||
return msg_id != -1;
|
||||
}
|
||||
|
||||
bool MqttHandler::is_connected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
bool MqttHandler::send_discovery(const char* component, const char* name,
|
||||
const char* config) {
|
||||
if (!connected) return false;
|
||||
|
||||
// Format discovery topic
|
||||
char topic[128];
|
||||
snprintf(topic, sizeof(topic), "homeassistant/%s/%s/config",
|
||||
component, name);
|
||||
|
||||
return publish(topic, 0, true, config);
|
||||
}
|
||||
|
||||
bool MqttHandler::send_telemetry(const char* payload) {
|
||||
if (!connected) return false;
|
||||
|
||||
return publish("espresense/telemetry", 0, false, payload);
|
||||
}
|
||||
|
||||
void MqttHandler::connect() {
|
||||
if (client) {
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
}
|
||||
|
||||
void MqttHandler::disconnect() {
|
||||
if (client) {
|
||||
esp_mqtt_client_stop(client);
|
||||
}
|
||||
connected = false;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#include "bh1750.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char* TAG = "BH1750";
|
||||
|
||||
// Static member initialization
|
||||
i2c_port_t BH1750::i2c_port = I2C_NUM_0;
|
||||
uint8_t BH1750::device_addr = 0x23;
|
||||
BH1750::Mode BH1750::current_mode = BH1750::CONTINUOUS_HIGH_RES_MODE;
|
||||
|
||||
esp_err_t BH1750::init(i2c_port_t i2c_num, uint8_t addr) {
|
||||
i2c_port = i2c_num;
|
||||
device_addr = addr;
|
||||
|
||||
// Power on the sensor
|
||||
esp_err_t ret = write_command(0x01);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to power on sensor");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Set default mode
|
||||
ret = set_mode(CONTINUOUS_HIGH_RES_MODE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set mode");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BH1750::write_command(uint8_t cmd) {
|
||||
i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd_handle);
|
||||
i2c_master_write_byte(cmd_handle, (device_addr << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd_handle, cmd, true);
|
||||
i2c_master_stop(cmd_handle);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd_handle, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t BH1750::set_mode(Mode mode) {
|
||||
esp_err_t ret = write_command(mode);
|
||||
if (ret == ESP_OK) {
|
||||
current_mode = mode;
|
||||
// Wait for measurement to be ready
|
||||
// High resolution mode needs 120ms, low resolution needs 16ms
|
||||
vTaskDelay(pdMS_TO_TICKS(mode == CONTINUOUS_HIGH_RES_MODE ? 120 : 16));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t BH1750::read_light(float* lux) {
|
||||
uint8_t data[2];
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_READ, true);
|
||||
i2c_master_read(cmd, data, 2, I2C_MASTER_LAST_NACK);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read sensor data");
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t level = (data[0] << 8) | data[1];
|
||||
*lux = level / 1.2f; // Convert to lux according to datasheet
|
||||
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
#include "bme280.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "BME280";
|
||||
|
||||
// Static member initialization
|
||||
i2c_port_t BME280::i2c_port = I2C_NUM_0;
|
||||
uint8_t BME280::device_addr = 0x76;
|
||||
|
||||
// Calibration data initialization
|
||||
uint16_t BME280::dig_T1 = 0;
|
||||
int16_t BME280::dig_T2 = 0;
|
||||
int16_t BME280::dig_T3 = 0;
|
||||
uint16_t BME280::dig_P1 = 0;
|
||||
int16_t BME280::dig_P2 = 0;
|
||||
int16_t BME280::dig_P3 = 0;
|
||||
int16_t BME280::dig_P4 = 0;
|
||||
int16_t BME280::dig_P5 = 0;
|
||||
int16_t BME280::dig_P6 = 0;
|
||||
int16_t BME280::dig_P7 = 0;
|
||||
int16_t BME280::dig_P8 = 0;
|
||||
int16_t BME280::dig_P9 = 0;
|
||||
uint8_t BME280::dig_H1 = 0;
|
||||
int16_t BME280::dig_H2 = 0;
|
||||
uint8_t BME280::dig_H3 = 0;
|
||||
int16_t BME280::dig_H4 = 0;
|
||||
int16_t BME280::dig_H5 = 0;
|
||||
int8_t BME280::dig_H6 = 0;
|
||||
|
||||
esp_err_t BME280::init(i2c_port_t i2c_num, uint8_t addr) {
|
||||
i2c_port = i2c_num;
|
||||
device_addr = addr;
|
||||
|
||||
// Read chip ID
|
||||
uint8_t chip_id;
|
||||
esp_err_t ret = read_registers(0xD0, &chip_id, 1);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read chip ID");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (chip_id != 0x60) {
|
||||
ESP_LOGE(TAG, "Unexpected chip ID: 0x%02x", chip_id);
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// Read calibration data
|
||||
ret = read_calibration_data();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read calibration data");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Configure sensor
|
||||
// Normal mode, temperature and pressure oversampling x1
|
||||
write_register(0xF4, 0x27);
|
||||
// Humidity oversampling x1
|
||||
write_register(0xF2, 0x01);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BME280::read_registers(uint8_t reg, uint8_t* data, size_t len) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, reg, true);
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_READ, true);
|
||||
if (len > 1) {
|
||||
i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
|
||||
}
|
||||
i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t BME280::write_register(uint8_t reg, uint8_t value) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, reg, true);
|
||||
i2c_master_write_byte(cmd, value, true);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t BME280::read_calibration_data() {
|
||||
uint8_t buffer[26];
|
||||
esp_err_t ret;
|
||||
|
||||
// Read temperature and pressure calibration data
|
||||
ret = read_registers(0x88, buffer, 26);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
dig_T1 = (buffer[1] << 8) | buffer[0];
|
||||
dig_T2 = (buffer[3] << 8) | buffer[2];
|
||||
dig_T3 = (buffer[5] << 8) | buffer[4];
|
||||
dig_P1 = (buffer[7] << 8) | buffer[6];
|
||||
dig_P2 = (buffer[9] << 8) | buffer[8];
|
||||
dig_P3 = (buffer[11] << 8) | buffer[10];
|
||||
dig_P4 = (buffer[13] << 8) | buffer[12];
|
||||
dig_P5 = (buffer[15] << 8) | buffer[14];
|
||||
dig_P6 = (buffer[17] << 8) | buffer[16];
|
||||
dig_P7 = (buffer[19] << 8) | buffer[18];
|
||||
dig_P8 = (buffer[21] << 8) | buffer[20];
|
||||
dig_P9 = (buffer[23] << 8) | buffer[22];
|
||||
dig_H1 = buffer[25];
|
||||
|
||||
// Read humidity calibration data
|
||||
ret = read_registers(0xE1, buffer, 7);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
dig_H2 = (buffer[1] << 8) | buffer[0];
|
||||
dig_H3 = buffer[2];
|
||||
dig_H4 = (buffer[3] << 4) | (buffer[4] & 0x0F);
|
||||
dig_H5 = (buffer[5] << 4) | (buffer[4] >> 4);
|
||||
dig_H6 = buffer[6];
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BME280::read_temperature(float* temp) {
|
||||
uint8_t data[3];
|
||||
esp_err_t ret = read_registers(0xFA, data, 3);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
int32_t adc_T = (data[0] << 16) | (data[1] << 8) | data[2];
|
||||
adc_T >>= 4;
|
||||
|
||||
int32_t var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
|
||||
int32_t var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14;
|
||||
|
||||
int32_t t_fine = var1 + var2;
|
||||
*temp = (t_fine * 5 + 128) >> 8;
|
||||
*temp /= 100.0f;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BME280::read_pressure(float* pressure) {
|
||||
uint8_t data[3];
|
||||
esp_err_t ret = read_registers(0xF7, data, 3);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
int32_t adc_P = (data[0] << 16) | (data[1] << 8) | data[2];
|
||||
adc_P >>= 4;
|
||||
|
||||
// Pressure compensation calculation
|
||||
int64_t var1, var2, p;
|
||||
var1 = ((int64_t)t_fine) - 128000;
|
||||
var2 = var1 * var1 * (int64_t)dig_P6;
|
||||
var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
|
||||
var2 = var2 + (((int64_t)dig_P4) << 35);
|
||||
var1 = ((var1 * var1 * (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
|
||||
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)dig_P1) >> 33;
|
||||
if (var1 == 0) return ESP_FAIL;
|
||||
|
||||
p = 1048576 - adc_P;
|
||||
p = (((p << 31) - var2) * 3125) / var1;
|
||||
var1 = (((int64_t)dig_P9) * (p >> 13) * (p >> 13)) >> 25;
|
||||
var2 = (((int64_t)dig_P8) * p) >> 19;
|
||||
p = ((p + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
|
||||
|
||||
*pressure = (float)p / 256.0f;
|
||||
*pressure /= 100.0f; // Convert to hPa
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t BME280::read_humidity(float* humidity) {
|
||||
uint8_t data[2];
|
||||
esp_err_t ret = read_registers(0xFD, data, 2);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
int32_t adc_H = (data[0] << 8) | data[1];
|
||||
|
||||
int32_t v_x1_u32r = (t_fine - ((int32_t)76800));
|
||||
v_x1_u32r = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1_u32r)) +
|
||||
((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dig_H6)) >> 10) *
|
||||
(((v_x1_u32r * ((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
|
||||
((int32_t)2097152)) * ((int32_t)dig_H2) + 8192) >> 14));
|
||||
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)dig_H1)) >> 4));
|
||||
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
|
||||
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
|
||||
|
||||
*humidity = (float)(v_x1_u32r >> 12) / 1024.0f;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
#include "dht.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
static const char* TAG = "DHT";
|
||||
|
||||
// Static member initialization
|
||||
gpio_num_t DHT::gpio_pin = GPIO_NUM_NC;
|
||||
DHT::Type DHT::sensor_type = DHT::DHT22;
|
||||
|
||||
esp_err_t DHT::init(gpio_num_t gpio_num, Type type) {
|
||||
gpio_pin = gpio_num;
|
||||
sensor_type = type;
|
||||
|
||||
// Configure GPIO
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << gpio_num),
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
esp_err_t ret = gpio_config(&io_conf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to configure GPIO");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Initial state is high
|
||||
gpio_set_level(gpio_pin, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait for sensor to stabilize
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void DHT::delay_us(uint32_t us) {
|
||||
uint32_t start = esp_timer_get_time();
|
||||
while (esp_timer_get_time() - start < us);
|
||||
}
|
||||
|
||||
int DHT::wait_state_change(int level, int timeout_us) {
|
||||
int us_waited = 0;
|
||||
while (gpio_get_level(gpio_pin) == level) {
|
||||
if (us_waited > timeout_us) return -1;
|
||||
delay_us(1);
|
||||
us_waited++;
|
||||
}
|
||||
return us_waited;
|
||||
}
|
||||
|
||||
esp_err_t DHT::read_data(uint8_t* data) {
|
||||
uint8_t bits[5] = {0};
|
||||
uint8_t cnt = 7;
|
||||
uint8_t idx = 0;
|
||||
|
||||
// Clear data array
|
||||
for (int i = 0; i < 5; i++) data[i] = 0;
|
||||
|
||||
// Send start signal
|
||||
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(gpio_pin, 0);
|
||||
delay_us(sensor_type == DHT11 ? 18000 : 1000); // Hold low for 18ms (DHT11) or 1ms (DHT22)
|
||||
gpio_set_level(gpio_pin, 1);
|
||||
delay_us(40);
|
||||
|
||||
gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
|
||||
|
||||
// Read sensor response
|
||||
if (wait_state_change(0, 80) == -1) return ESP_ERR_TIMEOUT;
|
||||
if (wait_state_change(1, 80) == -1) return ESP_ERR_TIMEOUT;
|
||||
|
||||
// Read data
|
||||
for (int i = 0; i < 40; i++) {
|
||||
if (wait_state_change(0, 50) == -1) return ESP_ERR_TIMEOUT;
|
||||
int us = wait_state_change(1, 70);
|
||||
if (us == -1) return ESP_ERR_TIMEOUT;
|
||||
|
||||
if (us > 40) {
|
||||
bits[idx] |= (1 << cnt);
|
||||
}
|
||||
if (cnt == 0) {
|
||||
cnt = 7;
|
||||
idx++;
|
||||
} else {
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify checksum
|
||||
if (bits[4] != ((bits[0] + bits[1] + bits[2] + bits[3]) & 0xFF)) {
|
||||
ESP_LOGE(TAG, "Checksum failed");
|
||||
return ESP_ERR_INVALID_CRC;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) data[i] = bits[i];
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t DHT::read_temperature(float* temperature) {
|
||||
uint8_t data[5];
|
||||
esp_err_t ret = read_data(data);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
if (sensor_type == DHT11) {
|
||||
*temperature = data[2];
|
||||
if (data[3] & 0x80) {
|
||||
*temperature = -(*temperature);
|
||||
}
|
||||
} else {
|
||||
*temperature = ((data[2] & 0x7F) << 8) + data[3];
|
||||
*temperature *= 0.1;
|
||||
if (data[2] & 0x80) {
|
||||
*temperature = -(*temperature);
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t DHT::read_humidity(float* humidity) {
|
||||
uint8_t data[5];
|
||||
esp_err_t ret = read_data(data);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
if (sensor_type == DHT11) {
|
||||
*humidity = data[0];
|
||||
} else {
|
||||
*humidity = (data[0] << 8) + data[1];
|
||||
*humidity *= 0.1;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/i2c.h"
|
||||
|
||||
class BH1750 {
|
||||
public:
|
||||
enum Mode {
|
||||
CONTINUOUS_HIGH_RES_MODE = 0x10,
|
||||
CONTINUOUS_LOW_RES_MODE = 0x13,
|
||||
ONE_TIME_HIGH_RES_MODE = 0x20,
|
||||
ONE_TIME_LOW_RES_MODE = 0x23
|
||||
};
|
||||
|
||||
static esp_err_t init(i2c_port_t i2c_num, uint8_t addr = 0x23);
|
||||
static esp_err_t read_light(float* lux);
|
||||
static esp_err_t set_mode(Mode mode);
|
||||
|
||||
private:
|
||||
static i2c_port_t i2c_port;
|
||||
static uint8_t device_addr;
|
||||
static Mode current_mode;
|
||||
|
||||
static esp_err_t write_command(uint8_t cmd);
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/i2c.h"
|
||||
|
||||
class BME280 {
|
||||
public:
|
||||
static esp_err_t init(i2c_port_t i2c_num, uint8_t addr = 0x76);
|
||||
static esp_err_t read_temperature(float* temp);
|
||||
static esp_err_t read_humidity(float* humidity);
|
||||
static esp_err_t read_pressure(float* pressure);
|
||||
|
||||
private:
|
||||
static i2c_port_t i2c_port;
|
||||
static uint8_t device_addr;
|
||||
|
||||
// Calibration data
|
||||
static uint16_t dig_T1;
|
||||
static int16_t dig_T2;
|
||||
static int16_t dig_T3;
|
||||
static uint16_t dig_P1;
|
||||
static int16_t dig_P2;
|
||||
static int16_t dig_P3;
|
||||
static int16_t dig_P4;
|
||||
static int16_t dig_P5;
|
||||
static int16_t dig_P6;
|
||||
static int16_t dig_P7;
|
||||
static int16_t dig_P8;
|
||||
static int16_t dig_P9;
|
||||
static uint8_t dig_H1;
|
||||
static int16_t dig_H2;
|
||||
static uint8_t dig_H3;
|
||||
static int16_t dig_H4;
|
||||
static int16_t dig_H5;
|
||||
static int8_t dig_H6;
|
||||
|
||||
static esp_err_t read_calibration_data();
|
||||
static esp_err_t read_registers(uint8_t reg, uint8_t* data, size_t len);
|
||||
static esp_err_t write_register(uint8_t reg, uint8_t value);
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
class DHT {
|
||||
public:
|
||||
enum Type {
|
||||
DHT11 = 11,
|
||||
DHT22 = 22
|
||||
};
|
||||
|
||||
static esp_err_t init(gpio_num_t gpio_num, Type type = DHT22);
|
||||
static esp_err_t read_temperature(float* temperature);
|
||||
static esp_err_t read_humidity(float* humidity);
|
||||
|
||||
private:
|
||||
static gpio_num_t gpio_pin;
|
||||
static Type sensor_type;
|
||||
|
||||
static esp_err_t read_data(uint8_t* data);
|
||||
static void delay_us(uint32_t us);
|
||||
static int wait_state_change(int level, int timeout_us);
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "bme280.h"
|
||||
#include "bh1750.h"
|
||||
#include "dht.h"
|
||||
|
||||
class SensorManager {
|
||||
public:
|
||||
static esp_err_t init(i2c_port_t i2c_port = I2C_NUM_0,
|
||||
gpio_num_t sda = GPIO_NUM_21,
|
||||
gpio_num_t scl = GPIO_NUM_22,
|
||||
uint32_t freq = 100000);
|
||||
|
||||
// Sensor initialization methods
|
||||
static esp_err_t init_bme280(uint8_t addr = 0x76);
|
||||
static esp_err_t init_bh1750(uint8_t addr = 0x23);
|
||||
static esp_err_t init_dht(gpio_num_t gpio_num, DHT::Type type = DHT::DHT22);
|
||||
|
||||
// Sensor reading methods
|
||||
static esp_err_t read_temperature(float* temp, const char* sensor = "bme280");
|
||||
static esp_err_t read_humidity(float* humidity, const char* sensor = "bme280");
|
||||
static esp_err_t read_pressure(float* pressure);
|
||||
static esp_err_t read_light(float* lux);
|
||||
|
||||
private:
|
||||
static i2c_port_t i2c_num;
|
||||
static bool bme280_initialized;
|
||||
static bool bh1750_initialized;
|
||||
static bool dht_initialized;
|
||||
|
||||
static esp_err_t init_i2c(gpio_num_t sda, gpio_num_t scl, uint32_t freq);
|
||||
};
|
|
@ -0,0 +1,114 @@
|
|||
#include "sensor_manager.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "SensorManager";
|
||||
|
||||
// Static member initialization
|
||||
i2c_port_t SensorManager::i2c_num = I2C_NUM_0;
|
||||
bool SensorManager::bme280_initialized = false;
|
||||
bool SensorManager::bh1750_initialized = false;
|
||||
bool SensorManager::dht_initialized = false;
|
||||
|
||||
esp_err_t SensorManager::init(i2c_port_t i2c_port, gpio_num_t sda, gpio_num_t scl, uint32_t freq) {
|
||||
i2c_num = i2c_port;
|
||||
return init_i2c(sda, scl, freq);
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::init_i2c(gpio_num_t sda, gpio_num_t scl, uint32_t freq) {
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = sda,
|
||||
.scl_io_num = scl,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = freq
|
||||
}
|
||||
};
|
||||
|
||||
esp_err_t ret = i2c_param_config(i2c_num, &conf);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
return i2c_driver_install(i2c_num, conf.mode, 0, 0, 0);
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::init_bme280(uint8_t addr) {
|
||||
esp_err_t ret = BME280::init(i2c_num, addr);
|
||||
if (ret == ESP_OK) {
|
||||
bme280_initialized = true;
|
||||
ESP_LOGI(TAG, "BME280 initialized successfully");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::init_bh1750(uint8_t addr) {
|
||||
esp_err_t ret = BH1750::init(i2c_num, addr);
|
||||
if (ret == ESP_OK) {
|
||||
bh1750_initialized = true;
|
||||
ESP_LOGI(TAG, "BH1750 initialized successfully");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::init_dht(gpio_num_t gpio_num, DHT::Type type) {
|
||||
esp_err_t ret = DHT::init(gpio_num, type);
|
||||
if (ret == ESP_OK) {
|
||||
dht_initialized = true;
|
||||
ESP_LOGI(TAG, "DHT sensor initialized successfully");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::read_temperature(float* temp, const char* sensor) {
|
||||
if (strcmp(sensor, "bme280") == 0) {
|
||||
if (!bme280_initialized) {
|
||||
ESP_LOGE(TAG, "BME280 not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return BME280::read_temperature(temp);
|
||||
} else if (strcmp(sensor, "dht") == 0) {
|
||||
if (!dht_initialized) {
|
||||
ESP_LOGE(TAG, "DHT not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return DHT::read_temperature(temp);
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Unknown sensor type for temperature reading");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::read_humidity(float* humidity, const char* sensor) {
|
||||
if (strcmp(sensor, "bme280") == 0) {
|
||||
if (!bme280_initialized) {
|
||||
ESP_LOGE(TAG, "BME280 not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return BME280::read_humidity(humidity);
|
||||
} else if (strcmp(sensor, "dht") == 0) {
|
||||
if (!dht_initialized) {
|
||||
ESP_LOGE(TAG, "DHT not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return DHT::read_humidity(humidity);
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Unknown sensor type for humidity reading");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::read_pressure(float* pressure) {
|
||||
if (!bme280_initialized) {
|
||||
ESP_LOGE(TAG, "BME280 not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return BME280::read_pressure(pressure);
|
||||
}
|
||||
|
||||
esp_err_t SensorManager::read_light(float* lux) {
|
||||
if (!bh1750_initialized) {
|
||||
ESP_LOGE(TAG, "BH1750 not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return BH1750::read_light(lux);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
// Component headers
|
||||
#include "ble_fingerprint.h"
|
||||
#include "mqtt_handler.h"
|
||||
|
||||
// Global variables
|
||||
extern TimerHandle_t reconnectTimer;
|
||||
extern TaskHandle_t scanTaskHandle;
|
||||
extern unsigned long updateStartedMillis;
|
||||
extern unsigned long lastTeleMillis;
|
||||
extern int reconnectTries;
|
||||
extern int teleFails;
|
||||
extern int reportFailed;
|
||||
extern bool online;
|
||||
extern bool sentDiscovery;
|
||||
extern UBaseType_t bleStack;
|
||||
|
||||
// Configuration
|
||||
extern std::string room;
|
||||
extern std::string mqttHost;
|
||||
extern std::string mqttUser;
|
||||
extern std::string mqttPass;
|
||||
extern uint16_t mqttPort;
|
||||
|
||||
// Settings
|
||||
extern bool discovery;
|
||||
extern bool publishTele;
|
||||
extern bool publishRooms;
|
||||
extern bool publishDevices;
|
||||
|
||||
// Function declarations
|
||||
void app_main(void);
|
||||
bool sendTelemetry(unsigned int totalSeen, unsigned int totalFpSeen,
|
||||
unsigned int totalFpQueried, unsigned int totalFpReported,
|
||||
unsigned int count);
|
||||
|
||||
// Constants
|
||||
constexpr const char* DEFAULT_MQTT_HOST = "mqtt.local";
|
||||
constexpr uint16_t DEFAULT_MQTT_PORT = 1883;
|
||||
constexpr const char* DEFAULT_MQTT_USER = "";
|
||||
constexpr const char* DEFAULT_MQTT_PASSWORD = "";
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
#include "main.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_mac.h"
|
||||
#include "cJSON.h"
|
||||
#include "sensor_manager.h"
|
||||
|
||||
static const char *TAG = "ESPresense";
|
||||
|
||||
// Global variables initialization
|
||||
TimerHandle_t reconnectTimer = nullptr;
|
||||
TaskHandle_t scanTaskHandle = nullptr;
|
||||
unsigned long updateStartedMillis = 0;
|
||||
unsigned long lastTeleMillis = 0;
|
||||
int reconnectTries = 0;
|
||||
int teleFails = 0;
|
||||
int reportFailed = 0;
|
||||
bool online = false;
|
||||
bool sentDiscovery = false;
|
||||
UBaseType_t bleStack = 0;
|
||||
|
||||
// Configuration
|
||||
std::string room;
|
||||
std::string mqttHost = DEFAULT_MQTT_HOST;
|
||||
std::string mqttUser = DEFAULT_MQTT_USER;
|
||||
std::string mqttPass = DEFAULT_MQTT_PASSWORD;
|
||||
uint16_t mqttPort = DEFAULT_MQTT_PORT;
|
||||
|
||||
// Settings
|
||||
bool discovery = true;
|
||||
bool publishTele = true;
|
||||
bool publishRooms = false;
|
||||
bool publishDevices = true;
|
||||
|
||||
static void scan_task(void* arg) {
|
||||
while (true) {
|
||||
BleFingerprint::start_scan();
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Small delay between scans
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_nvs(void)
|
||||
{
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
static void initialize_wifi(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
}
|
||||
|
||||
static void load_config(void)
|
||||
{
|
||||
nvs_handle_t nvs;
|
||||
esp_err_t err = nvs_open("config", NVS_READWRITE, &nvs);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error opening NVS handle");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read room name or generate default
|
||||
size_t required_size;
|
||||
err = nvs_get_str(nvs, "room", nullptr, &required_size);
|
||||
if (err == ESP_OK) {
|
||||
char* room_buf = new char[required_size];
|
||||
nvs_get_str(nvs, "room", room_buf, &required_size);
|
||||
room = room_buf;
|
||||
delete[] room_buf;
|
||||
} else {
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
char room_buf[18];
|
||||
snprintf(room_buf, sizeof(room_buf), "esp-%02x%02x%02x", mac[3], mac[4], mac[5]);
|
||||
room = room_buf;
|
||||
}
|
||||
|
||||
nvs_close(nvs);
|
||||
}
|
||||
|
||||
static void initialize_sensors(void)
|
||||
{
|
||||
esp_err_t ret = SensorManager::init(I2C_NUM_0, GPIO_NUM_21, GPIO_NUM_22);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize I2C");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize BME280 if available
|
||||
ret = SensorManager::init_bme280();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "BME280 not found");
|
||||
}
|
||||
|
||||
// Initialize BH1750 if available
|
||||
ret = SensorManager::init_bh1750();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "BH1750 not found");
|
||||
}
|
||||
|
||||
// Initialize DHT22 if available
|
||||
ret = SensorManager::init_dht(GPIO_NUM_23, DHT::DHT22);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "DHT22 not found");
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "ESPresense starting...");
|
||||
|
||||
// Initialize NVS
|
||||
initialize_nvs();
|
||||
|
||||
// Load configuration
|
||||
load_config();
|
||||
|
||||
// Initialize WiFi
|
||||
initialize_wifi();
|
||||
|
||||
// Initialize sensors
|
||||
initialize_sensors();
|
||||
|
||||
// Initialize BLE
|
||||
esp_err_t ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Bluetooth memory release failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Initialize controller failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Enable controller failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Init bluedroid failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Enable bluedroid failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize BLE scanning
|
||||
BleFingerprint::init();
|
||||
|
||||
// Create BLE scan task
|
||||
xTaskCreate(scan_task, "scan_task", 4096, nullptr, 5, &scanTaskHandle);
|
||||
|
||||
// Initialize MQTT
|
||||
MqttHandler::init(mqttHost, mqttPort, mqttUser, mqttPass);
|
||||
}
|
||||
|
||||
bool sendTelemetry(unsigned int totalSeen, unsigned int totalFpSeen,
|
||||
unsigned int totalFpQueried, unsigned int totalFpReported,
|
||||
unsigned int count)
|
||||
{
|
||||
if (!MqttHandler::is_connected()) {
|
||||
ESP_LOGW(TAG, "MQTT not connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t now = esp_timer_get_time() / 1000; // Convert to milliseconds
|
||||
|
||||
if (now - lastTeleMillis < 15000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lastTeleMillis = now;
|
||||
|
||||
// Create JSON document using cJSON
|
||||
cJSON *doc = cJSON_CreateObject();
|
||||
|
||||
// Add telemetry data
|
||||
char ip[16];
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
sprintf(ip, IPSTR, IP2STR(&ip_info.ip));
|
||||
cJSON_AddStringToObject(doc, "ip", ip);
|
||||
|
||||
cJSON_AddNumberToObject(doc, "uptime", esp_timer_get_time() / 1000000);
|
||||
|
||||
int8_t rssi;
|
||||
esp_wifi_get_rssi(&rssi);
|
||||
cJSON_AddNumberToObject(doc, "rssi", rssi);
|
||||
|
||||
// Add sensor data if available
|
||||
float value;
|
||||
if (SensorManager::read_temperature(&value, "bme280") == ESP_OK) {
|
||||
cJSON_AddNumberToObject(doc, "temperature", value);
|
||||
}
|
||||
if (SensorManager::read_humidity(&value, "bme280") == ESP_OK) {
|
||||
cJSON_AddNumberToObject(doc, "humidity", value);
|
||||
}
|
||||
if (SensorManager::read_pressure(&value) == ESP_OK) {
|
||||
cJSON_AddNumberToObject(doc, "pressure", value);
|
||||
}
|
||||
if (SensorManager::read_light(&value) == ESP_OK) {
|
||||
cJSON_AddNumberToObject(doc, "light", value);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
cJSON_AddNumberToObject(doc, "count", count);
|
||||
}
|
||||
if (totalSeen > 0) {
|
||||
cJSON_AddNumberToObject(doc, "adverts", totalSeen);
|
||||
}
|
||||
|
||||
char *json_str = cJSON_Print(doc);
|
||||
bool success = MqttHandler::send_telemetry(json_str);
|
||||
|
||||
cJSON_Delete(doc);
|
||||
free(json_str);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
[platformio]
|
||||
default_envs = esp32
|
||||
build_cache_dir = ~/.buildcache
|
||||
extra_configs = platformio_override.ini
|
||||
|
||||
[common]
|
||||
framework = espidf
|
||||
platform = espressif32
|
||||
platform_packages =
|
||||
framework-espidf @ ~5.1.0
|
||||
check_tool = cppcheck, clangtidy
|
||||
check_flags = clangtidy: --config-file=.clang-tidy
|
||||
check_skip_packages = yes
|
||||
|
||||
build_flags =
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat=2
|
||||
-Wno-format-nonliteral
|
||||
-D CONFIG_BT_NIMBLE_TASK_STACK_SIZE=5632
|
||||
-D CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5632
|
||||
-D CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
|
||||
-D CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=20
|
||||
-D CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
|
||||
build_unflags =
|
||||
-Wswitch-unreachable
|
||||
-Wstringop-overflow
|
||||
-Wincompatible-pointer-types
|
||||
-Wnonnull-compare
|
||||
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder, time
|
||||
upload_speed = 1500000
|
||||
extra_scripts = update_ts.py
|
||||
|
||||
[esp32]
|
||||
extends = common
|
||||
board = esp32dev
|
||||
debug_tool = esp-prog
|
||||
build_flags =
|
||||
-mtarget-align
|
||||
-D ARDUINO_ARCH_ESP32
|
||||
-D CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
|
||||
-D REPORT_PINNED_TO_CORE=1
|
||||
-D CONFIG_USE_ETHERNET
|
||||
${common.build_flags}
|
||||
|
||||
[esp32c3]
|
||||
extends = common
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.flash_mode = dio
|
||||
build_flags =
|
||||
-D ARDUINO_ARCH_ESP32
|
||||
-D ARDUINO_ARCH_ESP32C3
|
||||
-D CONFIG_IDF_TARGET_ESP32C3
|
||||
-D CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
|
||||
-D REPORT_PINNED_TO_CORE=0
|
||||
-D ESP32C3
|
||||
${common.build_flags}
|
||||
|
||||
[esp32c3-cdc]
|
||||
extends = esp32c3
|
||||
build_flags =
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
${esp32c3.build_flags}
|
||||
|
||||
[esp32s3]
|
||||
extends = common
|
||||
board = dfrobot_firebeetle2_esp32s3
|
||||
build_flags =
|
||||
-D ARDUINO_ARCH_ESP32
|
||||
-D ARDUINO_ARCH_ESP32S3
|
||||
-D CONFIG_IDF_TARGET_ESP32S3
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D REPORT_PINNED_TO_CORE=1
|
||||
-D ESP32S3
|
||||
${common.build_flags}
|
||||
|
||||
[esp32s3-cdc]
|
||||
extends = esp32s3
|
||||
build_flags =
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
${esp32s3.build_flags}
|
||||
|
||||
[env:esp32]
|
||||
extends = esp32
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D FIRMWARE='"esp32"'
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
||||
|
||||
[env:esp32c3]
|
||||
extends = esp32c3
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D FIRMWARE='"esp32c3"'
|
||||
-D SENSORS
|
||||
${esp32c3.build_flags}
|
||||
|
||||
[env:esp32c3-cdc]
|
||||
extends = esp32c3-cdc
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D FIRMWARE='"esp32c3-cdc"'
|
||||
-D SENSORS
|
||||
${esp32c3-cdc.build_flags}
|
||||
|
||||
[env:esp32s3]
|
||||
extends = esp32s3
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D FIRMWARE='"esp32s3"'
|
||||
-D SENSORS
|
||||
${esp32s3.build_flags}
|
||||
|
||||
[env:esp32s3-cdc]
|
||||
extends = esp32s3-cdc
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D FIRMWARE='"esp32s3-cdc"'
|
||||
-D SENSORS
|
||||
${esp32s3-cdc.build_flags}
|
||||
|
||||
[env:esp32-verbose]
|
||||
extends = esp32
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=2
|
||||
-D FIRMWARE='"esp32-verbose"'
|
||||
-D VERBOSE
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
||||
|
||||
[env:esp32c3-verbose]
|
||||
extends = esp32c3
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=2
|
||||
-D FIRMWARE='"esp32c3-verbose"'
|
||||
-D VERBOSE
|
||||
-D SENSORS
|
||||
${esp32c3.build_flags}
|
||||
|
||||
[env:esp32s3-verbose]
|
||||
extends = esp32s3
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=2
|
||||
-D FIRMWARE='"esp32s3-verbose"'
|
||||
-D VERBOSE
|
||||
-D SENSORS
|
||||
${esp32s3.build_flags}
|
||||
|
||||
[env:m5stickc]
|
||||
extends = esp32
|
||||
board = m5stick-c
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D TFT_FONT=1
|
||||
-D M5STICK
|
||||
-D FIRMWARE='"m5stickc"'
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
||||
|
||||
[env:m5stickc-plus]
|
||||
extends = esp32
|
||||
board = m5stick-c
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D TFT_FONT=2
|
||||
-D M5STICK
|
||||
-D PLUS
|
||||
-D FIRMWARE='"m5stickc-plus"'
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
||||
|
||||
[env:m5atom]
|
||||
extends = esp32
|
||||
board = m5stack-atom
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D M5ATOM
|
||||
-D MATRIX
|
||||
-D FIRMWARE='"m5atom"'
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
||||
|
||||
[env:macchina-a0]
|
||||
extends = esp32
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D MACCHINA_A0
|
||||
-D FIRMWARE='"macchina-a0"'
|
||||
-D SENSORS
|
||||
${esp32.build_flags}
|
Loading…
Reference in New Issue