mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 15:04:54 +01:00
Merge branch 'dev' into optolink
This commit is contained in:
commit
8f57f428f0
178 changed files with 2749 additions and 153 deletions
|
@ -7,8 +7,21 @@
|
||||||
"PIP_BREAK_SYSTEM_PACKAGES": "1",
|
"PIP_BREAK_SYSTEM_PACKAGES": "1",
|
||||||
"PIP_ROOT_USER_ACTION": "ignore"
|
"PIP_ROOT_USER_ACTION": "ignore"
|
||||||
},
|
},
|
||||||
"runArgs": ["--privileged", "-e", "ESPHOME_DASHBOARD_USE_PING=1"],
|
"runArgs": [
|
||||||
|
"--privileged",
|
||||||
|
"-e",
|
||||||
|
"ESPHOME_DASHBOARD_USE_PING=1"
|
||||||
|
// uncomment and edit the path in order to pass though local USB serial to the conatiner
|
||||||
|
// , "--device=/dev/ttyACM0"
|
||||||
|
],
|
||||||
"appPort": 6052,
|
"appPort": 6052,
|
||||||
|
// if you are using avahi in the host device, uncomment these to allow the
|
||||||
|
// devcontainer to find devices via mdns
|
||||||
|
//"mounts": [
|
||||||
|
// "type=bind,source=/dev/bus/usb,target=/dev/bus/usb",
|
||||||
|
// "type=bind,source=/var/run/dbus,target=/var/run/dbus",
|
||||||
|
// "type=bind,source=/var/run/avahi-daemon/socket,target=/var/run/avahi-daemon/socket"
|
||||||
|
//],
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
|
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -11,6 +11,7 @@ on:
|
||||||
- "**"
|
- "**"
|
||||||
- "!.github/workflows/*.yml"
|
- "!.github/workflows/*.yml"
|
||||||
- ".github/workflows/ci.yml"
|
- ".github/workflows/ci.yml"
|
||||||
|
- "!.yamllint"
|
||||||
merge_group:
|
merge_group:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -218,7 +219,7 @@ jobs:
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pytest -vv --cov-report=xml --tb=native tests
|
pytest -vv --cov-report=xml --tb=native tests
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
|
|
1
.github/workflows/needs-docs.yml
vendored
1
.github/workflows/needs-docs.yml
vendored
|
@ -1,5 +1,6 @@
|
||||||
name: Needs Docs
|
name: Needs Docs
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [labeled, unlabeled]
|
types: [labeled, unlabeled]
|
||||||
|
|
3
.github/workflows/sync-device-classes.yml
vendored
3
.github/workflows/sync-device-classes.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
name: Synchronise Device Classes from Home Assistant
|
name: Synchronise Device Classes from Home Assistant
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
|
@ -36,7 +37,7 @@ jobs:
|
||||||
python ./script/sync-device_class.py
|
python ./script/sync-device_class.py
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: peter-evans/create-pull-request@v5.0.2
|
uses: peter-evans/create-pull-request@v6.0.0
|
||||||
with:
|
with:
|
||||||
commit-message: "Synchronise Device Classes from Home Assistant"
|
commit-message: "Synchronise Device Classes from Home Assistant"
|
||||||
committer: esphomebot <esphome@nabucasa.com>
|
committer: esphomebot <esphome@nabucasa.com>
|
||||||
|
|
6
.github/workflows/yaml-lint.yml
vendored
6
.github/workflows/yaml-lint.yml
vendored
|
@ -1,5 +1,7 @@
|
||||||
|
---
|
||||||
name: YAML lint
|
name: YAML lint
|
||||||
|
|
||||||
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [dev, beta, release]
|
branches: [dev, beta, release]
|
||||||
|
@ -19,4 +21,6 @@ jobs:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.1
|
||||||
- name: Run yamllint
|
- name: Run yamllint
|
||||||
uses: frenck/action-yamllint@v1.4.2
|
uses: frenck/action-yamllint@v1.5.0
|
||||||
|
with:
|
||||||
|
strict: true
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||||
rev: 23.12.1
|
rev: 24.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args:
|
args:
|
||||||
|
@ -27,7 +27,7 @@ repos:
|
||||||
- --branch=release
|
- --branch=release
|
||||||
- --branch=beta
|
- --branch=beta
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.15.0
|
rev: v3.15.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py39-plus]
|
args: [--py39-plus]
|
||||||
|
|
19
.yamllint
19
.yamllint
|
@ -1,3 +1,18 @@
|
||||||
---
|
---
|
||||||
ignore: |
|
extends: default
|
||||||
venv/
|
|
||||||
|
ignore-from-file: .gitignore
|
||||||
|
|
||||||
|
rules:
|
||||||
|
document-start: disable
|
||||||
|
empty-lines:
|
||||||
|
level: error
|
||||||
|
max: 1
|
||||||
|
max-start: 0
|
||||||
|
max-end: 1
|
||||||
|
indentation:
|
||||||
|
level: error
|
||||||
|
spaces: 2
|
||||||
|
indent-sequences: true
|
||||||
|
check-multi-line-strings: false
|
||||||
|
line-length: disable
|
||||||
|
|
|
@ -372,6 +372,7 @@ esphome/components/uart/button/* @ssieb
|
||||||
esphome/components/ufire_ec/* @pvizeli
|
esphome/components/ufire_ec/* @pvizeli
|
||||||
esphome/components/ufire_ise/* @pvizeli
|
esphome/components/ufire_ise/* @pvizeli
|
||||||
esphome/components/ultrasonic/* @OttoWinter
|
esphome/components/ultrasonic/* @OttoWinter
|
||||||
|
esphome/components/uponor_smatrix/* @kroimon
|
||||||
esphome/components/vbus/* @ssieb
|
esphome/components/vbus/* @ssieb
|
||||||
esphome/components/veml3235/* @kbx81
|
esphome/components/veml3235/* @kbx81
|
||||||
esphome/components/version/* @esphome/core
|
esphome/components/version/* @esphome/core
|
||||||
|
|
|
@ -4,6 +4,7 @@ from esphome.components import sensor, uart
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_CURRENT,
|
CONF_CURRENT,
|
||||||
CONF_ENERGY,
|
CONF_ENERGY,
|
||||||
|
CONF_EXTERNAL_TEMPERATURE,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_POWER,
|
CONF_POWER,
|
||||||
CONF_VOLTAGE,
|
CONF_VOLTAGE,
|
||||||
|
@ -24,7 +25,6 @@ from esphome.const import (
|
||||||
DEPENDENCIES = ["uart"]
|
DEPENDENCIES = ["uart"]
|
||||||
|
|
||||||
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
||||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
|
||||||
|
|
||||||
bl0940_ns = cg.esphome_ns.namespace("bl0940")
|
bl0940_ns = cg.esphome_ns.namespace("bl0940")
|
||||||
BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
|
BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
|
||||||
|
|
|
@ -7,6 +7,8 @@ CODEOWNERS = ["@ellull"]
|
||||||
|
|
||||||
DEPENDENCIES = ["i2c"]
|
DEPENDENCIES = ["i2c"]
|
||||||
|
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
CONF_PWM = "pwm"
|
CONF_PWM = "pwm"
|
||||||
CONF_DIVIDER = "divider"
|
CONF_DIVIDER = "divider"
|
||||||
CONF_DAC = "dac"
|
CONF_DAC = "dac"
|
||||||
|
|
|
@ -2,6 +2,7 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import sensor
|
from esphome.components import sensor
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_EXTERNAL_TEMPERATURE,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_SPEED,
|
CONF_SPEED,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
@ -16,7 +17,6 @@ from .. import EMC2101_COMPONENT_SCHEMA, CONF_EMC2101_ID, emc2101_ns
|
||||||
DEPENDENCIES = ["emc2101"]
|
DEPENDENCIES = ["emc2101"]
|
||||||
|
|
||||||
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
||||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
|
||||||
CONF_DUTY_CYCLE = "duty_cycle"
|
CONF_DUTY_CYCLE = "duty_cycle"
|
||||||
|
|
||||||
EMC2101Sensor = emc2101_ns.class_("EMC2101Sensor", cg.PollingComponent)
|
EMC2101Sensor = emc2101_ns.class_("EMC2101Sensor", cg.PollingComponent)
|
||||||
|
|
|
@ -336,6 +336,8 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t FingerprintGrowComponent::send_command_() {
|
uint8_t FingerprintGrowComponent::send_command_() {
|
||||||
|
while (this->available())
|
||||||
|
this->read();
|
||||||
this->write((uint8_t) (START_CODE >> 8));
|
this->write((uint8_t) (START_CODE >> 8));
|
||||||
this->write((uint8_t) (START_CODE & 0xFF));
|
this->write((uint8_t) (START_CODE & 0xFF));
|
||||||
this->write(this->address_[0]);
|
this->write(this->address_[0]);
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
"""Support for Honeywell HumidIcon HIH"""
|
"""Support for Honeywell HumidIcon HIH"""
|
||||||
|
|
||||||
CODEOWNERS = ["@Benichou34"]
|
CODEOWNERS = ["@Benichou34"]
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
"""Support for Honeywell ABP2"""
|
"""Support for Honeywell ABP2"""
|
||||||
|
|
||||||
CODEOWNERS = ["@jpfaff"]
|
CODEOWNERS = ["@jpfaff"]
|
||||||
|
|
|
@ -24,7 +24,7 @@ void ArduinoI2CBus::setup() {
|
||||||
}
|
}
|
||||||
next_bus_num++;
|
next_bus_num++;
|
||||||
#elif defined(USE_ESP8266)
|
#elif defined(USE_ESP8266)
|
||||||
wire_ = &Wire; // NOLINT(cppcoreguidelines-prefer-member-initializer)
|
wire_ = new TwoWire(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
#elif defined(USE_RP2040)
|
#elif defined(USE_RP2040)
|
||||||
static bool first = true;
|
static bool first = true;
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -35,6 +35,16 @@ void ArduinoI2CBus::setup() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
this->set_pins_and_clock_();
|
||||||
|
|
||||||
|
this->initialized_ = true;
|
||||||
|
if (this->scan_) {
|
||||||
|
ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
|
||||||
|
this->i2c_scan_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArduinoI2CBus::set_pins_and_clock_() {
|
||||||
#ifdef USE_RP2040
|
#ifdef USE_RP2040
|
||||||
wire_->setSDA(this->sda_pin_);
|
wire_->setSDA(this->sda_pin_);
|
||||||
wire_->setSCL(this->scl_pin_);
|
wire_->setSCL(this->scl_pin_);
|
||||||
|
@ -43,12 +53,8 @@ void ArduinoI2CBus::setup() {
|
||||||
wire_->begin(static_cast<int>(sda_pin_), static_cast<int>(scl_pin_));
|
wire_->begin(static_cast<int>(sda_pin_), static_cast<int>(scl_pin_));
|
||||||
#endif
|
#endif
|
||||||
wire_->setClock(frequency_);
|
wire_->setClock(frequency_);
|
||||||
initialized_ = true;
|
|
||||||
if (this->scan_) {
|
|
||||||
ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
|
|
||||||
this->i2c_scan_();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoI2CBus::dump_config() {
|
void ArduinoI2CBus::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "I2C Bus:");
|
ESP_LOGCONFIG(TAG, "I2C Bus:");
|
||||||
ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_);
|
ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_);
|
||||||
|
@ -82,6 +88,10 @@ void ArduinoI2CBus::dump_config() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) {
|
ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt) {
|
||||||
|
#if defined(USE_ESP8266)
|
||||||
|
this->set_pins_and_clock_(); // reconfigure Wire global state in case there are multiple instances
|
||||||
|
#endif
|
||||||
|
|
||||||
// logging is only enabled with vv level, if warnings are shown the caller
|
// logging is only enabled with vv level, if warnings are shown the caller
|
||||||
// should log them
|
// should log them
|
||||||
if (!initialized_) {
|
if (!initialized_) {
|
||||||
|
@ -120,6 +130,10 @@ ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt, bool stop) {
|
ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt, bool stop) {
|
||||||
|
#if defined(USE_ESP8266)
|
||||||
|
this->set_pins_and_clock_(); // reconfigure Wire global state in case there are multiple instances
|
||||||
|
#endif
|
||||||
|
|
||||||
// logging is only enabled with vv level, if warnings are shown the caller
|
// logging is only enabled with vv level, if warnings are shown the caller
|
||||||
// should log them
|
// should log them
|
||||||
if (!initialized_) {
|
if (!initialized_) {
|
||||||
|
@ -164,7 +178,7 @@ ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cn
|
||||||
return ERROR_UNKNOWN;
|
return ERROR_UNKNOWN;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
ESP_LOGVV(TAG, "TX failed: not acknowledged");
|
ESP_LOGVV(TAG, "TX failed: not acknowledged: %d", status);
|
||||||
return ERROR_NOT_ACKNOWLEDGED;
|
return ERROR_NOT_ACKNOWLEDGED;
|
||||||
case 5:
|
case 5:
|
||||||
ESP_LOGVV(TAG, "TX failed: timeout");
|
ESP_LOGVV(TAG, "TX failed: timeout");
|
||||||
|
|
|
@ -30,6 +30,7 @@ class ArduinoI2CBus : public I2CBus, public Component {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void recover_();
|
void recover_();
|
||||||
|
void set_pins_and_clock_();
|
||||||
RecoveryCode recovery_result_;
|
RecoveryCode recovery_result_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -3,6 +3,7 @@ import esphome.config_validation as cv
|
||||||
from esphome.components import sensor, esp32_ble_tracker
|
from esphome.components import sensor, esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_BATTERY_LEVEL,
|
CONF_BATTERY_LEVEL,
|
||||||
|
CONF_EXTERNAL_TEMPERATURE,
|
||||||
CONF_HUMIDITY,
|
CONF_HUMIDITY,
|
||||||
CONF_MAC_ADDRESS,
|
CONF_MAC_ADDRESS,
|
||||||
CONF_TEMPERATURE,
|
CONF_TEMPERATURE,
|
||||||
|
@ -19,8 +20,6 @@ from esphome.const import (
|
||||||
CODEOWNERS = ["@fkirill"]
|
CODEOWNERS = ["@fkirill"]
|
||||||
DEPENDENCIES = ["esp32_ble_tracker"]
|
DEPENDENCIES = ["esp32_ble_tracker"]
|
||||||
|
|
||||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
|
||||||
|
|
||||||
inkbird_ibsth1_mini_ns = cg.esphome_ns.namespace("inkbird_ibsth1_mini")
|
inkbird_ibsth1_mini_ns = cg.esphome_ns.namespace("inkbird_ibsth1_mini")
|
||||||
InkbirdIbstH1Mini = inkbird_ibsth1_mini_ns.class_(
|
InkbirdIbstH1Mini = inkbird_ibsth1_mini_ns.class_(
|
||||||
"InkbirdIbstH1Mini", esp32_ble_tracker.ESPBTDeviceListener, cg.Component
|
"InkbirdIbstH1Mini", esp32_ble_tracker.ESPBTDeviceListener, cg.Component
|
||||||
|
|
|
@ -8,10 +8,23 @@ namespace ltr390 {
|
||||||
|
|
||||||
static const char *const TAG = "ltr390";
|
static const char *const TAG = "ltr390";
|
||||||
|
|
||||||
|
static const uint8_t LTR390_MAIN_CTRL = 0x00;
|
||||||
|
static const uint8_t LTR390_MEAS_RATE = 0x04;
|
||||||
|
static const uint8_t LTR390_GAIN = 0x05;
|
||||||
|
static const uint8_t LTR390_PART_ID = 0x06;
|
||||||
|
static const uint8_t LTR390_MAIN_STATUS = 0x07;
|
||||||
|
|
||||||
static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0};
|
static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0};
|
||||||
static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125};
|
static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125};
|
||||||
|
|
||||||
|
// Request fastest measurement rate - will be slowed by device if conversion rate is slower.
|
||||||
|
static const float RESOLUTION_SETTING[6] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50};
|
||||||
static const uint32_t MODEADDRESSES[2] = {0x0D, 0x10};
|
static const uint32_t MODEADDRESSES[2] = {0x0D, 0x10};
|
||||||
|
|
||||||
|
static const float SENSITIVITY_MAX = 2300;
|
||||||
|
static const float INTG_MAX = RESOLUTIONVALUE[0] * 100;
|
||||||
|
static const int GAIN_MAX = GAINVALUES[4];
|
||||||
|
|
||||||
uint32_t little_endian_bytes_to_int(const uint8_t *buffer, uint8_t num_bytes) {
|
uint32_t little_endian_bytes_to_int(const uint8_t *buffer, uint8_t num_bytes) {
|
||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
@ -58,7 +71,7 @@ void LTR390Component::read_als_() {
|
||||||
uint32_t als = *val;
|
uint32_t als = *val;
|
||||||
|
|
||||||
if (this->light_sensor_ != nullptr) {
|
if (this->light_sensor_ != nullptr) {
|
||||||
float lux = (0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_]) * this->wfac_;
|
float lux = ((0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_])) * this->wfac_;
|
||||||
this->light_sensor_->publish_state(lux);
|
this->light_sensor_->publish_state(lux);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +87,7 @@ void LTR390Component::read_uvs_() {
|
||||||
uint32_t uv = *val;
|
uint32_t uv = *val;
|
||||||
|
|
||||||
if (this->uvi_sensor_ != nullptr) {
|
if (this->uvi_sensor_ != nullptr) {
|
||||||
this->uvi_sensor_->publish_state(uv / LTR390_SENSITIVITY * this->wfac_);
|
this->uvi_sensor_->publish_state((uv / this->sensitivity_) * this->wfac_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->uv_sensor_ != nullptr) {
|
if (this->uv_sensor_ != nullptr) {
|
||||||
|
@ -132,12 +145,13 @@ void LTR390Component::setup() {
|
||||||
// Set gain
|
// Set gain
|
||||||
this->reg(LTR390_GAIN) = gain_;
|
this->reg(LTR390_GAIN) = gain_;
|
||||||
|
|
||||||
// Set resolution
|
// Set resolution and measurement rate
|
||||||
uint8_t res = this->reg(LTR390_MEAS_RATE).get();
|
this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_];
|
||||||
// resolution is in bits 5-7
|
|
||||||
res &= ~0b01110000;
|
// Set sensitivity by linearly scaling against known value in the datasheet
|
||||||
res |= res << 4;
|
float gain_scale = GAINVALUES[this->gain_] / GAIN_MAX;
|
||||||
this->reg(LTR390_MEAS_RATE) = res;
|
float intg_scale = (RESOLUTIONVALUE[this->res_] * 100) / INTG_MAX;
|
||||||
|
this->sensitivity_ = SENSITIVITY_MAX * gain_scale * intg_scale;
|
||||||
|
|
||||||
// Set sensor read state
|
// Set sensor read state
|
||||||
this->reading_ = false;
|
this->reading_ = false;
|
||||||
|
|
|
@ -17,14 +17,6 @@ enum LTR390CTRL {
|
||||||
};
|
};
|
||||||
|
|
||||||
// enums from https://github.com/adafruit/Adafruit_LTR390/
|
// enums from https://github.com/adafruit/Adafruit_LTR390/
|
||||||
|
|
||||||
static const uint8_t LTR390_MAIN_CTRL = 0x00;
|
|
||||||
static const uint8_t LTR390_MEAS_RATE = 0x04;
|
|
||||||
static const uint8_t LTR390_GAIN = 0x05;
|
|
||||||
static const uint8_t LTR390_PART_ID = 0x06;
|
|
||||||
static const uint8_t LTR390_MAIN_STATUS = 0x07;
|
|
||||||
static const float LTR390_SENSITIVITY = 2300.0;
|
|
||||||
|
|
||||||
// Sensing modes
|
// Sensing modes
|
||||||
enum LTR390MODE {
|
enum LTR390MODE {
|
||||||
LTR390_MODE_ALS,
|
LTR390_MODE_ALS,
|
||||||
|
@ -81,6 +73,7 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
|
|
||||||
LTR390GAIN gain_;
|
LTR390GAIN gain_;
|
||||||
LTR390RESOLUTION res_;
|
LTR390RESOLUTION res_;
|
||||||
|
float sensitivity_;
|
||||||
float wfac_;
|
float wfac_;
|
||||||
|
|
||||||
sensor::Sensor *light_sensor_{nullptr};
|
sensor::Sensor *light_sensor_{nullptr};
|
||||||
|
|
|
@ -8,6 +8,7 @@ from esphome.const import (
|
||||||
CONF_RESOLUTION,
|
CONF_RESOLUTION,
|
||||||
UNIT_LUX,
|
UNIT_LUX,
|
||||||
ICON_BRIGHTNESS_5,
|
ICON_BRIGHTNESS_5,
|
||||||
|
DEVICE_CLASS_EMPTY,
|
||||||
DEVICE_CLASS_ILLUMINANCE,
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,22 +62,22 @@ CONFIG_SCHEMA = cv.All(
|
||||||
unit_of_measurement=UNIT_COUNTS,
|
unit_of_measurement=UNIT_COUNTS,
|
||||||
icon=ICON_BRIGHTNESS_5,
|
icon=ICON_BRIGHTNESS_5,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
device_class=DEVICE_CLASS_EMPTY,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_UV_INDEX): sensor.sensor_schema(
|
cv.Optional(CONF_UV_INDEX): sensor.sensor_schema(
|
||||||
unit_of_measurement=UNIT_UVI,
|
unit_of_measurement=UNIT_UVI,
|
||||||
icon=ICON_BRIGHTNESS_5,
|
icon=ICON_BRIGHTNESS_5,
|
||||||
accuracy_decimals=5,
|
accuracy_decimals=5,
|
||||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
device_class=DEVICE_CLASS_EMPTY,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_UV): sensor.sensor_schema(
|
cv.Optional(CONF_UV): sensor.sensor_schema(
|
||||||
unit_of_measurement=UNIT_COUNTS,
|
unit_of_measurement=UNIT_COUNTS,
|
||||||
icon=ICON_BRIGHTNESS_5,
|
icon=ICON_BRIGHTNESS_5,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
device_class=DEVICE_CLASS_EMPTY,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_GAIN, default="X3"): cv.enum(GAIN_OPTIONS),
|
cv.Optional(CONF_GAIN, default="X18"): cv.enum(GAIN_OPTIONS),
|
||||||
cv.Optional(CONF_RESOLUTION, default=18): cv.enum(RES_OPTIONS),
|
cv.Optional(CONF_RESOLUTION, default=20): cv.enum(RES_OPTIONS),
|
||||||
cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range(
|
cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range(
|
||||||
min=1.0
|
min=1.0
|
||||||
),
|
),
|
||||||
|
|
|
@ -74,7 +74,8 @@ CONF_FORCE_SW = "force_sw"
|
||||||
CONF_INTERFACE = "interface"
|
CONF_INTERFACE = "interface"
|
||||||
CONF_INTERFACE_INDEX = "interface_index"
|
CONF_INTERFACE_INDEX = "interface_index"
|
||||||
|
|
||||||
# RP2040 SPI pin assignments are complicated. Refer to https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
# RP2040 SPI pin assignments are complicated;
|
||||||
|
# refer to GPIO function select table in https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
||||||
|
|
||||||
RP_SPI_PINSETS = [
|
RP_SPI_PINSETS = [
|
||||||
{
|
{
|
||||||
|
@ -85,7 +86,7 @@ RP_SPI_PINSETS = [
|
||||||
{
|
{
|
||||||
CONF_MISO_PIN: [8, 12, 24, 28, -1],
|
CONF_MISO_PIN: [8, 12, 24, 28, -1],
|
||||||
CONF_CLK_PIN: [10, 14, 26],
|
CONF_CLK_PIN: [10, 14, 26],
|
||||||
CONF_MOSI_PIN: [11, 23, 27, -1],
|
CONF_MOSI_PIN: [11, 15, 27, -1],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ from esphome.const import (
|
||||||
CODEOWNERS = ["@freekode"]
|
CODEOWNERS = ["@freekode"]
|
||||||
|
|
||||||
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
||||||
|
TM1651Brightness = tm1651_ns.enum("TM1651Brightness")
|
||||||
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
||||||
|
|
||||||
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
||||||
|
@ -24,9 +25,9 @@ TurnOffAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
||||||
CONF_LEVEL_PERCENT = "level_percent"
|
CONF_LEVEL_PERCENT = "level_percent"
|
||||||
|
|
||||||
TM1651_BRIGHTNESS_OPTIONS = {
|
TM1651_BRIGHTNESS_OPTIONS = {
|
||||||
1: TM1651Display.TM1651_BRIGHTNESS_LOW,
|
1: TM1651Brightness.TM1651_BRIGHTNESS_LOW,
|
||||||
2: TM1651Display.TM1651_BRIGHTNESS_MEDIUM,
|
2: TM1651Brightness.TM1651_BRIGHTNESS_MEDIUM,
|
||||||
3: TM1651Display.TM1651_BRIGHTNESS_HIGH,
|
3: TM1651Brightness.TM1651_BRIGHTNESS_HIGH,
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
|
|
@ -12,9 +12,9 @@ static const char *const TAG = "tm1651.display";
|
||||||
static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100;
|
static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100;
|
||||||
static const uint8_t TM1651_MAX_LEVEL = 7;
|
static const uint8_t TM1651_MAX_LEVEL = 7;
|
||||||
|
|
||||||
static const uint8_t TM1651_BRIGHTNESS_LOW = 0;
|
static const uint8_t TM1651_BRIGHTNESS_LOW_HW = 0;
|
||||||
static const uint8_t TM1651_BRIGHTNESS_MEDIUM = 2;
|
static const uint8_t TM1651_BRIGHTNESS_MEDIUM_HW = 2;
|
||||||
static const uint8_t TM1651_BRIGHTNESS_HIGH = 7;
|
static const uint8_t TM1651_BRIGHTNESS_HIGH_HW = 7;
|
||||||
|
|
||||||
void TM1651Display::setup() {
|
void TM1651Display::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up TM1651...");
|
ESP_LOGCONFIG(TAG, "Setting up TM1651...");
|
||||||
|
@ -78,14 +78,14 @@ uint8_t TM1651Display::calculate_level_(uint8_t new_level) {
|
||||||
|
|
||||||
uint8_t TM1651Display::calculate_brightness_(uint8_t new_brightness) {
|
uint8_t TM1651Display::calculate_brightness_(uint8_t new_brightness) {
|
||||||
if (new_brightness <= 1) {
|
if (new_brightness <= 1) {
|
||||||
return TM1651_BRIGHTNESS_LOW;
|
return TM1651_BRIGHTNESS_LOW_HW;
|
||||||
} else if (new_brightness == 2) {
|
} else if (new_brightness == 2) {
|
||||||
return TM1651_BRIGHTNESS_MEDIUM;
|
return TM1651_BRIGHTNESS_MEDIUM_HW;
|
||||||
} else if (new_brightness >= 3) {
|
} else if (new_brightness >= 3) {
|
||||||
return TM1651_BRIGHTNESS_HIGH;
|
return TM1651_BRIGHTNESS_HIGH_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TM1651_BRIGHTNESS_LOW;
|
return TM1651_BRIGHTNESS_LOW_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tm1651
|
} // namespace tm1651
|
||||||
|
|
|
@ -13,6 +13,12 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tm1651 {
|
namespace tm1651 {
|
||||||
|
|
||||||
|
enum TM1651Brightness : uint8_t {
|
||||||
|
TM1651_BRIGHTNESS_LOW = 1,
|
||||||
|
TM1651_BRIGHTNESS_MEDIUM = 2,
|
||||||
|
TM1651_BRIGHTNESS_HIGH = 3,
|
||||||
|
};
|
||||||
|
|
||||||
class TM1651Display : public Component {
|
class TM1651Display : public Component {
|
||||||
public:
|
public:
|
||||||
void set_clk_pin(InternalGPIOPin *pin) { clk_pin_ = pin; }
|
void set_clk_pin(InternalGPIOPin *pin) { clk_pin_ = pin; }
|
||||||
|
@ -24,6 +30,7 @@ class TM1651Display : public Component {
|
||||||
void set_level_percent(uint8_t new_level);
|
void set_level_percent(uint8_t new_level);
|
||||||
void set_level(uint8_t new_level);
|
void set_level(uint8_t new_level);
|
||||||
void set_brightness(uint8_t new_brightness);
|
void set_brightness(uint8_t new_brightness);
|
||||||
|
void set_brightness(TM1651Brightness new_brightness) { this->set_brightness(static_cast<uint8_t>(new_brightness)); }
|
||||||
|
|
||||||
void turn_on();
|
void turn_on();
|
||||||
void turn_off();
|
void turn_off();
|
||||||
|
|
|
@ -7,6 +7,7 @@ reading temperatures to a resolution of 0.0625°C.
|
||||||
https://www.sparkfun.com/datasheets/Sensors/Temperature/tmp102.pdf
|
https://www.sparkfun.com/datasheets/Sensors/Temperature/tmp102.pdf
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import i2c, sensor
|
from esphome.components import i2c, sensor
|
||||||
|
|
|
@ -34,9 +34,13 @@ void TuyaFan::setup() {
|
||||||
}
|
}
|
||||||
if (this->oscillation_id_.has_value()) {
|
if (this->oscillation_id_.has_value()) {
|
||||||
this->parent_->register_listener(*this->oscillation_id_, [this](const TuyaDatapoint &datapoint) {
|
this->parent_->register_listener(*this->oscillation_id_, [this](const TuyaDatapoint &datapoint) {
|
||||||
|
// Whether data type is BOOL or ENUM, it will still be a 1 or a 0, so the functions below are valid in both
|
||||||
|
// scenarios
|
||||||
ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
|
ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
|
||||||
this->oscillating = datapoint.value_bool;
|
this->oscillating = datapoint.value_bool;
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
|
|
||||||
|
this->oscillation_type_ = datapoint.type;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this->direction_id_.has_value()) {
|
if (this->direction_id_.has_value()) {
|
||||||
|
@ -80,7 +84,11 @@ void TuyaFan::control(const fan::FanCall &call) {
|
||||||
this->parent_->set_boolean_datapoint_value(*this->switch_id_, *call.get_state());
|
this->parent_->set_boolean_datapoint_value(*this->switch_id_, *call.get_state());
|
||||||
}
|
}
|
||||||
if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) {
|
if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) {
|
||||||
this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
if (this->oscillation_type_ == TuyaDatapointType::ENUM) {
|
||||||
|
this->parent_->set_enum_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
||||||
|
} else if (this->speed_type_ == TuyaDatapointType::BOOLEAN) {
|
||||||
|
this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this->direction_id_.has_value() && call.get_direction().has_value()) {
|
if (this->direction_id_.has_value() && call.get_direction().has_value()) {
|
||||||
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
|
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
|
||||||
|
|
|
@ -29,6 +29,7 @@ class TuyaFan : public Component, public fan::Fan {
|
||||||
optional<uint8_t> direction_id_{};
|
optional<uint8_t> direction_id_{};
|
||||||
int speed_count_{};
|
int speed_count_{};
|
||||||
TuyaDatapointType speed_type_{};
|
TuyaDatapointType speed_type_{};
|
||||||
|
TuyaDatapointType oscillation_type_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tuya
|
} // namespace tuya
|
||||||
|
|
78
esphome/components/uponor_smatrix/__init__.py
Normal file
78
esphome/components/uponor_smatrix/__init__.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import uart, time
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ADDRESS,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_TIME_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODEOWNERS = ["@kroimon"]
|
||||||
|
|
||||||
|
DEPENDENCIES = ["uart"]
|
||||||
|
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
|
uponor_smatrix_ns = cg.esphome_ns.namespace("uponor_smatrix")
|
||||||
|
UponorSmatrixComponent = uponor_smatrix_ns.class_(
|
||||||
|
"UponorSmatrixComponent", cg.Component, uart.UARTDevice
|
||||||
|
)
|
||||||
|
UponorSmatrixDevice = uponor_smatrix_ns.class_(
|
||||||
|
"UponorSmatrixDevice", cg.Parented.template(UponorSmatrixComponent)
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_UPONOR_SMATRIX_ID = "uponor_smatrix_id"
|
||||||
|
CONF_TIME_DEVICE_ADDRESS = "time_device_address"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(UponorSmatrixComponent),
|
||||||
|
cv.Optional(CONF_ADDRESS): cv.hex_uint16_t,
|
||||||
|
cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
|
||||||
|
cv.Optional(CONF_TIME_DEVICE_ADDRESS): cv.hex_uint16_t,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
.extend(uart.UART_DEVICE_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||||
|
"uponor_smatrix",
|
||||||
|
baud_rate=19200,
|
||||||
|
require_tx=True,
|
||||||
|
require_rx=True,
|
||||||
|
data_bits=8,
|
||||||
|
parity=None,
|
||||||
|
stop_bits=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
# A schema to use for all Uponor Smatrix devices
|
||||||
|
UPONOR_SMATRIX_DEVICE_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_UPONOR_SMATRIX_ID): cv.use_id(UponorSmatrixComponent),
|
||||||
|
cv.Required(CONF_ADDRESS): cv.hex_uint16_t,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
cg.add_global(uponor_smatrix_ns.using)
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await uart.register_uart_device(var, config)
|
||||||
|
|
||||||
|
if address := config.get(CONF_ADDRESS):
|
||||||
|
cg.add(var.set_system_address(address))
|
||||||
|
if time_id := config.get(CONF_TIME_ID):
|
||||||
|
time_ = await cg.get_variable(time_id)
|
||||||
|
cg.add(var.set_time_id(time_))
|
||||||
|
if time_device_address := config.get(CONF_TIME_DEVICE_ADDRESS):
|
||||||
|
cg.add(var.set_time_device_address(time_device_address))
|
||||||
|
|
||||||
|
|
||||||
|
async def register_uponor_smatrix_device(var, config):
|
||||||
|
parent = await cg.get_variable(config[CONF_UPONOR_SMATRIX_ID])
|
||||||
|
cg.add(var.set_parent(parent))
|
||||||
|
cg.add(var.set_device_address(config[CONF_ADDRESS]))
|
||||||
|
cg.add(parent.register_device(var))
|
33
esphome/components/uponor_smatrix/climate/__init__.py
Normal file
33
esphome/components/uponor_smatrix/climate/__init__.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import climate
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
from .. import (
|
||||||
|
uponor_smatrix_ns,
|
||||||
|
UponorSmatrixDevice,
|
||||||
|
UPONOR_SMATRIX_DEVICE_SCHEMA,
|
||||||
|
register_uponor_smatrix_device,
|
||||||
|
)
|
||||||
|
|
||||||
|
DEPENDENCIES = ["uponor_smatrix"]
|
||||||
|
|
||||||
|
UponorSmatrixClimate = uponor_smatrix_ns.class_(
|
||||||
|
"UponorSmatrixClimate",
|
||||||
|
climate.Climate,
|
||||||
|
cg.Component,
|
||||||
|
UponorSmatrixDevice,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = climate.CLIMATE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(UponorSmatrixClimate),
|
||||||
|
}
|
||||||
|
).extend(UPONOR_SMATRIX_DEVICE_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await climate.register_climate(var, config)
|
||||||
|
await register_uponor_smatrix_device(var, config)
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include "uponor_smatrix_climate.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
static const char *const TAG = "uponor_smatrix.climate";
|
||||||
|
|
||||||
|
void UponorSmatrixClimate::dump_config() {
|
||||||
|
LOG_CLIMATE("", "Uponor Smatrix Climate", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " Device address: 0x%04X", this->address_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixClimate::loop() {
|
||||||
|
const uint32_t now = millis();
|
||||||
|
|
||||||
|
// Publish state after all update packets are processed
|
||||||
|
if (this->last_data_ != 0 && (now - this->last_data_ > 100) && this->target_temperature_raw_ != 0) {
|
||||||
|
float temp = raw_to_celsius((this->preset == climate::CLIMATE_PRESET_ECO)
|
||||||
|
? (this->target_temperature_raw_ - this->eco_setback_value_raw_)
|
||||||
|
: this->target_temperature_raw_);
|
||||||
|
float step = this->get_traits().get_visual_target_temperature_step();
|
||||||
|
this->target_temperature = roundf(temp / step) * step;
|
||||||
|
this->publish_state();
|
||||||
|
this->last_data_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
climate::ClimateTraits UponorSmatrixClimate::traits() {
|
||||||
|
auto traits = climate::ClimateTraits();
|
||||||
|
traits.set_supports_current_temperature(true);
|
||||||
|
traits.set_supports_current_humidity(true);
|
||||||
|
traits.set_supported_modes({climate::CLIMATE_MODE_HEAT});
|
||||||
|
traits.set_supports_action(true);
|
||||||
|
traits.set_supported_presets({climate::CLIMATE_PRESET_ECO});
|
||||||
|
traits.set_visual_min_temperature(this->min_temperature_);
|
||||||
|
traits.set_visual_max_temperature(this->max_temperature_);
|
||||||
|
traits.set_visual_current_temperature_step(0.1f);
|
||||||
|
traits.set_visual_target_temperature_step(0.5f);
|
||||||
|
return traits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixClimate::control(const climate::ClimateCall &call) {
|
||||||
|
if (call.get_target_temperature().has_value()) {
|
||||||
|
uint16_t temp = celsius_to_raw(*call.get_target_temperature());
|
||||||
|
if (this->preset == climate::CLIMATE_PRESET_ECO) {
|
||||||
|
// During ECO mode, the thermostat automatically substracts the setback value from the setpoint,
|
||||||
|
// so we need to add it here first
|
||||||
|
temp += this->eco_setback_value_raw_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For unknown reasons, we need to send a null setpoint first for the thermostat to react
|
||||||
|
UponorSmatrixData data[] = {{UPONOR_ID_TARGET_TEMP, 0}, {UPONOR_ID_TARGET_TEMP, temp}};
|
||||||
|
this->send(data, sizeof(data) / sizeof(data[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixClimate::on_device_data(const UponorSmatrixData *data, size_t data_len) {
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
switch (data[i].id) {
|
||||||
|
case UPONOR_ID_TARGET_TEMP_MIN:
|
||||||
|
this->min_temperature_ = raw_to_celsius(data[i].value);
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_TARGET_TEMP_MAX:
|
||||||
|
this->max_temperature_ = raw_to_celsius(data[i].value);
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_TARGET_TEMP:
|
||||||
|
// Ignore invalid values here as they are used by the controller to explicitely request the setpoint from a
|
||||||
|
// thermostat
|
||||||
|
if (data[i].value != UPONOR_INVALID_VALUE)
|
||||||
|
this->target_temperature_raw_ = data[i].value;
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_ECO_SETBACK:
|
||||||
|
this->eco_setback_value_raw_ = data[i].value;
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_DEMAND:
|
||||||
|
if (data[i].value & 0x1000) {
|
||||||
|
this->mode = climate::CLIMATE_MODE_COOL;
|
||||||
|
this->action = (data[i].value & 0x0040) ? climate::CLIMATE_ACTION_COOLING : climate::CLIMATE_ACTION_IDLE;
|
||||||
|
} else {
|
||||||
|
this->mode = climate::CLIMATE_MODE_HEAT;
|
||||||
|
this->action = (data[i].value & 0x0040) ? climate::CLIMATE_ACTION_HEATING : climate::CLIMATE_ACTION_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_MODE1:
|
||||||
|
this->set_preset_((data[i].value & 0x0008) ? climate::CLIMATE_PRESET_ECO : climate::CLIMATE_PRESET_NONE);
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_ROOM_TEMP:
|
||||||
|
this->current_temperature = raw_to_celsius(data[i].value);
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_HUMIDITY:
|
||||||
|
this->current_humidity = data[i].value & 0x00FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->last_data_ = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/climate/climate.h"
|
||||||
|
#include "esphome/components/uponor_smatrix/uponor_smatrix.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
class UponorSmatrixClimate : public climate::Climate, public Component, public UponorSmatrixDevice {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
climate::ClimateTraits traits() override;
|
||||||
|
void control(const climate::ClimateCall &call) override;
|
||||||
|
void on_device_data(const UponorSmatrixData *data, size_t data_len) override;
|
||||||
|
|
||||||
|
uint32_t last_data_;
|
||||||
|
float min_temperature_{5.0f};
|
||||||
|
float max_temperature_{35.0f};
|
||||||
|
uint16_t eco_setback_value_raw_{0x0048};
|
||||||
|
uint16_t target_temperature_raw_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
70
esphome/components/uponor_smatrix/sensor/__init__.py
Normal file
70
esphome/components/uponor_smatrix/sensor/__init__.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_EXTERNAL_TEMPERATURE,
|
||||||
|
CONF_HUMIDITY,
|
||||||
|
CONF_TEMPERATURE,
|
||||||
|
CONF_ID,
|
||||||
|
DEVICE_CLASS_HUMIDITY,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
UNIT_CELSIUS,
|
||||||
|
UNIT_PERCENT,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .. import (
|
||||||
|
uponor_smatrix_ns,
|
||||||
|
UponorSmatrixDevice,
|
||||||
|
UPONOR_SMATRIX_DEVICE_SCHEMA,
|
||||||
|
register_uponor_smatrix_device,
|
||||||
|
)
|
||||||
|
|
||||||
|
DEPENDENCIES = ["uponor_smatrix"]
|
||||||
|
|
||||||
|
UponorSmatrixSensor = uponor_smatrix_ns.class_(
|
||||||
|
"UponorSmatrixSensor",
|
||||||
|
sensor.Sensor,
|
||||||
|
cg.Component,
|
||||||
|
UponorSmatrixDevice,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.COMPONENT_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(UponorSmatrixSensor),
|
||||||
|
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_PERCENT,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_HUMIDITY,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
).extend(UPONOR_SMATRIX_DEVICE_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await register_uponor_smatrix_device(var, config)
|
||||||
|
|
||||||
|
if temperature_config := config.get(CONF_TEMPERATURE):
|
||||||
|
sens = await sensor.new_sensor(temperature_config)
|
||||||
|
cg.add(var.set_temperature_sensor(sens))
|
||||||
|
if external_temperature_config := config.get(CONF_EXTERNAL_TEMPERATURE):
|
||||||
|
sens = await sensor.new_sensor(external_temperature_config)
|
||||||
|
cg.add(var.set_external_temperature_sensor(sens))
|
||||||
|
if humidity_config := config.get(CONF_HUMIDITY):
|
||||||
|
sens = await sensor.new_sensor(humidity_config)
|
||||||
|
cg.add(var.set_humidity_sensor(sens))
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "uponor_smatrix_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
static const char *const TAG = "uponor_smatrix.sensor";
|
||||||
|
|
||||||
|
void UponorSmatrixSensor::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Uponor Smatrix Sensor");
|
||||||
|
ESP_LOGCONFIG(TAG, " Device address: 0x%04X", this->address_);
|
||||||
|
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||||
|
LOG_SENSOR(" ", "External Temperature", this->external_temperature_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixSensor::on_device_data(const UponorSmatrixData *data, size_t data_len) {
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
switch (data[i].id) {
|
||||||
|
case UPONOR_ID_ROOM_TEMP:
|
||||||
|
if (this->temperature_sensor_ != nullptr)
|
||||||
|
this->temperature_sensor_->publish_state(raw_to_celsius(data[i].value));
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_EXTERNAL_TEMP:
|
||||||
|
if (this->external_temperature_sensor_ != nullptr)
|
||||||
|
this->external_temperature_sensor_->publish_state(raw_to_celsius(data[i].value));
|
||||||
|
break;
|
||||||
|
case UPONOR_ID_HUMIDITY:
|
||||||
|
if (this->humidity_sensor_ != nullptr)
|
||||||
|
this->humidity_sensor_->publish_state(data[i].value & 0x00FF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/uponor_smatrix/uponor_smatrix.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
class UponorSmatrixSensor : public sensor::Sensor, public Component, public UponorSmatrixDevice {
|
||||||
|
SUB_SENSOR(temperature)
|
||||||
|
SUB_SENSOR(external_temperature)
|
||||||
|
SUB_SENSOR(humidity)
|
||||||
|
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_device_data(const UponorSmatrixData *data, size_t data_len) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
225
esphome/components/uponor_smatrix/uponor_smatrix.cpp
Normal file
225
esphome/components/uponor_smatrix/uponor_smatrix.cpp
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
#include "uponor_smatrix.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
static const char *const TAG = "uponor_smatrix";
|
||||||
|
|
||||||
|
void UponorSmatrixComponent::setup() {
|
||||||
|
#ifdef USE_TIME
|
||||||
|
if (this->time_id_ != nullptr) {
|
||||||
|
this->time_id_->add_on_time_sync_callback([this] { this->send_time(); });
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixComponent::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Uponor Smatrix");
|
||||||
|
ESP_LOGCONFIG(TAG, " System address: 0x%04X", this->address_);
|
||||||
|
#ifdef USE_TIME
|
||||||
|
if (this->time_id_ != nullptr) {
|
||||||
|
ESP_LOGCONFIG(TAG, " Time synchronization: YES");
|
||||||
|
ESP_LOGCONFIG(TAG, " Time master device address: 0x%04X", this->time_device_address_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->check_uart_settings(19200);
|
||||||
|
|
||||||
|
if (!this->unknown_devices_.empty()) {
|
||||||
|
ESP_LOGCONFIG(TAG, " Detected unknown device addresses:");
|
||||||
|
for (auto device_address : this->unknown_devices_) {
|
||||||
|
ESP_LOGCONFIG(TAG, " 0x%04X", device_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UponorSmatrixComponent::loop() {
|
||||||
|
const uint32_t now = millis();
|
||||||
|
|
||||||
|
// Discard stale data
|
||||||
|
if (!this->rx_buffer_.empty() && (now - this->last_rx_ > 50)) {
|
||||||
|
ESP_LOGD(TAG, "Discarding %d bytes of unparsed data", this->rx_buffer_.size());
|
||||||
|
this->rx_buffer_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read incoming data
|
||||||
|
while (this->available()) {
|
||||||
|
// The controller polls devices every 10 seconds, with around 200 ms between devices.
|
||||||
|
// Remember timestamps so we can send our own packets when the bus is expected to be silent.
|
||||||
|
if (now - this->last_rx_ > 500) {
|
||||||
|
this->last_poll_start_ = now;
|
||||||
|
}
|
||||||
|
this->last_rx_ = now;
|
||||||
|
|
||||||
|
uint8_t byte;
|
||||||
|
this->read_byte(&byte);
|
||||||
|
if (this->parse_byte_(byte)) {
|
||||||
|
this->rx_buffer_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send packets during bus silence
|
||||||
|
if ((now - this->last_rx_ > 300) && (now - this->last_poll_start_ < 9500) && (now - this->last_tx_ > 200)) {
|
||||||
|
// Only build time packet when bus is silent and queue is empty to make sure we can send it right away
|
||||||
|
if (this->send_time_requested_ && this->tx_queue_.empty() && this->do_send_time_())
|
||||||
|
this->send_time_requested_ = false;
|
||||||
|
// Send the next packet in the queue
|
||||||
|
if (!this->tx_queue_.empty()) {
|
||||||
|
auto packet = std::move(this->tx_queue_.front());
|
||||||
|
this->tx_queue_.pop();
|
||||||
|
|
||||||
|
this->write_array(packet);
|
||||||
|
this->flush();
|
||||||
|
|
||||||
|
this->last_tx_ = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
|
||||||
|
this->rx_buffer_.push_back(byte);
|
||||||
|
const uint8_t *packet = this->rx_buffer_.data();
|
||||||
|
size_t packet_len = this->rx_buffer_.size();
|
||||||
|
|
||||||
|
if (packet_len < 7) {
|
||||||
|
// Minimum packet size is 7 bytes, wait for more
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t system_address = encode_uint16(packet[0], packet[1]);
|
||||||
|
uint16_t device_address = encode_uint16(packet[2], packet[3]);
|
||||||
|
uint16_t crc = encode_uint16(packet[packet_len - 1], packet[packet_len - 2]);
|
||||||
|
|
||||||
|
uint16_t computed_crc = crc16(packet, packet_len - 2);
|
||||||
|
if (crc != computed_crc) {
|
||||||
|
// CRC did not match, more data might be coming
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "Received packet: sys=%04X, dev=%04X, data=%s, crc=%04X", system_address, device_address,
|
||||||
|
format_hex(&packet[4], packet_len - 6).c_str(), crc);
|
||||||
|
|
||||||
|
// Detect or check system address
|
||||||
|
if (this->address_ == 0) {
|
||||||
|
ESP_LOGI(TAG, "Using detected system address 0x%04X", system_address);
|
||||||
|
this->address_ = system_address;
|
||||||
|
} else if (this->address_ != system_address) {
|
||||||
|
// This should never happen except if the system address was set or detected incorrectly, so warn the user.
|
||||||
|
ESP_LOGW(TAG, "Received packet from unknown system address 0x%04X", system_address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle packet
|
||||||
|
size_t data_len = (packet_len - 6) / 3;
|
||||||
|
if (data_len == 0) {
|
||||||
|
if (packet[4] == UPONOR_ID_REQUEST)
|
||||||
|
ESP_LOGVV(TAG, "Ignoring request packet for device 0x%04X", device_address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode packet payload data for easy access
|
||||||
|
UponorSmatrixData data[data_len];
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
data[i].id = packet[(i * 3) + 4];
|
||||||
|
data[i].value = encode_uint16(packet[(i * 3) + 5], packet[(i * 3) + 6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
// Detect device that acts as time master if not set explicitely
|
||||||
|
if (this->time_device_address_ == 0 && data_len >= 2) {
|
||||||
|
// The first thermostat paired to the controller will act as the time master. Time can only be manually adjusted at
|
||||||
|
// this first thermostat. To synchronize time, we need to know its address, so we search for packets coming from a
|
||||||
|
// thermostat sending both room temperature and time information.
|
||||||
|
bool found_temperature = false;
|
||||||
|
bool found_time = false;
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
if (data[i].id == UPONOR_ID_ROOM_TEMP)
|
||||||
|
found_temperature = true;
|
||||||
|
if (data[i].id == UPONOR_ID_DATETIME1)
|
||||||
|
found_time = true;
|
||||||
|
if (found_temperature && found_time) {
|
||||||
|
ESP_LOGI(TAG, "Using detected time device address 0x%04X", device_address);
|
||||||
|
this->time_device_address_ = device_address;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Forward data to device components
|
||||||
|
bool found = false;
|
||||||
|
for (auto *device : this->devices_) {
|
||||||
|
if (device->address_ == device_address) {
|
||||||
|
found = true;
|
||||||
|
device->on_device_data(data, data_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log unknown device addresses
|
||||||
|
if (!found && !this->unknown_devices_.count(device_address)) {
|
||||||
|
ESP_LOGI(TAG, "Received packet for unknown device address 0x%04X ", device_address);
|
||||||
|
this->unknown_devices_.insert(device_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true to reset buffer
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixData *data, size_t data_len) {
|
||||||
|
if (this->address_ == 0 || device_address == 0 || data == nullptr || data_len == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Assemble packet for send queue. All fields are big-endian except for the little-endian checksum.
|
||||||
|
std::vector<uint8_t> packet(6 + 3 * data_len);
|
||||||
|
packet.push_back(this->address_ >> 8);
|
||||||
|
packet.push_back(this->address_ >> 0);
|
||||||
|
packet.push_back(device_address >> 8);
|
||||||
|
packet.push_back(device_address >> 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < data_len; i++) {
|
||||||
|
packet.push_back(data[i].id);
|
||||||
|
packet.push_back(data[i].value >> 8);
|
||||||
|
packet.push_back(data[i].value >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto crc = crc16(packet.data(), packet.size());
|
||||||
|
packet.push_back(crc >> 0);
|
||||||
|
packet.push_back(crc >> 8);
|
||||||
|
|
||||||
|
this->tx_queue_.push(packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
bool UponorSmatrixComponent::do_send_time_() {
|
||||||
|
if (this->time_device_address_ == 0 || this->time_id_ == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ESPTime now = this->time_id_->now();
|
||||||
|
if (!now.is_valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t year = now.year - 2000;
|
||||||
|
uint8_t month = now.month;
|
||||||
|
// ESPHome days are [1-7] starting with Sunday, Uponor days are [0-6] starting with Monday
|
||||||
|
uint8_t day_of_week = (now.day_of_week == 1) ? 6 : (now.day_of_week - 2);
|
||||||
|
uint8_t day_of_month = now.day_of_month;
|
||||||
|
uint8_t hour = now.hour;
|
||||||
|
uint8_t minute = now.minute;
|
||||||
|
uint8_t second = now.second;
|
||||||
|
|
||||||
|
uint16_t time1 = (year & 0x7F) << 7 | (month & 0x0F) << 3 | (day_of_week & 0x07);
|
||||||
|
uint16_t time2 = (day_of_month & 0x1F) << 11 | (hour & 0x1F) << 6 | (minute & 0x3F);
|
||||||
|
uint16_t time3 = second;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Sending local time: %04d-%02d-%02d %02d:%02d:%02d", now.year, now.month, now.day_of_month, now.hour,
|
||||||
|
now.minute, now.second);
|
||||||
|
|
||||||
|
UponorSmatrixData data[] = {{UPONOR_ID_DATETIME1, time1}, {UPONOR_ID_DATETIME2, time2}, {UPONOR_ID_DATETIME3, time3}};
|
||||||
|
return this->send(this->time_device_address_, data, sizeof(data) / sizeof(data[0]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
128
esphome/components/uponor_smatrix/uponor_smatrix.h
Normal file
128
esphome/components/uponor_smatrix/uponor_smatrix.h
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/uart/uart.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#include "esphome/core/time.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace uponor_smatrix {
|
||||||
|
|
||||||
|
/// Date/Time Part 1 (year, month, day of week)
|
||||||
|
static const uint8_t UPONOR_ID_DATETIME1 = 0x08;
|
||||||
|
/// Date/Time Part 2 (day of month, hour, minute)
|
||||||
|
static const uint8_t UPONOR_ID_DATETIME2 = 0x09;
|
||||||
|
/// Date/Time Part 3 (seconds)
|
||||||
|
static const uint8_t UPONOR_ID_DATETIME3 = 0x0A;
|
||||||
|
/// Unknown (observed values: 0x0342, 0x0024)
|
||||||
|
static const uint8_t UPONOR_ID_UNKNOWN1 = 0x0C;
|
||||||
|
/// Outdoor Temperature? (sent by controller)
|
||||||
|
static const uint8_t UPONOR_ID_OUTDOOR_TEMP = 0x2D;
|
||||||
|
/// Unknown (observed values: 0x8000)
|
||||||
|
static const uint8_t UPONOR_ID_UNKNOWN2 = 0x35;
|
||||||
|
/// Room Temperature Setpoint Minimum
|
||||||
|
static const uint8_t UPONOR_ID_TARGET_TEMP_MIN = 0x37;
|
||||||
|
/// Room Temperature Setpoint Maximum
|
||||||
|
static const uint8_t UPONOR_ID_TARGET_TEMP_MAX = 0x38;
|
||||||
|
/// Room Temperature Setpoint
|
||||||
|
static const uint8_t UPONOR_ID_TARGET_TEMP = 0x3B;
|
||||||
|
/// Room Temperature Setpoint Setback for ECO Mode
|
||||||
|
static const uint8_t UPONOR_ID_ECO_SETBACK = 0x3C;
|
||||||
|
/// Heating/Cooling Demand
|
||||||
|
static const uint8_t UPONOR_ID_DEMAND = 0x3D;
|
||||||
|
/// Thermostat Operating Mode 1 (ECO state, program schedule state)
|
||||||
|
static const uint8_t UPONOR_ID_MODE1 = 0x3E;
|
||||||
|
/// Thermostat Operating Mode 2 (sensor configuration, heating/cooling allowed)
|
||||||
|
static const uint8_t UPONOR_ID_MODE2 = 0x3F;
|
||||||
|
/// Current Room Temperature
|
||||||
|
static const uint8_t UPONOR_ID_ROOM_TEMP = 0x40;
|
||||||
|
/// Current External (Floor/Outdoor) Sensor Temperature
|
||||||
|
static const uint8_t UPONOR_ID_EXTERNAL_TEMP = 0x41;
|
||||||
|
/// Current Room Humidity
|
||||||
|
static const uint8_t UPONOR_ID_HUMIDITY = 0x42;
|
||||||
|
/// Data Request (sent by controller)
|
||||||
|
static const uint8_t UPONOR_ID_REQUEST = 0xFF;
|
||||||
|
|
||||||
|
/// Indicating an invalid/missing value
|
||||||
|
static const uint16_t UPONOR_INVALID_VALUE = 0x7FFF;
|
||||||
|
|
||||||
|
struct UponorSmatrixData {
|
||||||
|
uint8_t id;
|
||||||
|
uint16_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UponorSmatrixDevice;
|
||||||
|
|
||||||
|
class UponorSmatrixComponent : public uart::UARTDevice, public Component {
|
||||||
|
public:
|
||||||
|
UponorSmatrixComponent() = default;
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
void set_system_address(uint16_t address) { this->address_ = address; }
|
||||||
|
void register_device(UponorSmatrixDevice *device) { this->devices_.push_back(device); }
|
||||||
|
|
||||||
|
bool send(uint16_t device_address, const UponorSmatrixData *data, size_t data_len);
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; }
|
||||||
|
void set_time_device_address(uint16_t address) { this->time_device_address_ = address; }
|
||||||
|
void send_time() { this->send_time_requested_ = true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool parse_byte_(uint8_t byte);
|
||||||
|
|
||||||
|
uint16_t address_;
|
||||||
|
std::vector<UponorSmatrixDevice *> devices_;
|
||||||
|
std::set<uint16_t> unknown_devices_;
|
||||||
|
|
||||||
|
std::vector<uint8_t> rx_buffer_;
|
||||||
|
std::queue<std::vector<uint8_t>> tx_queue_;
|
||||||
|
uint32_t last_rx_;
|
||||||
|
uint32_t last_tx_;
|
||||||
|
uint32_t last_poll_start_;
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
time::RealTimeClock *time_id_{nullptr};
|
||||||
|
uint16_t time_device_address_;
|
||||||
|
bool send_time_requested_;
|
||||||
|
bool do_send_time_();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class UponorSmatrixDevice : public Parented<UponorSmatrixComponent> {
|
||||||
|
public:
|
||||||
|
void set_device_address(uint16_t address) { this->address_ = address; }
|
||||||
|
|
||||||
|
virtual void on_device_data(const UponorSmatrixData *data, size_t data_len) = 0;
|
||||||
|
bool send(const UponorSmatrixData *data, size_t data_len) {
|
||||||
|
return this->parent_->send(this->address_, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend UponorSmatrixComponent;
|
||||||
|
uint16_t address_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float raw_to_celsius(uint16_t raw) {
|
||||||
|
return (raw == UPONOR_INVALID_VALUE) ? NAN : fahrenheit_to_celsius(raw / 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t celsius_to_raw(float celsius) {
|
||||||
|
return std::isnan(celsius) ? UPONOR_INVALID_VALUE
|
||||||
|
: static_cast<uint16_t>(lroundf(celsius_to_fahrenheit(celsius) * 10.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uponor_smatrix
|
||||||
|
} // namespace esphome
|
|
@ -32,6 +32,7 @@ CONF_ON_TTS_START = "on_tts_start"
|
||||||
CONF_ON_TTS_STREAM_START = "on_tts_stream_start"
|
CONF_ON_TTS_STREAM_START = "on_tts_stream_start"
|
||||||
CONF_ON_TTS_STREAM_END = "on_tts_stream_end"
|
CONF_ON_TTS_STREAM_END = "on_tts_stream_end"
|
||||||
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
||||||
|
CONF_ON_IDLE = "on_idle"
|
||||||
|
|
||||||
CONF_SILENCE_DETECTION = "silence_detection"
|
CONF_SILENCE_DETECTION = "silence_detection"
|
||||||
CONF_USE_WAKE_WORD = "use_wake_word"
|
CONF_USE_WAKE_WORD = "use_wake_word"
|
||||||
|
@ -127,6 +128,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Optional(CONF_ON_TTS_STREAM_END): automation.validate_automation(
|
cv.Optional(CONF_ON_TTS_STREAM_END): automation.validate_automation(
|
||||||
single=True
|
single=True
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_ON_IDLE): automation.validate_automation(single=True),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
tts_stream_validate,
|
tts_stream_validate,
|
||||||
|
@ -259,6 +261,13 @@ async def to_code(config):
|
||||||
config[CONF_ON_TTS_STREAM_END],
|
config[CONF_ON_TTS_STREAM_END],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if CONF_ON_IDLE in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_idle_trigger(),
|
||||||
|
[],
|
||||||
|
config[CONF_ON_IDLE],
|
||||||
|
)
|
||||||
|
|
||||||
cg.add_define("USE_VOICE_ASSISTANT")
|
cg.add_define("USE_VOICE_ASSISTANT")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,8 @@ void VoiceAssistant::loop() {
|
||||||
switch (this->state_) {
|
switch (this->state_) {
|
||||||
case State::IDLE: {
|
case State::IDLE: {
|
||||||
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
||||||
|
this->idle_trigger_->trigger();
|
||||||
|
|
||||||
this->ring_buffer_->reset();
|
this->ring_buffer_->reset();
|
||||||
#ifdef USE_ESP_ADF
|
#ifdef USE_ESP_ADF
|
||||||
if (this->use_wake_word_) {
|
if (this->use_wake_word_) {
|
||||||
|
@ -618,6 +620,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||||
{
|
{
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
}
|
}
|
||||||
|
} else if (this->state_ == State::AWAITING_RESPONSE) {
|
||||||
|
// No TTS start event ("nevermind")
|
||||||
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
}
|
}
|
||||||
this->defer([this]() { this->end_trigger_->trigger(); });
|
this->defer([this]() { this->end_trigger_->trigger(); });
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -116,6 +116,7 @@ class VoiceAssistant : public Component {
|
||||||
Trigger<std::string> *get_tts_end_trigger() const { return this->tts_end_trigger_; }
|
Trigger<std::string> *get_tts_end_trigger() const { return this->tts_end_trigger_; }
|
||||||
Trigger<std::string> *get_tts_start_trigger() const { return this->tts_start_trigger_; }
|
Trigger<std::string> *get_tts_start_trigger() const { return this->tts_start_trigger_; }
|
||||||
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
||||||
|
Trigger<> *get_idle_trigger() const { return this->idle_trigger_; }
|
||||||
|
|
||||||
Trigger<> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
Trigger<> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
||||||
Trigger<> *get_client_disconnected_trigger() const { return this->client_disconnected_trigger_; }
|
Trigger<> *get_client_disconnected_trigger() const { return this->client_disconnected_trigger_; }
|
||||||
|
@ -148,6 +149,7 @@ class VoiceAssistant : public Component {
|
||||||
Trigger<std::string> *tts_end_trigger_ = new Trigger<std::string>();
|
Trigger<std::string> *tts_end_trigger_ = new Trigger<std::string>();
|
||||||
Trigger<std::string> *tts_start_trigger_ = new Trigger<std::string>();
|
Trigger<std::string> *tts_start_trigger_ = new Trigger<std::string>();
|
||||||
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
Trigger<> *idle_trigger_ = new Trigger<>();
|
||||||
|
|
||||||
Trigger<> *client_connected_trigger_ = new Trigger<>();
|
Trigger<> *client_connected_trigger_ = new Trigger<>();
|
||||||
Trigger<> *client_disconnected_trigger_ = new Trigger<>();
|
Trigger<> *client_disconnected_trigger_ = new Trigger<>();
|
||||||
|
|
|
@ -785,6 +785,8 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
|
||||||
obj->position, start_config);
|
obj->position, start_config);
|
||||||
root["current_operation"] = cover::cover_operation_to_str(obj->current_operation);
|
root["current_operation"] = cover::cover_operation_to_str(obj->current_operation);
|
||||||
|
|
||||||
|
if (obj->get_traits().get_supports_position())
|
||||||
|
root["position"] = obj->position;
|
||||||
if (obj->get_traits().get_supports_tilt())
|
if (obj->get_traits().get_supports_tilt())
|
||||||
root["tilt"] = obj->tilt;
|
root["tilt"] = obj->tilt;
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
The cryptography package is loaded lazily in the functions
|
The cryptography package is loaded lazily in the functions
|
||||||
so that it doesn't crash if it's not installed.
|
so that it doesn't crash if it's not installed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
|
@ -292,8 +292,7 @@ class ConfigValidationStep(abc.ABC):
|
||||||
priority: float = 0.0
|
priority: float = 0.0
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def run(self, result: Config) -> None:
|
def run(self, result: Config) -> None: ... # noqa: E704
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class LoadValidationStep(ConfigValidationStep):
|
class LoadValidationStep(ConfigValidationStep):
|
||||||
|
|
|
@ -251,6 +251,7 @@ CONF_EXPORT_ACTIVE_ENERGY = "export_active_energy"
|
||||||
CONF_EXPORT_REACTIVE_ENERGY = "export_reactive_energy"
|
CONF_EXPORT_REACTIVE_ENERGY = "export_reactive_energy"
|
||||||
CONF_EXTERNAL_CLOCK_INPUT = "external_clock_input"
|
CONF_EXTERNAL_CLOCK_INPUT = "external_clock_input"
|
||||||
CONF_EXTERNAL_COMPONENTS = "external_components"
|
CONF_EXTERNAL_COMPONENTS = "external_components"
|
||||||
|
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||||
CONF_EXTERNAL_VCC = "external_vcc"
|
CONF_EXTERNAL_VCC = "external_vcc"
|
||||||
CONF_FALLING_EDGE = "falling_edge"
|
CONF_FALLING_EDGE = "falling_edge"
|
||||||
CONF_FAMILY = "family"
|
CONF_FAMILY = "family"
|
||||||
|
|
|
@ -8,3 +8,5 @@ MAX_EXECUTOR_WORKERS = 48
|
||||||
|
|
||||||
|
|
||||||
SENTINEL = object()
|
SENTINEL = object()
|
||||||
|
|
||||||
|
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import TYPE_CHECKING, Any, Callable
|
from typing import TYPE_CHECKING, Any, Callable
|
||||||
|
from collections.abc import Coroutine
|
||||||
|
|
||||||
from ..zeroconf import DiscoveredImport
|
from ..zeroconf import DiscoveredImport
|
||||||
from .dns import DNSCache
|
from .dns import DNSCache
|
||||||
|
@ -71,6 +73,7 @@ class ESPHomeDashboard:
|
||||||
"mdns_status",
|
"mdns_status",
|
||||||
"settings",
|
"settings",
|
||||||
"dns_cache",
|
"dns_cache",
|
||||||
|
"_background_tasks",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
@ -85,6 +88,7 @@ class ESPHomeDashboard:
|
||||||
self.mdns_status: MDNSStatus | None = None
|
self.mdns_status: MDNSStatus | None = None
|
||||||
self.settings = DashboardSettings()
|
self.settings = DashboardSettings()
|
||||||
self.dns_cache = DNSCache()
|
self.dns_cache = DNSCache()
|
||||||
|
self._background_tasks: set[asyncio.Task] = set()
|
||||||
|
|
||||||
async def async_setup(self) -> None:
|
async def async_setup(self) -> None:
|
||||||
"""Setup the dashboard."""
|
"""Setup the dashboard."""
|
||||||
|
@ -132,7 +136,19 @@ class ESPHomeDashboard:
|
||||||
if settings.status_use_mqtt:
|
if settings.status_use_mqtt:
|
||||||
status_thread_mqtt.join()
|
status_thread_mqtt.join()
|
||||||
self.mqtt_ping_request.set()
|
self.mqtt_ping_request.set()
|
||||||
|
for task in self._background_tasks:
|
||||||
|
task.cancel()
|
||||||
|
with contextlib.suppress(asyncio.CancelledError):
|
||||||
|
await task
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
|
|
||||||
|
def async_create_background_task(
|
||||||
|
self, coro: Coroutine[Any, Any, Any]
|
||||||
|
) -> asyncio.Task:
|
||||||
|
"""Create a background task."""
|
||||||
|
task = self.loop.create_task(coro)
|
||||||
|
task.add_done_callback(self._background_tasks.discard)
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
DASHBOARD = ESPHomeDashboard()
|
DASHBOARD = ESPHomeDashboard()
|
||||||
|
|
|
@ -10,12 +10,14 @@ from esphome import const, util
|
||||||
from esphome.storage_json import StorageJSON, ext_storage_path
|
from esphome.storage_json import StorageJSON, ext_storage_path
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
DASHBOARD_COMMAND,
|
||||||
EVENT_ENTRY_ADDED,
|
EVENT_ENTRY_ADDED,
|
||||||
EVENT_ENTRY_REMOVED,
|
EVENT_ENTRY_REMOVED,
|
||||||
EVENT_ENTRY_STATE_CHANGED,
|
EVENT_ENTRY_STATE_CHANGED,
|
||||||
EVENT_ENTRY_UPDATED,
|
EVENT_ENTRY_UPDATED,
|
||||||
)
|
)
|
||||||
from .enum import StrEnum
|
from .enum import StrEnum
|
||||||
|
from .util.subprocess import async_run_system_command
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .core import ESPHomeDashboard
|
from .core import ESPHomeDashboard
|
||||||
|
@ -235,6 +237,14 @@ class DashboardEntries:
|
||||||
)
|
)
|
||||||
return path_to_cache_key
|
return path_to_cache_key
|
||||||
|
|
||||||
|
def async_schedule_storage_json_update(self, filename: str) -> None:
|
||||||
|
"""Schedule a task to update the storage JSON file."""
|
||||||
|
self._dashboard.async_create_background_task(
|
||||||
|
async_run_system_command(
|
||||||
|
[*DASHBOARD_COMMAND, "compile", "--only-generate", filename]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashboardEntry:
|
class DashboardEntry:
|
||||||
"""Represents a single dashboard entry.
|
"""Represents a single dashboard entry.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Enum backports from standard lib."""
|
"""Enum backports from standard lib."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
|
@ -9,11 +9,11 @@ import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import secrets
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
||||||
|
@ -40,6 +40,7 @@ from esphome.storage_json import StorageJSON, ext_storage_path, trash_storage_pa
|
||||||
from esphome.util import get_serial_ports, shlex_quote
|
from esphome.util import get_serial_ports, shlex_quote
|
||||||
from esphome.yaml_util import FastestAvailableSafeLoader
|
from esphome.yaml_util import FastestAvailableSafeLoader
|
||||||
|
|
||||||
|
from .const import DASHBOARD_COMMAND
|
||||||
from .core import DASHBOARD
|
from .core import DASHBOARD
|
||||||
from .entries import EntryState, entry_state_to_bool
|
from .entries import EntryState, entry_state_to_bool
|
||||||
from .util.file import write_file
|
from .util.file import write_file
|
||||||
|
@ -286,9 +287,6 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
|
||||||
|
|
||||||
|
|
||||||
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
||||||
"""Base class for commands that require a port."""
|
"""Base class for commands that require a port."""
|
||||||
|
|
||||||
|
@ -808,8 +806,16 @@ class EditRequestHandler(BaseHandler):
|
||||||
@bind_config
|
@bind_config
|
||||||
async def get(self, configuration: str | None = None) -> None:
|
async def get(self, configuration: str | None = None) -> None:
|
||||||
"""Get the content of a file."""
|
"""Get the content of a file."""
|
||||||
loop = asyncio.get_running_loop()
|
if not configuration.endswith((".yaml", ".yml")):
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
filename = settings.rel_path(configuration)
|
filename = settings.rel_path(configuration)
|
||||||
|
if Path(filename).resolve().parent != settings.absolute_config_dir:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
content = await loop.run_in_executor(
|
content = await loop.run_in_executor(
|
||||||
None, self._read_file, filename, configuration
|
None, self._read_file, filename, configuration
|
||||||
)
|
)
|
||||||
|
@ -835,15 +841,19 @@ class EditRequestHandler(BaseHandler):
|
||||||
@bind_config
|
@bind_config
|
||||||
async def post(self, configuration: str | None = None) -> None:
|
async def post(self, configuration: str | None = None) -> None:
|
||||||
"""Write the content of a file."""
|
"""Write the content of a file."""
|
||||||
|
if not configuration.endswith((".yaml", ".yml")):
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
filename = settings.rel_path(configuration)
|
||||||
|
if Path(filename).resolve().parent != settings.absolute_config_dir:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
config_file = settings.rel_path(configuration)
|
await loop.run_in_executor(None, self._write_file, filename, self.request.body)
|
||||||
await loop.run_in_executor(
|
|
||||||
None, self._write_file, config_file, self.request.body
|
|
||||||
)
|
|
||||||
# Ensure the StorageJSON is updated as well
|
# Ensure the StorageJSON is updated as well
|
||||||
await async_run_system_command(
|
DASHBOARD.entries.async_schedule_storage_json_update(filename)
|
||||||
[*DASHBOARD_COMMAND, "compile", "--only-generate", config_file]
|
|
||||||
)
|
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -206,8 +206,11 @@ def perform_ota(
|
||||||
|
|
||||||
_, version = receive_exactly(sock, 2, "version", RESPONSE_OK)
|
_, version = receive_exactly(sock, 2, "version", RESPONSE_OK)
|
||||||
_LOGGER.debug("Device support OTA version: %s", version)
|
_LOGGER.debug("Device support OTA version: %s", version)
|
||||||
if version not in (OTA_VERSION_1_0, OTA_VERSION_2_0):
|
supported_versions = (OTA_VERSION_1_0, OTA_VERSION_2_0)
|
||||||
raise OTAError(f"Unsupported OTA version {version}")
|
if version not in supported_versions:
|
||||||
|
raise OTAError(
|
||||||
|
f"Device uses unsupported OTA version {version}, this ESPHome supports {supported_versions}"
|
||||||
|
)
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
send_check(sock, FEATURE_SUPPORTS_COMPRESSION, "features")
|
send_check(sock, FEATURE_SUPPORTS_COMPRESSION, "features")
|
||||||
|
|
|
@ -8,7 +8,6 @@ originally do.
|
||||||
However there is a property to further disable decorator
|
However there is a property to further disable decorator
|
||||||
impact."""
|
impact."""
|
||||||
|
|
||||||
|
|
||||||
# This is set to true by script/build_language_schema.py
|
# This is set to true by script/build_language_schema.py
|
||||||
# only, so data is collected (again functionality is not modified)
|
# only, so data is collected (again functionality is not modified)
|
||||||
EnableSchemaExtraction = False
|
EnableSchemaExtraction = False
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""This helper module tracks commonly used types in the esphome python codebase."""
|
"""This helper module tracks commonly used types in the esphome python codebase."""
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from esphome.core import ID, Lambda, EsphomeCore
|
from esphome.core import ID, Lambda, EsphomeCore
|
||||||
|
|
|
@ -64,7 +64,7 @@ class _Schema(vol.Schema):
|
||||||
|
|
||||||
# Recursively compile schema
|
# Recursively compile schema
|
||||||
_compiled_schema = {}
|
_compiled_schema = {}
|
||||||
for skey, svalue in vol.iteritems(schema):
|
for skey, svalue in schema.items():
|
||||||
new_key = self._compile(skey)
|
new_key = self._compile(skey)
|
||||||
new_value = self._compile(svalue)
|
new_value = self._compile(svalue)
|
||||||
_compiled_schema[skey] = (new_key, new_value)
|
_compiled_schema[skey] = (new_key, new_value)
|
||||||
|
|
|
@ -110,7 +110,7 @@ class DashboardImportDiscovery:
|
||||||
self, zeroconf: Zeroconf, info: AsyncServiceInfo, service_type: str, name: str
|
self, zeroconf: Zeroconf, info: AsyncServiceInfo, service_type: str, name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Process a service info."""
|
"""Process a service info."""
|
||||||
if await info.async_request(zeroconf):
|
if await info.async_request(zeroconf, timeout=3000):
|
||||||
self._process_service_info(name, info)
|
self._process_service_info(name, info)
|
||||||
|
|
||||||
def _process_service_info(self, name: str, info: ServiceInfo) -> None:
|
def _process_service_info(self, name: str, info: ServiceInfo) -> None:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
async_timeout==4.0.3; python_version <= "3.10"
|
async_timeout==4.0.3; python_version <= "3.10"
|
||||||
cryptography==42.0.2
|
cryptography==42.0.2
|
||||||
voluptuous==0.14.1
|
voluptuous==0.14.2
|
||||||
PyYAML==6.0.1
|
PyYAML==6.0.1
|
||||||
paho-mqtt==1.6.1
|
paho-mqtt==1.6.1
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
|
@ -13,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile
|
||||||
esptool==4.7.0
|
esptool==4.7.0
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
esphome-dashboard==20231107.0
|
esphome-dashboard==20231107.0
|
||||||
aioesphomeapi==21.0.2
|
aioesphomeapi==22.0.0
|
||||||
zeroconf==0.131.0
|
zeroconf==0.131.0
|
||||||
python-magic==0.4.27
|
python-magic==0.4.27
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
pylint==3.0.3
|
pylint==3.0.3
|
||||||
flake8==7.0.0 # also change in .pre-commit-config.yaml when updating
|
flake8==7.0.0 # also change in .pre-commit-config.yaml when updating
|
||||||
black==23.12.1 # also change in .pre-commit-config.yaml when updating
|
black==24.2.0 # also change in .pre-commit-config.yaml when updating
|
||||||
pyupgrade==3.15.0 # also change in .pre-commit-config.yaml when updating
|
pyupgrade==3.15.1 # also change in .pre-commit-config.yaml when updating
|
||||||
pre-commit
|
pre-commit
|
||||||
|
|
||||||
# Unit tests
|
# Unit tests
|
||||||
pytest==7.4.4
|
pytest==8.0.1
|
||||||
pytest-cov==4.1.0
|
pytest-cov==4.1.0
|
||||||
pytest-mock==3.12.0
|
pytest-mock==3.12.0
|
||||||
pytest-asyncio==0.23.5
|
pytest-asyncio==0.23.5
|
||||||
|
|
|
@ -849,9 +849,11 @@ def convert(schema, config_var, path):
|
||||||
|
|
||||||
config_var["id_type"] = {
|
config_var["id_type"] = {
|
||||||
"class": str(data.base),
|
"class": str(data.base),
|
||||||
"parents": [str(x.base) for x in parents]
|
"parents": (
|
||||||
if isinstance(parents, list)
|
[str(x.base) for x in parents]
|
||||||
else None,
|
if isinstance(parents, list)
|
||||||
|
else None
|
||||||
|
),
|
||||||
}
|
}
|
||||||
elif schema_type == "use_id":
|
elif schema_type == "use_id":
|
||||||
if inspect.ismodule(data):
|
if inspect.ismodule(data):
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
set -e
|
set -e
|
||||||
# set -x
|
# set -x
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt-get install avahi-utils -y
|
||||||
|
|
||||||
mkdir -p config
|
mkdir -p config
|
||||||
script/setup
|
script/setup
|
||||||
|
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
||||||
- id: rgb565_animation
|
- id: rgb565_animation
|
||||||
file: ../../pnglogo.png
|
file: ../../pnglogo.png
|
||||||
type: RGB565
|
type: RGB565
|
||||||
use_transparency: no
|
use_transparency: false
|
||||||
|
|
43
tests/components/dac7678/test.esp32-c3-idf.yaml
Normal file
43
tests/components/dac7678/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 5
|
||||||
|
sda: 4
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
43
tests/components/dac7678/test.esp32-c3.yaml
Normal file
43
tests/components/dac7678/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 5
|
||||||
|
sda: 4
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
43
tests/components/dac7678/test.esp32-idf.yaml
Normal file
43
tests/components/dac7678/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 16
|
||||||
|
sda: 17
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
43
tests/components/dac7678/test.esp32.yaml
Normal file
43
tests/components/dac7678/test.esp32.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 16
|
||||||
|
sda: 17
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
43
tests/components/dac7678/test.esp8266.yaml
Normal file
43
tests/components/dac7678/test.esp8266.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 5
|
||||||
|
sda: 4
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
43
tests/components/dac7678/test.rp2040.yaml
Normal file
43
tests/components/dac7678/test.rp2040.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
i2c:
|
||||||
|
- id: i2c_dac7678
|
||||||
|
scl: 5
|
||||||
|
sda: 4
|
||||||
|
|
||||||
|
dac7678:
|
||||||
|
address: 0x4A
|
||||||
|
id: dac7678_hub
|
||||||
|
internal_reference: true
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 0
|
||||||
|
id: dac7678_1_ch0
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 1
|
||||||
|
id: dac7678_1_ch1
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 2
|
||||||
|
id: dac7678_1_ch2
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 3
|
||||||
|
id: dac7678_1_ch3
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 4
|
||||||
|
id: dac7678_1_ch4
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 5
|
||||||
|
id: dac7678_1_ch5
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 6
|
||||||
|
id: dac7678_1_ch6
|
||||||
|
- platform: dac7678
|
||||||
|
dac7678_id: dac7678_hub
|
||||||
|
channel: 7
|
||||||
|
id: dac7678_1_ch7
|
12
tests/components/daikin/test.esp32.yaml
Normal file
12
tests/components/daikin/test.esp32.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: heatpumpir
|
||||||
|
protocol: daikin
|
||||||
|
horizontal_default: middle
|
||||||
|
vertical_default: middle
|
||||||
|
name: HeatpumpIR Climate
|
||||||
|
min_temperature: 18
|
||||||
|
max_temperature: 30
|
12
tests/components/daikin/test.esp8266.yaml
Normal file
12
tests/components/daikin/test.esp8266.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 5
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: heatpumpir
|
||||||
|
protocol: daikin
|
||||||
|
horizontal_default: middle
|
||||||
|
vertical_default: middle
|
||||||
|
name: HeatpumpIR Climate
|
||||||
|
min_temperature: 18
|
||||||
|
max_temperature: 30
|
7
tests/components/daikin_brc/test.esp32-c3-idf.yaml
Normal file
7
tests/components/daikin_brc/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: daikin_brc
|
||||||
|
name: Daikin_brc Climate
|
7
tests/components/daikin_brc/test.esp32-c3.yaml
Normal file
7
tests/components/daikin_brc/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: daikin_brc
|
||||||
|
name: Daikin_brc Climate
|
7
tests/components/daikin_brc/test.esp32-idf.yaml
Normal file
7
tests/components/daikin_brc/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: daikin_brc
|
||||||
|
name: Daikin_brc Climate
|
7
tests/components/daikin_brc/test.esp32.yaml
Normal file
7
tests/components/daikin_brc/test.esp32.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: daikin_brc
|
||||||
|
name: Daikin_brc Climate
|
7
tests/components/daikin_brc/test.esp8266.yaml
Normal file
7
tests/components/daikin_brc/test.esp8266.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 5
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: daikin_brc
|
||||||
|
name: Daikin_brc Climate
|
11
tests/components/dallas/test.esp32-c3-idf.yaml
Normal file
11
tests/components/dallas/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
11
tests/components/dallas/test.esp32-c3.yaml
Normal file
11
tests/components/dallas/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
11
tests/components/dallas/test.esp32-idf.yaml
Normal file
11
tests/components/dallas/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
11
tests/components/dallas/test.esp32.yaml
Normal file
11
tests/components/dallas/test.esp32.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
11
tests/components/dallas/test.esp8266.yaml
Normal file
11
tests/components/dallas/test.esp8266.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
11
tests/components/dallas/test.rp2040.yaml
Normal file
11
tests/components/dallas/test.rp2040.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
dallas:
|
||||||
|
pin: 4
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: dallas
|
||||||
|
address: 0x1C0000031EDD2A28
|
||||||
|
name: Dallas Temperature
|
||||||
|
resolution: 9
|
||||||
|
- platform: dallas
|
||||||
|
index: 1
|
||||||
|
name: Dallas Temperature
|
55
tests/components/daly_bms/test.esp32-c3-idf.yaml
Normal file
55
tests/components/daly_bms/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 4
|
||||||
|
rx_pin:
|
||||||
|
number: 5
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
55
tests/components/daly_bms/test.esp32-c3.yaml
Normal file
55
tests/components/daly_bms/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 4
|
||||||
|
rx_pin:
|
||||||
|
number: 5
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
55
tests/components/daly_bms/test.esp32-idf.yaml
Normal file
55
tests/components/daly_bms/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 17
|
||||||
|
rx_pin:
|
||||||
|
number: 16
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
55
tests/components/daly_bms/test.esp32.yaml
Normal file
55
tests/components/daly_bms/test.esp32.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 17
|
||||||
|
rx_pin:
|
||||||
|
number: 16
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
55
tests/components/daly_bms/test.esp8266.yaml
Normal file
55
tests/components/daly_bms/test.esp8266.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 4
|
||||||
|
rx_pin:
|
||||||
|
number: 5
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
55
tests/components/daly_bms/test.rp2040.yaml
Normal file
55
tests/components/daly_bms/test.rp2040.yaml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_daly_bms
|
||||||
|
tx_pin:
|
||||||
|
number: 4
|
||||||
|
rx_pin:
|
||||||
|
number: 5
|
||||||
|
baud_rate: 4800
|
||||||
|
|
||||||
|
daly_bms:
|
||||||
|
update_interval: 20s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
charging_mos_enabled:
|
||||||
|
name: Charging MOS
|
||||||
|
discharging_mos_enabled:
|
||||||
|
name: Discharging MOS
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
voltage:
|
||||||
|
name: Battery Voltage
|
||||||
|
current:
|
||||||
|
name: Battery Current
|
||||||
|
battery_level:
|
||||||
|
name: Battery Level
|
||||||
|
max_cell_voltage:
|
||||||
|
name: Max Cell Voltage
|
||||||
|
max_cell_voltage_number:
|
||||||
|
name: Max Cell Voltage Number
|
||||||
|
min_cell_voltage:
|
||||||
|
name: Min Cell Voltage
|
||||||
|
min_cell_voltage_number:
|
||||||
|
name: Min Cell Voltage Number
|
||||||
|
max_temperature:
|
||||||
|
name: Max Temperature
|
||||||
|
max_temperature_probe_number:
|
||||||
|
name: Max Temperature Probe Number
|
||||||
|
min_temperature:
|
||||||
|
name: Min Temperature
|
||||||
|
min_temperature_probe_number:
|
||||||
|
name: Min Temperature Probe Number
|
||||||
|
remaining_capacity:
|
||||||
|
name: Remaining Capacity
|
||||||
|
cells_number:
|
||||||
|
name: Cells Number
|
||||||
|
temperature_1:
|
||||||
|
name: Temperature 1
|
||||||
|
temperature_2:
|
||||||
|
name: Temperature 2
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: daly_bms
|
||||||
|
status:
|
||||||
|
name: BMS Status
|
1
tests/components/debug/test.esp32-c3-idf.yaml
Normal file
1
tests/components/debug/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
1
tests/components/debug/test.esp32-c3.yaml
Normal file
1
tests/components/debug/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
1
tests/components/debug/test.esp32-idf.yaml
Normal file
1
tests/components/debug/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
1
tests/components/debug/test.esp32.yaml
Normal file
1
tests/components/debug/test.esp32.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
1
tests/components/debug/test.esp8266.yaml
Normal file
1
tests/components/debug/test.esp8266.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
1
tests/components/debug/test.rp2040.yaml
Normal file
1
tests/components/debug/test.rp2040.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debug:
|
14
tests/components/deep_sleep/test.esp32-c3-idf.yaml
Normal file
14
tests/components/deep_sleep/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
then:
|
||||||
|
- deep_sleep.prevent
|
||||||
|
- delay: 1s
|
||||||
|
- deep_sleep.allow
|
||||||
|
|
||||||
|
deep_sleep:
|
||||||
|
run_duration:
|
||||||
|
default: 10s
|
||||||
|
gpio_wakeup_reason: 30s
|
||||||
|
sleep_duration: 50s
|
||||||
|
wakeup_pin: 4
|
||||||
|
wakeup_pin_mode: INVERT_WAKEUP
|
14
tests/components/deep_sleep/test.esp32-c3.yaml
Normal file
14
tests/components/deep_sleep/test.esp32-c3.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
then:
|
||||||
|
- deep_sleep.prevent
|
||||||
|
- delay: 1s
|
||||||
|
- deep_sleep.allow
|
||||||
|
|
||||||
|
deep_sleep:
|
||||||
|
run_duration:
|
||||||
|
default: 10s
|
||||||
|
gpio_wakeup_reason: 30s
|
||||||
|
sleep_duration: 50s
|
||||||
|
wakeup_pin: 4
|
||||||
|
wakeup_pin_mode: INVERT_WAKEUP
|
14
tests/components/deep_sleep/test.esp32-idf.yaml
Normal file
14
tests/components/deep_sleep/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
then:
|
||||||
|
- deep_sleep.prevent
|
||||||
|
- delay: 1s
|
||||||
|
- deep_sleep.allow
|
||||||
|
|
||||||
|
deep_sleep:
|
||||||
|
run_duration:
|
||||||
|
default: 10s
|
||||||
|
gpio_wakeup_reason: 30s
|
||||||
|
sleep_duration: 50s
|
||||||
|
wakeup_pin: 4
|
||||||
|
wakeup_pin_mode: INVERT_WAKEUP
|
14
tests/components/deep_sleep/test.esp32.yaml
Normal file
14
tests/components/deep_sleep/test.esp32.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
then:
|
||||||
|
- deep_sleep.prevent
|
||||||
|
- delay: 1s
|
||||||
|
- deep_sleep.allow
|
||||||
|
|
||||||
|
deep_sleep:
|
||||||
|
run_duration:
|
||||||
|
default: 10s
|
||||||
|
gpio_wakeup_reason: 30s
|
||||||
|
sleep_duration: 50s
|
||||||
|
wakeup_pin: 4
|
||||||
|
wakeup_pin_mode: INVERT_WAKEUP
|
10
tests/components/deep_sleep/test.esp8266.yaml
Normal file
10
tests/components/deep_sleep/test.esp8266.yaml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
then:
|
||||||
|
- deep_sleep.prevent
|
||||||
|
- delay: 1s
|
||||||
|
- deep_sleep.allow
|
||||||
|
|
||||||
|
deep_sleep:
|
||||||
|
run_duration: 10s
|
||||||
|
sleep_duration: 50s
|
7
tests/components/delonghi/test.esp32-c3-idf.yaml
Normal file
7
tests/components/delonghi/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
remote_transmitter:
|
||||||
|
pin: 2
|
||||||
|
carrier_duty_percent: 50%
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: delonghi
|
||||||
|
name: Delonghi Climate
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue