mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 08:28:12 +01:00
Add support for the SM300D2 7-in-1 sensor module (#1524)
* Added support for SM300D2 sensor module * Fixed lint errors due to added tvoc config * add device class Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
This commit is contained in:
parent
ac25b138f5
commit
8e93735861
8 changed files with 219 additions and 4 deletions
|
@ -2,7 +2,7 @@ import esphome.codegen as cg
|
|||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY, ICON_RADIATOR, UNIT_PARTS_PER_MILLION, \
|
||||
UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, CONF_HUMIDITY, ICON_MOLECULE_CO2
|
||||
UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, CONF_TVOC, CONF_HUMIDITY, ICON_MOLECULE_CO2
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
|
@ -10,7 +10,6 @@ ccs811_ns = cg.esphome_ns.namespace('ccs811')
|
|||
CCS811Component = ccs811_ns.class_('CCS811Component', cg.PollingComponent, i2c.I2CDevice)
|
||||
|
||||
CONF_ECO2 = 'eco2'
|
||||
CONF_TVOC = 'tvoc'
|
||||
CONF_BASELINE = 'baseline'
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
|
|
|
@ -2,7 +2,7 @@ import esphome.codegen as cg
|
|||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY, ICON_RADIATOR, UNIT_PARTS_PER_MILLION, \
|
||||
UNIT_PARTS_PER_BILLION, ICON_MOLECULE_CO2
|
||||
UNIT_PARTS_PER_BILLION, ICON_MOLECULE_CO2, CONF_TVOC
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
|
@ -10,7 +10,6 @@ sgp30_ns = cg.esphome_ns.namespace('sgp30')
|
|||
SGP30Component = sgp30_ns.class_('SGP30Component', cg.PollingComponent, i2c.I2CDevice)
|
||||
|
||||
CONF_ECO2 = 'eco2'
|
||||
CONF_TVOC = 'tvoc'
|
||||
CONF_BASELINE = 'baseline'
|
||||
CONF_ECO2_BASELINE = 'eco2_baseline'
|
||||
CONF_TVOC_BASELINE = 'tvoc_baseline'
|
||||
|
|
0
esphome/components/sm300d2/__init__.py
Normal file
0
esphome/components/sm300d2/__init__.py
Normal file
61
esphome/components/sm300d2/sensor.py
Normal file
61
esphome/components/sm300d2/sensor.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, uart
|
||||
from esphome.const import CONF_ID, CONF_CO2, CONF_FORMALDEHYDE, CONF_TVOC, CONF_PM_2_5, \
|
||||
CONF_PM_10_0, CONF_TEMPERATURE, CONF_HUMIDITY, DEVICE_CLASS_EMPTY, DEVICE_CLASS_TEMPERATURE, \
|
||||
DEVICE_CLASS_HUMIDITY, UNIT_PARTS_PER_MILLION, UNIT_MICROGRAMS_PER_CUBIC_METER, UNIT_CELSIUS, \
|
||||
UNIT_PERCENT, ICON_EMPTY, ICON_MOLECULE_CO2, ICON_FLASK, ICON_CHEMICAL_WEAPON, ICON_GRAIN
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
sm300d2_ns = cg.esphome_ns.namespace('sm300d2')
|
||||
SM300D2Sensor = sm300d2_ns.class_('SM300D2Sensor', cg.PollingComponent, uart.UARTDevice)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(SM300D2Sensor),
|
||||
|
||||
cv.Optional(CONF_CO2):
|
||||
sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY),
|
||||
cv.Optional(CONF_FORMALDEHYDE):
|
||||
sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_FLASK, 0, DEVICE_CLASS_EMPTY),
|
||||
cv.Optional(CONF_TVOC):
|
||||
sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0,
|
||||
DEVICE_CLASS_EMPTY),
|
||||
cv.Optional(CONF_PM_2_5):
|
||||
sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_GRAIN, 0, DEVICE_CLASS_EMPTY),
|
||||
cv.Optional(CONF_PM_10_0):
|
||||
sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_GRAIN, 0, DEVICE_CLASS_EMPTY),
|
||||
cv.Optional(CONF_TEMPERATURE):
|
||||
sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 0, DEVICE_CLASS_TEMPERATURE),
|
||||
cv.Optional(CONF_HUMIDITY):
|
||||
sensor.sensor_schema(UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY),
|
||||
|
||||
}).extend(cv.polling_component_schema('60s')).extend(uart.UART_DEVICE_SCHEMA))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield uart.register_uart_device(var, config)
|
||||
|
||||
if CONF_CO2 in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_CO2])
|
||||
cg.add(var.set_co2_sensor(sens))
|
||||
if CONF_FORMALDEHYDE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_FORMALDEHYDE])
|
||||
cg.add(var.set_formaldehyde_sensor(sens))
|
||||
if CONF_TVOC in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_TVOC])
|
||||
cg.add(var.set_tvoc_sensor(sens))
|
||||
if CONF_PM_2_5 in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_PM_2_5])
|
||||
cg.add(var.set_pm_2_5_sensor(sens))
|
||||
if CONF_PM_10_0 in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_PM_10_0])
|
||||
cg.add(var.set_pm_10_0_sensor(sens))
|
||||
if CONF_TEMPERATURE in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
if CONF_HUMIDITY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
|
||||
cg.add(var.set_humidity_sensor(sens))
|
99
esphome/components/sm300d2/sm300d2.cpp
Normal file
99
esphome/components/sm300d2/sm300d2.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "sm300d2.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sm300d2 {
|
||||
|
||||
static const char *TAG = "sm300d2";
|
||||
static const uint8_t SM300D2_RESPONSE_LENGTH = 17;
|
||||
|
||||
void SM300D2Sensor::update() {
|
||||
uint8_t response[SM300D2_RESPONSE_LENGTH];
|
||||
|
||||
flush();
|
||||
bool read_success = read_array(response, SM300D2_RESPONSE_LENGTH);
|
||||
flush();
|
||||
|
||||
if (!read_success) {
|
||||
ESP_LOGW(TAG, "Reading data from SM300D2 failed!");
|
||||
status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response[0] != 0x3C || response[1] != 0x02) {
|
||||
ESP_LOGW(TAG, "Invalid preamble for SM300D2 response!");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t calculated_checksum = this->sm300d2_checksum_(response);
|
||||
if (calculated_checksum != response[SM300D2_RESPONSE_LENGTH - 1]) {
|
||||
ESP_LOGW(TAG, "SM300D2 Checksum doesn't match: 0x%02X!=0x%02X", response[SM300D2_RESPONSE_LENGTH - 1],
|
||||
calculated_checksum);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
|
||||
ESP_LOGW(TAG, "Successfully read SM300D2 data");
|
||||
|
||||
const uint16_t co2 = (response[2] * 256) + response[3];
|
||||
const uint16_t formaldehyde = (response[4] * 256) + response[5];
|
||||
const uint16_t tvoc = (response[6] * 256) + response[7];
|
||||
const uint16_t pm_2_5 = (response[8] * 256) + response[9];
|
||||
const uint16_t pm_10_0 = (response[10] * 256) + response[11];
|
||||
const float temperature = response[12] + (response[13] * 0.1);
|
||||
const float humidity = response[14] + (response[15] * 0.1);
|
||||
|
||||
ESP_LOGD(TAG, "Received CO₂: %u ppm", co2);
|
||||
if (this->co2_sensor_ != nullptr)
|
||||
this->co2_sensor_->publish_state(co2);
|
||||
|
||||
ESP_LOGD(TAG, "Received Formaldehyde: %u µg/m³", formaldehyde);
|
||||
if (this->formaldehyde_sensor_ != nullptr)
|
||||
this->formaldehyde_sensor_->publish_state(formaldehyde);
|
||||
|
||||
ESP_LOGD(TAG, "Received TVOC: %u µg/m³", tvoc);
|
||||
if (this->tvoc_sensor_ != nullptr)
|
||||
this->tvoc_sensor_->publish_state(tvoc);
|
||||
|
||||
ESP_LOGD(TAG, "Received PM2.5: %u µg/m³", pm_2_5);
|
||||
if (this->pm_2_5_sensor_ != nullptr)
|
||||
this->pm_2_5_sensor_->publish_state(pm_2_5);
|
||||
|
||||
ESP_LOGD(TAG, "Received pm_10_0: %u µg/m³", pm_10_0);
|
||||
if (this->pm_10_0_sensor_ != nullptr)
|
||||
this->pm_10_0_sensor_->publish_state(pm_10_0);
|
||||
|
||||
ESP_LOGD(TAG, "Received Temperature: %.2f °C", temperature);
|
||||
if (this->temperature_sensor_ != nullptr)
|
||||
this->temperature_sensor_->publish_state(temperature);
|
||||
|
||||
ESP_LOGD(TAG, "Received Humidity: %.2f percent", humidity);
|
||||
if (this->humidity_sensor_ != nullptr)
|
||||
this->humidity_sensor_->publish_state(humidity);
|
||||
}
|
||||
|
||||
uint16_t SM300D2Sensor::sm300d2_checksum_(uint8_t *ptr) {
|
||||
uint8_t sum = 0;
|
||||
for (int i = 0; i < (SM300D2_RESPONSE_LENGTH - 1); i++) {
|
||||
sum += *ptr++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void SM300D2Sensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "SM300D2:");
|
||||
LOG_SENSOR(" ", "CO2", this->co2_sensor_);
|
||||
LOG_SENSOR(" ", "Formaldehyde", this->formaldehyde_sensor_);
|
||||
LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_);
|
||||
LOG_SENSOR(" ", "PM2.5", this->pm_2_5_sensor_);
|
||||
LOG_SENSOR(" ", "PM10", this->pm_10_0_sensor_);
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
this->check_uart_settings(9600);
|
||||
}
|
||||
|
||||
} // namespace sm300d2
|
||||
} // namespace esphome
|
38
esphome/components/sm300d2/sm300d2.h
Normal file
38
esphome/components/sm300d2/sm300d2.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sm300d2 {
|
||||
|
||||
class SM300D2Sensor : public PollingComponent, public uart::UARTDevice {
|
||||
public:
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
void set_co2_sensor(sensor::Sensor *co2_sensor) { co2_sensor_ = co2_sensor; }
|
||||
void set_formaldehyde_sensor(sensor::Sensor *formaldehyde_sensor) { formaldehyde_sensor_ = formaldehyde_sensor; }
|
||||
void set_tvoc_sensor(sensor::Sensor *tvoc_sensor) { tvoc_sensor_ = tvoc_sensor; }
|
||||
void set_pm_2_5_sensor(sensor::Sensor *pm_2_5_sensor) { pm_2_5_sensor_ = pm_2_5_sensor; }
|
||||
void set_pm_10_0_sensor(sensor::Sensor *pm_10_0_sensor) { pm_10_0_sensor_ = pm_10_0_sensor; }
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
|
||||
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
uint16_t sm300d2_checksum_(uint8_t *ptr);
|
||||
|
||||
sensor::Sensor *co2_sensor_{nullptr};
|
||||
sensor::Sensor *formaldehyde_sensor_{nullptr};
|
||||
sensor::Sensor *tvoc_sensor_{nullptr};
|
||||
sensor::Sensor *pm_2_5_sensor_{nullptr};
|
||||
sensor::Sensor *pm_10_0_sensor_{nullptr};
|
||||
sensor::Sensor *temperature_sensor_{nullptr};
|
||||
sensor::Sensor *humidity_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace sm300d2
|
||||
} // namespace esphome
|
|
@ -538,6 +538,7 @@ CONF_TRIGGER_ID = 'trigger_id'
|
|||
CONF_TRIGGER_PIN = 'trigger_pin'
|
||||
CONF_TURN_OFF_ACTION = 'turn_off_action'
|
||||
CONF_TURN_ON_ACTION = 'turn_on_action'
|
||||
CONF_TVOC = 'tvoc'
|
||||
CONF_TX_BUFFER_SIZE = 'tx_buffer_size'
|
||||
CONF_TX_PIN = 'tx_pin'
|
||||
CONF_TX_POWER = 'tx_power'
|
||||
|
@ -595,10 +596,12 @@ ICON_COUNTER = 'mdi:counter'
|
|||
ICON_CURRENT_AC = 'mdi:current-ac'
|
||||
ICON_EMPTY = ''
|
||||
ICON_FLASH = 'mdi:flash'
|
||||
ICON_FLASK = 'mdi:flask'
|
||||
ICON_FLASK_OUTLINE = 'mdi:flask-outline'
|
||||
ICON_FLOWER = 'mdi:flower'
|
||||
ICON_GAS_CYLINDER = 'mdi:gas-cylinder'
|
||||
ICON_GAUGE = 'mdi:gauge'
|
||||
ICON_GRAIN = 'mdi:grain'
|
||||
ICON_LIGHTBULB = 'mdi:lightbulb'
|
||||
ICON_MAGNET = 'mdi:magnet'
|
||||
ICON_MOLECULE_CO2 = 'mdi:molecule-co2'
|
||||
|
|
|
@ -642,6 +642,22 @@ sensor:
|
|||
co2:
|
||||
name: 'SenseAir CO2 Value'
|
||||
update_interval: 15s
|
||||
- platform: sm300d2
|
||||
co2:
|
||||
name: "SM300D2 CO2 Value"
|
||||
formaldehyde:
|
||||
name: "SM300D2 Formaldehyde Value"
|
||||
tvoc:
|
||||
name: "SM300D2 TVOC Value"
|
||||
pm_2_5:
|
||||
name: "SM300D2 PM2.5 Value"
|
||||
pm_10_0:
|
||||
name: "SM300D2 PM10 Value"
|
||||
temperature:
|
||||
name: "SM300D2 Temperature Value"
|
||||
humidity:
|
||||
name: "SM300D2 Humidity Value"
|
||||
update_interval: 60s
|
||||
- platform: sht3xd
|
||||
temperature:
|
||||
name: 'Living Room Temperature 8'
|
||||
|
|
Loading…
Reference in a new issue