mirror of
https://github.com/esphome/esphome.git
synced 2024-12-23 14:04:53 +01:00
commit
efa8f0730d
275 changed files with 6532 additions and 1734 deletions
1
.github/ISSUE_TEMPLATE/config.yml
vendored
1
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -9,4 +9,3 @@ contact_links:
|
||||||
- name: Frequently Asked Question
|
- name: Frequently Asked Question
|
||||||
url: https://esphome.io/guides/faq.html
|
url: https://esphome.io/guides/faq.html
|
||||||
about: Please view the FAQ for common questions and what to include in a bug report.
|
about: Please view the FAQ for common questions and what to include in a bug report.
|
||||||
|
|
||||||
|
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -80,7 +80,7 @@ jobs:
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: '3.7'
|
python-version: '3.8'
|
||||||
|
|
||||||
- name: Cache virtualenv
|
- name: Cache virtualenv
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -77,6 +77,7 @@ venv/
|
||||||
ENV/
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
|
venv-*/
|
||||||
|
|
||||||
# mypy
|
# mypy
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
|
|
|
@ -25,3 +25,8 @@ repos:
|
||||||
- --branch=dev
|
- --branch=dev
|
||||||
- --branch=release
|
- --branch=release
|
||||||
- --branch=beta
|
- --branch=beta
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v2.31.0
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: [--py38-plus]
|
||||||
|
|
11
CODEOWNERS
11
CODEOWNERS
|
@ -19,6 +19,7 @@ esphome/components/airthings_wave_mini/* @ncareau
|
||||||
esphome/components/airthings_wave_plus/* @jeromelaban
|
esphome/components/airthings_wave_plus/* @jeromelaban
|
||||||
esphome/components/am43/* @buxtronix
|
esphome/components/am43/* @buxtronix
|
||||||
esphome/components/am43/cover/* @buxtronix
|
esphome/components/am43/cover/* @buxtronix
|
||||||
|
esphome/components/analog_threshold/* @ianchi
|
||||||
esphome/components/animation/* @syndlex
|
esphome/components/animation/* @syndlex
|
||||||
esphome/components/anova/* @buxtronix
|
esphome/components/anova/* @buxtronix
|
||||||
esphome/components/api/* @OttoWinter
|
esphome/components/api/* @OttoWinter
|
||||||
|
@ -27,6 +28,7 @@ esphome/components/atc_mithermometer/* @ahpohl
|
||||||
esphome/components/b_parasite/* @rbaron
|
esphome/components/b_parasite/* @rbaron
|
||||||
esphome/components/ballu/* @bazuchan
|
esphome/components/ballu/* @bazuchan
|
||||||
esphome/components/bang_bang/* @OttoWinter
|
esphome/components/bang_bang/* @OttoWinter
|
||||||
|
esphome/components/bh1750/* @OttoWinter
|
||||||
esphome/components/binary_sensor/* @esphome/core
|
esphome/components/binary_sensor/* @esphome/core
|
||||||
esphome/components/bl0940/* @tobias-
|
esphome/components/bl0940/* @tobias-
|
||||||
esphome/components/ble_client/* @buxtronix
|
esphome/components/ble_client/* @buxtronix
|
||||||
|
@ -42,6 +44,7 @@ esphome/components/climate/* @esphome/core
|
||||||
esphome/components/climate_ir/* @glmnet
|
esphome/components/climate_ir/* @glmnet
|
||||||
esphome/components/color_temperature/* @jesserockz
|
esphome/components/color_temperature/* @jesserockz
|
||||||
esphome/components/coolix/* @glmnet
|
esphome/components/coolix/* @glmnet
|
||||||
|
esphome/components/copy/* @OttoWinter
|
||||||
esphome/components/cover/* @esphome/core
|
esphome/components/cover/* @esphome/core
|
||||||
esphome/components/cs5460a/* @balrog-kun
|
esphome/components/cs5460a/* @balrog-kun
|
||||||
esphome/components/cse7761/* @berfenger
|
esphome/components/cse7761/* @berfenger
|
||||||
|
@ -77,6 +80,7 @@ esphome/components/hbridge/light/* @DotNetDann
|
||||||
esphome/components/heatpumpir/* @rob-deutsch
|
esphome/components/heatpumpir/* @rob-deutsch
|
||||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||||
esphome/components/homeassistant/* @OttoWinter
|
esphome/components/homeassistant/* @OttoWinter
|
||||||
|
esphome/components/honeywellabp/* @RubyBailey
|
||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
||||||
esphome/components/i2c/* @esphome/core
|
esphome/components/i2c/* @esphome/core
|
||||||
esphome/components/improv_serial/* @esphome/core
|
esphome/components/improv_serial/* @esphome/core
|
||||||
|
@ -93,6 +97,7 @@ esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||||
esphome/components/lock/* @esphome/core
|
esphome/components/lock/* @esphome/core
|
||||||
esphome/components/logger/* @esphome/core
|
esphome/components/logger/* @esphome/core
|
||||||
esphome/components/ltr390/* @sjtrny
|
esphome/components/ltr390/* @sjtrny
|
||||||
|
esphome/components/max44009/* @berfenger
|
||||||
esphome/components/max7219digit/* @rspaargaren
|
esphome/components/max7219digit/* @rspaargaren
|
||||||
esphome/components/max9611/* @mckaymatthew
|
esphome/components/max9611/* @mckaymatthew
|
||||||
esphome/components/mcp23008/* @jesserockz
|
esphome/components/mcp23008/* @jesserockz
|
||||||
|
@ -104,6 +109,7 @@ esphome/components/mcp23x17_base/* @jesserockz
|
||||||
esphome/components/mcp23xxx_base/* @jesserockz
|
esphome/components/mcp23xxx_base/* @jesserockz
|
||||||
esphome/components/mcp2515/* @danielschramm @mvturnho
|
esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||||
esphome/components/mcp3204/* @rsumner
|
esphome/components/mcp3204/* @rsumner
|
||||||
|
esphome/components/mcp4728/* @berfenger
|
||||||
esphome/components/mcp47a1/* @jesserockz
|
esphome/components/mcp47a1/* @jesserockz
|
||||||
esphome/components/mcp9808/* @k7hpn
|
esphome/components/mcp9808/* @k7hpn
|
||||||
esphome/components/md5/* @esphome/core
|
esphome/components/md5/* @esphome/core
|
||||||
|
@ -120,6 +126,9 @@ esphome/components/modbus_controller/select/* @martgras @stegm
|
||||||
esphome/components/modbus_controller/sensor/* @martgras
|
esphome/components/modbus_controller/sensor/* @martgras
|
||||||
esphome/components/modbus_controller/switch/* @martgras
|
esphome/components/modbus_controller/switch/* @martgras
|
||||||
esphome/components/modbus_controller/text_sensor/* @martgras
|
esphome/components/modbus_controller/text_sensor/* @martgras
|
||||||
|
esphome/components/mopeka_ble/* @spbrogan
|
||||||
|
esphome/components/mopeka_pro_check/* @spbrogan
|
||||||
|
esphome/components/mpu6886/* @fabaff
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/nextion/* @senexcrenshaw
|
esphome/components/nextion/* @senexcrenshaw
|
||||||
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
||||||
|
@ -140,7 +149,7 @@ esphome/components/pn532_spi/* @OttoWinter @jesserockz
|
||||||
esphome/components/power_supply/* @esphome/core
|
esphome/components/power_supply/* @esphome/core
|
||||||
esphome/components/preferences/* @esphome/core
|
esphome/components/preferences/* @esphome/core
|
||||||
esphome/components/psram/* @esphome/core
|
esphome/components/psram/* @esphome/core
|
||||||
esphome/components/pulse_meter/* @stevebaxter
|
esphome/components/pulse_meter/* @cstaahl @stevebaxter
|
||||||
esphome/components/pvvx_mithermometer/* @pasiz
|
esphome/components/pvvx_mithermometer/* @pasiz
|
||||||
esphome/components/qr_code/* @wjtje
|
esphome/components/qr_code/* @wjtje
|
||||||
esphome/components/radon_eye_ble/* @jeffeb3
|
esphome/components/radon_eye_ble/* @jeffeb3
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
# One of "docker", "hassio"
|
# One of "docker", "hassio"
|
||||||
ARG BASEIMGTYPE=docker
|
ARG BASEIMGTYPE=docker
|
||||||
|
|
||||||
|
# https://github.com/hassio-addons/addon-debian-base/releases
|
||||||
FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64
|
FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64
|
||||||
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64
|
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64
|
||||||
FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7
|
FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7
|
||||||
|
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-amd64
|
FROM debian:bullseye-20220125-slim AS base-docker-amd64
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-arm64
|
FROM debian:bullseye-20220125-slim AS base-docker-arm64
|
||||||
FROM debian:bullseye-20220125-slim AS base-docker-armv7
|
FROM debian:bullseye-20220125-slim AS base-docker-armv7
|
||||||
|
@ -43,7 +45,7 @@ RUN \
|
||||||
# Ubuntu python3-pip is missing wheel
|
# Ubuntu python3-pip is missing wheel
|
||||||
pip3 install --no-cache-dir \
|
pip3 install --no-cache-dir \
|
||||||
wheel==0.37.1 \
|
wheel==0.37.1 \
|
||||||
platformio==5.2.4 \
|
platformio==5.2.5 \
|
||||||
# Change some platformio settings
|
# Change some platformio settings
|
||||||
&& platformio settings set enable_telemetry No \
|
&& platformio settings set enable_telemetry No \
|
||||||
&& platformio settings set check_libraries_interval 1000000 \
|
&& platformio settings set check_libraries_interval 1000000 \
|
||||||
|
@ -52,16 +54,16 @@ RUN \
|
||||||
&& mkdir -p /piolibs
|
&& mkdir -p /piolibs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ======================= docker-type image =======================
|
|
||||||
FROM base AS docker
|
|
||||||
|
|
||||||
# First install requirements to leverage caching when requirements don't change
|
# First install requirements to leverage caching when requirements don't change
|
||||||
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
||||||
RUN \
|
RUN \
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
&& /platformio_install_deps.py /platformio.ini
|
||||||
|
|
||||||
|
|
||||||
|
# ======================= docker-type image =======================
|
||||||
|
FROM base AS docker
|
||||||
|
|
||||||
# Copy esphome and install
|
# Copy esphome and install
|
||||||
COPY . /esphome
|
COPY . /esphome
|
||||||
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
||||||
|
@ -93,7 +95,7 @@ RUN \
|
||||||
apt-get update \
|
apt-get update \
|
||||||
# Use pinned versions so that we get updates with build caching
|
# Use pinned versions so that we get updates with build caching
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
nginx=1.18.0-6.1 \
|
nginx-light=1.18.0-6.1 \
|
||||||
&& rm -rf \
|
&& rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
|
@ -104,12 +106,6 @@ ARG BUILD_VERSION=dev
|
||||||
# Copy root filesystem
|
# Copy root filesystem
|
||||||
COPY docker/ha-addon-rootfs/ /
|
COPY docker/ha-addon-rootfs/ /
|
||||||
|
|
||||||
# First install requirements to leverage caching when requirements don't change
|
|
||||||
COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
|
|
||||||
RUN \
|
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
|
||||||
|
|
||||||
# Copy esphome and install
|
# Copy esphome and install
|
||||||
COPY . /esphome
|
COPY . /esphome
|
||||||
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
|
||||||
|
@ -147,10 +143,8 @@ RUN \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
/var/lib/apt/lists/*
|
/var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini /
|
COPY requirements_test.txt /
|
||||||
RUN \
|
RUN pip3 install --no-cache-dir -r /requirements_test.txt
|
||||||
pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \
|
|
||||||
&& /platformio_install_deps.py /platformio.ini
|
|
||||||
|
|
||||||
VOLUME ["/esphome"]
|
VOLUME ["/esphome"]
|
||||||
WORKDIR /esphome
|
WORKDIR /esphome
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
# Check SSL requirements, if enabled
|
# Check SSL requirements, if enabled
|
||||||
if bashio::config.true 'ssl'; then
|
if bashio::config.true 'ssl'; then
|
||||||
if ! bashio::config.has_value 'certfile'; then
|
if ! bashio::config.has_value 'certfile'; then
|
||||||
bashio::fatal 'SSL is enabled, but no certfile was specified.'
|
bashio::log.fatal 'SSL is enabled, but no certfile was specified.'
|
||||||
bashio::exit.nok
|
bashio::exit.nok
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! bashio::config.has_value 'keyfile'; then
|
if ! bashio::config.has_value 'keyfile'; then
|
||||||
bashio::fatal 'SSL is enabled, but no keyfile was specified'
|
bashio::log.fatal 'SSL is enabled, but no keyfile was specified'
|
||||||
bashio::exit.nok
|
bashio::exit.nok
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -778,10 +778,10 @@ def run_esphome(argv):
|
||||||
_LOGGER.warning("Please instead use:")
|
_LOGGER.warning("Please instead use:")
|
||||||
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
|
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
|
||||||
|
|
||||||
if sys.version_info < (3, 7, 0):
|
if sys.version_info < (3, 8, 0):
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"You're running ESPHome with Python <3.7. ESPHome is no longer compatible "
|
"You're running ESPHome with Python <3.8. ESPHome is no longer compatible "
|
||||||
"with this Python version. Please reinstall ESPHome with Python 3.7+"
|
"with this Python version. Please reinstall ESPHome with Python 3.8+"
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,7 @@ ADCSensor = adc_ns.class_(
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
ADCSensor,
|
||||||
unit_of_measurement=UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
accuracy_decimals=2,
|
accuracy_decimals=2,
|
||||||
device_class=DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
|
@ -140,7 +141,6 @@ CONFIG_SCHEMA = cv.All(
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ADCSensor),
|
|
||||||
cv.Required(CONF_PIN): validate_adc_pin,
|
cv.Required(CONF_PIN): validate_adc_pin,
|
||||||
cv.Optional(CONF_RAW, default=False): cv.boolean,
|
cv.Optional(CONF_RAW, default=False): cv.boolean,
|
||||||
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
|
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
|
||||||
|
|
|
@ -52,6 +52,7 @@ ADS1115Sensor = ads1115_ns.class_(
|
||||||
CONF_ADS1115_ID = "ads1115_id"
|
CONF_ADS1115_ID = "ads1115_id"
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
ADS1115Sensor,
|
||||||
unit_of_measurement=UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
accuracy_decimals=3,
|
accuracy_decimals=3,
|
||||||
device_class=DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
|
@ -59,7 +60,6 @@ CONFIG_SCHEMA = (
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ADS1115Sensor),
|
|
||||||
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
|
cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
|
||||||
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
|
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
|
||||||
cv.Required(CONF_GAIN): validate_gain,
|
cv.Required(CONF_GAIN): validate_gain,
|
||||||
|
|
1
esphome/components/analog_threshold/__init__.py
Normal file
1
esphome/components/analog_threshold/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CODEOWNERS = ["@ianchi"]
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "analog_threshold_binary_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace analog_threshold {
|
||||||
|
|
||||||
|
static const char *const TAG = "analog_threshold.binary_sensor";
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::setup() {
|
||||||
|
float sensor_value = this->sensor_->get_state();
|
||||||
|
|
||||||
|
// TRUE state is defined to be when sensor is >= threshold
|
||||||
|
// so when undefined sensor value initialize to FALSE
|
||||||
|
if (std::isnan(sensor_value)) {
|
||||||
|
this->publish_initial_state(false);
|
||||||
|
} else {
|
||||||
|
this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
||||||
|
this->sensor_ = analog_sensor;
|
||||||
|
|
||||||
|
this->sensor_->add_on_state_callback([this](float sensor_value) {
|
||||||
|
// if there is an invalid sensor reading, ignore the change and keep the current state
|
||||||
|
if (!std::isnan(sensor_value)) {
|
||||||
|
this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogThresholdBinarySensor::dump_config() {
|
||||||
|
LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
|
||||||
|
LOG_SENSOR(" ", "Sensor", this->sensor_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace analog_threshold
|
||||||
|
} // namespace esphome
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace analog_threshold {
|
||||||
|
|
||||||
|
class AnalogThresholdBinarySensor : public Component, public binary_sensor::BinarySensor {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
void setup() override;
|
||||||
|
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
void set_sensor(sensor::Sensor *analog_sensor);
|
||||||
|
void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; }
|
||||||
|
void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sensor::Sensor *sensor_{nullptr};
|
||||||
|
|
||||||
|
float upper_threshold_;
|
||||||
|
float lower_threshold_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace analog_threshold
|
||||||
|
} // namespace esphome
|
44
esphome/components/analog_threshold/binary_sensor.py
Normal file
44
esphome/components/analog_threshold/binary_sensor.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import binary_sensor, sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_SENSOR_ID,
|
||||||
|
CONF_THRESHOLD,
|
||||||
|
)
|
||||||
|
|
||||||
|
analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold")
|
||||||
|
|
||||||
|
AnalogThresholdBinarySensor = analog_threshold_ns.class_(
|
||||||
|
"AnalogThresholdBinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_UPPER = "upper"
|
||||||
|
CONF_LOWER = "lower"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(AnalogThresholdBinarySensor),
|
||||||
|
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
||||||
|
cv.Required(CONF_THRESHOLD): cv.Any(
|
||||||
|
cv.float_,
|
||||||
|
cv.Schema(
|
||||||
|
{cv.Required(CONF_UPPER): cv.float_, cv.Required(CONF_LOWER): cv.float_}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
sens = await cg.get_variable(config[CONF_SENSOR_ID])
|
||||||
|
cg.add(var.set_sensor(sens))
|
||||||
|
|
||||||
|
if isinstance(config[CONF_THRESHOLD], float):
|
||||||
|
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD]))
|
||||||
|
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD]))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER]))
|
||||||
|
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER]))
|
|
@ -1,7 +1,7 @@
|
||||||
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 binary_sensor
|
from esphome.components import binary_sensor
|
||||||
from esphome.const import CONF_DIRECTION, CONF_DEVICE_CLASS, DEVICE_CLASS_MOVING
|
from esphome.const import CONF_DIRECTION, DEVICE_CLASS_MOVING
|
||||||
from . import APDS9960, CONF_APDS9960_ID
|
from . import APDS9960, CONF_APDS9960_ID
|
||||||
|
|
||||||
DEPENDENCIES = ["apds9960"]
|
DEPENDENCIES = ["apds9960"]
|
||||||
|
@ -13,13 +13,12 @@ DIRECTIONS = {
|
||||||
"RIGHT": "set_right_direction",
|
"RIGHT": "set_right_direction",
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||||
|
device_class=DEVICE_CLASS_MOVING
|
||||||
|
).extend(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
|
|
||||||
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
||||||
cv.Optional(
|
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
|
||||||
CONF_DEVICE_CLASS, default=DEVICE_CLASS_MOVING
|
|
||||||
): binary_sensor.device_class,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ void APIConnection::loop() {
|
||||||
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str());
|
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str());
|
||||||
}
|
}
|
||||||
} else if (now - this->last_traffic_ > keepalive) {
|
} else if (now - this->last_traffic_ > keepalive) {
|
||||||
|
ESP_LOGVV(TAG, "Sending keepalive PING...");
|
||||||
this->sent_ping_ = true;
|
this->sent_ping_ = true;
|
||||||
this->send_ping_request(PingRequest());
|
this->send_ping_request(PingRequest());
|
||||||
}
|
}
|
||||||
|
@ -908,7 +909,7 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this->last_traffic_ = millis();
|
// Do not set last_traffic_ on send
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void APIConnection::on_unauthenticated_access() {
|
void APIConnection::on_unauthenticated_access() {
|
||||||
|
|
|
@ -21,7 +21,6 @@ async def async_run_logs(config, address):
|
||||||
if CONF_ENCRYPTION in conf:
|
if CONF_ENCRYPTION in conf:
|
||||||
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY]
|
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY]
|
||||||
_LOGGER.info("Starting log output from %s using esphome API", address)
|
_LOGGER.info("Starting log output from %s using esphome API", address)
|
||||||
zc = zeroconf.Zeroconf()
|
|
||||||
cli = APIClient(
|
cli = APIClient(
|
||||||
address,
|
address,
|
||||||
port,
|
port,
|
||||||
|
|
|
@ -5,7 +5,7 @@ from . import AS3935, CONF_AS3935_ID
|
||||||
|
|
||||||
DEPENDENCIES = ["as3935"]
|
DEPENDENCIES = ["as3935"]
|
||||||
|
|
||||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
|
cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ from esphome.components import sensor
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DISTANCE,
|
CONF_DISTANCE,
|
||||||
CONF_LIGHTNING_ENERGY,
|
CONF_LIGHTNING_ENERGY,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
UNIT_KILOMETER,
|
UNIT_KILOMETER,
|
||||||
ICON_SIGNAL_DISTANCE_VARIANT,
|
ICON_SIGNAL_DISTANCE_VARIANT,
|
||||||
ICON_FLASH,
|
ICON_FLASH,
|
||||||
|
@ -20,12 +19,10 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
unit_of_measurement=UNIT_KILOMETER,
|
unit_of_measurement=UNIT_KILOMETER,
|
||||||
icon=ICON_SIGNAL_DISTANCE_VARIANT,
|
icon=ICON_SIGNAL_DISTANCE_VARIANT,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
state_class=STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
|
cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
|
||||||
icon=ICON_FLASH,
|
icon=ICON_FLASH,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
state_class=STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
|
@ -9,18 +9,109 @@ static const char *const TAG = "bh1750.sensor";
|
||||||
static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
|
static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
|
||||||
static const uint8_t BH1750_COMMAND_MT_REG_HI = 0b01000000; // last 3 bits
|
static const uint8_t BH1750_COMMAND_MT_REG_HI = 0b01000000; // last 3 bits
|
||||||
static const uint8_t BH1750_COMMAND_MT_REG_LO = 0b01100000; // last 5 bits
|
static const uint8_t BH1750_COMMAND_MT_REG_LO = 0b01100000; // last 5 bits
|
||||||
|
static const uint8_t BH1750_COMMAND_ONE_TIME_L = 0b00100011;
|
||||||
|
static const uint8_t BH1750_COMMAND_ONE_TIME_H = 0b00100000;
|
||||||
|
static const uint8_t BH1750_COMMAND_ONE_TIME_H2 = 0b00100001;
|
||||||
|
|
||||||
|
/*
|
||||||
|
bh1750 properties:
|
||||||
|
|
||||||
|
L-resolution mode:
|
||||||
|
- resolution 4lx (@ mtreg=69)
|
||||||
|
- measurement time: typ=16ms, max=24ms, scaled by MTreg value divided by 69
|
||||||
|
- formula: counts / 1.2 * (69 / MTreg) lx
|
||||||
|
H-resolution mode:
|
||||||
|
- resolution 1lx (@ mtreg=69)
|
||||||
|
- measurement time: typ=120ms, max=180ms, scaled by MTreg value divided by 69
|
||||||
|
- formula: counts / 1.2 * (69 / MTreg) lx
|
||||||
|
H-resolution mode2:
|
||||||
|
- resolution 0.5lx (@ mtreg=69)
|
||||||
|
- measurement time: typ=120ms, max=180ms, scaled by MTreg value divided by 69
|
||||||
|
- formula: counts / 1.2 * (69 / MTreg) / 2 lx
|
||||||
|
|
||||||
|
MTreg:
|
||||||
|
- min=31, default=69, max=254
|
||||||
|
|
||||||
|
-> only reason to use l-resolution is faster, but offers no higher range
|
||||||
|
-> below ~7000lx, makes sense to use H-resolution2 @ MTreg=254
|
||||||
|
-> try to maximize MTreg to get lowest noise level
|
||||||
|
*/
|
||||||
|
|
||||||
void BH1750Sensor::setup() {
|
void BH1750Sensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up BH1750 '%s'...", this->name_.c_str());
|
ESP_LOGCONFIG(TAG, "Setting up BH1750 '%s'...", this->name_.c_str());
|
||||||
if (!this->write_bytes(BH1750_COMMAND_POWER_ON, nullptr, 0)) {
|
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
|
||||||
|
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t mtreg_hi = (this->measurement_duration_ >> 5) & 0b111;
|
void BH1750Sensor::read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function<void(float)> &f) {
|
||||||
uint8_t mtreg_lo = (this->measurement_duration_ >> 0) & 0b11111;
|
// turn on (after one-shot sensor automatically powers down)
|
||||||
this->write_bytes(BH1750_COMMAND_MT_REG_HI | mtreg_hi, nullptr, 0);
|
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
|
||||||
this->write_bytes(BH1750_COMMAND_MT_REG_LO | mtreg_lo, nullptr, 0);
|
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGW(TAG, "Turning on BH1750 failed");
|
||||||
|
f(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active_mtreg_ != mtreg) {
|
||||||
|
// set mtreg
|
||||||
|
uint8_t mtreg_hi = BH1750_COMMAND_MT_REG_HI | ((mtreg >> 5) & 0b111);
|
||||||
|
uint8_t mtreg_lo = BH1750_COMMAND_MT_REG_LO | ((mtreg >> 0) & 0b11111);
|
||||||
|
if (this->write(&mtreg_hi, 1) != i2c::ERROR_OK || this->write(&mtreg_lo, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGW(TAG, "Setting measurement time for BH1750 failed");
|
||||||
|
active_mtreg_ = 0;
|
||||||
|
f(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
active_mtreg_ = mtreg;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cmd;
|
||||||
|
uint16_t meas_time;
|
||||||
|
switch (mode) {
|
||||||
|
case BH1750_MODE_L:
|
||||||
|
cmd = BH1750_COMMAND_ONE_TIME_L;
|
||||||
|
meas_time = 24 * mtreg / 69;
|
||||||
|
break;
|
||||||
|
case BH1750_MODE_H:
|
||||||
|
cmd = BH1750_COMMAND_ONE_TIME_H;
|
||||||
|
meas_time = 180 * mtreg / 69;
|
||||||
|
break;
|
||||||
|
case BH1750_MODE_H2:
|
||||||
|
cmd = BH1750_COMMAND_ONE_TIME_H2;
|
||||||
|
meas_time = 180 * mtreg / 69;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->write(&cmd, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGW(TAG, "Starting measurement for BH1750 failed");
|
||||||
|
f(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// probably not needed, but adjust for rounding
|
||||||
|
meas_time++;
|
||||||
|
|
||||||
|
this->set_timeout("read", meas_time, [this, mode, mtreg, f]() {
|
||||||
|
uint16_t raw_value;
|
||||||
|
if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGW(TAG, "Reading BH1750 data failed");
|
||||||
|
f(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raw_value = i2c::i2ctohs(raw_value);
|
||||||
|
|
||||||
|
float lx = float(raw_value) / 1.2f;
|
||||||
|
lx *= 69.0f / mtreg;
|
||||||
|
if (mode == BH1750_MODE_H2)
|
||||||
|
lx /= 2.0f;
|
||||||
|
|
||||||
|
f(lx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BH1750Sensor::dump_config() {
|
void BH1750Sensor::dump_config() {
|
||||||
|
@ -30,64 +121,49 @@ void BH1750Sensor::dump_config() {
|
||||||
ESP_LOGE(TAG, "Communication with BH1750 failed!");
|
ESP_LOGE(TAG, "Communication with BH1750 failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *resolution_s;
|
|
||||||
switch (this->resolution_) {
|
|
||||||
case BH1750_RESOLUTION_0P5_LX:
|
|
||||||
resolution_s = "0.5";
|
|
||||||
break;
|
|
||||||
case BH1750_RESOLUTION_1P0_LX:
|
|
||||||
resolution_s = "1";
|
|
||||||
break;
|
|
||||||
case BH1750_RESOLUTION_4P0_LX:
|
|
||||||
resolution_s = "4";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
resolution_s = "Unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ESP_LOGCONFIG(TAG, " Resolution: %s", resolution_s);
|
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BH1750Sensor::update() {
|
void BH1750Sensor::update() {
|
||||||
if (!this->write_bytes(this->resolution_, nullptr, 0))
|
// first do a quick measurement in L-mode with full range
|
||||||
return;
|
// to find right range
|
||||||
|
this->read_lx_(BH1750_MODE_L, 31, [this](float val) {
|
||||||
|
if (std::isnan(val)) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t wait = 0;
|
BH1750Mode use_mode;
|
||||||
// use max conversion times
|
uint8_t use_mtreg;
|
||||||
switch (this->resolution_) {
|
if (val <= 7000) {
|
||||||
case BH1750_RESOLUTION_0P5_LX:
|
use_mode = BH1750_MODE_H2;
|
||||||
case BH1750_RESOLUTION_1P0_LX:
|
use_mtreg = 254;
|
||||||
wait = 180;
|
} else {
|
||||||
break;
|
use_mode = BH1750_MODE_H;
|
||||||
case BH1750_RESOLUTION_4P0_LX:
|
// lx = counts / 1.2 * (69 / mtreg)
|
||||||
wait = 24;
|
// -> mtreg = counts / 1.2 * (69 / lx)
|
||||||
break;
|
// calculate for counts=50000 (allow some range to not saturate, but maximize mtreg)
|
||||||
}
|
// -> mtreg = 50000*(10/12)*(69/lx)
|
||||||
|
int ideal_mtreg = 50000 * 10 * 69 / (12 * (int) val);
|
||||||
|
use_mtreg = std::min(254, std::max(31, ideal_mtreg));
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "L result: %f -> Calculated mode=%d, mtreg=%d", val, (int) use_mode, use_mtreg);
|
||||||
|
|
||||||
this->set_timeout("illuminance", wait, [this]() { this->read_data_(); });
|
this->read_lx_(use_mode, use_mtreg, [this](float val) {
|
||||||
|
if (std::isnan(val)) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(NAN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "'%s': Got illuminance=%.1flx", this->get_name().c_str(), val);
|
||||||
|
this->status_clear_warning();
|
||||||
|
this->publish_state(val);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
float BH1750Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
float BH1750Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
void BH1750Sensor::read_data_() {
|
|
||||||
uint16_t raw_value;
|
|
||||||
if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
|
|
||||||
this->status_set_warning();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
raw_value = i2c::i2ctohs(raw_value);
|
|
||||||
|
|
||||||
float lx = float(raw_value) / 1.2f;
|
|
||||||
lx *= 69.0f / this->measurement_duration_;
|
|
||||||
if (this->resolution_ == BH1750_RESOLUTION_0P5_LX) {
|
|
||||||
lx /= 2.0f;
|
|
||||||
}
|
|
||||||
ESP_LOGD(TAG, "'%s': Got illuminance=%.1flx", this->get_name().c_str(), lx);
|
|
||||||
this->publish_state(lx);
|
|
||||||
this->status_clear_warning();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BH1750Sensor::set_resolution(BH1750Resolution resolution) { this->resolution_ = resolution; }
|
|
||||||
|
|
||||||
} // namespace bh1750
|
} // namespace bh1750
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -7,29 +7,15 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace bh1750 {
|
namespace bh1750 {
|
||||||
|
|
||||||
/// Enum listing all resolutions that can be used with the BH1750
|
enum BH1750Mode {
|
||||||
enum BH1750Resolution {
|
BH1750_MODE_L,
|
||||||
BH1750_RESOLUTION_4P0_LX = 0b00100011, // one-time low resolution mode
|
BH1750_MODE_H,
|
||||||
BH1750_RESOLUTION_1P0_LX = 0b00100000, // one-time high resolution mode 1
|
BH1750_MODE_H2,
|
||||||
BH1750_RESOLUTION_0P5_LX = 0b00100001, // one-time high resolution mode 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This class implements support for the i2c-based BH1750 ambient light sensor.
|
/// This class implements support for the i2c-based BH1750 ambient light sensor.
|
||||||
class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
/** Set the resolution of this sensor.
|
|
||||||
*
|
|
||||||
* Possible values are:
|
|
||||||
*
|
|
||||||
* - `BH1750_RESOLUTION_4P0_LX`
|
|
||||||
* - `BH1750_RESOLUTION_1P0_LX`
|
|
||||||
* - `BH1750_RESOLUTION_0P5_LX` (default)
|
|
||||||
*
|
|
||||||
* @param resolution The new resolution of the sensor.
|
|
||||||
*/
|
|
||||||
void set_resolution(BH1750Resolution resolution);
|
|
||||||
void set_measurement_duration(uint8_t measurement_duration) { measurement_duration_ = measurement_duration; }
|
|
||||||
|
|
||||||
// ========== INTERNAL METHODS ==========
|
// ========== INTERNAL METHODS ==========
|
||||||
// (In most use cases you won't need these)
|
// (In most use cases you won't need these)
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
@ -38,10 +24,9 @@ class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c:
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void read_data_();
|
void read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function<void(float)> &f);
|
||||||
|
|
||||||
BH1750Resolution resolution_{BH1750_RESOLUTION_0P5_LX};
|
uint8_t active_mtreg_{0};
|
||||||
uint8_t measurement_duration_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace bh1750
|
} // namespace bh1750
|
||||||
|
|
|
@ -2,31 +2,23 @@ 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
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
|
||||||
CONF_RESOLUTION,
|
|
||||||
DEVICE_CLASS_ILLUMINANCE,
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_LUX,
|
UNIT_LUX,
|
||||||
CONF_MEASUREMENT_DURATION,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
DEPENDENCIES = ["i2c"]
|
DEPENDENCIES = ["i2c"]
|
||||||
|
CODEOWNERS = ["@OttoWinter"]
|
||||||
|
|
||||||
bh1750_ns = cg.esphome_ns.namespace("bh1750")
|
bh1750_ns = cg.esphome_ns.namespace("bh1750")
|
||||||
BH1750Resolution = bh1750_ns.enum("BH1750Resolution")
|
|
||||||
BH1750_RESOLUTIONS = {
|
|
||||||
4.0: BH1750Resolution.BH1750_RESOLUTION_4P0_LX,
|
|
||||||
1.0: BH1750Resolution.BH1750_RESOLUTION_1P0_LX,
|
|
||||||
0.5: BH1750Resolution.BH1750_RESOLUTION_0P5_LX,
|
|
||||||
}
|
|
||||||
|
|
||||||
BH1750Sensor = bh1750_ns.class_(
|
BH1750Sensor = bh1750_ns.class_(
|
||||||
"BH1750Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
|
"BH1750Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
|
||||||
)
|
)
|
||||||
|
|
||||||
CONF_MEASUREMENT_TIME = "measurement_time"
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
BH1750Sensor,
|
||||||
unit_of_measurement=UNIT_LUX,
|
unit_of_measurement=UNIT_LUX,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
@ -34,15 +26,11 @@ CONFIG_SCHEMA = (
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BH1750Sensor),
|
cv.Optional("resolution"): cv.invalid(
|
||||||
cv.Optional(CONF_RESOLUTION, default=0.5): cv.enum(
|
"The 'resolution' option has been removed. The optimal value is now dynamically calculated."
|
||||||
BH1750_RESOLUTIONS, float=True
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MEASUREMENT_DURATION, default=69): cv.int_range(
|
cv.Optional("measurement_duration"): cv.invalid(
|
||||||
min=31, max=254
|
"The 'measurement_duration' option has been removed. The optimal value is now dynamically calculated."
|
||||||
),
|
|
||||||
cv.Optional(CONF_MEASUREMENT_TIME): cv.invalid(
|
|
||||||
"The 'measurement_time' option has been replaced with 'measurement_duration' in 1.18.0"
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -52,10 +40,6 @@ CONFIG_SCHEMA = (
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
await i2c.register_i2c_device(var, config)
|
await i2c.register_i2c_device(var, config)
|
||||||
|
|
||||||
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
|
|
||||||
cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION]))
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
from esphome.cpp_generator import MockObjClass
|
||||||
from esphome.cpp_helpers import setup_entity
|
from esphome.cpp_helpers import setup_entity
|
||||||
from esphome import automation, core
|
from esphome import automation, core
|
||||||
from esphome.automation import Condition, maybe_simple_id
|
from esphome.automation import Condition, maybe_simple_id
|
||||||
|
@ -7,7 +8,9 @@ from esphome.components import mqtt
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DELAY,
|
CONF_DELAY,
|
||||||
CONF_DEVICE_CLASS,
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
CONF_FILTERS,
|
CONF_FILTERS,
|
||||||
|
CONF_ICON,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_INVALID_COOLDOWN,
|
CONF_INVALID_COOLDOWN,
|
||||||
CONF_INVERTED,
|
CONF_INVERTED,
|
||||||
|
@ -22,7 +25,6 @@ from esphome.const import (
|
||||||
CONF_STATE,
|
CONF_STATE,
|
||||||
CONF_TIMING,
|
CONF_TIMING,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_NAME,
|
|
||||||
CONF_MQTT_ID,
|
CONF_MQTT_ID,
|
||||||
DEVICE_CLASS_EMPTY,
|
DEVICE_CLASS_EMPTY,
|
||||||
DEVICE_CLASS_BATTERY,
|
DEVICE_CLASS_BATTERY,
|
||||||
|
@ -315,7 +317,7 @@ def validate_multi_click_timing(value):
|
||||||
return timings
|
return timings
|
||||||
|
|
||||||
|
|
||||||
device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
||||||
|
|
||||||
|
|
||||||
BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
|
BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
|
||||||
|
@ -324,7 +326,7 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex
|
||||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
||||||
mqtt.MQTTBinarySensorComponent
|
mqtt.MQTTBinarySensorComponent
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_DEVICE_CLASS): device_class,
|
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
|
||||||
cv.Optional(CONF_FILTERS): validate_filters,
|
cv.Optional(CONF_FILTERS): validate_filters,
|
||||||
cv.Optional(CONF_ON_PRESS): automation.validate_automation(
|
cv.Optional(CONF_ON_PRESS): automation.validate_automation(
|
||||||
{
|
{
|
||||||
|
@ -377,6 +379,39 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_UNDEF = object()
|
||||||
|
|
||||||
|
|
||||||
|
def binary_sensor_schema(
|
||||||
|
class_: MockObjClass = _UNDEF,
|
||||||
|
*,
|
||||||
|
icon: str = _UNDEF,
|
||||||
|
entity_category: str = _UNDEF,
|
||||||
|
device_class: str = _UNDEF,
|
||||||
|
) -> cv.Schema:
|
||||||
|
schema = BINARY_SENSOR_SCHEMA
|
||||||
|
if class_ is not _UNDEF:
|
||||||
|
schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
|
||||||
|
if icon is not _UNDEF:
|
||||||
|
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
|
||||||
|
if entity_category is not _UNDEF:
|
||||||
|
schema = schema.extend(
|
||||||
|
{
|
||||||
|
cv.Optional(
|
||||||
|
CONF_ENTITY_CATEGORY, default=entity_category
|
||||||
|
): cv.entity_category
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if device_class is not _UNDEF:
|
||||||
|
schema = schema.extend(
|
||||||
|
{
|
||||||
|
cv.Optional(
|
||||||
|
CONF_DEVICE_CLASS, default=device_class
|
||||||
|
): validate_device_class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return schema
|
||||||
|
|
||||||
|
|
||||||
async def setup_binary_sensor_core_(var, config):
|
async def setup_binary_sensor_core_(var, config):
|
||||||
await setup_entity(var, config)
|
await setup_entity(var, config)
|
||||||
|
@ -443,7 +478,7 @@ async def register_binary_sensor(var, config):
|
||||||
|
|
||||||
|
|
||||||
async def new_binary_sensor(config):
|
async def new_binary_sensor(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await register_binary_sensor(var, config)
|
await register_binary_sensor(var, config)
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,7 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string BinarySensor::device_class() { return ""; }
|
std::string BinarySensor::device_class() { return ""; }
|
||||||
BinarySensor::BinarySensor(const std::string &name) : EntityBase(name), state(false) {}
|
BinarySensor::BinarySensor() : state(false) {}
|
||||||
BinarySensor::BinarySensor() : BinarySensor("") {}
|
|
||||||
void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
|
void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
|
||||||
std::string BinarySensor::get_device_class() {
|
std::string BinarySensor::get_device_class() {
|
||||||
if (this->device_class_.has_value())
|
if (this->device_class_.has_value())
|
||||||
|
|
|
@ -26,11 +26,6 @@ namespace binary_sensor {
|
||||||
class BinarySensor : public EntityBase {
|
class BinarySensor : public EntityBase {
|
||||||
public:
|
public:
|
||||||
explicit BinarySensor();
|
explicit BinarySensor();
|
||||||
/** Construct a binary sensor with the specified name
|
|
||||||
*
|
|
||||||
* @param name Name of this binary sensor.
|
|
||||||
*/
|
|
||||||
explicit BinarySensor(const std::string &name);
|
|
||||||
|
|
||||||
/** Add a callback to be notified of state changes.
|
/** Add a callback to be notified of state changes.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,14 +3,12 @@ import esphome.config_validation as cv
|
||||||
|
|
||||||
from esphome.components import sensor, binary_sensor
|
from esphome.components import sensor, binary_sensor
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
|
||||||
CONF_CHANNELS,
|
CONF_CHANNELS,
|
||||||
CONF_VALUE,
|
CONF_VALUE,
|
||||||
CONF_TYPE,
|
CONF_TYPE,
|
||||||
ICON_CHECK_CIRCLE_OUTLINE,
|
ICON_CHECK_CIRCLE_OUTLINE,
|
||||||
CONF_BINARY_SENSOR,
|
CONF_BINARY_SENSOR,
|
||||||
CONF_GROUP,
|
CONF_GROUP,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
DEPENDENCIES = ["binary_sensor"]
|
DEPENDENCIES = ["binary_sensor"]
|
||||||
|
@ -33,12 +31,11 @@ entry = {
|
||||||
CONFIG_SCHEMA = cv.typed_schema(
|
CONFIG_SCHEMA = cv.typed_schema(
|
||||||
{
|
{
|
||||||
CONF_GROUP: sensor.sensor_schema(
|
CONF_GROUP: sensor.sensor_schema(
|
||||||
|
BinarySensorMap,
|
||||||
icon=ICON_CHECK_CIRCLE_OUTLINE,
|
icon=ICON_CHECK_CIRCLE_OUTLINE,
|
||||||
accuracy_decimals=0,
|
accuracy_decimals=0,
|
||||||
state_class=STATE_CLASS_NONE,
|
|
||||||
).extend(
|
).extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BinarySensorMap),
|
|
||||||
cv.Required(CONF_CHANNELS): cv.All(
|
cv.Required(CONF_CHANNELS): cv.All(
|
||||||
cv.ensure_list(entry), cv.Length(min=1)
|
cv.ensure_list(entry), cv.Length(min=1)
|
||||||
),
|
),
|
||||||
|
@ -50,9 +47,8 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
|
|
||||||
constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
|
constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
|
||||||
cg.add(var.set_sensor_type(constant))
|
cg.add(var.set_sensor_type(constant))
|
||||||
|
|
|
@ -12,9 +12,7 @@ from esphome.const import (
|
||||||
DEVICE_CLASS_POWER,
|
DEVICE_CLASS_POWER,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
ICON_EMPTY,
|
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
UNIT_AMPERE,
|
UNIT_AMPERE,
|
||||||
UNIT_CELSIUS,
|
UNIT_CELSIUS,
|
||||||
UNIT_KILOWATT_HOURS,
|
UNIT_KILOWATT_HOURS,
|
||||||
|
@ -35,38 +33,39 @@ CONFIG_SCHEMA = (
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BL0940),
|
cv.GenerateID(): cv.declare_id(BL0940),
|
||||||
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
||||||
UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
|
unit_of_measurement=UNIT_VOLT,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
||||||
UNIT_AMPERE,
|
unit_of_measurement=UNIT_AMPERE,
|
||||||
ICON_EMPTY,
|
accuracy_decimals=2,
|
||||||
2,
|
device_class=DEVICE_CLASS_CURRENT,
|
||||||
DEVICE_CLASS_CURRENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_MEASUREMENT,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
||||||
UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
|
unit_of_measurement=UNIT_WATT,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_POWER,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
|
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
|
||||||
UNIT_KILOWATT_HOURS,
|
unit_of_measurement=UNIT_KILOWATT_HOURS,
|
||||||
ICON_EMPTY,
|
accuracy_decimals=0,
|
||||||
0,
|
device_class=DEVICE_CLASS_ENERGY,
|
||||||
DEVICE_CLASS_ENERGY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
|
cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_EMPTY,
|
accuracy_decimals=0,
|
||||||
0,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
|
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_EMPTY,
|
accuracy_decimals=0,
|
||||||
0,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,9 +2,7 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import sensor, ble_client, esp32_ble_tracker
|
from esphome.components import sensor, ble_client, esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
|
||||||
CONF_LAMBDA,
|
CONF_LAMBDA,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_SERVICE_UUID,
|
CONF_SERVICE_UUID,
|
||||||
)
|
)
|
||||||
|
@ -31,12 +29,11 @@ BLESensorNotifyTrigger = ble_client_ns.class_(
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
BLESensor,
|
||||||
accuracy_decimals=0,
|
accuracy_decimals=0,
|
||||||
state_class=STATE_CLASS_NONE,
|
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BLESensor),
|
|
||||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
|
@ -57,7 +54,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||||
cg.add(
|
cg.add(
|
||||||
var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
||||||
|
@ -124,7 +121,6 @@ async def to_code(config):
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await ble_client.register_ble_node(var, config)
|
await ble_client.register_ble_node(var, config)
|
||||||
cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
|
cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
for conf in config.get(CONF_ON_NOTIFY, []):
|
for conf in config.get(CONF_ON_NOTIFY, []):
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
await ble_client.register_ble_node(trigger, config)
|
await ble_client.register_ble_node(trigger, config)
|
||||||
|
|
121
esphome/components/ble_client/text_sensor/__init__.py
Normal file
121
esphome/components/ble_client/text_sensor/__init__.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import text_sensor, ble_client, esp32_ble_tracker
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_TRIGGER_ID,
|
||||||
|
CONF_SERVICE_UUID,
|
||||||
|
)
|
||||||
|
from esphome import automation
|
||||||
|
from .. import ble_client_ns
|
||||||
|
|
||||||
|
DEPENDENCIES = ["ble_client"]
|
||||||
|
|
||||||
|
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
||||||
|
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
||||||
|
|
||||||
|
CONF_NOTIFY = "notify"
|
||||||
|
CONF_ON_NOTIFY = "on_notify"
|
||||||
|
|
||||||
|
adv_data_t = cg.std_vector.template(cg.uint8)
|
||||||
|
adv_data_t_const_ref = adv_data_t.operator("ref").operator("const")
|
||||||
|
|
||||||
|
BLETextSensor = ble_client_ns.class_(
|
||||||
|
"BLETextSensor",
|
||||||
|
text_sensor.TextSensor,
|
||||||
|
cg.PollingComponent,
|
||||||
|
ble_client.BLEClientNode,
|
||||||
|
)
|
||||||
|
BLETextSensorNotifyTrigger = ble_client_ns.class_(
|
||||||
|
"BLETextSensorNotifyTrigger", automation.Trigger.template(cg.std_string)
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
text_sensor.TEXT_SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(BLETextSensor),
|
||||||
|
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
|
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
|
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
|
cv.Optional(CONF_NOTIFY, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_ON_NOTIFY): automation.validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||||
|
BLETextSensorNotifyTrigger
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
.extend(ble_client.BLE_CLIENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||||
|
cg.add(
|
||||||
|
var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
||||||
|
)
|
||||||
|
elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid32_format):
|
||||||
|
cg.add(
|
||||||
|
var.set_service_uuid32(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
||||||
|
)
|
||||||
|
elif len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid128_format):
|
||||||
|
uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID])
|
||||||
|
cg.add(var.set_service_uuid128(uuid128))
|
||||||
|
|
||||||
|
if len(config[CONF_CHARACTERISTIC_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||||
|
cg.add(
|
||||||
|
var.set_char_uuid16(
|
||||||
|
esp32_ble_tracker.as_hex(config[CONF_CHARACTERISTIC_UUID])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif len(config[CONF_CHARACTERISTIC_UUID]) == len(
|
||||||
|
esp32_ble_tracker.bt_uuid32_format
|
||||||
|
):
|
||||||
|
cg.add(
|
||||||
|
var.set_char_uuid32(
|
||||||
|
esp32_ble_tracker.as_hex(config[CONF_CHARACTERISTIC_UUID])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif len(config[CONF_CHARACTERISTIC_UUID]) == len(
|
||||||
|
esp32_ble_tracker.bt_uuid128_format
|
||||||
|
):
|
||||||
|
uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
||||||
|
config[CONF_CHARACTERISTIC_UUID]
|
||||||
|
)
|
||||||
|
cg.add(var.set_char_uuid128(uuid128))
|
||||||
|
|
||||||
|
if CONF_DESCRIPTOR_UUID in config:
|
||||||
|
if len(config[CONF_DESCRIPTOR_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||||
|
cg.add(
|
||||||
|
var.set_descr_uuid16(
|
||||||
|
esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif len(config[CONF_DESCRIPTOR_UUID]) == len(
|
||||||
|
esp32_ble_tracker.bt_uuid32_format
|
||||||
|
):
|
||||||
|
cg.add(
|
||||||
|
var.set_descr_uuid32(
|
||||||
|
esp32_ble_tracker.as_hex(config[CONF_DESCRIPTOR_UUID])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif len(config[CONF_DESCRIPTOR_UUID]) == len(
|
||||||
|
esp32_ble_tracker.bt_uuid128_format
|
||||||
|
):
|
||||||
|
uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
||||||
|
config[CONF_DESCRIPTOR_UUID]
|
||||||
|
)
|
||||||
|
cg.add(var.set_descr_uuid128(uuid128))
|
||||||
|
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await ble_client.register_ble_node(var, config)
|
||||||
|
cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
|
||||||
|
await text_sensor.register_text_sensor(var, config)
|
||||||
|
for conf in config.get(CONF_ON_NOTIFY, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await ble_client.register_ble_node(trigger, config)
|
||||||
|
await automation.build_automation(trigger, [(cg.std_string, "x")], conf)
|
38
esphome/components/ble_client/text_sensor/automation.h
Normal file
38
esphome/components/ble_client/text_sensor/automation.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/components/ble_client/text_sensor/ble_text_sensor.h"
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ble_client {
|
||||||
|
|
||||||
|
class BLETextSensorNotifyTrigger : public Trigger<std::string>, public BLETextSensor {
|
||||||
|
public:
|
||||||
|
explicit BLETextSensorNotifyTrigger(BLETextSensor *sensor) { sensor_ = sensor; }
|
||||||
|
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
|
esp_ble_gattc_cb_param_t *param) override {
|
||||||
|
switch (event) {
|
||||||
|
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||||
|
this->sensor_->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_NOTIFY_EVT: {
|
||||||
|
if (param->notify.conn_id != this->sensor_->parent()->conn_id || param->notify.handle != this->sensor_->handle)
|
||||||
|
break;
|
||||||
|
this->trigger(this->sensor_->parse_data(param->notify.value, param->notify.value_len));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BLETextSensor *sensor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ble_client
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
137
esphome/components/ble_client/text_sensor/ble_text_sensor.cpp
Normal file
137
esphome/components/ble_client/text_sensor/ble_text_sensor.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#include "ble_text_sensor.h"
|
||||||
|
|
||||||
|
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ble_client {
|
||||||
|
|
||||||
|
static const char *const TAG = "ble_text_sensor";
|
||||||
|
|
||||||
|
static const std::string EMPTY = "";
|
||||||
|
|
||||||
|
uint32_t BLETextSensor::hash_base() { return 193967603UL; }
|
||||||
|
|
||||||
|
void BLETextSensor::loop() {}
|
||||||
|
|
||||||
|
void BLETextSensor::dump_config() {
|
||||||
|
LOG_TEXT_SENSOR("", "BLE Text Sensor", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " MAC address : %s", this->parent()->address_str().c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Service UUID : %s", this->service_uuid_.to_string().c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Characteristic UUID: %s", this->char_uuid_.to_string().c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Descriptor UUID : %s", this->descr_uuid_.to_string().c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Notifications : %s", YESNO(this->notify_));
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
|
esp_ble_gattc_cb_param_t *param) {
|
||||||
|
switch (event) {
|
||||||
|
case ESP_GATTC_OPEN_EVT: {
|
||||||
|
if (param->open.status == ESP_GATT_OK) {
|
||||||
|
ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_DISCONNECT_EVT: {
|
||||||
|
ESP_LOGW(TAG, "[%s] Disconnected!", this->get_name().c_str());
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(EMPTY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||||
|
this->handle = 0;
|
||||||
|
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
|
||||||
|
if (chr == nullptr) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(EMPTY);
|
||||||
|
ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(),
|
||||||
|
this->char_uuid_.to_string().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->handle = chr->handle;
|
||||||
|
if (this->descr_uuid_.get_uuid().len > 0) {
|
||||||
|
auto *descr = chr->get_descriptor(this->descr_uuid_);
|
||||||
|
if (descr == nullptr) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(EMPTY);
|
||||||
|
ESP_LOGW(TAG, "No sensor descriptor found at service %s char %s descr %s",
|
||||||
|
this->service_uuid_.to_string().c_str(), this->char_uuid_.to_string().c_str(),
|
||||||
|
this->descr_uuid_.to_string().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->handle = descr->handle;
|
||||||
|
}
|
||||||
|
if (this->notify_) {
|
||||||
|
auto status =
|
||||||
|
esp_ble_gattc_register_for_notify(this->parent()->gattc_if, this->parent()->remote_bda, chr->handle);
|
||||||
|
if (status) {
|
||||||
|
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_READ_CHAR_EVT: {
|
||||||
|
if (param->read.conn_id != this->parent()->conn_id)
|
||||||
|
break;
|
||||||
|
if (param->read.status != ESP_GATT_OK) {
|
||||||
|
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (param->read.handle == this->handle) {
|
||||||
|
this->status_clear_warning();
|
||||||
|
this->publish_state(this->parse_data(param->read.value, param->read.value_len));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_NOTIFY_EVT: {
|
||||||
|
if (param->notify.conn_id != this->parent()->conn_id || param->notify.handle != this->handle)
|
||||||
|
break;
|
||||||
|
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
|
||||||
|
param->notify.handle, param->notify.value[0]);
|
||||||
|
this->publish_state(this->parse_data(param->notify.value, param->notify.value_len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||||
|
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BLETextSensor::parse_data(uint8_t *value, uint16_t value_len) {
|
||||||
|
std::string text(value, value + value_len);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLETextSensor::update() {
|
||||||
|
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||||
|
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->handle == 0) {
|
||||||
|
ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto status =
|
||||||
|
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle, ESP_GATT_AUTH_REQ_NONE);
|
||||||
|
if (status) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->publish_state(EMPTY);
|
||||||
|
ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ble_client
|
||||||
|
} // namespace esphome
|
||||||
|
#endif
|
47
esphome/components/ble_client/text_sensor/ble_text_sensor.h
Normal file
47
esphome/components/ble_client/text_sensor/ble_text_sensor.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/ble_client/ble_client.h"
|
||||||
|
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||||
|
#include "esphome/components/text_sensor/text_sensor.h"
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
#include <esp_gattc_api.h>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ble_client {
|
||||||
|
|
||||||
|
namespace espbt = esphome::esp32_ble_tracker;
|
||||||
|
|
||||||
|
class BLETextSensor : public text_sensor::TextSensor, public PollingComponent, public BLEClientNode {
|
||||||
|
public:
|
||||||
|
void loop() override;
|
||||||
|
void update() override;
|
||||||
|
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
|
esp_ble_gattc_cb_param_t *param) override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||||
|
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||||
|
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
void set_char_uuid16(uint16_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||||
|
void set_char_uuid32(uint32_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||||
|
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||||
|
void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||||
|
void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
void set_enable_notify(bool notify) { this->notify_ = notify; }
|
||||||
|
std::string parse_data(uint8_t *value, uint16_t value_len);
|
||||||
|
uint16_t handle;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t hash_base() override;
|
||||||
|
bool notify_;
|
||||||
|
espbt::ESPBTUUID service_uuid_;
|
||||||
|
espbt::ESPBTUUID char_uuid_;
|
||||||
|
espbt::ESPBTUUID descr_uuid_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ble_client
|
||||||
|
} // namespace esphome
|
||||||
|
#endif
|
|
@ -7,7 +7,6 @@ from esphome.const import (
|
||||||
CONF_IBEACON_MAJOR,
|
CONF_IBEACON_MAJOR,
|
||||||
CONF_IBEACON_MINOR,
|
CONF_IBEACON_MINOR,
|
||||||
CONF_IBEACON_UUID,
|
CONF_IBEACON_UUID,
|
||||||
CONF_ID,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
DEPENDENCIES = ["esp32_ble_tracker"]
|
DEPENDENCIES = ["esp32_ble_tracker"]
|
||||||
|
@ -30,9 +29,9 @@ def _validate(config):
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
binary_sensor.binary_sensor_schema(BLEPresenceDevice)
|
||||||
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BLEPresenceDevice),
|
|
||||||
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
|
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
|
||||||
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
|
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
|
||||||
|
@ -48,10 +47,9 @@ CONFIG_SCHEMA = cv.All(
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await esp32_ble_tracker.register_ble_device(var, config)
|
await esp32_ble_tracker.register_ble_device(var, config)
|
||||||
await binary_sensor.register_binary_sensor(var, config)
|
|
||||||
|
|
||||||
if CONF_MAC_ADDRESS in config:
|
if CONF_MAC_ADDRESS in config:
|
||||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||||
|
|
|
@ -4,7 +4,6 @@ from esphome.components import sensor, esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_SERVICE_UUID,
|
CONF_SERVICE_UUID,
|
||||||
CONF_MAC_ADDRESS,
|
CONF_MAC_ADDRESS,
|
||||||
CONF_ID,
|
|
||||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_DECIBEL,
|
UNIT_DECIBEL,
|
||||||
|
@ -19,6 +18,7 @@ BLERSSISensor = ble_rssi_ns.class_(
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
BLERSSISensor,
|
||||||
unit_of_measurement=UNIT_DECIBEL,
|
unit_of_measurement=UNIT_DECIBEL,
|
||||||
accuracy_decimals=0,
|
accuracy_decimals=0,
|
||||||
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
|
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||||
|
@ -26,7 +26,6 @@ CONFIG_SCHEMA = cv.All(
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(BLERSSISensor),
|
|
||||||
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
|
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
|
||||||
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
}
|
}
|
||||||
|
@ -38,10 +37,9 @@ CONFIG_SCHEMA = cv.All(
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await esp32_ble_tracker.register_ble_device(var, config)
|
await esp32_ble_tracker.register_ble_device(var, config)
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
|
|
||||||
if CONF_MAC_ADDRESS in config:
|
if CONF_MAC_ADDRESS in config:
|
||||||
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||||
|
|
|
@ -13,7 +13,7 @@ BLEScanner = ble_scanner_ns.class_(
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
text_sensor.text_sensor_schema(klass=BLEScanner)
|
text_sensor.text_sensor_schema(BLEScanner)
|
||||||
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
|
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
|
||||||
.extend(cv.COMPONENT_SCHEMA)
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,11 +18,7 @@ void Button::add_on_press_callback(std::function<void()> &&callback) { this->pre
|
||||||
uint32_t Button::hash_base() { return 1495763804UL; }
|
uint32_t Button::hash_base() { return 1495763804UL; }
|
||||||
|
|
||||||
void Button::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
|
void Button::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
|
||||||
std::string Button::get_device_class() {
|
std::string Button::get_device_class() { return this->device_class_; }
|
||||||
if (this->device_class_.has_value())
|
|
||||||
return *this->device_class_;
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace button
|
} // namespace button
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -45,12 +45,12 @@ class Button : public EntityBase {
|
||||||
protected:
|
protected:
|
||||||
/** You should implement this virtual method if you want to create your own button.
|
/** You should implement this virtual method if you want to create your own button.
|
||||||
*/
|
*/
|
||||||
virtual void press_action(){};
|
virtual void press_action() = 0;
|
||||||
|
|
||||||
uint32_t hash_base() override;
|
uint32_t hash_base() override;
|
||||||
|
|
||||||
CallbackManager<void()> press_callback_{};
|
CallbackManager<void()> press_callback_{};
|
||||||
optional<std::string> device_class_{};
|
std::string device_class_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace button
|
} // namespace button
|
||||||
|
|
|
@ -8,6 +8,7 @@ CODEOWNERS = ["@mvturnho", "@danielschramm"]
|
||||||
IS_PLATFORM_COMPONENT = True
|
IS_PLATFORM_COMPONENT = True
|
||||||
|
|
||||||
CONF_CAN_ID = "can_id"
|
CONF_CAN_ID = "can_id"
|
||||||
|
CONF_CAN_ID_MASK = "can_id_mask"
|
||||||
CONF_USE_EXTENDED_ID = "use_extended_id"
|
CONF_USE_EXTENDED_ID = "use_extended_id"
|
||||||
CONF_CANBUS_ID = "canbus_id"
|
CONF_CANBUS_ID = "canbus_id"
|
||||||
CONF_BIT_RATE = "bit_rate"
|
CONF_BIT_RATE = "bit_rate"
|
||||||
|
@ -38,7 +39,7 @@ canbus_ns = cg.esphome_ns.namespace("canbus")
|
||||||
CanbusComponent = canbus_ns.class_("CanbusComponent", cg.Component)
|
CanbusComponent = canbus_ns.class_("CanbusComponent", cg.Component)
|
||||||
CanbusTrigger = canbus_ns.class_(
|
CanbusTrigger = canbus_ns.class_(
|
||||||
"CanbusTrigger",
|
"CanbusTrigger",
|
||||||
automation.Trigger.template(cg.std_vector.template(cg.uint8)),
|
automation.Trigger.template(cg.std_vector.template(cg.uint8), cg.uint32),
|
||||||
cg.Component,
|
cg.Component,
|
||||||
)
|
)
|
||||||
CanSpeed = canbus_ns.enum("CAN_SPEED")
|
CanSpeed = canbus_ns.enum("CAN_SPEED")
|
||||||
|
@ -72,6 +73,9 @@ CANBUS_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
|
||||||
cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF),
|
cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF),
|
||||||
|
cv.Optional(CONF_CAN_ID_MASK, default=0x1FFFFFFF): cv.int_range(
|
||||||
|
min=0, max=0x1FFFFFFF
|
||||||
|
),
|
||||||
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
|
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
|
||||||
},
|
},
|
||||||
validate_id,
|
validate_id,
|
||||||
|
@ -90,11 +94,16 @@ async def setup_canbus_core_(var, config):
|
||||||
|
|
||||||
for conf in config.get(CONF_ON_FRAME, []):
|
for conf in config.get(CONF_ON_FRAME, []):
|
||||||
can_id = conf[CONF_CAN_ID]
|
can_id = conf[CONF_CAN_ID]
|
||||||
|
can_id_mask = conf[CONF_CAN_ID_MASK]
|
||||||
ext_id = conf[CONF_USE_EXTENDED_ID]
|
ext_id = conf[CONF_USE_EXTENDED_ID]
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id)
|
trigger = cg.new_Pvariable(
|
||||||
|
conf[CONF_TRIGGER_ID], var, can_id, can_id_mask, ext_id
|
||||||
|
)
|
||||||
await cg.register_component(trigger, conf)
|
await cg.register_component(trigger, conf)
|
||||||
await automation.build_automation(
|
await automation.build_automation(
|
||||||
trigger, [(cg.std_vector.template(cg.uint8), "x")], conf
|
trigger,
|
||||||
|
[(cg.std_vector.template(cg.uint8), "x"), (cg.uint32, "can_id")],
|
||||||
|
conf,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +135,6 @@ async def canbus_action_to_code(config, action_id, template_arg, args):
|
||||||
if CONF_CAN_ID in config:
|
if CONF_CAN_ID in config:
|
||||||
can_id = await cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
|
can_id = await cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
|
||||||
cg.add(var.set_can_id(can_id))
|
cg.add(var.set_can_id(can_id))
|
||||||
|
|
||||||
use_extended_id = await cg.templatable(
|
use_extended_id = await cg.templatable(
|
||||||
config[CONF_USE_EXTENDED_ID], args, cg.uint32
|
config[CONF_USE_EXTENDED_ID], args, cg.uint32
|
||||||
)
|
)
|
||||||
|
|
|
@ -56,13 +56,15 @@ void Canbus::add_trigger(CanbusTrigger *trigger) {
|
||||||
|
|
||||||
void Canbus::loop() {
|
void Canbus::loop() {
|
||||||
struct CanFrame can_message;
|
struct CanFrame can_message;
|
||||||
// readmessage
|
// read all messages until queue is empty
|
||||||
if (this->read_message(&can_message) == canbus::ERROR_OK) {
|
int message_counter = 0;
|
||||||
|
while (this->read_message(&can_message) == canbus::ERROR_OK) {
|
||||||
|
message_counter++;
|
||||||
if (can_message.use_extended_id) {
|
if (can_message.use_extended_id) {
|
||||||
ESP_LOGD(TAG, "received can message extended can_id=0x%x size=%d", can_message.can_id,
|
ESP_LOGD(TAG, "received can message (#%d) extended can_id=0x%x size=%d", message_counter, can_message.can_id,
|
||||||
can_message.can_data_length_code);
|
can_message.can_data_length_code);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "received can message std can_id=0x%x size=%d", can_message.can_id,
|
ESP_LOGD(TAG, "received can message (#%d) std can_id=0x%x size=%d", message_counter, can_message.can_id,
|
||||||
can_message.can_data_length_code);
|
can_message.can_data_length_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +78,9 @@ void Canbus::loop() {
|
||||||
|
|
||||||
// fire all triggers
|
// fire all triggers
|
||||||
for (auto *trigger : this->triggers_) {
|
for (auto *trigger : this->triggers_) {
|
||||||
if ((trigger->can_id_ == can_message.can_id) && (trigger->use_extended_id_ == can_message.use_extended_id)) {
|
if ((trigger->can_id_ == (can_message.can_id & trigger->can_id_mask_)) &&
|
||||||
trigger->trigger(data);
|
(trigger->use_extended_id_ == can_message.use_extended_id)) {
|
||||||
|
trigger->trigger(data, can_message.can_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,17 +116,19 @@ template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public P
|
||||||
std::vector<uint8_t> data_static_{};
|
std::vector<uint8_t> data_static_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class CanbusTrigger : public Trigger<std::vector<uint8_t>>, public Component {
|
class CanbusTrigger : public Trigger<std::vector<uint8_t>, uint32_t>, public Component {
|
||||||
friend class Canbus;
|
friend class Canbus;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const bool use_extended_id)
|
explicit CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const std::uint32_t can_id_mask,
|
||||||
: parent_(parent), can_id_(can_id), use_extended_id_(use_extended_id){};
|
const bool use_extended_id)
|
||||||
|
: parent_(parent), can_id_(can_id), can_id_mask_(can_id_mask), use_extended_id_(use_extended_id){};
|
||||||
void setup() override { this->parent_->add_trigger(this); }
|
void setup() override { this->parent_->add_trigger(this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Canbus *parent_;
|
Canbus *parent_;
|
||||||
uint32_t can_id_;
|
uint32_t can_id_;
|
||||||
|
uint32_t can_id_mask_;
|
||||||
bool use_extended_id_;
|
bool use_extended_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
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 binary_sensor
|
from esphome.components import binary_sensor
|
||||||
from esphome.const import CONF_CHANNEL, CONF_ID
|
from esphome.const import CONF_CHANNEL
|
||||||
from . import cap1188_ns, CAP1188Component, CONF_CAP1188_ID
|
from . import cap1188_ns, CAP1188Component, CONF_CAP1188_ID
|
||||||
|
|
||||||
DEPENDENCIES = ["cap1188"]
|
DEPENDENCIES = ["cap1188"]
|
||||||
CAP1188Channel = cap1188_ns.class_("CAP1188Channel", binary_sensor.BinarySensor)
|
CAP1188Channel = cap1188_ns.class_("CAP1188Channel", binary_sensor.BinarySensor)
|
||||||
|
|
||||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(CAP1188Channel).extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(CAP1188Channel),
|
|
||||||
cv.GenerateID(CONF_CAP1188_ID): cv.use_id(CAP1188Component),
|
cv.GenerateID(CONF_CAP1188_ID): cv.use_id(CAP1188Component),
|
||||||
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
|
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
|
||||||
}
|
}
|
||||||
|
@ -17,8 +16,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
await binary_sensor.register_binary_sensor(var, config)
|
|
||||||
hub = await cg.get_variable(config[CONF_CAP1188_ID])
|
hub = await cg.get_variable(config[CONF_CAP1188_ID])
|
||||||
cg.add(var.set_channel(config[CONF_CHANNEL]))
|
cg.add(var.set_channel(config[CONF_CHANNEL]))
|
||||||
|
|
||||||
|
|
107
esphome/components/captive_portal/captive_index.h
Normal file
107
esphome/components/captive_portal/captive_index.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#pragma once
|
||||||
|
// Generated from https://github.com/esphome/esphome-webserver
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
namespace esphome {
|
||||||
|
|
||||||
|
namespace captive_portal {
|
||||||
|
|
||||||
|
const uint8_t INDEX_GZ[] PROGMEM = {
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xdd, 0x58, 0x09, 0x6f, 0xdc, 0x36, 0x16, 0xfe, 0x2b,
|
||||||
|
0xac, 0x92, 0x74, 0x34, 0x8d, 0xc5, 0xd1, 0x31, 0x97, 0x35, 0xd2, 0x14, 0x89, 0x37, 0x45, 0x0b, 0x24, 0x69, 0x00,
|
||||||
|
0xbb, 0x5d, 0x14, 0x69, 0x00, 0x73, 0x24, 0x6a, 0xc4, 0x58, 0xa2, 0x54, 0x91, 0x9a, 0x23, 0x83, 0xd9, 0xdf, 0xde,
|
||||||
|
0x47, 0x52, 0x73, 0x38, 0x6b, 0x2f, 0x90, 0x62, 0x8b, 0xa2, 0x4d, 0x6c, 0x9a, 0xc7, 0x3b, 0x3f, 0xf2, 0xf1, 0x3d,
|
||||||
|
0x2a, 0xfa, 0x2a, 0xad, 0x12, 0xb9, 0xad, 0x29, 0xca, 0x65, 0x59, 0xcc, 0x23, 0xd5, 0xa2, 0x82, 0xf0, 0x65, 0x4c,
|
||||||
|
0x39, 0x8c, 0x28, 0x49, 0xe7, 0x51, 0x49, 0x25, 0x41, 0x49, 0x4e, 0x1a, 0x41, 0x65, 0xfc, 0xd3, 0xcd, 0x77, 0xce,
|
||||||
|
0x14, 0x0d, 0xe6, 0x51, 0xc1, 0xf8, 0x1d, 0x6a, 0x68, 0x11, 0xb3, 0xa4, 0xe2, 0x28, 0x6f, 0x68, 0x16, 0xa7, 0x44,
|
||||||
|
0x92, 0x90, 0x95, 0x64, 0x49, 0x15, 0x81, 0x66, 0xe3, 0xa4, 0xa4, 0xf1, 0x8a, 0xd1, 0x75, 0x5d, 0x35, 0x12, 0x01,
|
||||||
|
0xa5, 0xa4, 0x5c, 0xc6, 0xd6, 0x9a, 0xa5, 0x32, 0x8f, 0x53, 0xba, 0x62, 0x09, 0x75, 0xf4, 0xe0, 0x82, 0x71, 0x26,
|
||||||
|
0x19, 0x29, 0x1c, 0x91, 0x90, 0x82, 0xc6, 0xde, 0x45, 0x2b, 0x68, 0xa3, 0x07, 0x64, 0x01, 0x63, 0x5e, 0x59, 0x20,
|
||||||
|
0x52, 0x24, 0x0d, 0xab, 0x25, 0x52, 0xf6, 0xc6, 0x65, 0x95, 0xb6, 0x05, 0x9d, 0x67, 0x2d, 0x4f, 0x24, 0x03, 0x0b,
|
||||||
|
0x84, 0xcd, 0xfb, 0xbb, 0x82, 0x4a, 0x44, 0xe3, 0x37, 0x44, 0xe6, 0xb8, 0x24, 0x1b, 0xdb, 0x74, 0x18, 0xb7, 0xfd,
|
||||||
|
0x6f, 0x6c, 0xfe, 0xdc, 0x73, 0xdd, 0xfe, 0x85, 0x6e, 0xdc, 0xfe, 0x00, 0xfe, 0xce, 0x1a, 0x2a, 0xdb, 0x86, 0x23,
|
||||||
|
0x62, 0xdf, 0x46, 0x35, 0x50, 0xa2, 0x34, 0xb6, 0x4a, 0xcf, 0xc7, 0xae, 0x3b, 0x45, 0xde, 0x25, 0xf6, 0x47, 0x8e,
|
||||||
|
0xe7, 0xe1, 0xc0, 0xf1, 0x46, 0xc9, 0xc4, 0x19, 0x21, 0x6f, 0x08, 0x8d, 0xef, 0xe3, 0x11, 0x72, 0x3f, 0x59, 0x28,
|
||||||
|
0x63, 0x45, 0x11, 0x5b, 0xbc, 0xe2, 0xd4, 0x42, 0x42, 0x36, 0xd5, 0x1d, 0x8d, 0xad, 0xa4, 0x6d, 0x1a, 0xf0, 0xee,
|
||||||
|
0xaa, 0x2a, 0xaa, 0x06, 0xac, 0xfd, 0x95, 0xa3, 0x7b, 0xff, 0xbe, 0x58, 0x87, 0x6c, 0x08, 0x17, 0x59, 0xd5, 0x94,
|
||||||
|
0xb1, 0xa5, 0x41, 0xb1, 0x9f, 0xee, 0xe8, 0x1e, 0xa9, 0xa6, 0x7f, 0xb6, 0xe8, 0x54, 0x0d, 0x5b, 0x32, 0x1e, 0x5b,
|
||||||
|
0x9e, 0x8f, 0xbc, 0x29, 0xe8, 0xbd, 0xed, 0xef, 0x8f, 0xa0, 0x10, 0x05, 0x4a, 0xe7, 0x66, 0x65, 0xbf, 0xbf, 0x8d,
|
||||||
|
0xc4, 0x6a, 0x89, 0x36, 0x65, 0xc1, 0x45, 0x6c, 0xe5, 0x52, 0xd6, 0xe1, 0x60, 0xb0, 0x5e, 0xaf, 0xf1, 0x3a, 0xc0,
|
||||||
|
0x55, 0xb3, 0x1c, 0xf8, 0xae, 0xeb, 0x0e, 0x80, 0xc2, 0x42, 0x66, 0x7f, 0x2c, 0x7f, 0x68, 0xa1, 0x9c, 0xb2, 0x65,
|
||||||
|
0x2e, 0x75, 0x7f, 0xfe, 0x74, 0xc7, 0xf7, 0x91, 0xa2, 0x98, 0xdf, 0x7e, 0x38, 0xd3, 0xd2, 0x9c, 0x69, 0xe1, 0xdf,
|
||||||
|
0x12, 0xdb, 0x3a, 0xb8, 0xda, 0x7b, 0xa3, 0x8c, 0x9a, 0x10, 0x1f, 0xf9, 0xc8, 0xd5, 0xff, 0x7d, 0x47, 0xf5, 0xbb,
|
||||||
|
0x91, 0xf3, 0xd9, 0x08, 0x9d, 0x8d, 0xe0, 0xaf, 0x02, 0xd0, 0x2f, 0xc7, 0xce, 0xe5, 0x91, 0xdf, 0x53, 0xeb, 0x2b,
|
||||||
|
0xcf, 0x3d, 0x4d, 0x28, 0xa6, 0xef, 0xc7, 0xe7, 0x63, 0xc7, 0xff, 0x59, 0x11, 0x68, 0xf4, 0x8f, 0x5c, 0x8e, 0x9f,
|
||||||
|
0x7b, 0x3f, 0x8f, 0xc9, 0x08, 0x8d, 0xba, 0x99, 0x91, 0xa3, 0xfa, 0xc7, 0x91, 0xd6, 0x85, 0x46, 0x2b, 0x20, 0x2b,
|
||||||
|
0x9d, 0xb1, 0x33, 0x22, 0x01, 0x0a, 0x3a, 0xab, 0xa0, 0x07, 0xd3, 0x63, 0xe0, 0x3e, 0x9b, 0x73, 0x82, 0x4f, 0xbd,
|
||||||
|
0xc1, 0xdc, 0xea, 0x87, 0x96, 0x75, 0x82, 0xa1, 0x3a, 0x87, 0x01, 0x7f, 0xac, 0xe0, 0xdc, 0x59, 0x56, 0x7f, 0x6f,
|
||||||
|
0x7d, 0x2b, 0xc8, 0x8a, 0x5a, 0x71, 0x1c, 0x43, 0xa8, 0xb5, 0x25, 0x9c, 0x10, 0x5c, 0x54, 0x09, 0x51, 0x2c, 0x58,
|
||||||
|
0x50, 0xd2, 0x24, 0xf9, 0xd7, 0x5f, 0xdb, 0xc7, 0xa5, 0x25, 0x95, 0xaf, 0x0a, 0xaa, 0xba, 0xe2, 0xe5, 0xf6, 0x86,
|
||||||
|
0x2c, 0xdf, 0x42, 0x00, 0xd9, 0x16, 0x11, 0x2c, 0xa5, 0x56, 0xff, 0xbd, 0xfb, 0x01, 0x0b, 0xb9, 0x2d, 0x28, 0x4e,
|
||||||
|
0x99, 0xa8, 0x0b, 0xb2, 0x8d, 0xad, 0x05, 0xc8, 0xba, 0xb3, 0xfa, 0x17, 0x19, 0x95, 0x49, 0x6e, 0x5b, 0x03, 0x08,
|
||||||
|
0xb1, 0x8c, 0x2d, 0xf1, 0x47, 0x51, 0x71, 0xab, 0x8f, 0x65, 0x4e, 0xb9, 0x6d, 0x1f, 0x2c, 0x54, 0xf6, 0x71, 0xbd,
|
||||||
|
0x64, 0x3f, 0xb4, 0x74, 0xb4, 0x41, 0x32, 0xa9, 0x42, 0x0e, 0xab, 0xe0, 0xbd, 0x38, 0xce, 0x2e, 0xaa, 0x74, 0xfb,
|
||||||
|
0x88, 0x79, 0xb9, 0x67, 0x6c, 0x63, 0x9c, 0xd3, 0xe6, 0x86, 0x6e, 0xe0, 0xb8, 0xfc, 0x9b, 0x7d, 0xc7, 0xd0, 0x5b,
|
||||||
|
0x2a, 0xd7, 0x55, 0x73, 0x27, 0x42, 0x64, 0x3d, 0x37, 0xe2, 0x66, 0x26, 0x42, 0x39, 0x26, 0xb5, 0xc0, 0xa2, 0x80,
|
||||||
|
0xf0, 0xb7, 0xbd, 0x3e, 0xc4, 0x6a, 0x7d, 0xdf, 0x14, 0x83, 0xe2, 0x6d, 0x94, 0xb2, 0x15, 0x4a, 0x0a, 0x22, 0xe0,
|
||||||
|
0xb8, 0x72, 0x23, 0xcb, 0x42, 0x87, 0xb8, 0xaa, 0x78, 0x02, 0xfc, 0x77, 0xb1, 0xf5, 0x00, 0x76, 0x2f, 0xb7, 0x3f,
|
||||||
|
0xa4, 0x76, 0x4f, 0x00, 0x6a, 0xbd, 0x3e, 0x5e, 0x91, 0xa2, 0xa5, 0x28, 0x46, 0x32, 0x67, 0xe2, 0x64, 0xe2, 0xec,
|
||||||
|
0x51, 0xb6, 0x5a, 0xdc, 0x01, 0x57, 0x06, 0xcb, 0xc2, 0xee, 0x5b, 0xc7, 0x38, 0x8e, 0x88, 0xb9, 0xe5, 0xac, 0x27,
|
||||||
|
0xd6, 0x67, 0x36, 0x39, 0x05, 0xcd, 0xa4, 0x75, 0x16, 0xf0, 0x4f, 0x77, 0x70, 0x1b, 0xe1, 0x06, 0xf4, 0xf7, 0xf7,
|
||||||
|
0xa7, 0xd9, 0x48, 0xd4, 0x84, 0x7f, 0xce, 0xaa, 0x6c, 0xd4, 0x81, 0x85, 0x55, 0x4f, 0x45, 0x17, 0x10, 0x9d, 0x74,
|
||||||
|
0x0e, 0xc8, 0xb1, 0xff, 0x74, 0x07, 0x71, 0xa6, 0x8e, 0xce, 0xdd, 0x49, 0x68, 0x34, 0x00, 0x84, 0xe6, 0xb7, 0xfb,
|
||||||
|
0x7e, 0xff, 0xe4, 0xce, 0x6f, 0x2d, 0x6d, 0xb6, 0xd7, 0xb4, 0xa0, 0x89, 0xac, 0x1a, 0xdb, 0x7a, 0x02, 0x9a, 0xe0,
|
||||||
|
0x24, 0x68, 0xbf, 0xbf, 0xbf, 0x79, 0xf3, 0x3a, 0xae, 0x6c, 0xda, 0xbf, 0x78, 0x8c, 0x5a, 0xdd, 0xea, 0xef, 0xe1,
|
||||||
|
0x56, 0xff, 0x4f, 0xdc, 0x53, 0xf7, 0x7a, 0xef, 0x03, 0xb0, 0x1a, 0xaf, 0x4f, 0x97, 0xbb, 0xba, 0x00, 0x9e, 0xc3,
|
||||||
|
0x25, 0x72, 0x61, 0x3d, 0x17, 0xb6, 0x33, 0x1e, 0xf5, 0x41, 0x3d, 0xfc, 0x80, 0xe9, 0xfa, 0x7a, 0x86, 0x6b, 0x5a,
|
||||||
|
0x1d, 0xd1, 0xf9, 0x37, 0xbb, 0x45, 0xb5, 0x71, 0x04, 0xfb, 0xc4, 0xf8, 0x32, 0x64, 0x3c, 0xa7, 0x0d, 0x93, 0x7b,
|
||||||
|
0x30, 0x17, 0x6e, 0xfa, 0xba, 0x95, 0xbb, 0x9a, 0xa4, 0xa9, 0x5a, 0x19, 0xd5, 0x9b, 0x59, 0x06, 0x79, 0x41, 0x51,
|
||||||
|
0xd2, 0xd0, 0xa3, 0xe5, 0xde, 0xac, 0xeb, 0x2b, 0x28, 0xbc, 0x1c, 0x3d, 0xdb, 0xab, 0x83, 0xb7, 0x93, 0xb0, 0x65,
|
||||||
|
0x0e, 0x29, 0xd8, 0x92, 0x87, 0x09, 0xd8, 0x4d, 0x1b, 0xc3, 0x94, 0x91, 0x92, 0x15, 0xdb, 0x50, 0xc0, 0x65, 0xe8,
|
||||||
|
0x40, 0xc2, 0x60, 0xd9, 0x7e, 0xd1, 0x4a, 0x59, 0x71, 0xd0, 0xdd, 0xa4, 0xb4, 0x09, 0xdd, 0x99, 0xe9, 0x38, 0x0d,
|
||||||
|
0x49, 0x59, 0x2b, 0x42, 0x1c, 0x34, 0xb4, 0x9c, 0x2d, 0x48, 0x72, 0xb7, 0x6c, 0xaa, 0x96, 0xa7, 0x4e, 0xa2, 0x6e,
|
||||||
|
0xeb, 0xf0, 0x89, 0x97, 0x91, 0x80, 0x26, 0xb3, 0x6e, 0x94, 0x65, 0xd9, 0x0c, 0x90, 0xa0, 0x8e, 0xb9, 0xfc, 0x42,
|
||||||
|
0x1f, 0x0f, 0x15, 0xdb, 0x99, 0x99, 0xd8, 0x57, 0x13, 0xc6, 0x46, 0x48, 0x25, 0xcf, 0x66, 0x07, 0x77, 0xdc, 0x19,
|
||||||
|
0xa4, 0x01, 0x01, 0x42, 0x6a, 0x88, 0x7f, 0x30, 0x73, 0x5f, 0x12, 0xc6, 0xcf, 0xad, 0x57, 0x67, 0x65, 0xd6, 0x85,
|
||||||
|
0x2f, 0xc0, 0xa2, 0xd5, 0xe8, 0x20, 0x9e, 0x41, 0xa2, 0x32, 0xb9, 0x30, 0xf4, 0xc7, 0x6e, 0xbd, 0xd9, 0xe3, 0xee,
|
||||||
|
0x8c, 0xec, 0x0e, 0xd4, 0x59, 0x41, 0x37, 0xb3, 0x8f, 0xad, 0x90, 0x2c, 0xdb, 0x3a, 0x5d, 0x2e, 0x0d, 0xe1, 0xbc,
|
||||||
|
0x40, 0x0e, 0x5d, 0x00, 0x29, 0xa5, 0x7c, 0xa6, 0x75, 0x38, 0x4c, 0xd2, 0x52, 0x74, 0x38, 0x1d, 0xc5, 0xe8, 0x53,
|
||||||
|
0x7a, 0x5f, 0xd6, 0xff, 0xa2, 0x56, 0xc7, 0x71, 0x57, 0x92, 0x06, 0x72, 0x8b, 0xb3, 0xa8, 0x00, 0xd3, 0x32, 0x74,
|
||||||
|
0x26, 0xb0, 0x57, 0xdd, 0x94, 0x12, 0x06, 0x9e, 0x83, 0x99, 0xfa, 0x6e, 0x3a, 0xe0, 0xed, 0xd5, 0x1b, 0x24, 0xaa,
|
||||||
|
0x82, 0xa5, 0x1d, 0x9d, 0x26, 0x41, 0xee, 0x11, 0x1e, 0x0f, 0xb6, 0x1b, 0xa9, 0xb9, 0x03, 0xd4, 0xc3, 0x6c, 0x4a,
|
||||||
|
0x3c, 0xf7, 0x81, 0x1d, 0x49, 0xb3, 0xcc, 0x5f, 0x64, 0x47, 0xa4, 0x54, 0xaa, 0xdd, 0xb3, 0xee, 0x54, 0xf8, 0x43,
|
||||||
|
0x10, 0x70, 0xd8, 0x1b, 0xe8, 0xef, 0x99, 0x8e, 0x8b, 0xdd, 0x99, 0x14, 0x7d, 0x52, 0xc3, 0xb6, 0x29, 0xec, 0x87,
|
||||||
|
0x4e, 0xee, 0xb3, 0xe0, 0xea, 0x94, 0x09, 0x7b, 0x8f, 0x67, 0xc2, 0x1e, 0x52, 0xb5, 0xcb, 0xcb, 0x6a, 0x13, 0xf7,
|
||||||
|
0x74, 0x4e, 0x1a, 0xc2, 0x4f, 0xef, 0x59, 0xf0, 0x0a, 0xf8, 0xff, 0x2f, 0x29, 0xee, 0x0f, 0xa7, 0xb7, 0x2f, 0x48,
|
||||||
|
0x6d, 0x5f, 0x98, 0xd5, 0x8c, 0x77, 0xca, 0x79, 0xe8, 0x41, 0xfa, 0x62, 0x58, 0xb0, 0xa5, 0xf7, 0x67, 0x40, 0xfb,
|
||||||
|
0xdf, 0x38, 0x06, 0x2f, 0xbc, 0x29, 0xbe, 0x44, 0xba, 0x31, 0x10, 0xe1, 0x60, 0x8a, 0x26, 0x57, 0x43, 0x3c, 0xf4,
|
||||||
|
0x90, 0xaa, 0x9a, 0xc6, 0x68, 0x82, 0xa7, 0x40, 0x30, 0xc6, 0xc1, 0x04, 0x26, 0x90, 0xef, 0xe1, 0xd1, 0x6b, 0x3f,
|
||||||
|
0xc0, 0xe3, 0x11, 0x50, 0xf9, 0x2e, 0x0e, 0x7c, 0x64, 0x68, 0xc7, 0xd8, 0x07, 0x71, 0x8a, 0x24, 0x28, 0x01, 0xe8,
|
||||||
|
0x24, 0xc0, 0xee, 0x04, 0xc4, 0x8d, 0xb1, 0x7b, 0x89, 0xa7, 0x63, 0x34, 0xc5, 0x13, 0x80, 0x0e, 0x0f, 0x47, 0x85,
|
||||||
|
0x33, 0xc2, 0x1e, 0x4c, 0x07, 0x63, 0x32, 0xc5, 0xc3, 0x00, 0xe9, 0xc6, 0xc0, 0x31, 0x01, 0x11, 0x0e, 0x76, 0xbd,
|
||||||
|
0xd7, 0x01, 0xf6, 0x27, 0xa0, 0x77, 0x38, 0x7c, 0x01, 0x62, 0x2f, 0x87, 0xc8, 0xb4, 0x06, 0x5e, 0x50, 0x30, 0x7a,
|
||||||
|
0x0c, 0x34, 0xff, 0x9f, 0x0b, 0x1a, 0x40, 0xe2, 0xa1, 0x00, 0x5f, 0x42, 0xec, 0x7a, 0x8a, 0xdf, 0xb4, 0x06, 0x37,
|
||||||
|
0xcf, 0x43, 0xee, 0x1f, 0xc6, 0x2c, 0xf8, 0xe7, 0x62, 0xe6, 0x29, 0x04, 0xa0, 0x0b, 0xba, 0x41, 0x0e, 0xd2, 0x8d,
|
||||||
|
0xd1, 0x0d, 0xcc, 0xd3, 0xab, 0x4b, 0x34, 0x05, 0xae, 0xf1, 0x14, 0x5d, 0xa2, 0x91, 0x42, 0x17, 0xd8, 0x87, 0x86,
|
||||||
|
0xc9, 0x01, 0xa6, 0x2f, 0x84, 0x71, 0xf8, 0x37, 0x86, 0xf1, 0x31, 0x9f, 0xfe, 0xc6, 0x2e, 0xfd, 0x15, 0x57, 0x10,
|
||||||
|
0x94, 0x63, 0xba, 0x0c, 0x8b, 0x06, 0xe6, 0x15, 0xaf, 0xaa, 0x28, 0x78, 0x94, 0x43, 0x35, 0x02, 0xef, 0x7a, 0x0f,
|
||||||
|
0xb1, 0x34, 0xce, 0xbd, 0xf9, 0xbd, 0x2a, 0x1d, 0x28, 0xbd, 0x79, 0xa4, 0xd3, 0xf9, 0xfc, 0x26, 0xa7, 0xe8, 0xd5,
|
||||||
|
0xf5, 0x3b, 0x78, 0x08, 0x16, 0x05, 0xe2, 0xd5, 0x1a, 0xde, 0x9b, 0x5b, 0x24, 0x2b, 0xf5, 0x82, 0xe7, 0x50, 0x2a,
|
||||||
|
0xaa, 0x2e, 0x3c, 0x20, 0x50, 0x57, 0x2c, 0x60, 0x8c, 0xa3, 0x45, 0x33, 0x7f, 0x57, 0x50, 0x22, 0x28, 0x5a, 0xb2,
|
||||||
|
0x15, 0x45, 0x4c, 0x42, 0x1d, 0x50, 0x52, 0x24, 0x99, 0x6a, 0x8e, 0x8c, 0x9a, 0xee, 0x6d, 0x25, 0x69, 0x88, 0xae,
|
||||||
|
0xaa, 0x7a, 0xab, 0x85, 0x24, 0x39, 0xe1, 0x4b, 0x9a, 0x1e, 0x84, 0x29, 0xea, 0x6d, 0xd5, 0x36, 0xe8, 0x97, 0x17,
|
||||||
|
0x6f, 0x5e, 0xab, 0x87, 0x36, 0x45, 0x4e, 0xa7, 0x6c, 0x23, 0xd1, 0x8f, 0x37, 0x2f, 0x50, 0x5b, 0xc3, 0xa6, 0x53,
|
||||||
|
0x63, 0x5b, 0xb5, 0xa2, 0xcd, 0x1a, 0x2a, 0x4b, 0xaa, 0x48, 0x40, 0xb9, 0xa0, 0x52, 0x42, 0xa1, 0x21, 0x30, 0x94,
|
||||||
|
0xce, 0xda, 0x13, 0x53, 0x75, 0x83, 0xbb, 0x20, 0x7e, 0xde, 0x95, 0xd7, 0x51, 0x1e, 0x18, 0xd7, 0xaf, 0x3b, 0x6a,
|
||||||
|
0x70, 0x3d, 0x98, 0x47, 0xea, 0x39, 0x8d, 0x88, 0x7e, 0x84, 0xc4, 0x83, 0x35, 0xcb, 0x98, 0x7a, 0xb8, 0xcd, 0x23,
|
||||||
|
0x5d, 0x8f, 0x2a, 0x09, 0xaa, 0x24, 0x32, 0x5f, 0x34, 0x74, 0xaf, 0xa0, 0x7c, 0x09, 0xaf, 0x64, 0xd8, 0x70, 0xa8,
|
||||||
|
0x50, 0x12, 0x9a, 0x57, 0x05, 0x54, 0x40, 0xf1, 0xf5, 0xf5, 0x0f, 0xff, 0x52, 0x9f, 0x3f, 0xc0, 0xcf, 0x13, 0x27,
|
||||||
|
0x3c, 0x29, 0x0c, 0xa3, 0xea, 0x74, 0x7c, 0xe3, 0xa1, 0xf9, 0x90, 0x51, 0xc3, 0x7b, 0x00, 0xfc, 0x4e, 0xef, 0x49,
|
||||||
|
0x79, 0x77, 0x98, 0xec, 0x24, 0xe9, 0x5f, 0x5d, 0xd9, 0x1a, 0x26, 0xd1, 0x2e, 0x4a, 0x26, 0xe7, 0xd7, 0x60, 0x60,
|
||||||
|
0x34, 0x30, 0x0b, 0xe0, 0x9c, 0x72, 0xc0, 0xd0, 0xe6, 0x1d, 0x0f, 0xec, 0xa8, 0x42, 0xec, 0x27, 0x8d, 0x98, 0xd9,
|
||||||
|
0x60, 0xed, 0x65, 0x49, 0x65, 0x5e, 0xa5, 0xf1, 0xbb, 0x1f, 0xaf, 0x6f, 0x8e, 0x1e, 0x77, 0xb0, 0x52, 0x9e, 0x98,
|
||||||
|
0x0f, 0x2c, 0x6d, 0x21, 0x59, 0x4d, 0x1a, 0xa9, 0xc5, 0x3a, 0x2a, 0xce, 0x0e, 0x1e, 0xe9, 0x75, 0xbd, 0x33, 0xda,
|
||||||
|
0xa9, 0x8e, 0x71, 0x30, 0x47, 0x0f, 0xd9, 0x78, 0xd0, 0xfd, 0x99, 0x95, 0x03, 0x73, 0x14, 0x07, 0xe6, 0x5c, 0x0e,
|
||||||
|
0xf4, 0xe7, 0xa7, 0xdf, 0x01, 0xf1, 0x69, 0xfc, 0xac, 0x8e, 0x12, 0x00, 0x00};
|
||||||
|
|
||||||
|
} // namespace captive_portal
|
||||||
|
} // namespace esphome
|
|
@ -4,60 +4,27 @@
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/components/wifi/wifi_component.h"
|
#include "esphome/components/wifi/wifi_component.h"
|
||||||
|
#include "captive_index.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace captive_portal {
|
namespace captive_portal {
|
||||||
|
|
||||||
static const char *const TAG = "captive_portal";
|
static const char *const TAG = "captive_portal";
|
||||||
|
|
||||||
void CaptivePortal::handle_index(AsyncWebServerRequest *request) {
|
void CaptivePortal::handle_config(AsyncWebServerRequest *request) {
|
||||||
AsyncResponseStream *stream = request->beginResponseStream("text/html");
|
AsyncResponseStream *stream = request->beginResponseStream("application/json");
|
||||||
stream->print(F("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" "
|
stream->addHeader("cache-control", "public, max-age=0, must-revalidate");
|
||||||
"content=\"width=device-width,initial-scale=1,user-scalable=no\"/><title>"));
|
stream->printf(R"({"name":"%s","aps":[{})", App.get_name().c_str());
|
||||||
stream->print(App.get_name().c_str());
|
|
||||||
stream->print(F("</title><link rel=\"stylesheet\" href=\"/stylesheet.css\">"));
|
|
||||||
stream->print(F("<script>function c(l){document.getElementById('ssid').value=l.innerText||l.textContent; "
|
|
||||||
"document.getElementById('psk').focus();}</script>"));
|
|
||||||
stream->print(F("</head>"));
|
|
||||||
stream->print(F("<body><div class=\"main\"><h1>WiFi Networks</h1>"));
|
|
||||||
|
|
||||||
if (request->hasArg("save")) {
|
|
||||||
stream->print(F("<div class=\"info\">The ESP will now try to connect to the network...<br/>Please give it some "
|
|
||||||
"time to connect.<br/>Note: Copy the changed network to your YAML file - the next OTA update will "
|
|
||||||
"overwrite these settings.</div>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &scan : wifi::global_wifi_component->get_scan_result()) {
|
for (auto &scan : wifi::global_wifi_component->get_scan_result()) {
|
||||||
if (scan.get_is_hidden())
|
if (scan.get_is_hidden())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
stream->print(F("<div class=\"network\" onclick=\"c(this)\"><a href=\"#\" class=\"network-left\">"));
|
// Assumes no " in ssid, possible unicode isses?
|
||||||
|
stream->printf(R"(,{"ssid":"%s","rssi":%d,"lock":%d})", scan.get_ssid().c_str(), scan.get_rssi(),
|
||||||
if (scan.get_rssi() >= -50) {
|
scan.get_with_auth());
|
||||||
stream->print(F("<img src=\"/wifi-strength-4.svg\">"));
|
|
||||||
} else if (scan.get_rssi() >= -65) {
|
|
||||||
stream->print(F("<img src=\"/wifi-strength-3.svg\">"));
|
|
||||||
} else if (scan.get_rssi() >= -85) {
|
|
||||||
stream->print(F("<img src=\"/wifi-strength-2.svg\">"));
|
|
||||||
} else {
|
|
||||||
stream->print(F("<img src=\"/wifi-strength-1.svg\">"));
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->print(F("<span class=\"network-ssid\">"));
|
|
||||||
stream->print(scan.get_ssid().c_str());
|
|
||||||
stream->print(F("</span></a>"));
|
|
||||||
if (scan.get_with_auth()) {
|
|
||||||
stream->print(F("<img src=\"/lock.svg\">"));
|
|
||||||
}
|
|
||||||
stream->print(F("</div>"));
|
|
||||||
}
|
}
|
||||||
|
stream->print(F("]}"));
|
||||||
stream->print(F("<h3>WiFi Settings</h3><form method=\"GET\" action=\"/wifisave\"><input id=\"ssid\" name=\"ssid\" "
|
|
||||||
"length=32 placeholder=\"SSID\"><br/><input id=\"psk\" name=\"psk\" length=64 type=\"password\" "
|
|
||||||
"placeholder=\"Password\"><br/><br/><button type=\"submit\">Save</button></form><br><hr><br>"));
|
|
||||||
stream->print(F("<h1>OTA Update</h1><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
|
|
||||||
"type=\"file\" name=\"update\"><button type=\"submit\">Update</button></form>"));
|
|
||||||
stream->print(F("</div></body></html>"));
|
|
||||||
request->send(stream);
|
request->send(stream);
|
||||||
}
|
}
|
||||||
void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
||||||
|
@ -68,7 +35,7 @@ void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
||||||
ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str());
|
ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str());
|
||||||
wifi::global_wifi_component->save_wifi_sta(ssid, psk);
|
wifi::global_wifi_component->save_wifi_sta(ssid, psk);
|
||||||
wifi::global_wifi_component->start_scanning();
|
wifi::global_wifi_component->start_scanning();
|
||||||
request->redirect("/?save=true");
|
request->redirect("/?save");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CaptivePortal::setup() {}
|
void CaptivePortal::setup() {}
|
||||||
|
@ -98,44 +65,21 @@ void CaptivePortal::start() {
|
||||||
this->active_ = true;
|
this->active_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char STYLESHEET_CSS[] PROGMEM =
|
|
||||||
R"(*{box-sizing:inherit}div,input{padding:5px;font-size:1em}input{width:95%}body{text-align:center;font-family:sans-serif}button{border:0;border-radius:.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;padding:0}.main{text-align:left;display:inline-block;min-width:260px}.network{display:flex;justify-content:space-between;align-items:center}.network-left{display:flex;align-items:center}.network-ssid{margin-bottom:-7px;margin-left:10px}.info{border:1px solid;margin:10px 0;padding:15px 10px;color:#4f8a10;background-color:#dff2bf})";
|
|
||||||
const char LOCK_SVG[] PROGMEM =
|
|
||||||
R"(<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M12 17a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2 2 2 0 0 0 2 2m6-9a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2h1V6a5 5 0 0 1 5-5 5 5 0 0 1 5 5v2h1m-6-5a3 3 0 0 0-3 3v2h6V6a3 3 0 0 0-3-3z"/></svg>)";
|
|
||||||
|
|
||||||
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
||||||
if (req->url() == "/") {
|
if (req->url() == "/") {
|
||||||
this->handle_index(req);
|
AsyncWebServerResponse *response = req->beginResponse_P(200, "text/html", INDEX_GZ, sizeof(INDEX_GZ));
|
||||||
|
response->addHeader("Content-Encoding", "gzip");
|
||||||
|
req->send(response);
|
||||||
|
return;
|
||||||
|
} else if (req->url() == "/config.json") {
|
||||||
|
this->handle_config(req);
|
||||||
return;
|
return;
|
||||||
} else if (req->url() == "/wifisave") {
|
} else if (req->url() == "/wifisave") {
|
||||||
this->handle_wifisave(req);
|
this->handle_wifisave(req);
|
||||||
return;
|
return;
|
||||||
} else if (req->url() == "/stylesheet.css") {
|
|
||||||
req->send_P(200, "text/css", STYLESHEET_CSS);
|
|
||||||
return;
|
|
||||||
} else if (req->url() == "/lock.svg") {
|
|
||||||
req->send_P(200, "image/svg+xml", LOCK_SVG);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncResponseStream *stream = req->beginResponseStream("image/svg+xml");
|
|
||||||
stream->print(F("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\"><path d=\"M12 3A18.9 18.9 0 0 "
|
|
||||||
"0 .38 7C4.41 12.06 7.89 16.37 12 21.5L23.65 7C20.32 4.41 16.22 3 12 "));
|
|
||||||
if (req->url() == "/wifi-strength-4.svg") {
|
|
||||||
stream->print(F("3z"));
|
|
||||||
} else {
|
|
||||||
if (req->url() == "/wifi-strength-1.svg") {
|
|
||||||
stream->print(F("3m0 2c3.07 0 6.09.86 8.71 2.45l-5.1 6.36a8.43 8.43 0 0 0-7.22-.01L3.27 7.4"));
|
|
||||||
} else if (req->url() == "/wifi-strength-2.svg") {
|
|
||||||
stream->print(F("3m0 2c3.07 0 6.09.86 8.71 2.45l-3.21 3.98a11.32 11.32 0 0 0-11 0L3.27 7.4"));
|
|
||||||
} else if (req->url() == "/wifi-strength-3.svg") {
|
|
||||||
stream->print(F("3m0 2c3.07 0 6.09.86 8.71 2.45l-1.94 2.43A13.6 13.6 0 0 0 12 8C9 8 6.68 9 5.21 9.84l-1.94-2."));
|
|
||||||
}
|
|
||||||
stream->print(F("4A16.94 16.94 0 0 1 12 5z"));
|
|
||||||
}
|
|
||||||
stream->print(F("\"/></svg>"));
|
|
||||||
req->send(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptivePortal::CaptivePortal(web_server_base::WebServerBase *base) : base_(base) { global_captive_portal = this; }
|
CaptivePortal::CaptivePortal(web_server_base::WebServerBase *base) : base_(base) { global_captive_portal = this; }
|
||||||
float CaptivePortal::get_setup_priority() const {
|
float CaptivePortal::get_setup_priority() const {
|
||||||
// Before WiFi
|
// Before WiFi
|
||||||
|
|
|
@ -58,7 +58,7 @@ class CaptivePortal : public AsyncWebHandler, public Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_index(AsyncWebServerRequest *request);
|
void handle_config(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
void handle_wifisave(AsyncWebServerRequest *request);
|
void handle_wifisave(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
<!-- HTTP_HEAD -->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
|
||||||
<title>{{ App.get_name() }}</title>
|
|
||||||
<link rel="stylesheet" href="./stylesheet.css">
|
|
||||||
<script>
|
|
||||||
function c(l) {
|
|
||||||
document.getElementById('ssid').value = l.innerText || l.textContent;
|
|
||||||
document.getElementById('psk').focus();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main">
|
|
||||||
<h1>WiFi Networks</h1>
|
|
||||||
<div class="info">
|
|
||||||
The ESP will now try to connect to the network...<br/>
|
|
||||||
Please give it some time to connect.<br/>
|
|
||||||
Note: Copy the changed network to your YAML file - the next OTA update will overwrite these settings.
|
|
||||||
</div>
|
|
||||||
<div class="network" onclick="c(this)">
|
|
||||||
<a href="#" class="network-left">
|
|
||||||
<img src="./wifi-strength-4.svg">
|
|
||||||
<span class="network-ssid">AP1</span>
|
|
||||||
</a>
|
|
||||||
<img src="./lock.svg">
|
|
||||||
</div>
|
|
||||||
<div class="network" onclick="c(this)">
|
|
||||||
<a href="#" class="network-left">
|
|
||||||
<img src="./wifi-strength-2.svg">
|
|
||||||
<span class="network-ssid">AP2</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>WiFi Settings</h3>
|
|
||||||
<form method="GET" action="/wifisave">
|
|
||||||
<input id="ssid" name="ssid" length=32 placeholder="SSID"><br/>
|
|
||||||
<input id="psk" name="psk" length=64 type="password" placeholder="Password"><br/>
|
|
||||||
<br/>
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
<br><hr>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h1>OTA Update</h1>
|
|
||||||
<form method="POST" action="/update" enctype="multipart/form-data">
|
|
||||||
<input type="file" name="update">
|
|
||||||
<button type="submit">Update</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M12 17a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2 2 2 0 0 0 2 2m6-9a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2h1V6a5 5 0 0 1 5-5 5 5 0 0 1 5 5v2h1m-6-5a3 3 0 0 0-3 3v2h6V6a3 3 0 0 0-3-3z"/></svg>
|
|
Before Width: | Height: | Size: 307 B |
|
@ -1,58 +0,0 @@
|
||||||
* {
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
div, input {
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
text-align: center;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0.3rem;
|
|
||||||
background-color: #1fa3ec;
|
|
||||||
color: #fff;
|
|
||||||
line-height: 2.4rem;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
text-align: left;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 260px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-ssid {
|
|
||||||
margin-bottom: -7px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
border: 1px solid;
|
|
||||||
margin: 10px 0px;
|
|
||||||
padding: 15px 10px;
|
|
||||||
color: #4f8a10;
|
|
||||||
background-color: #dff2bf;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M12 3A18.9 18.9 0 0 0 .38 7C4.41 12.06 7.89 16.37 12 21.5L23.65 7C20.32 4.41 16.22 3 12 3m0 2c3.07 0 6.09.86 8.71 2.45l-5.1 6.36a8.43 8.43 0 0 0-7.22-.01L3.27 7.44A16.94 16.94 0 0 1 12 5z"/></svg>
|
|
Before Width: | Height: | Size: 268 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M12 3A18.9 18.9 0 0 0 .38 7C4.41 12.06 7.89 16.37 12 21.5L23.65 7C20.32 4.41 16.22 3 12 3m0 2c3.07 0 6.09.86 8.71 2.45l-3.21 3.98a11.32 11.32 0 0 0-11 0L3.27 7.44A16.94 16.94 0 0 1 12 5z"/></svg>
|
|
Before Width: | Height: | Size: 267 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M12 3A18.9 18.9 0 0 0 .38 7C4.41 12.06 7.89 16.37 12 21.5L23.65 7C20.32 4.41 16.22 3 12 3m0 2c3.07 0 6.09.86 8.71 2.45l-1.94 2.43A13.6 13.6 0 0 0 12 8C9 8 6.68 9 5.21 9.84l-1.94-2.4A16.94 16.94 0 0 1 12 5z"/></svg>
|
|
Before Width: | Height: | Size: 286 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M12 3A18.9 18.9 0 0 0 .38 7C4.41 12.06 7.89 16.37 12 21.5L23.65 7C20.32 4.41 16.22 3 12 3z"/></svg>
|
|
Before Width: | Height: | Size: 171 B |
|
@ -25,6 +25,7 @@ CONF_CD74HC4067_ID = "cd74hc4067_id"
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
CD74HC4067Sensor,
|
||||||
unit_of_measurement=UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
accuracy_decimals=3,
|
accuracy_decimals=3,
|
||||||
device_class=DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
|
@ -33,7 +34,6 @@ CONFIG_SCHEMA = (
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(CD74HC4067Sensor),
|
|
||||||
cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component),
|
cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component),
|
||||||
cv.Required(CONF_NUMBER): cv.int_range(0, 15),
|
cv.Required(CONF_NUMBER): cv.int_range(0, 15),
|
||||||
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
|
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
|
||||||
|
@ -47,8 +47,8 @@ async def to_code(config):
|
||||||
parent = await cg.get_variable(config[CONF_CD74HC4067_ID])
|
parent = await cg.get_variable(config[CONF_CD74HC4067_ID])
|
||||||
|
|
||||||
var = cg.new_Pvariable(config[CONF_ID], parent)
|
var = cg.new_Pvariable(config[CONF_ID], parent)
|
||||||
await cg.register_component(var, config)
|
|
||||||
await sensor.register_sensor(var, config)
|
await sensor.register_sensor(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
cg.add(var.set_pin(config[CONF_NUMBER]))
|
cg.add(var.set_pin(config[CONF_NUMBER]))
|
||||||
|
|
||||||
sens = await cg.get_variable(config[CONF_SENSOR])
|
sens = await cg.get_variable(config[CONF_SENSOR])
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "climate.h"
|
#include "climate.h"
|
||||||
|
#include "esphome/core/macros.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace climate {
|
namespace climate {
|
||||||
|
@ -326,14 +327,17 @@ optional<ClimateDeviceRestoreState> Climate::restore_state_() {
|
||||||
return recovered;
|
return recovered;
|
||||||
}
|
}
|
||||||
void Climate::save_state_() {
|
void Climate::save_state_() {
|
||||||
#if defined(USE_ESP_IDF) && !defined(CLANG_TIDY)
|
#if (defined(USE_ESP_IDF) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0))) && \
|
||||||
|
!defined(CLANG_TIDY)
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||||
|
#define TEMP_IGNORE_MEMACCESS
|
||||||
#endif
|
#endif
|
||||||
ClimateDeviceRestoreState state{};
|
ClimateDeviceRestoreState state{};
|
||||||
// initialize as zero to prevent random data on stack triggering erase
|
// initialize as zero to prevent random data on stack triggering erase
|
||||||
memset(&state, 0, sizeof(ClimateDeviceRestoreState));
|
memset(&state, 0, sizeof(ClimateDeviceRestoreState));
|
||||||
#if USE_ESP_IDF && !defined(CLANG_TIDY)
|
#ifdef TEMP_IGNORE_MEMACCESS
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#undef TEMP_IGNORE_MEMACCESS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
state.mode = this->mode;
|
state.mode = this->mode;
|
||||||
|
|
|
@ -141,7 +141,7 @@ class ClimateTraits {
|
||||||
}
|
}
|
||||||
bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); }
|
bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); }
|
||||||
bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); }
|
bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); }
|
||||||
std::set<ClimateSwingMode> get_supported_swing_modes() { return supported_swing_modes_; }
|
std::set<ClimateSwingMode> get_supported_swing_modes() const { return supported_swing_modes_; }
|
||||||
|
|
||||||
float get_visual_min_temperature() const { return visual_min_temperature_; }
|
float get_visual_min_temperature() const { return visual_min_temperature_; }
|
||||||
void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; }
|
void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; }
|
||||||
|
|
5
esphome/components/copy/__init__.py
Normal file
5
esphome/components/copy/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
CODEOWNERS = ["@OttoWinter"]
|
||||||
|
|
||||||
|
copy_ns = cg.esphome_ns.namespace("copy")
|
41
esphome/components/copy/binary_sensor/__init__.py
Normal file
41
esphome/components/copy/binary_sensor/__init__.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import binary_sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyBinarySensor = copy_ns.class_(
|
||||||
|
"CopyBinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
binary_sensor.binary_sensor_schema(CopyBinarySensor)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(binary_sensor.BinarySensor),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_DEVICE_CLASS, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
18
esphome/components/copy/binary_sensor/copy_binary_sensor.cpp
Normal file
18
esphome/components/copy/binary_sensor/copy_binary_sensor.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "copy_binary_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.binary_sensor";
|
||||||
|
|
||||||
|
void CopyBinarySensor::setup() {
|
||||||
|
source_->add_on_state_callback([this](bool value) { this->publish_state(value); });
|
||||||
|
if (source_->has_state())
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Copy Binary Sensor", this); }
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
21
esphome/components/copy/binary_sensor/copy_binary_sensor.h
Normal file
21
esphome/components/copy/binary_sensor/copy_binary_sensor.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyBinarySensor : public binary_sensor::BinarySensor, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(binary_sensor::BinarySensor *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binary_sensor::BinarySensor *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
42
esphome/components/copy/button/__init__.py
Normal file
42
esphome/components/copy/button/__init__.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import button
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyButton = copy_ns.class_("CopyButton", button.Button, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
button.button_schema()
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopyButton),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(button.Button),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_DEVICE_CLASS, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await button.register_button(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
14
esphome/components/copy/button/copy_button.cpp
Normal file
14
esphome/components/copy/button/copy_button.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "copy_button.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.button";
|
||||||
|
|
||||||
|
void CopyButton::dump_config() { LOG_BUTTON("", "Copy Button", this); }
|
||||||
|
|
||||||
|
void CopyButton::press_action() { source_->press(); }
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
22
esphome/components/copy/button/copy_button.h
Normal file
22
esphome/components/copy/button/copy_button.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/button/button.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyButton : public button::Button, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(button::Button *source) { source_ = source; }
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void press_action() override;
|
||||||
|
|
||||||
|
button::Button *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
38
esphome/components/copy/cover/__init__.py
Normal file
38
esphome/components/copy/cover/__init__.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import cover
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyCover = copy_ns.class_("CopyCover", cover.Cover, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopyCover),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(cover.Cover),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_DEVICE_CLASS, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cover.register_cover(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
50
esphome/components/copy/cover/copy_cover.cpp
Normal file
50
esphome/components/copy/cover/copy_cover.cpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include "copy_cover.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.cover";
|
||||||
|
|
||||||
|
void CopyCover::setup() {
|
||||||
|
source_->add_on_state_callback([this]() {
|
||||||
|
this->current_operation = this->source_->current_operation;
|
||||||
|
this->position = this->source_->position;
|
||||||
|
this->tilt = this->source_->tilt;
|
||||||
|
this->publish_state();
|
||||||
|
});
|
||||||
|
|
||||||
|
this->current_operation = this->source_->current_operation;
|
||||||
|
this->position = this->source_->position;
|
||||||
|
this->tilt = this->source_->tilt;
|
||||||
|
this->publish_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyCover::dump_config() { LOG_COVER("", "Copy Cover", this); }
|
||||||
|
|
||||||
|
cover::CoverTraits CopyCover::get_traits() {
|
||||||
|
auto base = source_->get_traits();
|
||||||
|
cover::CoverTraits traits{};
|
||||||
|
// copy traits manually so it doesn't break when new options are added
|
||||||
|
// but the control() method hasn't implemented them yet.
|
||||||
|
traits.set_is_assumed_state(base.get_is_assumed_state());
|
||||||
|
traits.set_supports_position(base.get_supports_position());
|
||||||
|
traits.set_supports_tilt(base.get_supports_tilt());
|
||||||
|
traits.set_supports_toggle(base.get_supports_toggle());
|
||||||
|
return traits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyCover::control(const cover::CoverCall &call) {
|
||||||
|
auto call2 = source_->make_call();
|
||||||
|
call2.set_stop(call.get_stop());
|
||||||
|
if (call.get_tilt().has_value())
|
||||||
|
call2.set_tilt(*call.get_tilt());
|
||||||
|
if (call.get_position().has_value())
|
||||||
|
call2.set_position(*call.get_position());
|
||||||
|
if (call.get_tilt().has_value())
|
||||||
|
call2.set_tilt(*call.get_tilt());
|
||||||
|
call2.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
25
esphome/components/copy/cover/copy_cover.h
Normal file
25
esphome/components/copy/cover/copy_cover.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/cover/cover.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyCover : public cover::Cover, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(cover::Cover *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
cover::CoverTraits get_traits() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const cover::CoverCall &call) override;
|
||||||
|
|
||||||
|
cover::Cover *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
36
esphome/components/copy/fan/__init__.py
Normal file
36
esphome/components/copy/fan/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import fan
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyFan = copy_ns.class_("CopyFan", fan.Fan, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopyFan),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(fan.Fan),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await fan.register_fan(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
53
esphome/components/copy/fan/copy_fan.cpp
Normal file
53
esphome/components/copy/fan/copy_fan.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include "copy_fan.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.fan";
|
||||||
|
|
||||||
|
void CopyFan::setup() {
|
||||||
|
source_->add_on_state_callback([this]() {
|
||||||
|
this->state = source_->state;
|
||||||
|
this->oscillating = source_->oscillating;
|
||||||
|
this->speed = source_->speed;
|
||||||
|
this->direction = source_->direction;
|
||||||
|
this->publish_state();
|
||||||
|
});
|
||||||
|
|
||||||
|
this->state = source_->state;
|
||||||
|
this->oscillating = source_->oscillating;
|
||||||
|
this->speed = source_->speed;
|
||||||
|
this->direction = source_->direction;
|
||||||
|
this->publish_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyFan::dump_config() { LOG_FAN("", "Copy Fan", this); }
|
||||||
|
|
||||||
|
fan::FanTraits CopyFan::get_traits() {
|
||||||
|
fan::FanTraits traits;
|
||||||
|
auto base = source_->get_traits();
|
||||||
|
// copy traits manually so it doesn't break when new options are added
|
||||||
|
// but the control() method hasn't implemented them yet.
|
||||||
|
traits.set_oscillation(base.supports_oscillation());
|
||||||
|
traits.set_speed(base.supports_speed());
|
||||||
|
traits.set_supported_speed_count(base.supported_speed_count());
|
||||||
|
traits.set_direction(base.supports_direction());
|
||||||
|
return traits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyFan::control(const fan::FanCall &call) {
|
||||||
|
auto call2 = source_->make_call();
|
||||||
|
if (call.get_state().has_value())
|
||||||
|
call2.set_state(*call.get_state());
|
||||||
|
if (call.get_oscillating().has_value())
|
||||||
|
call2.set_oscillating(*call.get_oscillating());
|
||||||
|
if (call.get_speed().has_value())
|
||||||
|
call2.set_speed(*call.get_speed());
|
||||||
|
if (call.get_direction().has_value())
|
||||||
|
call2.set_direction(*call.get_direction());
|
||||||
|
call2.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
26
esphome/components/copy/fan/copy_fan.h
Normal file
26
esphome/components/copy/fan/copy_fan.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/fan/fan.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyFan : public fan::Fan, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(fan::Fan *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
fan::FanTraits get_traits() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const fan::FanCall &call) override;
|
||||||
|
;
|
||||||
|
|
||||||
|
fan::Fan *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
36
esphome/components/copy/lock/__init__.py
Normal file
36
esphome/components/copy/lock/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import lock
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyLock = copy_ns.class_("CopyLock", lock.Lock, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = lock.LOCK_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopyLock),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(lock.Lock),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await lock.register_lock(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
29
esphome/components/copy/lock/copy_lock.cpp
Normal file
29
esphome/components/copy/lock/copy_lock.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "copy_lock.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.lock";
|
||||||
|
|
||||||
|
void CopyLock::setup() {
|
||||||
|
source_->add_on_state_callback([this]() { this->publish_state(source_->state); });
|
||||||
|
|
||||||
|
traits.set_assumed_state(source_->traits.get_assumed_state());
|
||||||
|
traits.set_requires_code(source_->traits.get_requires_code());
|
||||||
|
traits.set_supported_states(source_->traits.get_supported_states());
|
||||||
|
traits.set_supports_open(source_->traits.get_supports_open());
|
||||||
|
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyLock::dump_config() { LOG_LOCK("", "Copy Lock", this); }
|
||||||
|
|
||||||
|
void CopyLock::control(const lock::LockCall &call) {
|
||||||
|
auto call2 = source_->make_call();
|
||||||
|
call2.set_state(call.get_state());
|
||||||
|
call2.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
23
esphome/components/copy/lock/copy_lock.h
Normal file
23
esphome/components/copy/lock/copy_lock.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/lock/lock.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyLock : public lock::Lock, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(lock::Lock *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const lock::LockCall &call) override;
|
||||||
|
|
||||||
|
lock::Lock *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
38
esphome/components/copy/number/__init__.py
Normal file
38
esphome/components/copy/number/__init__.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import number
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_MODE,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyNumber = copy_ns.class_("CopyNumber", number.Number, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = number.NUMBER_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopyNumber),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(number.Number),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_UNIT_OF_MEASUREMENT, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_MODE, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await number.new_number(config, min_value=0, max_value=0, step=0)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
29
esphome/components/copy/number/copy_number.cpp
Normal file
29
esphome/components/copy/number/copy_number.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "copy_number.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.number";
|
||||||
|
|
||||||
|
void CopyNumber::setup() {
|
||||||
|
source_->add_on_state_callback([this](float value) { this->publish_state(value); });
|
||||||
|
|
||||||
|
traits.set_min_value(source_->traits.get_min_value());
|
||||||
|
traits.set_max_value(source_->traits.get_max_value());
|
||||||
|
traits.set_step(source_->traits.get_step());
|
||||||
|
|
||||||
|
if (source_->has_state())
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyNumber::dump_config() { LOG_NUMBER("", "Copy Number", this); }
|
||||||
|
|
||||||
|
void CopyNumber::control(float value) {
|
||||||
|
auto call2 = source_->make_call();
|
||||||
|
call2.set_value(value);
|
||||||
|
call2.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
23
esphome/components/copy/number/copy_number.h
Normal file
23
esphome/components/copy/number/copy_number.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/number/number.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyNumber : public number::Number, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(number::Number *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(float value) override;
|
||||||
|
|
||||||
|
number::Number *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
36
esphome/components/copy/select/__init__.py
Normal file
36
esphome/components/copy/select/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import select
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopySelect = copy_ns.class_("CopySelect", select.Select, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = select.SELECT_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopySelect),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await select.register_select(var, config, options=[])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
27
esphome/components/copy/select/copy_select.cpp
Normal file
27
esphome/components/copy/select/copy_select.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "copy_select.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.select";
|
||||||
|
|
||||||
|
void CopySelect::setup() {
|
||||||
|
source_->add_on_state_callback([this](const std::string &value) { this->publish_state(value); });
|
||||||
|
|
||||||
|
traits.set_options(source_->traits.get_options());
|
||||||
|
|
||||||
|
if (source_->has_state())
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopySelect::dump_config() { LOG_SELECT("", "Copy Select", this); }
|
||||||
|
|
||||||
|
void CopySelect::control(const std::string &value) {
|
||||||
|
auto call = source_->make_call();
|
||||||
|
call.set_option(value);
|
||||||
|
call.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
23
esphome/components/copy/select/copy_select.h
Normal file
23
esphome/components/copy/select/copy_select.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/select/select.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopySelect : public select::Select, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(select::Select *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const std::string &value) override;
|
||||||
|
|
||||||
|
select::Select *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
45
esphome/components/copy/sensor/__init__.py
Normal file
45
esphome/components/copy/sensor/__init__.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
CONF_STATE_CLASS,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
|
CONF_ACCURACY_DECIMALS,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopySensor = copy_ns.class_("CopySensor", sensor.Sensor, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
sensor.sensor_schema(CopySensor)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(sensor.Sensor),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_UNIT_OF_MEASUREMENT, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ACCURACY_DECIMALS, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_DEVICE_CLASS, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_STATE_CLASS, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await sensor.new_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
18
esphome/components/copy/sensor/copy_sensor.cpp
Normal file
18
esphome/components/copy/sensor/copy_sensor.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "copy_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.sensor";
|
||||||
|
|
||||||
|
void CopySensor::setup() {
|
||||||
|
source_->add_on_state_callback([this](float value) { this->publish_state(value); });
|
||||||
|
if (source_->has_state())
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopySensor::dump_config() { LOG_SENSOR("", "Copy Sensor", this); }
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
21
esphome/components/copy/sensor/copy_sensor.h
Normal file
21
esphome/components/copy/sensor/copy_sensor.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopySensor : public sensor::Sensor, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(sensor::Sensor *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sensor::Sensor *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
38
esphome/components/copy/switch/__init__.py
Normal file
38
esphome/components/copy/switch/__init__.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import switch
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopySwitch = copy_ns.class_("CopySwitch", switch.Switch, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(CopySwitch),
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(switch.Switch),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_DEVICE_CLASS, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await switch.register_switch(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
26
esphome/components/copy/switch/copy_switch.cpp
Normal file
26
esphome/components/copy/switch/copy_switch.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "copy_switch.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.switch";
|
||||||
|
|
||||||
|
void CopySwitch::setup() {
|
||||||
|
source_->add_on_state_callback([this](float value) { this->publish_state(value); });
|
||||||
|
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopySwitch::dump_config() { LOG_SWITCH("", "Copy Switch", this); }
|
||||||
|
|
||||||
|
void CopySwitch::write_state(bool state) {
|
||||||
|
if (state) {
|
||||||
|
source_->turn_on();
|
||||||
|
} else {
|
||||||
|
source_->turn_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
23
esphome/components/copy/switch/copy_switch.h
Normal file
23
esphome/components/copy/switch/copy_switch.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopySwitch : public switch_::Switch, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(switch_::Switch *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
|
||||||
|
switch_::Switch *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
37
esphome/components/copy/text_sensor/__init__.py
Normal file
37
esphome/components/copy/text_sensor/__init__.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import text_sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_SOURCE_ID,
|
||||||
|
)
|
||||||
|
from esphome.core.entity_helpers import inherit_property_from
|
||||||
|
|
||||||
|
from .. import copy_ns
|
||||||
|
|
||||||
|
CopyTextSensor = copy_ns.class_("CopyTextSensor", text_sensor.TextSensor, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
text_sensor.text_sensor_schema(CopyTextSensor)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SOURCE_ID): cv.use_id(text_sensor.TextSensor),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||||
|
inherit_property_from(CONF_ICON, CONF_SOURCE_ID),
|
||||||
|
inherit_property_from(CONF_ENTITY_CATEGORY, CONF_SOURCE_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await text_sensor.new_text_sensor(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||||
|
cg.add(var.set_source(source))
|
18
esphome/components/copy/text_sensor/copy_text_sensor.cpp
Normal file
18
esphome/components/copy/text_sensor/copy_text_sensor.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "copy_text_sensor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
static const char *const TAG = "copy.text_sensor";
|
||||||
|
|
||||||
|
void CopyTextSensor::setup() {
|
||||||
|
source_->add_on_state_callback([this](const std::string &value) { this->publish_state(value); });
|
||||||
|
if (source_->has_state())
|
||||||
|
this->publish_state(source_->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Copy Sensor", this); }
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
21
esphome/components/copy/text_sensor/copy_text_sensor.h
Normal file
21
esphome/components/copy/text_sensor/copy_text_sensor.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/text_sensor/text_sensor.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace copy {
|
||||||
|
|
||||||
|
class CopyTextSensor : public text_sensor::TextSensor, public Component {
|
||||||
|
public:
|
||||||
|
void set_source(text_sensor::TextSensor *source) { source_ = source; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
text_sensor::TextSensor *source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace copy
|
||||||
|
} // namespace esphome
|
|
@ -3,7 +3,6 @@ import esphome.config_validation as cv
|
||||||
from esphome.components import sensor, voltage_sampler
|
from esphome.components import sensor, voltage_sampler
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_SENSOR,
|
CONF_SENSOR,
|
||||||
CONF_ID,
|
|
||||||
DEVICE_CLASS_CURRENT,
|
DEVICE_CLASS_CURRENT,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_AMPERE,
|
UNIT_AMPERE,
|
||||||
|
@ -19,6 +18,7 @@ CTClampSensor = ct_clamp_ns.class_("CTClampSensor", sensor.Sensor, cg.PollingCom
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
CTClampSensor,
|
||||||
unit_of_measurement=UNIT_AMPERE,
|
unit_of_measurement=UNIT_AMPERE,
|
||||||
accuracy_decimals=2,
|
accuracy_decimals=2,
|
||||||
device_class=DEVICE_CLASS_CURRENT,
|
device_class=DEVICE_CLASS_CURRENT,
|
||||||
|
@ -26,7 +26,6 @@ CONFIG_SCHEMA = (
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(CTClampSensor),
|
|
||||||
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
|
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
|
||||||
cv.Optional(
|
cv.Optional(
|
||||||
CONF_SAMPLE_DURATION, default="200ms"
|
CONF_SAMPLE_DURATION, default="200ms"
|
||||||
|
@ -38,9 +37,8 @@ CONFIG_SCHEMA = (
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
|
|
||||||
sens = await cg.get_variable(config[CONF_SENSOR])
|
sens = await cg.get_variable(config[CONF_SENSOR])
|
||||||
cg.add(var.set_source(sens))
|
cg.add(var.set_source(sens))
|
||||||
|
|
|
@ -11,7 +11,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
|
cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
|
||||||
cv.Required(CONF_LAMBDA): cv.returning_lambda,
|
cv.Required(CONF_LAMBDA): cv.returning_lambda,
|
||||||
cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(
|
cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(
|
||||||
binary_sensor.BINARY_SENSOR_SCHEMA
|
binary_sensor.binary_sensor_schema()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,6 +32,11 @@ void DallasComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
|
ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
|
||||||
|
|
||||||
pin_->setup();
|
pin_->setup();
|
||||||
|
|
||||||
|
// clear bus with 480µs high, otherwise initial reset in search_vec() fails
|
||||||
|
pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
|
delayMicroseconds(480);
|
||||||
|
|
||||||
one_wire_ = new ESPOneWire(pin_); // NOLINT(cppcoreguidelines-owning-memory)
|
one_wire_ = new ESPOneWire(pin_); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
|
||||||
std::vector<uint64_t> raw_sensors;
|
std::vector<uint64_t> raw_sensors;
|
||||||
|
@ -99,20 +104,25 @@ void DallasComponent::update() {
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
if (!this->one_wire_->reset()) {
|
{
|
||||||
result = false;
|
InterruptLock lock;
|
||||||
} else {
|
result = this->one_wire_->reset();
|
||||||
result = true;
|
|
||||||
this->one_wire_->skip();
|
|
||||||
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ESP_LOGE(TAG, "Requesting conversion failed");
|
ESP_LOGE(TAG, "Requesting conversion failed");
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
|
for (auto *sensor : this->sensors_) {
|
||||||
|
sensor->publish_state(NAN);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
InterruptLock lock;
|
||||||
|
this->one_wire_->skip();
|
||||||
|
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto *sensor : this->sensors_) {
|
for (auto *sensor : this->sensors_) {
|
||||||
this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
|
this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
|
||||||
bool res = sensor->read_scratch_pad();
|
bool res = sensor->read_scratch_pad();
|
||||||
|
@ -152,16 +162,26 @@ const std::string &DallasTemperatureSensor::get_address_name() {
|
||||||
}
|
}
|
||||||
bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
||||||
auto *wire = this->parent_->one_wire_;
|
auto *wire = this->parent_->one_wire_;
|
||||||
if (!wire->reset()) {
|
|
||||||
return false;
|
{
|
||||||
|
InterruptLock lock;
|
||||||
|
|
||||||
|
if (!wire->reset()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wire->select(this->address_);
|
{
|
||||||
wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD);
|
InterruptLock lock;
|
||||||
|
|
||||||
for (unsigned char &i : this->scratch_pad_) {
|
wire->select(this->address_);
|
||||||
i = wire->read8();
|
wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD);
|
||||||
|
|
||||||
|
for (unsigned char &i : this->scratch_pad_) {
|
||||||
|
i = wire->read8();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool DallasTemperatureSensor::setup_sensor() {
|
bool DallasTemperatureSensor::setup_sensor() {
|
||||||
|
@ -200,17 +220,20 @@ bool DallasTemperatureSensor::setup_sensor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *wire = this->parent_->one_wire_;
|
auto *wire = this->parent_->one_wire_;
|
||||||
if (wire->reset()) {
|
{
|
||||||
wire->select(this->address_);
|
InterruptLock lock;
|
||||||
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
|
if (wire->reset()) {
|
||||||
wire->write8(this->scratch_pad_[2]); // high alarm temp
|
wire->select(this->address_);
|
||||||
wire->write8(this->scratch_pad_[3]); // low alarm temp
|
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
|
||||||
wire->write8(this->scratch_pad_[4]); // resolution
|
wire->write8(this->scratch_pad_[2]); // high alarm temp
|
||||||
wire->reset();
|
wire->write8(this->scratch_pad_[3]); // low alarm temp
|
||||||
|
wire->write8(this->scratch_pad_[4]); // resolution
|
||||||
|
wire->reset();
|
||||||
|
|
||||||
// write value to EEPROM
|
// write value to EEPROM
|
||||||
wire->select(this->address_);
|
wire->select(this->address_);
|
||||||
wire->write8(0x48);
|
wire->write8(0x48);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(20); // allow it to finish operation
|
delay(20); // allow it to finish operation
|
||||||
|
|
|
@ -15,8 +15,6 @@ ESPOneWire::ESPOneWire(InternalGPIOPin *pin) { pin_ = pin->to_isr(); }
|
||||||
bool HOT IRAM_ATTR ESPOneWire::reset() {
|
bool HOT IRAM_ATTR ESPOneWire::reset() {
|
||||||
// See reset here:
|
// See reset here:
|
||||||
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
||||||
InterruptLock lock;
|
|
||||||
|
|
||||||
// Wait for communication to clear (delay G)
|
// Wait for communication to clear (delay G)
|
||||||
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
uint8_t retries = 125;
|
uint8_t retries = 125;
|
||||||
|
@ -43,16 +41,18 @@ bool HOT IRAM_ATTR ESPOneWire::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
|
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
|
||||||
// See write 1/0 bit here:
|
|
||||||
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
|
||||||
InterruptLock lock;
|
|
||||||
|
|
||||||
// drive bus low
|
// drive bus low
|
||||||
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
||||||
pin_.digital_write(false);
|
pin_.digital_write(false);
|
||||||
|
|
||||||
uint32_t delay0 = bit ? 10 : 65;
|
// from datasheet:
|
||||||
uint32_t delay1 = bit ? 55 : 5;
|
// write 0 low time: t_low0: min=60µs, max=120µs
|
||||||
|
// write 1 low time: t_low1: min=1µs, max=15µs
|
||||||
|
// time slot: t_slot: min=60µs, max=120µs
|
||||||
|
// recovery time: t_rec: min=1µs
|
||||||
|
// ds18b20 appears to read the bus after roughly 14µs
|
||||||
|
uint32_t delay0 = bit ? 6 : 60;
|
||||||
|
uint32_t delay1 = bit ? 54 : 5;
|
||||||
|
|
||||||
// delay A/C
|
// delay A/C
|
||||||
delayMicroseconds(delay0);
|
delayMicroseconds(delay0);
|
||||||
|
@ -63,72 +63,100 @@ void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
|
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
|
||||||
// See read bit here:
|
// drive bus low
|
||||||
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
|
||||||
InterruptLock lock;
|
|
||||||
|
|
||||||
// drive bus low, delay A
|
|
||||||
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
||||||
pin_.digital_write(false);
|
pin_.digital_write(false);
|
||||||
|
|
||||||
|
// note: for reading we'll need very accurate timing, as the
|
||||||
|
// timing for the digital_read() is tight; according to the datasheet,
|
||||||
|
// we should read at the end of 16µs starting from the bus low
|
||||||
|
// typically, the ds18b20 pulls the line high after 11µs for a logical 1
|
||||||
|
// and 29µs for a logical 0
|
||||||
|
|
||||||
|
uint32_t start = micros();
|
||||||
|
// datasheet says >1µs
|
||||||
delayMicroseconds(3);
|
delayMicroseconds(3);
|
||||||
|
|
||||||
// release bus, delay E
|
// release bus, delay E
|
||||||
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
delayMicroseconds(10);
|
|
||||||
|
// Unfortunately some frameworks have different characteristics than others
|
||||||
|
// esp32 arduino appears to pull the bus low only after the digital_write(false),
|
||||||
|
// whereas on esp-idf it already happens during the pin_mode(OUTPUT)
|
||||||
|
// manually correct for this with these constants.
|
||||||
|
|
||||||
|
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
|
||||||
|
uint32_t timing_constant = 14;
|
||||||
|
#elif defined(USE_ESP32_FRAMEWORK_ESP_IDF)
|
||||||
|
uint32_t timing_constant = 12;
|
||||||
|
#else
|
||||||
|
uint32_t timing_constant = 14;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// measure from start value directly, to get best accurate timing no matter
|
||||||
|
// how long pin_mode/delayMicroseconds took
|
||||||
|
while (micros() - start < timing_constant)
|
||||||
|
;
|
||||||
|
|
||||||
// sample bus to read bit from peer
|
// sample bus to read bit from peer
|
||||||
bool r = pin_.digital_read();
|
bool r = pin_.digital_read();
|
||||||
|
|
||||||
// delay F
|
// read slot is at least 60µs; get as close to 60µs to spend less time with interrupts locked
|
||||||
delayMicroseconds(53);
|
uint32_t now = micros();
|
||||||
|
if (now - start < 60)
|
||||||
|
delayMicroseconds(60 - (now - start));
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPOneWire::write8(uint8_t val) {
|
void IRAM_ATTR ESPOneWire::write8(uint8_t val) {
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
this->write_bit(bool((1u << i) & val));
|
this->write_bit(bool((1u << i) & val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPOneWire::write64(uint64_t val) {
|
void IRAM_ATTR ESPOneWire::write64(uint64_t val) {
|
||||||
for (uint8_t i = 0; i < 64; i++) {
|
for (uint8_t i = 0; i < 64; i++) {
|
||||||
this->write_bit(bool((1ULL << i) & val));
|
this->write_bit(bool((1ULL << i) & val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ESPOneWire::read8() {
|
uint8_t IRAM_ATTR ESPOneWire::read8() {
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
ret |= (uint8_t(this->read_bit()) << i);
|
ret |= (uint8_t(this->read_bit()) << i);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
uint64_t ESPOneWire::read64() {
|
uint64_t IRAM_ATTR ESPOneWire::read64() {
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
ret |= (uint64_t(this->read_bit()) << i);
|
ret |= (uint64_t(this->read_bit()) << i);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
void ESPOneWire::select(uint64_t address) {
|
void IRAM_ATTR ESPOneWire::select(uint64_t address) {
|
||||||
this->write8(ONE_WIRE_ROM_SELECT);
|
this->write8(ONE_WIRE_ROM_SELECT);
|
||||||
this->write64(address);
|
this->write64(address);
|
||||||
}
|
}
|
||||||
void ESPOneWire::reset_search() {
|
void IRAM_ATTR ESPOneWire::reset_search() {
|
||||||
this->last_discrepancy_ = 0;
|
this->last_discrepancy_ = 0;
|
||||||
this->last_device_flag_ = false;
|
this->last_device_flag_ = false;
|
||||||
this->last_family_discrepancy_ = 0;
|
this->last_family_discrepancy_ = 0;
|
||||||
this->rom_number_ = 0;
|
this->rom_number_ = 0;
|
||||||
}
|
}
|
||||||
uint64_t ESPOneWire::search() {
|
uint64_t IRAM_ATTR ESPOneWire::search() {
|
||||||
if (this->last_device_flag_) {
|
if (this->last_device_flag_) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->reset()) {
|
{
|
||||||
// Reset failed or no devices present
|
InterruptLock lock;
|
||||||
this->reset_search();
|
if (!this->reset()) {
|
||||||
return 0u;
|
// Reset failed or no devices present
|
||||||
|
this->reset_search();
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t id_bit_number = 1;
|
uint8_t id_bit_number = 1;
|
||||||
|
@ -137,58 +165,61 @@ uint64_t ESPOneWire::search() {
|
||||||
bool search_result = false;
|
bool search_result = false;
|
||||||
uint8_t rom_byte_mask = 1;
|
uint8_t rom_byte_mask = 1;
|
||||||
|
|
||||||
// Initiate search
|
{
|
||||||
this->write8(ONE_WIRE_ROM_SEARCH);
|
InterruptLock lock;
|
||||||
do {
|
// Initiate search
|
||||||
// read bit
|
this->write8(ONE_WIRE_ROM_SEARCH);
|
||||||
bool id_bit = this->read_bit();
|
do {
|
||||||
// read its complement
|
// read bit
|
||||||
bool cmp_id_bit = this->read_bit();
|
bool id_bit = this->read_bit();
|
||||||
|
// read its complement
|
||||||
|
bool cmp_id_bit = this->read_bit();
|
||||||
|
|
||||||
if (id_bit && cmp_id_bit) {
|
if (id_bit && cmp_id_bit) {
|
||||||
// No devices participating in search
|
// No devices participating in search
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
bool branch;
|
|
||||||
|
|
||||||
if (id_bit != cmp_id_bit) {
|
|
||||||
// only chose one branch, the other one doesn't have any devices.
|
|
||||||
branch = id_bit;
|
|
||||||
} else {
|
|
||||||
// there are devices with both 0s and 1s at this bit
|
|
||||||
if (id_bit_number < this->last_discrepancy_) {
|
|
||||||
branch = (this->rom_number8_()[rom_byte_number] & rom_byte_mask) > 0;
|
|
||||||
} else {
|
|
||||||
branch = id_bit_number == this->last_discrepancy_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!branch) {
|
bool branch;
|
||||||
last_zero = id_bit_number;
|
|
||||||
if (last_zero < 9) {
|
if (id_bit != cmp_id_bit) {
|
||||||
this->last_discrepancy_ = last_zero;
|
// only chose one branch, the other one doesn't have any devices.
|
||||||
|
branch = id_bit;
|
||||||
|
} else {
|
||||||
|
// there are devices with both 0s and 1s at this bit
|
||||||
|
if (id_bit_number < this->last_discrepancy_) {
|
||||||
|
branch = (this->rom_number8_()[rom_byte_number] & rom_byte_mask) > 0;
|
||||||
|
} else {
|
||||||
|
branch = id_bit_number == this->last_discrepancy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!branch) {
|
||||||
|
last_zero = id_bit_number;
|
||||||
|
if (last_zero < 9) {
|
||||||
|
this->last_discrepancy_ = last_zero;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (branch) {
|
if (branch) {
|
||||||
// set bit
|
// set bit
|
||||||
this->rom_number8_()[rom_byte_number] |= rom_byte_mask;
|
this->rom_number8_()[rom_byte_number] |= rom_byte_mask;
|
||||||
} else {
|
} else {
|
||||||
// clear bit
|
// clear bit
|
||||||
this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask;
|
this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose/announce branch
|
// choose/announce branch
|
||||||
this->write_bit(branch);
|
this->write_bit(branch);
|
||||||
id_bit_number++;
|
id_bit_number++;
|
||||||
rom_byte_mask <<= 1;
|
rom_byte_mask <<= 1;
|
||||||
if (rom_byte_mask == 0u) {
|
if (rom_byte_mask == 0u) {
|
||||||
// go to next byte
|
// go to next byte
|
||||||
rom_byte_number++;
|
rom_byte_number++;
|
||||||
rom_byte_mask = 1;
|
rom_byte_mask = 1;
|
||||||
}
|
}
|
||||||
} while (rom_byte_number < 8); // loop through all bytes
|
} while (rom_byte_number < 8); // loop through all bytes
|
||||||
|
}
|
||||||
|
|
||||||
if (id_bit_number >= 65) {
|
if (id_bit_number >= 65) {
|
||||||
this->last_discrepancy_ = last_zero;
|
this->last_discrepancy_ = last_zero;
|
||||||
|
@ -217,7 +248,7 @@ std::vector<uint64_t> ESPOneWire::search_vec() {
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void ESPOneWire::skip() {
|
void IRAM_ATTR ESPOneWire::skip() {
|
||||||
this->write8(0xCC); // skip ROM
|
this->write8(0xCC); // skip ROM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ from esphome.const import (
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_CELSIUS,
|
UNIT_CELSIUS,
|
||||||
CONF_ID,
|
|
||||||
)
|
)
|
||||||
from . import DallasComponent, dallas_ns
|
from . import DallasComponent, dallas_ns
|
||||||
|
|
||||||
|
@ -17,13 +16,13 @@ DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sen
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
|
DallasTemperatureSensor,
|
||||||
unit_of_measurement=UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
accuracy_decimals=1,
|
accuracy_decimals=1,
|
||||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
state_class=STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
).extend(
|
).extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(DallasTemperatureSensor),
|
|
||||||
cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent),
|
cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent),
|
||||||
cv.Optional(CONF_ADDRESS): cv.hex_int,
|
cv.Optional(CONF_ADDRESS): cv.hex_int,
|
||||||
cv.Optional(CONF_INDEX): cv.positive_int,
|
cv.Optional(CONF_INDEX): cv.positive_int,
|
||||||
|
@ -36,7 +35,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
hub = await cg.get_variable(config[CONF_DALLAS_ID])
|
hub = await cg.get_variable(config[CONF_DALLAS_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = await sensor.new_sensor(config)
|
||||||
|
|
||||||
if CONF_ADDRESS in config:
|
if CONF_ADDRESS in config:
|
||||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||||
|
@ -49,4 +48,3 @@ async def to_code(config):
|
||||||
cg.add(var.set_parent(hub))
|
cg.add(var.set_parent(hub))
|
||||||
|
|
||||||
cg.add(hub.register_sensor(var))
|
cg.add(hub.register_sensor(var))
|
||||||
await sensor.register_sensor(var, config)
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
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 binary_sensor
|
from esphome.components import binary_sensor
|
||||||
from esphome.const import CONF_ID
|
|
||||||
from . import DalyBmsComponent, CONF_BMS_DALY_ID
|
from . import DalyBmsComponent, CONF_BMS_DALY_ID
|
||||||
|
|
||||||
CONF_CHARGING_MOS_ENABLED = "charging_mos_enabled"
|
CONF_CHARGING_MOS_ENABLED = "charging_mos_enabled"
|
||||||
|
@ -18,18 +17,10 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
|
cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
|
||||||
cv.Optional(
|
cv.Optional(
|
||||||
CONF_CHARGING_MOS_ENABLED
|
CONF_CHARGING_MOS_ENABLED
|
||||||
): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
): binary_sensor.binary_sensor_schema(),
|
||||||
{
|
|
||||||
cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
cv.Optional(
|
cv.Optional(
|
||||||
CONF_DISCHARGING_MOS_ENABLED
|
CONF_DISCHARGING_MOS_ENABLED
|
||||||
): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
): binary_sensor.binary_sensor_schema(),
|
||||||
{
|
|
||||||
cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
)
|
)
|
||||||
|
@ -38,9 +29,8 @@ CONFIG_SCHEMA = cv.All(
|
||||||
async def setup_conf(config, key, hub):
|
async def setup_conf(config, key, hub):
|
||||||
if key in config:
|
if key in config:
|
||||||
conf = config[key]
|
conf = config[key]
|
||||||
sens = cg.new_Pvariable(conf[CONF_ID])
|
var = await binary_sensor.new_binary_sensor(conf)
|
||||||
await binary_sensor.register_binary_sensor(sens, conf)
|
cg.add(getattr(hub, f"set_{key}_binary_sensor")(var))
|
||||||
cg.add(getattr(hub, f"set_{key}_binary_sensor")(sens))
|
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
|
|
|
@ -16,6 +16,7 @@ static const uint8_t DALY_REQUEST_MIN_MAX_VOLTAGE = 0x91;
|
||||||
static const uint8_t DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92;
|
static const uint8_t DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92;
|
||||||
static const uint8_t DALY_REQUEST_MOS = 0x93;
|
static const uint8_t DALY_REQUEST_MOS = 0x93;
|
||||||
static const uint8_t DALY_REQUEST_STATUS = 0x94;
|
static const uint8_t DALY_REQUEST_STATUS = 0x94;
|
||||||
|
static const uint8_t DALY_REQUEST_CELL_VOLTAGE = 0x95;
|
||||||
static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96;
|
static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96;
|
||||||
|
|
||||||
void DalyBmsComponent::setup() {}
|
void DalyBmsComponent::setup() {}
|
||||||
|
@ -31,6 +32,7 @@ void DalyBmsComponent::update() {
|
||||||
this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE);
|
this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE);
|
||||||
this->request_data_(DALY_REQUEST_MOS);
|
this->request_data_(DALY_REQUEST_MOS);
|
||||||
this->request_data_(DALY_REQUEST_STATUS);
|
this->request_data_(DALY_REQUEST_STATUS);
|
||||||
|
this->request_data_(DALY_REQUEST_CELL_VOLTAGE);
|
||||||
this->request_data_(DALY_REQUEST_TEMPERATURE);
|
this->request_data_(DALY_REQUEST_TEMPERATURE);
|
||||||
|
|
||||||
std::vector<uint8_t> get_battery_level_data;
|
std::vector<uint8_t> get_battery_level_data;
|
||||||
|
@ -166,6 +168,71 @@ void DalyBmsComponent::decode_data_(std::vector<uint8_t> data) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DALY_REQUEST_CELL_VOLTAGE:
|
||||||
|
switch (it[4]) {
|
||||||
|
case 1:
|
||||||
|
if (this->cell_1_voltage_) {
|
||||||
|
this->cell_1_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_2_voltage_) {
|
||||||
|
this->cell_2_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_3_voltage_) {
|
||||||
|
this->cell_3_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (this->cell_4_voltage_) {
|
||||||
|
this->cell_4_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_5_voltage_) {
|
||||||
|
this->cell_5_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_6_voltage_) {
|
||||||
|
this->cell_6_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (this->cell_7_voltage_) {
|
||||||
|
this->cell_7_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_8_voltage_) {
|
||||||
|
this->cell_8_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_9_voltage_) {
|
||||||
|
this->cell_9_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (this->cell_10_voltage_) {
|
||||||
|
this->cell_10_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_11_voltage_) {
|
||||||
|
this->cell_11_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_12_voltage_) {
|
||||||
|
this->cell_12_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (this->cell_13_voltage_) {
|
||||||
|
this->cell_13_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_14_voltage_) {
|
||||||
|
this->cell_14_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
|
||||||
|
}
|
||||||
|
if (this->cell_15_voltage_) {
|
||||||
|
this->cell_15_voltage_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if (this->cell_16_voltage_) {
|
||||||
|
this->cell_16_voltage_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,23 @@ class DalyBmsComponent : public PollingComponent, public uart::UARTDevice {
|
||||||
void set_cells_number_sensor(sensor::Sensor *cells_number) { cells_number_ = cells_number; }
|
void set_cells_number_sensor(sensor::Sensor *cells_number) { cells_number_ = cells_number; }
|
||||||
void set_temperature_1_sensor(sensor::Sensor *temperature_1_sensor) { temperature_1_sensor_ = temperature_1_sensor; }
|
void set_temperature_1_sensor(sensor::Sensor *temperature_1_sensor) { temperature_1_sensor_ = temperature_1_sensor; }
|
||||||
void set_temperature_2_sensor(sensor::Sensor *temperature_2_sensor) { temperature_2_sensor_ = temperature_2_sensor; }
|
void set_temperature_2_sensor(sensor::Sensor *temperature_2_sensor) { temperature_2_sensor_ = temperature_2_sensor; }
|
||||||
|
void set_cell_1_voltage_sensor(sensor::Sensor *cell_1_voltage) { cell_1_voltage_ = cell_1_voltage; }
|
||||||
|
void set_cell_2_voltage_sensor(sensor::Sensor *cell_2_voltage) { cell_2_voltage_ = cell_2_voltage; }
|
||||||
|
void set_cell_3_voltage_sensor(sensor::Sensor *cell_3_voltage) { cell_3_voltage_ = cell_3_voltage; }
|
||||||
|
void set_cell_4_voltage_sensor(sensor::Sensor *cell_4_voltage) { cell_4_voltage_ = cell_4_voltage; }
|
||||||
|
void set_cell_5_voltage_sensor(sensor::Sensor *cell_5_voltage) { cell_5_voltage_ = cell_5_voltage; }
|
||||||
|
void set_cell_6_voltage_sensor(sensor::Sensor *cell_6_voltage) { cell_6_voltage_ = cell_6_voltage; }
|
||||||
|
void set_cell_7_voltage_sensor(sensor::Sensor *cell_7_voltage) { cell_7_voltage_ = cell_7_voltage; }
|
||||||
|
void set_cell_8_voltage_sensor(sensor::Sensor *cell_8_voltage) { cell_8_voltage_ = cell_8_voltage; }
|
||||||
|
void set_cell_9_voltage_sensor(sensor::Sensor *cell_9_voltage) { cell_9_voltage_ = cell_9_voltage; }
|
||||||
|
void set_cell_10_voltage_sensor(sensor::Sensor *cell_10_voltage) { cell_10_voltage_ = cell_10_voltage; }
|
||||||
|
void set_cell_11_voltage_sensor(sensor::Sensor *cell_11_voltage) { cell_11_voltage_ = cell_11_voltage; }
|
||||||
|
void set_cell_12_voltage_sensor(sensor::Sensor *cell_12_voltage) { cell_12_voltage_ = cell_12_voltage; }
|
||||||
|
void set_cell_13_voltage_sensor(sensor::Sensor *cell_13_voltage) { cell_13_voltage_ = cell_13_voltage; }
|
||||||
|
void set_cell_14_voltage_sensor(sensor::Sensor *cell_14_voltage) { cell_14_voltage_ = cell_14_voltage; }
|
||||||
|
void set_cell_15_voltage_sensor(sensor::Sensor *cell_15_voltage) { cell_15_voltage_ = cell_15_voltage; }
|
||||||
|
void set_cell_16_voltage_sensor(sensor::Sensor *cell_16_voltage) { cell_16_voltage_ = cell_16_voltage; }
|
||||||
|
|
||||||
// TEXT_SENSORS
|
// TEXT_SENSORS
|
||||||
void set_status_text_sensor(text_sensor::TextSensor *status_text_sensor) { status_text_sensor_ = status_text_sensor; }
|
void set_status_text_sensor(text_sensor::TextSensor *status_text_sensor) { status_text_sensor_ = status_text_sensor; }
|
||||||
// BINARY_SENSORS
|
// BINARY_SENSORS
|
||||||
|
@ -72,6 +89,22 @@ class DalyBmsComponent : public PollingComponent, public uart::UARTDevice {
|
||||||
sensor::Sensor *cells_number_{nullptr};
|
sensor::Sensor *cells_number_{nullptr};
|
||||||
sensor::Sensor *temperature_1_sensor_{nullptr};
|
sensor::Sensor *temperature_1_sensor_{nullptr};
|
||||||
sensor::Sensor *temperature_2_sensor_{nullptr};
|
sensor::Sensor *temperature_2_sensor_{nullptr};
|
||||||
|
sensor::Sensor *cell_1_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_2_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_3_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_4_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_5_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_6_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_7_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_8_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_9_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_10_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_11_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_12_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_13_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_14_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_15_voltage_{nullptr};
|
||||||
|
sensor::Sensor *cell_16_voltage_{nullptr};
|
||||||
|
|
||||||
text_sensor::TextSensor *status_text_sensor_{nullptr};
|
text_sensor::TextSensor *status_text_sensor_{nullptr};
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,11 @@ from esphome.const import (
|
||||||
DEVICE_CLASS_CURRENT,
|
DEVICE_CLASS_CURRENT,
|
||||||
DEVICE_CLASS_BATTERY,
|
DEVICE_CLASS_BATTERY,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_NONE,
|
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
UNIT_AMPERE,
|
UNIT_AMPERE,
|
||||||
UNIT_PERCENT,
|
UNIT_PERCENT,
|
||||||
UNIT_CELSIUS,
|
UNIT_CELSIUS,
|
||||||
UNIT_EMPTY,
|
|
||||||
ICON_FLASH,
|
ICON_FLASH,
|
||||||
ICON_PERCENT,
|
ICON_PERCENT,
|
||||||
ICON_COUNTER,
|
ICON_COUNTER,
|
||||||
|
@ -39,6 +36,22 @@ CONF_REMAINING_CAPACITY = "remaining_capacity"
|
||||||
CONF_TEMPERATURE_1 = "temperature_1"
|
CONF_TEMPERATURE_1 = "temperature_1"
|
||||||
CONF_TEMPERATURE_2 = "temperature_2"
|
CONF_TEMPERATURE_2 = "temperature_2"
|
||||||
|
|
||||||
|
CONF_CELL_1_VOLTAGE = "cell_1_voltage"
|
||||||
|
CONF_CELL_2_VOLTAGE = "cell_2_voltage"
|
||||||
|
CONF_CELL_3_VOLTAGE = "cell_3_voltage"
|
||||||
|
CONF_CELL_4_VOLTAGE = "cell_4_voltage"
|
||||||
|
CONF_CELL_5_VOLTAGE = "cell_5_voltage"
|
||||||
|
CONF_CELL_6_VOLTAGE = "cell_6_voltage"
|
||||||
|
CONF_CELL_7_VOLTAGE = "cell_7_voltage"
|
||||||
|
CONF_CELL_8_VOLTAGE = "cell_8_voltage"
|
||||||
|
CONF_CELL_9_VOLTAGE = "cell_9_voltage"
|
||||||
|
CONF_CELL_10_VOLTAGE = "cell_10_voltage"
|
||||||
|
CONF_CELL_11_VOLTAGE = "cell_11_voltage"
|
||||||
|
CONF_CELL_12_VOLTAGE = "cell_12_voltage"
|
||||||
|
CONF_CELL_13_VOLTAGE = "cell_13_voltage"
|
||||||
|
CONF_CELL_14_VOLTAGE = "cell_14_voltage"
|
||||||
|
CONF_CELL_15_VOLTAGE = "cell_15_voltage"
|
||||||
|
CONF_CELL_16_VOLTAGE = "cell_16_voltage"
|
||||||
ICON_CURRENT_DC = "mdi:current-dc"
|
ICON_CURRENT_DC = "mdi:current-dc"
|
||||||
ICON_BATTERY_OUTLINE = "mdi:battery-outline"
|
ICON_BATTERY_OUTLINE = "mdi:battery-outline"
|
||||||
ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up"
|
ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up"
|
||||||
|
@ -63,117 +76,140 @@ TYPES = [
|
||||||
CONF_REMAINING_CAPACITY,
|
CONF_REMAINING_CAPACITY,
|
||||||
CONF_TEMPERATURE_1,
|
CONF_TEMPERATURE_1,
|
||||||
CONF_TEMPERATURE_2,
|
CONF_TEMPERATURE_2,
|
||||||
|
CONF_CELL_1_VOLTAGE,
|
||||||
|
CONF_CELL_2_VOLTAGE,
|
||||||
|
CONF_CELL_3_VOLTAGE,
|
||||||
|
CONF_CELL_4_VOLTAGE,
|
||||||
|
CONF_CELL_5_VOLTAGE,
|
||||||
|
CONF_CELL_6_VOLTAGE,
|
||||||
|
CONF_CELL_7_VOLTAGE,
|
||||||
|
CONF_CELL_8_VOLTAGE,
|
||||||
|
CONF_CELL_9_VOLTAGE,
|
||||||
|
CONF_CELL_10_VOLTAGE,
|
||||||
|
CONF_CELL_11_VOLTAGE,
|
||||||
|
CONF_CELL_12_VOLTAGE,
|
||||||
|
CONF_CELL_13_VOLTAGE,
|
||||||
|
CONF_CELL_14_VOLTAGE,
|
||||||
|
CONF_CELL_15_VOLTAGE,
|
||||||
|
CONF_CELL_16_VOLTAGE,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CELL_VOLTAGE_SCHEMA = sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_VOLT,
|
||||||
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
|
cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
|
||||||
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
|
||||||
UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
ICON_FLASH,
|
icon=ICON_FLASH,
|
||||||
1,
|
accuracy_decimals=1,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
||||||
UNIT_AMPERE,
|
unit_of_measurement=UNIT_AMPERE,
|
||||||
ICON_CURRENT_DC,
|
icon=ICON_CURRENT_DC,
|
||||||
1,
|
accuracy_decimals=1,
|
||||||
DEVICE_CLASS_CURRENT,
|
device_class=DEVICE_CLASS_CURRENT,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
|
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
|
||||||
UNIT_PERCENT,
|
unit_of_measurement=UNIT_PERCENT,
|
||||||
ICON_PERCENT,
|
icon=ICON_PERCENT,
|
||||||
1,
|
accuracy_decimals=1,
|
||||||
DEVICE_CLASS_BATTERY,
|
device_class=DEVICE_CLASS_BATTERY,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MAX_CELL_VOLTAGE): sensor.sensor_schema(
|
cv.Optional(CONF_MAX_CELL_VOLTAGE): sensor.sensor_schema(
|
||||||
UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
ICON_FLASH,
|
icon=ICON_FLASH,
|
||||||
2,
|
accuracy_decimals=2,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MAX_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
|
cv.Optional(CONF_MAX_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
|
||||||
UNIT_EMPTY,
|
icon=ICON_COUNTER,
|
||||||
ICON_COUNTER,
|
accuracy_decimals=0,
|
||||||
0,
|
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MIN_CELL_VOLTAGE): sensor.sensor_schema(
|
cv.Optional(CONF_MIN_CELL_VOLTAGE): sensor.sensor_schema(
|
||||||
UNIT_VOLT,
|
unit_of_measurement=UNIT_VOLT,
|
||||||
ICON_FLASH,
|
icon=ICON_FLASH,
|
||||||
2,
|
accuracy_decimals=2,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MIN_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
|
cv.Optional(CONF_MIN_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
|
||||||
UNIT_EMPTY,
|
icon=ICON_COUNTER,
|
||||||
ICON_COUNTER,
|
accuracy_decimals=0,
|
||||||
0,
|
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MAX_TEMPERATURE): sensor.sensor_schema(
|
cv.Optional(CONF_MAX_TEMPERATURE): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_THERMOMETER_CHEVRON_UP,
|
icon=ICON_THERMOMETER_CHEVRON_UP,
|
||||||
0,
|
accuracy_decimals=0,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MAX_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
|
cv.Optional(CONF_MAX_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
|
||||||
UNIT_EMPTY,
|
icon=ICON_COUNTER,
|
||||||
ICON_COUNTER,
|
accuracy_decimals=0,
|
||||||
0,
|
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MIN_TEMPERATURE): sensor.sensor_schema(
|
cv.Optional(CONF_MIN_TEMPERATURE): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_THERMOMETER_CHEVRON_DOWN,
|
icon=ICON_THERMOMETER_CHEVRON_DOWN,
|
||||||
0,
|
accuracy_decimals=0,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MIN_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
|
cv.Optional(CONF_MIN_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
|
||||||
UNIT_EMPTY,
|
icon=ICON_COUNTER,
|
||||||
ICON_COUNTER,
|
accuracy_decimals=0,
|
||||||
0,
|
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_REMAINING_CAPACITY): sensor.sensor_schema(
|
cv.Optional(CONF_REMAINING_CAPACITY): sensor.sensor_schema(
|
||||||
UNIT_AMPERE_HOUR,
|
unit_of_measurement=UNIT_AMPERE_HOUR,
|
||||||
ICON_GAUGE,
|
icon=ICON_GAUGE,
|
||||||
2,
|
accuracy_decimals=2,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
device_class=DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_CELLS_NUMBER): sensor.sensor_schema(
|
cv.Optional(CONF_CELLS_NUMBER): sensor.sensor_schema(
|
||||||
UNIT_EMPTY,
|
icon=ICON_COUNTER,
|
||||||
ICON_COUNTER,
|
accuracy_decimals=0,
|
||||||
0,
|
|
||||||
DEVICE_CLASS_EMPTY,
|
|
||||||
STATE_CLASS_NONE,
|
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema(
|
cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_THERMOMETER,
|
icon=ICON_THERMOMETER,
|
||||||
0,
|
accuracy_decimals=0,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema(
|
cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema(
|
||||||
UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
ICON_THERMOMETER,
|
icon=ICON_THERMOMETER,
|
||||||
0,
|
accuracy_decimals=0,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_CELL_1_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_2_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_3_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_4_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_5_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_6_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_7_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_8_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_9_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_10_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_11_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_12_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_13_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_14_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_15_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_CELL_16_VOLTAGE): CELL_VOLTAGE_SCHEMA,
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
)
|
)
|
||||||
|
|
|
@ -53,9 +53,9 @@ void DebugComponent::dump_config() {
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
LOG_SENSOR(" ", "Free space on heap", this->free_sensor_);
|
LOG_SENSOR(" ", "Free space on heap", this->free_sensor_);
|
||||||
LOG_SENSOR(" ", "Largest free heap block", this->block_sensor_);
|
LOG_SENSOR(" ", "Largest free heap block", this->block_sensor_);
|
||||||
#if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
||||||
LOG_SENSOR(" ", "Heap fragmentation", this->fragmentation_sensor_);
|
LOG_SENSOR(" ", "Heap fragmentation", this->fragmentation_sensor_);
|
||||||
#endif // defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
#endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
||||||
#endif // USE_SENSOR
|
#endif // USE_SENSOR
|
||||||
|
|
||||||
ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
|
ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
|
||||||
|
@ -316,7 +316,7 @@ void DebugComponent::update() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
||||||
if (this->fragmentation_sensor_ != nullptr) {
|
if (this->fragmentation_sensor_ != nullptr) {
|
||||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||||
this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
|
this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
|
||||||
|
|
|
@ -28,7 +28,7 @@ class DebugComponent : public PollingComponent {
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; }
|
void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; }
|
||||||
void set_block_sensor(sensor::Sensor *block_sensor) { block_sensor_ = block_sensor; }
|
void set_block_sensor(sensor::Sensor *block_sensor) { block_sensor_ = block_sensor; }
|
||||||
#if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
||||||
void set_fragmentation_sensor(sensor::Sensor *fragmentation_sensor) { fragmentation_sensor_ = fragmentation_sensor; }
|
void set_fragmentation_sensor(sensor::Sensor *fragmentation_sensor) { fragmentation_sensor_ = fragmentation_sensor; }
|
||||||
#endif
|
#endif
|
||||||
void set_loop_time_sensor(sensor::Sensor *loop_time_sensor) { loop_time_sensor_ = loop_time_sensor; }
|
void set_loop_time_sensor(sensor::Sensor *loop_time_sensor) { loop_time_sensor_ = loop_time_sensor; }
|
||||||
|
@ -42,7 +42,7 @@ class DebugComponent : public PollingComponent {
|
||||||
|
|
||||||
sensor::Sensor *free_sensor_{nullptr};
|
sensor::Sensor *free_sensor_{nullptr};
|
||||||
sensor::Sensor *block_sensor_{nullptr};
|
sensor::Sensor *block_sensor_{nullptr};
|
||||||
#if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
|
||||||
sensor::Sensor *fragmentation_sensor_{nullptr};
|
sensor::Sensor *fragmentation_sensor_{nullptr};
|
||||||
#endif
|
#endif
|
||||||
sensor::Sensor *loop_time_sensor_{nullptr};
|
sensor::Sensor *loop_time_sensor_{nullptr};
|
||||||
|
|
|
@ -6,6 +6,7 @@ from esphome.const import (
|
||||||
CONF_FRAGMENTATION,
|
CONF_FRAGMENTATION,
|
||||||
CONF_BLOCK,
|
CONF_BLOCK,
|
||||||
CONF_LOOP_TIME,
|
CONF_LOOP_TIME,
|
||||||
|
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
UNIT_MILLISECOND,
|
UNIT_MILLISECOND,
|
||||||
UNIT_PERCENT,
|
UNIT_PERCENT,
|
||||||
UNIT_BYTES,
|
UNIT_BYTES,
|
||||||
|
@ -18,14 +19,34 @@ DEPENDENCIES = ["debug"]
|
||||||
|
|
||||||
CONFIG_SCHEMA = {
|
CONFIG_SCHEMA = {
|
||||||
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
|
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
|
||||||
cv.Optional(CONF_FREE): sensor.sensor_schema(UNIT_BYTES, ICON_COUNTER, 0),
|
cv.Optional(CONF_FREE): sensor.sensor_schema(
|
||||||
cv.Optional(CONF_BLOCK): sensor.sensor_schema(UNIT_BYTES, ICON_COUNTER, 0),
|
unit_of_measurement=UNIT_BYTES,
|
||||||
|
icon=ICON_COUNTER,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_BLOCK): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_BYTES,
|
||||||
|
icon=ICON_COUNTER,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
),
|
||||||
cv.Optional(CONF_FRAGMENTATION): cv.All(
|
cv.Optional(CONF_FRAGMENTATION): cv.All(
|
||||||
cv.only_on_esp8266,
|
cv.only_on_esp8266,
|
||||||
cv.require_framework_version(esp8266_arduino=cv.Version(2, 5, 2)),
|
cv.require_framework_version(esp8266_arduino=cv.Version(2, 5, 2)),
|
||||||
sensor.sensor_schema(UNIT_PERCENT, ICON_COUNTER, 1),
|
sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_PERCENT,
|
||||||
|
icon=ICON_COUNTER,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_LOOP_TIME): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_MILLISECOND,
|
||||||
|
icon=ICON_TIMER,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_LOOP_TIME): sensor.sensor_schema(UNIT_MILLISECOND, ICON_TIMER, 0),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from esphome.components import text_sensor
|
from esphome.components import text_sensor
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.const import CONF_DEVICE
|
from esphome.const import CONF_DEVICE, ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
|
|
||||||
from . import CONF_DEBUG_ID, DebugComponent
|
from . import CONF_DEBUG_ID, DebugComponent
|
||||||
|
|
||||||
|
@ -11,7 +11,9 @@ DEPENDENCIES = ["debug"]
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
|
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
|
||||||
cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema(),
|
cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema(
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,39 @@ from esphome.const import (
|
||||||
CONF_WAKEUP_PIN,
|
CONF_WAKEUP_PIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from esphome.components.esp32 import get_esp32_variant
|
||||||
|
from esphome.components.esp32.const import (
|
||||||
|
VARIANT_ESP32,
|
||||||
|
VARIANT_ESP32C3,
|
||||||
|
)
|
||||||
|
|
||||||
|
WAKEUP_PINS = {
|
||||||
|
VARIANT_ESP32: [
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
12,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
15,
|
||||||
|
25,
|
||||||
|
26,
|
||||||
|
27,
|
||||||
|
32,
|
||||||
|
33,
|
||||||
|
34,
|
||||||
|
35,
|
||||||
|
36,
|
||||||
|
37,
|
||||||
|
38,
|
||||||
|
39,
|
||||||
|
],
|
||||||
|
VARIANT_ESP32C3: [0, 1, 2, 3, 4, 5],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def validate_pin_number(value):
|
def validate_pin_number(value):
|
||||||
valid_pins = [0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 37, 38, 39]
|
valid_pins = WAKEUP_PINS.get(get_esp32_variant(), WAKEUP_PINS[VARIANT_ESP32])
|
||||||
if value[CONF_NUMBER] not in valid_pins:
|
if value[CONF_NUMBER] not in valid_pins:
|
||||||
raise cv.Invalid(
|
raise cv.Invalid(
|
||||||
f"Only pins {', '.join(str(x) for x in valid_pins)} support wakeup"
|
f"Only pins {', '.join(str(x) for x in valid_pins)} support wakeup"
|
||||||
|
@ -21,6 +51,14 @@ def validate_pin_number(value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_config(config):
|
||||||
|
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_ESP32_EXT1_WAKEUP in config:
|
||||||
|
raise cv.Invalid("ESP32-C3 does not support wakeup from touch.")
|
||||||
|
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_TOUCH_WAKEUP in config:
|
||||||
|
raise cv.Invalid("ESP32-C3 does not support wakeup from ext1")
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep")
|
deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep")
|
||||||
DeepSleepComponent = deep_sleep_ns.class_("DeepSleepComponent", cg.Component)
|
DeepSleepComponent = deep_sleep_ns.class_("DeepSleepComponent", cg.Component)
|
||||||
EnterDeepSleepAction = deep_sleep_ns.class_("EnterDeepSleepAction", automation.Action)
|
EnterDeepSleepAction = deep_sleep_ns.class_("EnterDeepSleepAction", automation.Action)
|
||||||
|
|
|
@ -104,7 +104,7 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
||||||
|
|
||||||
App.run_safe_shutdown_hooks();
|
App.run_safe_shutdown_hooks();
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3)
|
||||||
if (this->sleep_duration_.has_value())
|
if (this->sleep_duration_.has_value())
|
||||||
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
|
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
|
||||||
if (this->wakeup_pin_ != nullptr) {
|
if (this->wakeup_pin_ != nullptr) {
|
||||||
|
@ -126,6 +126,18 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ESP32_VARIANT_ESP32C3
|
||||||
|
if (this->sleep_duration_.has_value())
|
||||||
|
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
|
||||||
|
if (this->wakeup_pin_ != nullptr) {
|
||||||
|
bool level = !this->wakeup_pin_->is_inverted();
|
||||||
|
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
|
||||||
|
level = !level;
|
||||||
|
}
|
||||||
|
esp_deep_sleep_enable_gpio_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
|
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#endif
|
#endif
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue