Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPS30: Add fan action #3410

Merged
merged 2 commits into from Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -182,6 +182,7 @@ esphome/components/sm2135/* @BoukeHaarsma23
esphome/components/socket/* @esphome/core
esphome/components/sonoff_d1/* @anatoly-savchenkov
esphome/components/spi/* @esphome/core
esphome/components/sps30/* @martgras
esphome/components/ssd1322_base/* @kbx81
esphome/components/ssd1322_spi/* @kbx81
esphome/components/ssd1325_base/* @kbx81
Expand Down
21 changes: 21 additions & 0 deletions esphome/components/sps30/automation.h
@@ -0,0 +1,21 @@
#pragma once

#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "sps30.h"

namespace esphome {
namespace sps30 {

template<typename... Ts> class StartFanAction : public Action<Ts...> {
public:
explicit StartFanAction(SPS30Component *sps30) : sps30_(sps30) {}

void play(Ts... x) override { this->sps30_->start_fan_cleaning(); }

protected:
SPS30Component *sps30_;
};

} // namespace sps30
} // namespace esphome
27 changes: 27 additions & 0 deletions esphome/components/sps30/sensor.py
@@ -1,6 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor, sensirion_common
from esphome import automation
from esphome.automation import maybe_simple_id
from esphome.const import (
CONF_ID,
CONF_PM_1_0,
Expand All @@ -25,6 +27,7 @@
ICON_RULER,
)

CODEOWNERS = ["@martgras"]
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["sensirion_common"]

Expand All @@ -33,6 +36,11 @@
"SPS30Component", cg.PollingComponent, sensirion_common.SensirionI2CDevice
)

# Actions
StartFanAction = sps30_ns.class_("StartFanAction", automation.Action)

CONF_AUTO_CLEANING_INTERVAL = "auto_cleaning_interval"

CONFIG_SCHEMA = (
cv.Schema(
{
Expand Down Expand Up @@ -100,6 +108,7 @@
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.update_interval,
}
)
.extend(cv.polling_component_schema("60s"))
Expand Down Expand Up @@ -151,3 +160,21 @@ async def to_code(config):
if CONF_PM_SIZE in config:
sens = await sensor.new_sensor(config[CONF_PM_SIZE])
cg.add(var.set_pm_size_sensor(sens))

if CONF_AUTO_CLEANING_INTERVAL in config:
cg.add(var.set_auto_cleaning_interval(config[CONF_AUTO_CLEANING_INTERVAL]))


SPS30_ACTION_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(SPS30Component),
}
)


@automation.register_action(
"sps30.start_fan_autoclean", StartFanAction, SPS30_ACTION_SCHEMA
)
async def sps30_fan_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
30 changes: 29 additions & 1 deletion esphome/components/sps30/sps30.cpp
@@ -1,5 +1,6 @@
#include "sps30.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "sps30.h"

namespace esphome {
namespace sps30 {
Expand Down Expand Up @@ -44,6 +45,22 @@ void SPS30Component::setup() {
this->serial_number_[i * 2 + 1] = uint16_t(uint16_t(raw_serial_number[i] & 0xFF));
}
ESP_LOGD(TAG, " Serial Number: '%s'", this->serial_number_);

bool result;
if (this->fan_interval_.has_value()) {
// override default value
result = write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS, this->fan_interval_.value());
} else {
result = write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS);
}
if (result) {
delay(20);
uint16_t secs[2];
if (this->read_data(secs, 2)) {
fan_interval_ = secs[0] << 16 | secs[1];
}
}

this->status_clear_warning();
this->skipped_data_read_cycles_ = 0;
this->start_continuous_measurement_();
Expand Down Expand Up @@ -206,5 +223,16 @@ bool SPS30Component::start_continuous_measurement_() {
return true;
}

bool SPS30Component::start_fan_cleaning() {
if (!write_command(SPS30_CMD_START_FAN_CLEANING)) {
this->status_set_warning();
ESP_LOGE(TAG, "write error start fan (%d)", this->last_error_);
return false;
} else {
ESP_LOGD(TAG, "Fan auto clean started");
}
return true;
}

} // namespace sps30
} // namespace esphome
5 changes: 4 additions & 1 deletion esphome/components/sps30/sps30.h
Expand Up @@ -22,12 +22,14 @@ class SPS30Component : public PollingComponent, public sensirion_common::Sensiri
void set_pmc_10_0_sensor(sensor::Sensor *pmc_10_0) { pmc_10_0_sensor_ = pmc_10_0; }

void set_pm_size_sensor(sensor::Sensor *pm_size) { pm_size_sensor_ = pm_size; }

void set_auto_cleaning_interval(uint32_t auto_cleaning_interval) { fan_interval_ = auto_cleaning_interval; }
void setup() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }

bool start_fan_cleaning();

protected:
char serial_number_[17] = {0}; /// Terminating NULL character
uint16_t raw_firmware_version_;
Expand All @@ -54,6 +56,7 @@ class SPS30Component : public PollingComponent, public sensirion_common::Sensiri
sensor::Sensor *pmc_4_0_sensor_{nullptr};
sensor::Sensor *pmc_10_0_sensor_{nullptr};
sensor::Sensor *pm_size_sensor_{nullptr};
optional<uint32_t> fan_interval_;
};

} // namespace sps30
Expand Down