Newer
Older
smart-home-server / devices / sensor / bme280_sensor.cpp
@root root 18 hours ago 6 KB Device. Sensor
#include "bme280_sensor.h"

Bme280Sensor::Bme280Sensor() {
}

Bme280Sensor::~Bme280Sensor() {
	if (_bme280 != nullptr) {
		delete _bme280;
		_bme280 = nullptr;
	}

	if (_bmp280 != nullptr) {
		delete _bmp280;
		_bmp280 = nullptr;
	}
}

bool Bme280Sensor::begin(TwoWire &wire, const Bme280Config &config) {
	_config = config;
	_wire = &wire;

	_wire -> begin(_config.sda_pin, _config.scl_pin, 400000);

	/*
		На случай повторной инициализации.
	*/
	if (_bme280 != nullptr) {
		delete _bme280;
		_bme280 = nullptr;
	}

	if (_bmp280 != nullptr) {
		delete _bmp280;
		_bmp280 = nullptr;
	}

	_sensor_type = BME_SENSOR_TYPE_UNKNOWN;
	_initialized = false;
	_online = false;
	_has_valid_data = false;
	_last_read_attempt_ms = 0;
	_last_success_read_ms = 0;

	_temperature_c = 0.0f;
	_pressure_hpa = 0.0f;
	_humidity_percent = 0.0f;

	_filtered_temperature_c = 0.0f;
	_filtered_pressure_hpa = 0.0f;
	_filtered_humidity_percent = 0.0f;

	/*
		Сначала пробуем BME280.
	*/
	if (init_bme280()) {
		_sensor_type = BME_SENSOR_TYPE_BME280;
		_initialized = true;
		_online = true;
		return true;
	}

	/*
		Если не вышло, пробуем BMP280.
	*/
	if (init_bmp280()) {
		_sensor_type = BME_SENSOR_TYPE_BMP280;
		_initialized = true;
		_online = true;
		return true;
	}

	_sensor_type = BME_SENSOR_TYPE_UNKNOWN;
	_initialized = false;
	_online = false;
	return false;
}

void Bme280Sensor::update() {
	if (!_initialized) {
		return;
	}

	uint32_t now_ms = millis();

	if (now_ms - _last_read_attempt_ms < _config.read_interval_ms) {
		return;
	}

	_last_read_attempt_ms = now_ms;

	float temperature = 0.0f;
	float pressure = 0.0f;
	float humidity = 0.0f;

	if (_sensor_type == BME_SENSOR_TYPE_BME280) {
		if (_bme280 == nullptr) {
			_online = false;
			return;
		}

		temperature = _bme280 -> readTemperature();
		pressure = _bme280 -> readPressure() / 100.0f;
		humidity = _bme280 -> readHumidity();

		if (isnan(temperature) || isnan(pressure) || isnan(humidity)) {
			_online = false;
			return;
		}

		_temperature_c = temperature;
		_pressure_hpa = pressure;
		_humidity_percent = humidity;

		update_filtered_temperature(temperature);
		update_filtered_pressure(pressure);
		update_filtered_humidity(humidity);
	} else if (_sensor_type == BME_SENSOR_TYPE_BMP280) {
		if (_bmp280 == nullptr) {
			_online = false;
			return;
		}

		temperature = _bmp280 -> readTemperature();
		pressure = _bmp280 -> readPressure() / 100.0f;

		if (isnan(temperature) || isnan(pressure)) {
			_online = false;
			return;
		}

		_temperature_c = temperature;
		_pressure_hpa = pressure;
		_humidity_percent = 0.0f;

		update_filtered_temperature(temperature);
		update_filtered_pressure(pressure);
	}

	_online = true;
	_has_valid_data = true;
	_last_success_read_ms = now_ms;
}

bool Bme280Sensor::is_online() const {
	return _online;
}

bool Bme280Sensor::has_valid_data() const {
	return _has_valid_data;
}

bool Bme280Sensor::is_stale() const {
	if (!_has_valid_data) {
		return true;
	}

	uint32_t now_ms = millis();
	return (now_ms - _last_success_read_ms) > _config.stale_after_ms;
}

BmeSensorType Bme280Sensor::get_sensor_type() const {
	return _sensor_type;
}

String Bme280Sensor::get_sensor_type_string() const {
	if (_sensor_type == BME_SENSOR_TYPE_BME280) {
		return "bme280";
	}

	if (_sensor_type == BME_SENSOR_TYPE_BMP280) {
		return "bmp280";
	}

	return "unknown";
}

float Bme280Sensor::get_temperature_c() const {
	return _filtered_temperature_c;
}

float Bme280Sensor::get_pressure_hpa() const {
	return _filtered_pressure_hpa;
}

float Bme280Sensor::get_humidity_percent() const {
	return _filtered_humidity_percent;
}

bool Bme280Sensor::has_humidity() const {
	return _sensor_type == BME_SENSOR_TYPE_BME280;
}

String Bme280Sensor::get_state_json() const {
	String json = "{";
	json += "\"sensor\":\"" + get_sensor_type_string() + "\",";
	json += "\"online\":" + String(_online ? "true" : "false") + ",";
	json += "\"has_valid_data\":" + String(_has_valid_data ? "true" : "false") + ",";
	json += "\"stale\":" + String(is_stale() ? "true" : "false") + ",";
	json += "\"i2c_address\":\"0x" + String(_config.i2c_address, HEX) + "\",";

	json += "\"data\":{";
	json += "\"temperature_c\":" + String(_filtered_temperature_c, 2) + ",";
	json += "\"pressure_hpa\":" + String(_filtered_pressure_hpa, 2);

	if (has_humidity()) {
		json += ",";
		json += "\"humidity_percent\":" + String(_filtered_humidity_percent, 2);
	}

	json += "}";

	json += "}";
	return json;
}

bool Bme280Sensor::init_bme280() {
	if (_wire == nullptr) {
		return false;
	}

	_bme280 = new Adafruit_BME280();

	if (_bme280 == nullptr) {
		return false;
	}

	bool ok = _bme280 -> begin(_config.i2c_address, _wire);

	if (!ok) {
		delete _bme280;
		_bme280 = nullptr;
		return false;
	}

	_bme280 -> setSampling(
		Adafruit_BME280::MODE_NORMAL,
		Adafruit_BME280::SAMPLING_X2,
		Adafruit_BME280::SAMPLING_X16,
		Adafruit_BME280::SAMPLING_X1,
		Adafruit_BME280::FILTER_X4,
		Adafruit_BME280::STANDBY_MS_500
	);

	return true;
}

bool Bme280Sensor::init_bmp280() {
	if (_wire == nullptr) {
		return false;
	}

	_bmp280 = new Adafruit_BMP280(_wire);

	if (_bmp280 == nullptr) {
		return false;
	}

	bool ok = _bmp280 -> begin(_config.i2c_address);

	if (!ok) {
		delete _bmp280;
		_bmp280 = nullptr;
		return false;
	}

	_bmp280 -> setSampling(
		Adafruit_BMP280::MODE_NORMAL,
		Adafruit_BMP280::SAMPLING_X2,
		Adafruit_BMP280::SAMPLING_X16,
		Adafruit_BMP280::FILTER_X4,
		Adafruit_BMP280::STANDBY_MS_500
	);

	return true;
}

void Bme280Sensor::update_filtered_temperature(float value) {
	if (!_has_valid_data || _filtered_temperature_c == 0.0f) {
		_filtered_temperature_c = value;
		return;
	}

	_filtered_temperature_c =
		(_filtered_temperature_c * (1.0f - _config.temperature_ema_alpha)) +
		(value * _config.temperature_ema_alpha);
}

void Bme280Sensor::update_filtered_pressure(float value) {
	if (!_has_valid_data || _filtered_pressure_hpa == 0.0f) {
		_filtered_pressure_hpa = value;
		return;
	}

	_filtered_pressure_hpa =
		(_filtered_pressure_hpa * (1.0f - _config.pressure_ema_alpha)) +
		(value * _config.pressure_ema_alpha);
}

void Bme280Sensor::update_filtered_humidity(float value) {
	if (!_has_valid_data || _filtered_humidity_percent == 0.0f) {
		_filtered_humidity_percent = value;
		return;
	}

	_filtered_humidity_percent =
		(_filtered_humidity_percent * (1.0f - _config.humidity_ema_alpha)) +
		(value * _config.humidity_ema_alpha);
}