mirror of
https://github.com/esphome/esphome.git
synced 2024-12-24 14:34: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_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,
|
||||
// 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": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
|
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -11,6 +11,7 @@ on:
|
|||
- "**"
|
||||
- "!.github/workflows/*.yml"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "!.yamllint"
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
|
@ -218,7 +219,7 @@ jobs:
|
|||
. venv/bin/activate
|
||||
pytest -vv --cov-report=xml --tb=native tests
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
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
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
pull_request:
|
||||
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
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
|
@ -36,7 +37,7 @@ jobs:
|
|||
python ./script/sync-device_class.py
|
||||
|
||||
- name: Commit changes
|
||||
uses: peter-evans/create-pull-request@v5.0.2
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
commit-message: "Synchronise Device Classes from Home Assistant"
|
||||
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
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
push:
|
||||
branches: [dev, beta, release]
|
||||
|
@ -19,4 +21,6 @@ jobs:
|
|||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- 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
|
||||
repos:
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.12.1
|
||||
rev: 24.2.0
|
||||
hooks:
|
||||
- id: black
|
||||
args:
|
||||
|
@ -27,7 +27,7 @@ repos:
|
|||
- --branch=release
|
||||
- --branch=beta
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.15.0
|
||||
rev: v3.15.1
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py39-plus]
|
||||
|
|
19
.yamllint
19
.yamllint
|
@ -1,3 +1,18 @@
|
|||
---
|
||||
ignore: |
|
||||
venv/
|
||||
extends: default
|
||||
|
||||
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_ise/* @pvizeli
|
||||
esphome/components/ultrasonic/* @OttoWinter
|
||||
esphome/components/uponor_smatrix/* @kroimon
|
||||
esphome/components/vbus/* @ssieb
|
||||
esphome/components/veml3235/* @kbx81
|
||||
esphome/components/version/* @esphome/core
|
||||
|
|
|
@ -4,6 +4,7 @@ from esphome.components import sensor, uart
|
|||
from esphome.const import (
|
||||
CONF_CURRENT,
|
||||
CONF_ENERGY,
|
||||
CONF_EXTERNAL_TEMPERATURE,
|
||||
CONF_ID,
|
||||
CONF_POWER,
|
||||
CONF_VOLTAGE,
|
||||
|
@ -24,7 +25,6 @@ from esphome.const import (
|
|||
DEPENDENCIES = ["uart"]
|
||||
|
||||
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
|
||||
bl0940_ns = cg.esphome_ns.namespace("bl0940")
|
||||
BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
|
||||
|
|
|
@ -7,6 +7,8 @@ CODEOWNERS = ["@ellull"]
|
|||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
MULTI_CONF = True
|
||||
|
||||
CONF_PWM = "pwm"
|
||||
CONF_DIVIDER = "divider"
|
||||
CONF_DAC = "dac"
|
||||
|
|
|
@ -2,6 +2,7 @@ import esphome.codegen as cg
|
|||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_EXTERNAL_TEMPERATURE,
|
||||
CONF_ID,
|
||||
CONF_SPEED,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
|
@ -16,7 +17,6 @@ from .. import EMC2101_COMPONENT_SCHEMA, CONF_EMC2101_ID, emc2101_ns
|
|||
DEPENDENCIES = ["emc2101"]
|
||||
|
||||
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
|
||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
CONF_DUTY_CYCLE = "duty_cycle"
|
||||
|
||||
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_() {
|
||||
while (this->available())
|
||||
this->read();
|
||||
this->write((uint8_t) (START_CODE >> 8));
|
||||
this->write((uint8_t) (START_CODE & 0xFF));
|
||||
this->write(this->address_[0]);
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
"""Support for Honeywell HumidIcon HIH"""
|
||||
|
||||
CODEOWNERS = ["@Benichou34"]
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
"""Support for Honeywell ABP2"""
|
||||
|
||||
CODEOWNERS = ["@jpfaff"]
|
||||
|
|
|
@ -24,7 +24,7 @@ void ArduinoI2CBus::setup() {
|
|||
}
|
||||
next_bus_num++;
|
||||
#elif defined(USE_ESP8266)
|
||||
wire_ = &Wire; // NOLINT(cppcoreguidelines-prefer-member-initializer)
|
||||
wire_ = new TwoWire(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
#elif defined(USE_RP2040)
|
||||
static bool first = true;
|
||||
if (first) {
|
||||
|
@ -35,6 +35,16 @@ void ArduinoI2CBus::setup() {
|
|||
}
|
||||
#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
|
||||
wire_->setSDA(this->sda_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_));
|
||||
#endif
|
||||
wire_->setClock(frequency_);
|
||||
initialized_ = true;
|
||||
if (this->scan_) {
|
||||
ESP_LOGV(TAG, "Scanning i2c bus for active devices...");
|
||||
this->i2c_scan_();
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoI2CBus::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "I2C Bus:");
|
||||
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) {
|
||||
#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
|
||||
// should log them
|
||||
if (!initialized_) {
|
||||
|
@ -120,6 +130,10 @@ ErrorCode ArduinoI2CBus::readv(uint8_t address, ReadBuffer *buffers, size_t cnt)
|
|||
return ERROR_OK;
|
||||
}
|
||||
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
|
||||
// should log them
|
||||
if (!initialized_) {
|
||||
|
@ -164,7 +178,7 @@ ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cn
|
|||
return ERROR_UNKNOWN;
|
||||
case 2:
|
||||
case 3:
|
||||
ESP_LOGVV(TAG, "TX failed: not acknowledged");
|
||||
ESP_LOGVV(TAG, "TX failed: not acknowledged: %d", status);
|
||||
return ERROR_NOT_ACKNOWLEDGED;
|
||||
case 5:
|
||||
ESP_LOGVV(TAG, "TX failed: timeout");
|
||||
|
|
|
@ -30,6 +30,7 @@ class ArduinoI2CBus : public I2CBus, public Component {
|
|||
|
||||
private:
|
||||
void recover_();
|
||||
void set_pins_and_clock_();
|
||||
RecoveryCode recovery_result_;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -3,6 +3,7 @@ import esphome.config_validation as cv
|
|||
from esphome.components import sensor, esp32_ble_tracker
|
||||
from esphome.const import (
|
||||
CONF_BATTERY_LEVEL,
|
||||
CONF_EXTERNAL_TEMPERATURE,
|
||||
CONF_HUMIDITY,
|
||||
CONF_MAC_ADDRESS,
|
||||
CONF_TEMPERATURE,
|
||||
|
@ -19,8 +20,6 @@ from esphome.const import (
|
|||
CODEOWNERS = ["@fkirill"]
|
||||
DEPENDENCIES = ["esp32_ble_tracker"]
|
||||
|
||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
|
||||
inkbird_ibsth1_mini_ns = cg.esphome_ns.namespace("inkbird_ibsth1_mini")
|
||||
InkbirdIbstH1Mini = inkbird_ibsth1_mini_ns.class_(
|
||||
"InkbirdIbstH1Mini", esp32_ble_tracker.ESPBTDeviceListener, cg.Component
|
||||
|
|
|
@ -8,10 +8,23 @@ namespace 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 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 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 value = 0;
|
||||
|
||||
|
@ -58,7 +71,7 @@ void LTR390Component::read_als_() {
|
|||
uint32_t als = *val;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -74,7 +87,7 @@ void LTR390Component::read_uvs_() {
|
|||
uint32_t uv = *val;
|
||||
|
||||
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) {
|
||||
|
@ -132,12 +145,13 @@ void LTR390Component::setup() {
|
|||
// Set gain
|
||||
this->reg(LTR390_GAIN) = gain_;
|
||||
|
||||
// Set resolution
|
||||
uint8_t res = this->reg(LTR390_MEAS_RATE).get();
|
||||
// resolution is in bits 5-7
|
||||
res &= ~0b01110000;
|
||||
res |= res << 4;
|
||||
this->reg(LTR390_MEAS_RATE) = res;
|
||||
// Set resolution and measurement rate
|
||||
this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_];
|
||||
|
||||
// Set sensitivity by linearly scaling against known value in the datasheet
|
||||
float gain_scale = GAINVALUES[this->gain_] / GAIN_MAX;
|
||||
float intg_scale = (RESOLUTIONVALUE[this->res_] * 100) / INTG_MAX;
|
||||
this->sensitivity_ = SENSITIVITY_MAX * gain_scale * intg_scale;
|
||||
|
||||
// Set sensor read state
|
||||
this->reading_ = false;
|
||||
|
|
|
@ -17,14 +17,6 @@ enum LTR390CTRL {
|
|||
};
|
||||
|
||||
// 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
|
||||
enum LTR390MODE {
|
||||
LTR390_MODE_ALS,
|
||||
|
@ -81,6 +73,7 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice {
|
|||
|
||||
LTR390GAIN gain_;
|
||||
LTR390RESOLUTION res_;
|
||||
float sensitivity_;
|
||||
float wfac_;
|
||||
|
||||
sensor::Sensor *light_sensor_{nullptr};
|
||||
|
|
|
@ -8,6 +8,7 @@ from esphome.const import (
|
|||
CONF_RESOLUTION,
|
||||
UNIT_LUX,
|
||||
ICON_BRIGHTNESS_5,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
)
|
||||
|
||||
|
@ -61,22 +62,22 @@ CONFIG_SCHEMA = cv.All(
|
|||
unit_of_measurement=UNIT_COUNTS,
|
||||
icon=ICON_BRIGHTNESS_5,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
device_class=DEVICE_CLASS_EMPTY,
|
||||
),
|
||||
cv.Optional(CONF_UV_INDEX): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_UVI,
|
||||
icon=ICON_BRIGHTNESS_5,
|
||||
accuracy_decimals=5,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
device_class=DEVICE_CLASS_EMPTY,
|
||||
),
|
||||
cv.Optional(CONF_UV): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_COUNTS,
|
||||
icon=ICON_BRIGHTNESS_5,
|
||||
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_RESOLUTION, default=18): cv.enum(RES_OPTIONS),
|
||||
cv.Optional(CONF_GAIN, default="X18"): cv.enum(GAIN_OPTIONS),
|
||||
cv.Optional(CONF_RESOLUTION, default=20): cv.enum(RES_OPTIONS),
|
||||
cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range(
|
||||
min=1.0
|
||||
),
|
||||
|
|
|
@ -74,7 +74,8 @@ CONF_FORCE_SW = "force_sw"
|
|||
CONF_INTERFACE = "interface"
|
||||
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 = [
|
||||
{
|
||||
|
@ -85,7 +86,7 @@ RP_SPI_PINSETS = [
|
|||
{
|
||||
CONF_MISO_PIN: [8, 12, 24, 28, -1],
|
||||
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"]
|
||||
|
||||
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
||||
TM1651Brightness = tm1651_ns.enum("TM1651Brightness")
|
||||
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
||||
|
||||
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
||||
|
@ -24,9 +25,9 @@ TurnOffAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
|||
CONF_LEVEL_PERCENT = "level_percent"
|
||||
|
||||
TM1651_BRIGHTNESS_OPTIONS = {
|
||||
1: TM1651Display.TM1651_BRIGHTNESS_LOW,
|
||||
2: TM1651Display.TM1651_BRIGHTNESS_MEDIUM,
|
||||
3: TM1651Display.TM1651_BRIGHTNESS_HIGH,
|
||||
1: TM1651Brightness.TM1651_BRIGHTNESS_LOW,
|
||||
2: TM1651Brightness.TM1651_BRIGHTNESS_MEDIUM,
|
||||
3: TM1651Brightness.TM1651_BRIGHTNESS_HIGH,
|
||||
}
|
||||
|
||||
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 TM1651_MAX_LEVEL = 7;
|
||||
|
||||
static const uint8_t TM1651_BRIGHTNESS_LOW = 0;
|
||||
static const uint8_t TM1651_BRIGHTNESS_MEDIUM = 2;
|
||||
static const uint8_t TM1651_BRIGHTNESS_HIGH = 7;
|
||||
static const uint8_t TM1651_BRIGHTNESS_LOW_HW = 0;
|
||||
static const uint8_t TM1651_BRIGHTNESS_MEDIUM_HW = 2;
|
||||
static const uint8_t TM1651_BRIGHTNESS_HIGH_HW = 7;
|
||||
|
||||
void TM1651Display::setup() {
|
||||
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) {
|
||||
if (new_brightness <= 1) {
|
||||
return TM1651_BRIGHTNESS_LOW;
|
||||
return TM1651_BRIGHTNESS_LOW_HW;
|
||||
} else if (new_brightness == 2) {
|
||||
return TM1651_BRIGHTNESS_MEDIUM;
|
||||
return TM1651_BRIGHTNESS_MEDIUM_HW;
|
||||
} 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
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
namespace esphome {
|
||||
namespace tm1651 {
|
||||
|
||||
enum TM1651Brightness : uint8_t {
|
||||
TM1651_BRIGHTNESS_LOW = 1,
|
||||
TM1651_BRIGHTNESS_MEDIUM = 2,
|
||||
TM1651_BRIGHTNESS_HIGH = 3,
|
||||
};
|
||||
|
||||
class TM1651Display : public Component {
|
||||
public:
|
||||
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(uint8_t new_level);
|
||||
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_off();
|
||||
|
|
|
@ -7,6 +7,7 @@ reading temperatures to a resolution of 0.0625°C.
|
|||
https://www.sparkfun.com/datasheets/Sensors/Temperature/tmp102.pdf
|
||||
|
||||
"""
|
||||
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
|
|
|
@ -34,9 +34,13 @@ void TuyaFan::setup() {
|
|||
}
|
||||
if (this->oscillation_id_.has_value()) {
|
||||
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));
|
||||
this->oscillating = datapoint.value_bool;
|
||||
this->publish_state();
|
||||
|
||||
this->oscillation_type_ = datapoint.type;
|
||||
});
|
||||
}
|
||||
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());
|
||||
}
|
||||
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()) {
|
||||
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
|
||||
|
|
|
@ -29,6 +29,7 @@ class TuyaFan : public Component, public fan::Fan {
|
|||
optional<uint8_t> direction_id_{};
|
||||
int speed_count_{};
|
||||
TuyaDatapointType speed_type_{};
|
||||
TuyaDatapointType oscillation_type_{};
|
||||
};
|
||||
|
||||
} // 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_END = "on_tts_stream_end"
|
||||
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
||||
CONF_ON_IDLE = "on_idle"
|
||||
|
||||
CONF_SILENCE_DETECTION = "silence_detection"
|
||||
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(
|
||||
single=True
|
||||
),
|
||||
cv.Optional(CONF_ON_IDLE): automation.validate_automation(single=True),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
tts_stream_validate,
|
||||
|
@ -259,6 +261,13 @@ async def to_code(config):
|
|||
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")
|
||||
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ void VoiceAssistant::loop() {
|
|||
switch (this->state_) {
|
||||
case State::IDLE: {
|
||||
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
||||
this->idle_trigger_->trigger();
|
||||
|
||||
this->ring_buffer_->reset();
|
||||
#ifdef USE_ESP_ADF
|
||||
if (this->use_wake_word_) {
|
||||
|
@ -618,6 +620,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|||
{
|
||||
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(); });
|
||||
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_start_trigger() const { return this->tts_start_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_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_start_trigger_ = new Trigger<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_disconnected_trigger_ = new Trigger<>();
|
||||
|
|
|
@ -785,6 +785,8 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
|
|||
obj->position, start_config);
|
||||
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())
|
||||
root["tilt"] = obj->tilt;
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
The cryptography package is loaded lazily in the functions
|
||||
so that it doesn't crash if it's not installed.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
|
|
|
@ -292,8 +292,7 @@ class ConfigValidationStep(abc.ABC):
|
|||
priority: float = 0.0
|
||||
|
||||
@abc.abstractmethod
|
||||
def run(self, result: Config) -> None:
|
||||
...
|
||||
def run(self, result: Config) -> None: ... # noqa: E704
|
||||
|
||||
|
||||
class LoadValidationStep(ConfigValidationStep):
|
||||
|
|
|
@ -251,6 +251,7 @@ CONF_EXPORT_ACTIVE_ENERGY = "export_active_energy"
|
|||
CONF_EXPORT_REACTIVE_ENERGY = "export_reactive_energy"
|
||||
CONF_EXTERNAL_CLOCK_INPUT = "external_clock_input"
|
||||
CONF_EXTERNAL_COMPONENTS = "external_components"
|
||||
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
CONF_EXTERNAL_VCC = "external_vcc"
|
||||
CONF_FALLING_EDGE = "falling_edge"
|
||||
CONF_FAMILY = "family"
|
||||
|
|
|
@ -8,3 +8,5 @@ MAX_EXECUTOR_WORKERS = 48
|
|||
|
||||
|
||||
SENTINEL = object()
|
||||
|
||||
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any, Callable
|
||||
from collections.abc import Coroutine
|
||||
|
||||
from ..zeroconf import DiscoveredImport
|
||||
from .dns import DNSCache
|
||||
|
@ -71,6 +73,7 @@ class ESPHomeDashboard:
|
|||
"mdns_status",
|
||||
"settings",
|
||||
"dns_cache",
|
||||
"_background_tasks",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
@ -85,6 +88,7 @@ class ESPHomeDashboard:
|
|||
self.mdns_status: MDNSStatus | None = None
|
||||
self.settings = DashboardSettings()
|
||||
self.dns_cache = DNSCache()
|
||||
self._background_tasks: set[asyncio.Task] = set()
|
||||
|
||||
async def async_setup(self) -> None:
|
||||
"""Setup the dashboard."""
|
||||
|
@ -132,7 +136,19 @@ class ESPHomeDashboard:
|
|||
if settings.status_use_mqtt:
|
||||
status_thread_mqtt.join()
|
||||
self.mqtt_ping_request.set()
|
||||
for task in self._background_tasks:
|
||||
task.cancel()
|
||||
with contextlib.suppress(asyncio.CancelledError):
|
||||
await task
|
||||
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()
|
||||
|
|
|
@ -10,12 +10,14 @@ from esphome import const, util
|
|||
from esphome.storage_json import StorageJSON, ext_storage_path
|
||||
|
||||
from .const import (
|
||||
DASHBOARD_COMMAND,
|
||||
EVENT_ENTRY_ADDED,
|
||||
EVENT_ENTRY_REMOVED,
|
||||
EVENT_ENTRY_STATE_CHANGED,
|
||||
EVENT_ENTRY_UPDATED,
|
||||
)
|
||||
from .enum import StrEnum
|
||||
from .util.subprocess import async_run_system_command
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .core import ESPHomeDashboard
|
||||
|
@ -235,6 +237,14 @@ class DashboardEntries:
|
|||
)
|
||||
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:
|
||||
"""Represents a single dashboard entry.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Enum backports from standard lib."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
|
|
|
@ -9,11 +9,11 @@ import hashlib
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import secrets
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
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.yaml_util import FastestAvailableSafeLoader
|
||||
|
||||
from .const import DASHBOARD_COMMAND
|
||||
from .core import DASHBOARD
|
||||
from .entries import EntryState, entry_state_to_bool
|
||||
from .util.file import write_file
|
||||
|
@ -286,9 +287,6 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
||||
|
||||
|
||||
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
||||
"""Base class for commands that require a port."""
|
||||
|
||||
|
@ -808,8 +806,16 @@ class EditRequestHandler(BaseHandler):
|
|||
@bind_config
|
||||
async def get(self, configuration: str | None = None) -> None:
|
||||
"""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)
|
||||
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(
|
||||
None, self._read_file, filename, configuration
|
||||
)
|
||||
|
@ -835,15 +841,19 @@ class EditRequestHandler(BaseHandler):
|
|||
@bind_config
|
||||
async def post(self, configuration: str | None = None) -> None:
|
||||
"""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()
|
||||
config_file = settings.rel_path(configuration)
|
||||
await loop.run_in_executor(
|
||||
None, self._write_file, config_file, self.request.body
|
||||
)
|
||||
await loop.run_in_executor(None, self._write_file, filename, self.request.body)
|
||||
# Ensure the StorageJSON is updated as well
|
||||
await async_run_system_command(
|
||||
[*DASHBOARD_COMMAND, "compile", "--only-generate", config_file]
|
||||
)
|
||||
DASHBOARD.entries.async_schedule_storage_json_update(filename)
|
||||
self.set_status(200)
|
||||
|
||||
|
||||
|
|
|
@ -206,8 +206,11 @@ def perform_ota(
|
|||
|
||||
_, version = receive_exactly(sock, 2, "version", RESPONSE_OK)
|
||||
_LOGGER.debug("Device support OTA version: %s", version)
|
||||
if version not in (OTA_VERSION_1_0, OTA_VERSION_2_0):
|
||||
raise OTAError(f"Unsupported OTA version {version}")
|
||||
supported_versions = (OTA_VERSION_1_0, OTA_VERSION_2_0)
|
||||
if version not in supported_versions:
|
||||
raise OTAError(
|
||||
f"Device uses unsupported OTA version {version}, this ESPHome supports {supported_versions}"
|
||||
)
|
||||
|
||||
# Features
|
||||
send_check(sock, FEATURE_SUPPORTS_COMPRESSION, "features")
|
||||
|
|
|
@ -8,7 +8,6 @@ originally do.
|
|||
However there is a property to further disable decorator
|
||||
impact."""
|
||||
|
||||
|
||||
# This is set to true by script/build_language_schema.py
|
||||
# only, so data is collected (again functionality is not modified)
|
||||
EnableSchemaExtraction = False
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""This helper module tracks commonly used types in the esphome python codebase."""
|
||||
|
||||
from typing import Union
|
||||
|
||||
from esphome.core import ID, Lambda, EsphomeCore
|
||||
|
|
|
@ -64,7 +64,7 @@ class _Schema(vol.Schema):
|
|||
|
||||
# Recursively compile schema
|
||||
_compiled_schema = {}
|
||||
for skey, svalue in vol.iteritems(schema):
|
||||
for skey, svalue in schema.items():
|
||||
new_key = self._compile(skey)
|
||||
new_value = self._compile(svalue)
|
||||
_compiled_schema[skey] = (new_key, new_value)
|
||||
|
|
|
@ -110,7 +110,7 @@ class DashboardImportDiscovery:
|
|||
self, zeroconf: Zeroconf, info: AsyncServiceInfo, service_type: str, name: str
|
||||
) -> None:
|
||||
"""Process a service info."""
|
||||
if await info.async_request(zeroconf):
|
||||
if await info.async_request(zeroconf, timeout=3000):
|
||||
self._process_service_info(name, info)
|
||||
|
||||
def _process_service_info(self, name: str, info: ServiceInfo) -> None:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
async_timeout==4.0.3; python_version <= "3.10"
|
||||
cryptography==42.0.2
|
||||
voluptuous==0.14.1
|
||||
voluptuous==0.14.2
|
||||
PyYAML==6.0.1
|
||||
paho-mqtt==1.6.1
|
||||
colorama==0.4.6
|
||||
|
@ -13,7 +13,7 @@ platformio==6.1.13 # When updating platformio, also update Dockerfile
|
|||
esptool==4.7.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20231107.0
|
||||
aioesphomeapi==21.0.2
|
||||
aioesphomeapi==22.0.0
|
||||
zeroconf==0.131.0
|
||||
python-magic==0.4.27
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
pylint==3.0.3
|
||||
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
|
||||
pyupgrade==3.15.0 # 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.1 # also change in .pre-commit-config.yaml when updating
|
||||
pre-commit
|
||||
|
||||
# Unit tests
|
||||
pytest==7.4.4
|
||||
pytest==8.0.1
|
||||
pytest-cov==4.1.0
|
||||
pytest-mock==3.12.0
|
||||
pytest-asyncio==0.23.5
|
||||
|
|
|
@ -849,9 +849,11 @@ def convert(schema, config_var, path):
|
|||
|
||||
config_var["id_type"] = {
|
||||
"class": str(data.base),
|
||||
"parents": [str(x.base) for x in parents]
|
||||
if isinstance(parents, list)
|
||||
else None,
|
||||
"parents": (
|
||||
[str(x.base) for x in parents]
|
||||
if isinstance(parents, list)
|
||||
else None
|
||||
),
|
||||
}
|
||||
elif schema_type == "use_id":
|
||||
if inspect.ismodule(data):
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
set -e
|
||||
# set -x
|
||||
|
||||
apt update
|
||||
apt-get install avahi-utils -y
|
||||
|
||||
mkdir -p config
|
||||
script/setup
|
||||
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
use_transparency: false
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
use_transparency: false
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
use_transparency: false
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
use_transparency: false
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
type: RGB565
|
||||
use_transparency: no
|
||||
use_transparency: false
|
||||
|
|
|
@ -20,4 +20,4 @@ animation:
|
|||
- id: rgb565_animation
|
||||
file: ../../pnglogo.png
|
||||
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