1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 16:41:50 +00:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Jesse Hills
a85b7b3f84 Code tidy 2021-12-22 15:58:02 +13:00
Jesse Hills
a207ed08a9 Merge branch 'dev' into pr/ciB89/1424-1 2021-12-22 15:49:07 +13:00
Ian
90c3cb62b3 Add tracker for OralB toothbrushes
The OralB toothbrushes expose some of their information in their bluetooth advertisement data.

This data lets us see the state (idle, running), brush mode (daily clean, tongue, whitening, etc.), pressure and some other bits of data.

This component lets you expose that data with config as follows:

```
esp32_ble_tracker:

sensor:
  - platform: oralb_brush
    mac_address: 00:00:00:00:00:00
    state:
      name: "Toothbrush State"
```

Checkout https://github.com/zewelor/bt-mqtt-gateway/blob/master/workers/toothbrush_homeassistant.py and https://esphome.io/components/esp32_ble_tracker.html for more information.
2020-05-03 15:23:21 +01:00
554 changed files with 4342 additions and 13697 deletions

View File

@@ -68,6 +68,8 @@ Checks: >-
-modernize-use-nodiscard,
-mpi-*,
-objc-*,
-readability-braces-around-statements,
-readability-const-return-type,
-readability-convert-member-functions-to-static,
-readability-else-after-return,
-readability-function-cognitive-complexity,
@@ -75,6 +77,10 @@ Checks: >-
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-make-member-function-const,
-readability-named-parameter,
-readability-qualified-auto,
-readability-redundant-access-specifiers,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-uppercase-literal-suffix,
-readability-use-anyofallof,
@@ -108,8 +114,6 @@ CheckOptions:
value: 'make_unique'
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
value: 'esphome/core/helpers.h'
- key: readability-braces-around-statements.ShortStatementLines
value: 2
- key: readability-identifier-naming.LocalVariableCase
value: 'lower_case'
- key: readability-identifier-naming.ClassCase
@@ -156,5 +160,3 @@ CheckOptions:
value: 'lower_case'
- key: readability-identifier-naming.VirtualMethodSuffix
value: ''
- key: readability-qualified-auto.AddConstToQualified
value: 0

View File

@@ -51,26 +51,26 @@ jobs:
name: Run script/clang-format
- id: clang-tidy
name: Run script/clang-tidy for ESP8266
options: --environment esp8266-arduino-tidy --grep USE_ESP8266
options: --environment esp8266-tidy --grep USE_ESP8266
pio_cache_key: tidyesp8266
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 1/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 1
name: Run script/clang-tidy for ESP32 1/4
options: --environment esp32-tidy --split-num 4 --split-at 1
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 2/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 2
name: Run script/clang-tidy for ESP32 2/4
options: --environment esp32-tidy --split-num 4 --split-at 2
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 3/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 3
name: Run script/clang-tidy for ESP32 3/4
options: --environment esp32-tidy --split-num 4 --split-at 3
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 4/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 4
name: Run script/clang-tidy for ESP32 4/4
options: --environment esp32-tidy --split-num 4 --split-at 4
pio_cache_key: tidyesp32
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF
name: Run script/clang-tidy for ESP32 esp-idf
options: --environment esp32-idf-tidy --grep USE_ESP_IDF
pio_cache_key: tidyesp32-idf

View File

@@ -137,18 +137,18 @@ jobs:
--build-type "${{ matrix.build_type }}" \
manifest
deploy-ha-addon-repo:
deploy-hassio-repo:
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest
needs: [deploy-docker]
steps:
- env:
TOKEN: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
TOKEN: ${{ secrets.DEPLOY_HASSIO_TOKEN }}
run: |
TAG="${GITHUB_REF#refs/tags/}"
curl \
-u ":$TOKEN" \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/esphome/home-assistant-addon/actions/workflows/bump-version.yml/dispatches \
https://api.github.com/repos/esphome/hassio/actions/workflows/bump-version.yml/dispatches \
-d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}"

View File

@@ -3,4 +3,4 @@ ports:
onOpen: open-preview
tasks:
- before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup
command: python -m esphome dashboard config
command: python -m esphome config dashboard

View File

@@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/ambv/black
rev: 22.1.0
rev: 20.8b1
hooks:
- id: black
args:
@@ -10,7 +10,7 @@ repos:
- --quiet
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
- repo: https://gitlab.com/pycqa/flake8
rev: 4.0.1
rev: 3.8.4
hooks:
- id: flake8
additional_dependencies:

View File

@@ -28,16 +28,13 @@ esphome/components/b_parasite/* @rbaron
esphome/components/ballu/* @bazuchan
esphome/components/bang_bang/* @OttoWinter
esphome/components/binary_sensor/* @esphome/core
esphome/components/bl0940/* @tobias-
esphome/components/ble_client/* @buxtronix
esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bmp3xx/* @martgras
esphome/components/button/* @esphome/core
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @MrEditor97
esphome/components/captive_portal/* @OttoWinter
esphome/components/ccs811/* @habbie
esphome/components/cd74hc4067/* @asoehlke
esphome/components/climate/* @esphome/core
esphome/components/climate_ir/* @glmnet
esphome/components/color_temperature/* @jesserockz
@@ -54,12 +51,10 @@ esphome/components/dfplayer/* @glmnet
esphome/components/dht/* @OttoWinter
esphome/components/ds1307/* @badbadc0ffee
esphome/components/dsmr/* @glmnet @zuidwijk
esphome/components/ektf2232/* @jesserockz
esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @jesserockz
esphome/components/esp32_ble_server/* @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/exposure_notifications/* @OttoWinter
@@ -80,21 +75,16 @@ esphome/components/homeassistant/* @OttoWinter
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/i2c/* @esphome/core
esphome/components/improv_serial/* @esphome/core
esphome/components/ina260/* @MrEditor97
esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter
esphome/components/interval/* @esphome/core
esphome/components/json/* @OttoWinter
esphome/components/kalman_combinator/* @Cat-Ion
esphome/components/ledc/* @OttoWinter
esphome/components/light/* @esphome/core
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/ltr390/* @sjtrny
esphome/components/max7219digit/* @rspaargaren
esphome/components/max9611/* @mckaymatthew
esphome/components/mcp23008/* @jesserockz
esphome/components/mcp23017/* @jesserockz
esphome/components/mcp23s08/* @SenexCrenshaw @jesserockz
@@ -103,20 +93,15 @@ esphome/components/mcp23x08_base/* @jesserockz
esphome/components/mcp23x17_base/* @jesserockz
esphome/components/mcp23xxx_base/* @jesserockz
esphome/components/mcp2515/* @danielschramm @mvturnho
esphome/components/mcp3204/* @rsumner
esphome/components/mcp47a1/* @jesserockz
esphome/components/mcp9808/* @k7hpn
esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core
esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey
esphome/components/mlx90393/* @functionpointer
esphome/components/modbus_controller/* @martgras
esphome/components/modbus_controller/binary_sensor/* @martgras
esphome/components/modbus_controller/number/* @martgras
esphome/components/modbus_controller/output/* @martgras
esphome/components/modbus_controller/select/* @martgras @stegm
esphome/components/modbus_controller/sensor/* @martgras
esphome/components/modbus_controller/switch/* @martgras
esphome/components/modbus_controller/text_sensor/* @martgras
@@ -139,12 +124,8 @@ esphome/components/pn532_i2c/* @OttoWinter @jesserockz
esphome/components/pn532_spi/* @OttoWinter @jesserockz
esphome/components/power_supply/* @esphome/core
esphome/components/preferences/* @esphome/core
esphome/components/psram/* @esphome/core
esphome/components/pulse_meter/* @stevebaxter
esphome/components/pvvx_mithermometer/* @pasiz
esphome/components/qr_code/* @wjtje
esphome/components/radon_eye_ble/* @jeffeb3
esphome/components/radon_eye_rd200/* @jeffeb3
esphome/components/rc522/* @glmnet
esphome/components/rc522_i2c/* @glmnet
esphome/components/rc522_spi/* @glmnet
@@ -196,7 +177,6 @@ esphome/components/tmp102/* @timsavage
esphome/components/tmp117/* @Azimath
esphome/components/tof10120/* @wstrzalka
esphome/components/toshiba/* @kbx81
esphome/components/touchscreen/* @jesserockz
esphome/components/tsl2591/* @wjcarpenter
esphome/components/tuya/binary_sensor/* @jesserockz
esphome/components/tuya/climate/* @jesserockz
@@ -207,10 +187,8 @@ esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core
esphome/components/ultrasonic/* @OttoWinter
esphome/components/version/* @esphome/core
esphome/components/wake_on_lan/* @willwill2will54
esphome/components/web_server_base/* @OttoWinter
esphome/components/whirlpool/* @glmnet
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc303/* @drug123
esphome/components/xiaomi_mhoc401/* @vevsvevs
esphome/components/xpt2046/* @numo68

View File

@@ -4,5 +4,4 @@ include requirements.txt
include esphome/dashboard/templates/*.html
recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE
recursive-include esphome *.cpp *.h *.tcc
recursive-include esphome *.py.script
recursive-include esphome LICENSE.txt

View File

@@ -5,12 +5,12 @@
# One of "docker", "hassio"
ARG BASEIMGTYPE=docker
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/armv7:5.2.3 AS base-hassio-armv7
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-armv7
FROM ghcr.io/hassio-addons/debian-base/amd64:5.1.1 AS base-hassio-amd64
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.1.1 AS base-hassio-arm64
FROM ghcr.io/hassio-addons/debian-base/armv7:5.1.1 AS base-hassio-armv7
FROM debian:bullseye-20211011-slim AS base-docker-amd64
FROM debian:bullseye-20211011-slim AS base-docker-arm64
FROM debian:bullseye-20211011-slim AS base-docker-armv7
# Use TARGETARCH/TARGETVARIANT defined by docker
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
@@ -23,11 +23,11 @@ RUN \
python3=3.9.2-3 \
python3-pip=20.3.4-4 \
python3-setuptools=52.0.0-4 \
python3-pil=8.1.2+dfsg-0.3+deb11u1 \
python3-pil=8.1.2+dfsg-0.3 \
python3-cryptography=3.3.2-1 \
iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u1 \
curl=7.74.0-1.3+b1 \
&& rm -rf \
/tmp/* \
/var/{cache,log}/* \
@@ -42,8 +42,8 @@ ENV \
RUN \
# Ubuntu python3-pip is missing wheel
pip3 install --no-cache-dir \
wheel==0.37.1 \
platformio==5.2.4 \
wheel==0.36.2 \
platformio==5.2.2 \
# Change some platformio settings
&& platformio settings set enable_telemetry No \
&& platformio settings set check_libraries_interval 1000000 \
@@ -64,7 +64,7 @@ RUN \
# Copy esphome and install
COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
RUN pip3 install --no-cache-dir -e /esphome
# Settings for dashboard
ENV USERNAME="" PASSWORD=""
@@ -102,7 +102,7 @@ RUN \
ARG BUILD_VERSION=dev
# Copy root filesystem
COPY docker/ha-addon-rootfs/ /
COPY docker/hassio-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 /
@@ -112,7 +112,7 @@ RUN \
# Copy esphome and install
COPY . /esphome
RUN pip3 install --no-cache-dir --no-use-pep517 -e /esphome
RUN pip3 install --no-cache-dir -e /esphome
# Labels
LABEL \

View File

@@ -32,7 +32,6 @@ parser.add_argument("--dry-run", action="store_true", help="Don't run any comman
subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
build_parser = subparsers.add_parser("build", help="Build the image")
build_parser.add_argument("--push", help="Also push the images", action="store_true")
build_parser.add_argument("--load", help="Load the docker image locally", action="store_true")
manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
@@ -133,8 +132,6 @@ def main():
cmd += ["--tag", img]
if args.push:
cmd += ["--push", "--cache-to", f"type=registry,ref={cache_img},mode=max"]
if args.load:
cmd += ["--load"]
run_command(*cmd, ".")
elif args.command == "manifest":

View File

@@ -10,7 +10,7 @@ server {
ssl_certificate_key /ssl/%%keyfile%%;
# Clear Hass.io Ingress header
proxy_set_header X-HA-Ingress "";
proxy_set_header X-Hassio-Ingress "";
# Redirect http requests to https on the same port.
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/

View File

@@ -4,7 +4,7 @@ server {
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
# Clear Hass.io Ingress header
proxy_set_header X-HA-Ingress "";
proxy_set_header X-Hassio-Ingress "";
location / {
proxy_pass http://esphome;

View File

@@ -3,8 +3,8 @@ server {
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
# Set Home Assistant Ingress header
proxy_set_header X-HA-Ingress "YES";
# Set Hass.io Ingress header
proxy_set_header X-Hassio-Ingress "YES";
location / {
# Only allow from Hass.io supervisor

View File

@@ -4,7 +4,7 @@
# Runs the ESPHome dashboard
# ==============================================================================
export ESPHOME_IS_HA_ADDON=true
export ESPHOME_IS_HASSIO=true
if bashio::config.true 'leave_front_door_open'; then
export DISABLE_HA_AUTHENTICATION=true
@@ -32,4 +32,4 @@ export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
bashio::log.info "Starting ESPHome dashboard..."
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --hassio

View File

@@ -661,7 +661,7 @@ def parse_args(argv):
"--open-ui", help="Open the dashboard UI in a browser.", action="store_true"
)
parser_dashboard.add_argument(
"--ha-addon", help=argparse.SUPPRESS, action="store_true"
"--hassio", help=argparse.SUPPRESS, action="store_true"
)
parser_dashboard.add_argument(
"--socket", help="Make the dashboard serve under a unix socket", type=str

View File

@@ -63,7 +63,6 @@ from esphome.cpp_types import ( # noqa
uint32,
uint64,
int32,
int64,
const_char_ptr,
NAN,
esphome_ns,
@@ -76,11 +75,11 @@ from esphome.cpp_types import ( # noqa
optional,
arduino_json_ns,
JsonObject,
JsonObjectConst,
JsonObjectRef,
JsonObjectConstRef,
Controller,
GPIOPin,
InternalGPIOPin,
gpio_Flags,
EntityCategory,
Parented,
)

View File

@@ -52,10 +52,10 @@ uint32_t IRAM_ATTR HOT AcDimmerDataStore::timer_intr(uint32_t now) {
this->gate_pin.digital_write(false);
}
if (time_since_zc < this->enable_time_us) {
if (time_since_zc < this->enable_time_us)
// Next event is enable, return time until that event
return this->enable_time_us - time_since_zc;
} else if (time_since_zc < disable_time_us) {
else if (time_since_zc < disable_time_us) {
// Next event is disable, return time until that event
return this->disable_time_us - time_since_zc;
}
@@ -74,10 +74,9 @@ uint32_t IRAM_ATTR HOT timer_interrupt() {
uint32_t min_dt_us = 1000;
uint32_t now = micros();
for (auto *dimmer : all_dimmers) {
if (dimmer == nullptr) {
if (dimmer == nullptr)
// no more dimmers
break;
}
uint32_t res = dimmer->timer_intr(now);
if (res != 0 && res < min_dt_us)
min_dt_us = res;
@@ -213,13 +212,12 @@ void AcDimmer::dump_config() {
LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_);
ESP_LOGCONFIG(TAG, " Min Power: %.1f%%", this->store_.min_power / 10.0f);
ESP_LOGCONFIG(TAG, " Init with half cycle: %s", YESNO(this->init_with_half_cycle_));
if (method_ == DIM_METHOD_LEADING_PULSE) {
if (method_ == DIM_METHOD_LEADING_PULSE)
ESP_LOGCONFIG(TAG, " Method: leading pulse");
} else if (method_ == DIM_METHOD_LEADING) {
else if (method_ == DIM_METHOD_LEADING)
ESP_LOGCONFIG(TAG, " Method: leading");
} else {
else
ESP_LOGCONFIG(TAG, " Method: trailing");
}
LOG_FLOAT_OUTPUT(this);
ESP_LOGV(TAG, " Estimated Frequency: %.3fHz", 1e6f / this->store_.cycle_time_us / 2);

View File

@@ -13,6 +13,7 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
public:
AdalightLightEffect(const std::string &name);
public:
void start() override;
void stop() override;
void apply(light::AddressableLight &it, const Color &current_color) override;
@@ -29,6 +30,7 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
void blank_all_leds_(light::AddressableLight &it);
Frame parse_frame_(light::AddressableLight &it);
protected:
uint32_t last_ack_{0};
uint32_t last_byte_{0};
uint32_t last_reset_{0};

View File

@@ -15,11 +15,6 @@ namespace esphome {
namespace adc {
static const char *const TAG = "adc";
// 13 bits for S3 / 12 bit for all other esp32 variants
// create a const to avoid the repated cast to enum
#ifdef USE_ESP32
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
#endif
void ADCSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
@@ -28,14 +23,14 @@ void ADCSensor::setup() {
#endif
#ifdef USE_ESP32
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
adc1_config_width(ADC_WIDTH_BIT_12);
if (!autorange_) {
adc1_config_channel_atten(channel_, attenuation_);
}
// load characteristics for each attenuation
for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) {
auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_BIT_12,
1100, // default vref
&cal_characteristics_[i]);
switch (cal_value) {
@@ -70,9 +65,9 @@ void ADCSensor::dump_config() {
#ifdef USE_ESP32
LOG_PIN(" Pin: ", pin_);
if (autorange_) {
if (autorange_)
ESP_LOGCONFIG(TAG, " Attenuation: auto");
} else {
else
switch (this->attenuation_) {
case ADC_ATTEN_DB_0:
ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
@@ -89,7 +84,6 @@ void ADCSensor::dump_config() {
default: // This is to satisfy the unused ADC_ATTEN_MAX
break;
}
}
#endif // USE_ESP32
LOG_UPDATE_INTERVAL(this);
}

View File

@@ -24,7 +24,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
case ESP_GATTC_SEARCH_CMPL_EVT: {
this->handle_ = 0;
auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_);
auto chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(),
sensors_data_characteristic_uuid_.to_string().c_str());
@@ -56,7 +56,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
}
void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) {
auto *value = (WaveMiniReadings *) raw_value;
auto value = (WaveMiniReadings *) raw_value;
if (sizeof(WaveMiniReadings) <= value_len) {
this->humidity_sensor_->publish_state(value->humidity / 100.0f);

View File

@@ -24,7 +24,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
case ESP_GATTC_SEARCH_CMPL_EVT: {
this->handle_ = 0;
auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_);
auto chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(),
sensors_data_characteristic_uuid_.to_string().c_str());
@@ -56,7 +56,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
}
void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) {
auto *value = (WavePlusReadings *) raw_value;
auto value = (WavePlusReadings *) raw_value;
if (sizeof(WavePlusReadings) <= value_len) {
ESP_LOGD(TAG, "version = %d", value->version);

View File

@@ -19,14 +19,12 @@ uint16_t crc_16(uint8_t *ptr, uint8_t length) {
//------------------------------
while (length--) {
crc ^= *ptr++;
for (i = 0; i < 8; i++) {
for (i = 0; i < 8; i++)
if ((crc & 0x01) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
} else
crc >>= 1;
}
}
}
return crc;
}

View File

@@ -39,7 +39,7 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
if (chr == nullptr) {
if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) {
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.",
@@ -75,14 +75,13 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
if (this->current_sensor_ > 0) {
if (this->illuminance_ != nullptr) {
auto *packet = this->encoder_->get_light_level_request();
auto packet = this->encoder_->get_light_level_request();
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
}
}
this->current_sensor_ = 0;
}
@@ -100,7 +99,7 @@ void Am43::update() {
}
if (this->current_sensor_ == 0) {
if (this->battery_ != nullptr) {
auto *packet = this->encoder_->get_battery_level_request();
auto packet = this->encoder_->get_battery_level_request();
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);

View File

@@ -5,7 +5,7 @@ from esphome.const import CONF_ID, CONF_PIN
CODEOWNERS = ["@buxtronix"]
DEPENDENCIES = ["ble_client"]
AUTO_LOAD = ["am43", "sensor"]
AUTO_LOAD = ["am43"]
CONF_INVERT_POSITION = "invert_position"

View File

@@ -25,16 +25,15 @@ void Am43Component::setup() {
void Am43Component::loop() {
if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) {
auto *packet = this->encoder_->get_send_pin_request(this->pin_);
auto packet = this->encoder_->get_send_pin_request(this->pin_);
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
if (status) {
if (status)
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
} else {
else
this->logged_in_ = true;
}
}
}
@@ -52,7 +51,7 @@ void Am43Component::control(const CoverCall &call) {
return;
}
if (call.get_stop()) {
auto *packet = this->encoder_->get_stop_request();
auto packet = this->encoder_->get_stop_request();
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
@@ -64,7 +63,7 @@ void Am43Component::control(const CoverCall &call) {
if (this->invert_position_)
pos = 1 - pos;
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
auto packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
@@ -81,7 +80,7 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
if (chr == nullptr) {
if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) {
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str());
@@ -121,7 +120,7 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
if (this->decoder_->has_pin_response()) {
if (this->decoder_->pin_ok_) {
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
auto *packet = this->encoder_->get_position_request();
auto packet = this->encoder_->get_position_request();
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);

View File

@@ -76,8 +76,6 @@ async def to_code(config):
pos = 0
for frameIndex in range(frames):
image.seek(frameIndex)
if CONF_RESIZE in config:
image.thumbnail(config[CONF_RESIZE])
frame = image.convert("RGB")
if CONF_RESIZE in config:
frame = frame.resize([width, height])

View File

@@ -40,7 +40,7 @@ void Anova::control(const ClimateCall &call) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}
if (call.get_target_temperature().has_value()) {
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
auto pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status)
@@ -57,7 +57,7 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
auto chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
@@ -114,10 +114,9 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length,
pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
}
}
}
break;
@@ -134,7 +133,7 @@ void Anova::update() {
return;
if (this->current_request_ < 2) {
auto *pkt = this->codec_->get_read_device_status_request();
auto pkt = this->codec_->get_read_device_status_request();
if (this->current_request_ == 0)
this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c');
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,

View File

@@ -36,7 +36,7 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode
traits.set_visual_temperature_step(0.1);
return traits;
}
void set_unit_of_measurement(const char *unit);
void set_unit_of_measurement(const char *);
protected:
std::unique_ptr<AnovaCodec> codec_;

View File

@@ -225,10 +225,9 @@ void APDS9960::read_gesture_data_() {
uint8_t fifo_level;
APDS9960_WARNING_CHECK(this->read_byte(0xAE, &fifo_level), "Reading FIFO level failed.");
if (fifo_level == 0) {
if (fifo_level == 0)
// no data to process
return;
}
APDS9960_WARNING_CHECK(fifo_level <= 32, "FIFO level has invalid value.")

View File

@@ -41,7 +41,6 @@ service APIConnection {
rpc number_command (NumberCommandRequest) returns (void) {}
rpc select_command (SelectCommandRequest) returns (void) {}
rpc button_command (ButtonCommandRequest) returns (void) {}
rpc lock_command (LockCommandRequest) returns (void) {}
}
@@ -96,9 +95,6 @@ message HelloResponse {
// and only exists for debugging/logging purposes.
// For example "ESPHome v1.10.0 on ESP8266"
string server_info = 3;
// The name of the server (App.get_name())
string name = 4;
}
// Message sent at the beginning of each connection to authenticate the client
@@ -529,7 +525,6 @@ message ListEntitiesSwitchResponse {
bool assumed_state = 6;
bool disabled_by_default = 7;
EntityCategory entity_category = 8;
string device_class = 9;
}
message SwitchStateResponse {
option (id) = 26;
@@ -958,63 +953,6 @@ message SelectCommandRequest {
string state = 2;
}
// ==================== LOCK ====================
enum LockState {
LOCK_STATE_NONE = 0;
LOCK_STATE_LOCKED = 1;
LOCK_STATE_UNLOCKED = 2;
LOCK_STATE_JAMMED = 3;
LOCK_STATE_LOCKING = 4;
LOCK_STATE_UNLOCKING = 5;
}
enum LockCommand {
LOCK_UNLOCK = 0;
LOCK_LOCK = 1;
LOCK_OPEN = 2;
}
message ListEntitiesLockResponse {
option (id) = 58;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_LOCK";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
bool disabled_by_default = 6;
EntityCategory entity_category = 7;
bool assumed_state = 8;
bool supports_open = 9;
bool requires_code = 10;
# Not yet implemented:
string code_format = 11;
}
message LockStateResponse {
option (id) = 59;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_LOCK";
option (no_delay) = true;
fixed32 key = 1;
LockState state = 2;
}
message LockCommandRequest {
option (id) = 60;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_LOCK";
option (no_delay) = true;
fixed32 key = 1;
LockCommand command = 2;
# Not yet implemented:
bool has_code = 3;
string code = 4;
}
// ==================== BUTTON ====================
message ListEntitiesButtonResponse {
option (id) = 61;
@@ -1039,4 +977,3 @@ message ButtonCommandRequest {
fixed32 key = 1;
}

View File

@@ -20,7 +20,6 @@ namespace esphome {
namespace api {
static const char *const TAG = "api.connection";
static const int ESP32_CAMERA_STOP_STREAM = 5000;
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
: parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
@@ -255,7 +254,7 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
// Shut-up about usage of deprecated speed_level_to_enum/speed_enum_to_level functions for a bit.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
bool APIConnection::send_fan_state(fan::Fan *fan) {
bool APIConnection::send_fan_state(fan::FanState *fan) {
if (!this->state_subscription_)
return false;
@@ -273,7 +272,7 @@ bool APIConnection::send_fan_state(fan::Fan *fan) {
resp.direction = static_cast<enums::FanDirection>(fan->direction);
return this->send_fan_state_response(resp);
}
bool APIConnection::send_fan_info(fan::Fan *fan) {
bool APIConnection::send_fan_info(fan::FanState *fan) {
auto traits = fan->get_traits();
ListEntitiesFanResponse msg;
msg.key = fan->get_object_id_hash();
@@ -290,7 +289,7 @@ bool APIConnection::send_fan_info(fan::Fan *fan) {
return this->send_list_entities_fan_response(msg);
}
void APIConnection::fan_command(const FanCommandRequest &msg) {
fan::Fan *fan = App.get_fan_by_key(msg.key);
fan::FanState *fan = App.get_fan_by_key(msg.key);
if (fan == nullptr)
return;
@@ -462,7 +461,6 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
msg.assumed_state = a_switch->assumed_state();
msg.disabled_by_default = a_switch->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(a_switch->get_entity_category());
msg.device_class = a_switch->get_device_class();
return this->send_list_entities_switch_response(msg);
}
void APIConnection::switch_command(const SwitchCommandRequest &msg) {
@@ -470,11 +468,10 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) {
if (a_switch == nullptr)
return;
if (msg.state) {
if (msg.state)
a_switch->turn_on();
} else {
else
a_switch->turn_off();
}
}
#endif
@@ -701,58 +698,13 @@ void APIConnection::button_command(const ButtonCommandRequest &msg) {
}
#endif
#ifdef USE_LOCK
bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) {
if (!this->state_subscription_)
return false;
LockStateResponse resp{};
resp.key = a_lock->get_object_id_hash();
resp.state = static_cast<enums::LockState>(state);
return this->send_lock_state_response(resp);
}
bool APIConnection::send_lock_info(lock::Lock *a_lock) {
ListEntitiesLockResponse msg;
msg.key = a_lock->get_object_id_hash();
msg.object_id = a_lock->get_object_id();
msg.name = a_lock->get_name();
msg.unique_id = get_default_unique_id("lock", a_lock);
msg.icon = a_lock->get_icon();
msg.assumed_state = a_lock->traits.get_assumed_state();
msg.disabled_by_default = a_lock->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(a_lock->get_entity_category());
msg.supports_open = a_lock->traits.get_supports_open();
msg.requires_code = a_lock->traits.get_requires_code();
return this->send_list_entities_lock_response(msg);
}
void APIConnection::lock_command(const LockCommandRequest &msg) {
lock::Lock *a_lock = App.get_lock_by_key(msg.key);
if (a_lock == nullptr)
return;
switch (msg.command) {
case enums::LOCK_UNLOCK:
a_lock->unlock();
break;
case enums::LOCK_LOCK:
a_lock->lock();
break;
case enums::LOCK_OPEN:
a_lock->open();
break;
}
}
#endif
#ifdef USE_ESP32_CAMERA
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
if (!this->state_subscription_)
return;
if (this->image_reader_.available())
return;
if (image->was_requested_by(esphome::esp32_camera::API_REQUESTER) ||
image->was_requested_by(esphome::esp32_camera::IDLE))
this->image_reader_.set_image(std::move(image));
this->image_reader_.set_image(std::move(image));
}
bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
ListEntitiesCameraResponse msg;
@@ -770,14 +722,9 @@ void APIConnection::camera_image(const CameraImageRequest &msg) {
return;
if (msg.single)
esp32_camera::global_esp32_camera->request_image(esphome::esp32_camera::API_REQUESTER);
if (msg.stream) {
esp32_camera::global_esp32_camera->start_stream(esphome::esp32_camera::API_REQUESTER);
App.scheduler.set_timeout(this->parent_, "api_esp32_camera_stop_stream", ESP32_CAMERA_STOP_STREAM, []() {
esp32_camera::global_esp32_camera->stop_stream(esphome::esp32_camera::API_REQUESTER);
});
}
esp32_camera::global_esp32_camera->request_image();
if (msg.stream)
esp32_camera::global_esp32_camera->request_stream();
}
#endif
@@ -811,8 +758,6 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
resp.api_version_major = 1;
resp.api_version_minor = 6;
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
this->connection_state_ = ConnectionState::CONNECTED;
return resp;
}
@@ -850,16 +795,15 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.project_version = ESPHOME_PROJECT_VERSION;
#endif
#ifdef USE_WEBSERVER
resp.webserver_port = USE_WEBSERVER_PORT;
resp.webserver_port = WEBSERVER_PORT;
#endif
return resp;
}
void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
for (auto &it : this->parent_->get_state_subs()) {
for (auto &it : this->parent_->get_state_subs())
if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
it.callback(msg.state);
}
}
}
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
bool found = false;

View File

@@ -32,8 +32,8 @@ class APIConnection : public APIServerConnection {
void cover_command(const CoverCommandRequest &msg) override;
#endif
#ifdef USE_FAN
bool send_fan_state(fan::Fan *fan);
bool send_fan_info(fan::Fan *fan);
bool send_fan_state(fan::FanState *fan);
bool send_fan_info(fan::FanState *fan);
void fan_command(const FanCommandRequest &msg) override;
#endif
#ifdef USE_LIGHT
@@ -77,11 +77,6 @@ class APIConnection : public APIServerConnection {
#ifdef USE_BUTTON
bool send_button_info(button::Button *button);
void button_command(const ButtonCommandRequest &msg) override;
#endif
#ifdef USE_LOCK
bool send_lock_state(lock::Lock *a_lock, lock::LockState state);
bool send_lock_info(lock::Lock *a_lock);
void lock_command(const LockCommandRequest &msg) override;
#endif
bool send_log_message(int level, const char *tag, const char *line);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {

View File

@@ -1,9 +1,7 @@
#include "api_frame_helper.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/application.h"
#include "proto.h"
#include <cstring>
@@ -303,16 +301,9 @@ APIError APINoiseFrameHelper::state_action_() {
}
if (state_ == State::SERVER_HELLO) {
// send server hello
std::vector<uint8_t> msg;
// chosen proto
msg.push_back(0x01);
// node name, terminated by null byte
const std::string &name = App.get_name();
const uint8_t *name_ptr = reinterpret_cast<const uint8_t *>(name.c_str());
msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
aerr = write_frame_(msg.data(), msg.size());
uint8_t msg[1];
msg[0] = 0x01; // chosen proto
aerr = write_frame_(msg, 1);
if (aerr != APIError::OK)
return aerr;
@@ -730,12 +721,7 @@ APIError APINoiseFrameHelper::shutdown(int how) {
}
extern "C" {
// declare how noise generates random bytes (here with a good HWRNG based on the RF system)
void noise_rand_bytes(void *output, size_t len) {
if (!esphome::random_bytes(reinterpret_cast<uint8_t *>(output), len)) {
ESP_LOGE(TAG, "Failed to acquire random bytes, rebooting!");
arch_restart();
}
}
void noise_rand_bytes(void *output, size_t len) { esphome::fill_random(reinterpret_cast<uint8_t *>(output), len); }
}
#endif // USE_API_NOISE

View File

@@ -278,36 +278,6 @@ template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) {
switch (value) {
case enums::LOCK_STATE_NONE:
return "LOCK_STATE_NONE";
case enums::LOCK_STATE_LOCKED:
return "LOCK_STATE_LOCKED";
case enums::LOCK_STATE_UNLOCKED:
return "LOCK_STATE_UNLOCKED";
case enums::LOCK_STATE_JAMMED:
return "LOCK_STATE_JAMMED";
case enums::LOCK_STATE_LOCKING:
return "LOCK_STATE_LOCKING";
case enums::LOCK_STATE_UNLOCKING:
return "LOCK_STATE_UNLOCKING";
default:
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) {
switch (value) {
case enums::LOCK_UNLOCK:
return "LOCK_UNLOCK";
case enums::LOCK_LOCK:
return "LOCK_LOCK";
case enums::LOCK_OPEN:
return "LOCK_OPEN";
default:
return "UNKNOWN";
}
}
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
@@ -349,10 +319,6 @@ bool HelloResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value)
this->server_info = value.as_string();
return true;
}
case 4: {
this->name = value.as_string();
return true;
}
default:
return false;
}
@@ -361,7 +327,6 @@ void HelloResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->api_version_major);
buffer.encode_uint32(2, this->api_version_minor);
buffer.encode_string(3, this->server_info);
buffer.encode_string(4, this->name);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HelloResponse::dump_to(std::string &out) const {
@@ -380,10 +345,6 @@ void HelloResponse::dump_to(std::string &out) const {
out.append(" server_info: ");
out.append("'").append(this->server_info).append("'");
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append("}");
}
#endif
@@ -2177,10 +2138,6 @@ bool ListEntitiesSwitchResponse::decode_length(uint32_t field_id, ProtoLengthDel
this->icon = value.as_string();
return true;
}
case 9: {
this->device_class = value.as_string();
return true;
}
default:
return false;
}
@@ -2204,7 +2161,6 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(6, this->assumed_state);
buffer.encode_bool(7, this->disabled_by_default);
buffer.encode_enum<enums::EntityCategory>(8, this->entity_category);
buffer.encode_string(9, this->device_class);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesSwitchResponse::dump_to(std::string &out) const {
@@ -2242,10 +2198,6 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const {
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" device_class: ");
out.append("'").append(this->device_class).append("'");
out.append("\n");
out.append("}");
}
#endif
@@ -4225,234 +4177,6 @@ void SelectCommandRequest::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool ListEntitiesLockResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 6: {
this->disabled_by_default = value.as_bool();
return true;
}
case 7: {
this->entity_category = value.as_enum<enums::EntityCategory>();
return true;
}
case 8: {
this->assumed_state = value.as_bool();
return true;
}
case 9: {
this->supports_open = value.as_bool();
return true;
}
case 10: {
this->requires_code = value.as_bool();
return true;
}
default:
return false;
}
}
bool ListEntitiesLockResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
this->object_id = value.as_string();
return true;
}
case 3: {
this->name = value.as_string();
return true;
}
case 4: {
this->unique_id = value.as_string();
return true;
}
case 5: {
this->icon = value.as_string();
return true;
}
case 11: {
this->code_format = value.as_string();
return true;
}
default:
return false;
}
}
bool ListEntitiesLockResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 2: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void ListEntitiesLockResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id);
buffer.encode_fixed32(2, this->key);
buffer.encode_string(3, this->name);
buffer.encode_string(4, this->unique_id);
buffer.encode_string(5, this->icon);
buffer.encode_bool(6, this->disabled_by_default);
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
buffer.encode_bool(8, this->assumed_state);
buffer.encode_bool(9, this->supports_open);
buffer.encode_bool(10, this->requires_code);
buffer.encode_string(11, this->code_format);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesLockResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("ListEntitiesLockResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
out.append("\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
out.append(buffer);
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" unique_id: ");
out.append("'").append(this->unique_id).append("'");
out.append("\n");
out.append(" icon: ");
out.append("'").append(this->icon).append("'");
out.append("\n");
out.append(" disabled_by_default: ");
out.append(YESNO(this->disabled_by_default));
out.append("\n");
out.append(" entity_category: ");
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
out.append("\n");
out.append(" assumed_state: ");
out.append(YESNO(this->assumed_state));
out.append("\n");
out.append(" supports_open: ");
out.append(YESNO(this->supports_open));
out.append("\n");
out.append(" requires_code: ");
out.append(YESNO(this->requires_code));
out.append("\n");
out.append(" code_format: ");
out.append("'").append(this->code_format).append("'");
out.append("\n");
out.append("}");
}
#endif
bool LockStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->state = value.as_enum<enums::LockState>();
return true;
}
default:
return false;
}
}
bool LockStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void LockStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_enum<enums::LockState>(2, this->state);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void LockStateResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("LockStateResponse {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
out.append(buffer);
out.append("\n");
out.append(" state: ");
out.append(proto_enum_to_string<enums::LockState>(this->state));
out.append("\n");
out.append("}");
}
#endif
bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->command = value.as_enum<enums::LockCommand>();
return true;
}
case 3: {
this->has_code = value.as_bool();
return true;
}
default:
return false;
}
}
bool LockCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4: {
this->code = value.as_string();
return true;
}
default:
return false;
}
}
bool LockCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
this->key = value.as_fixed32();
return true;
}
default:
return false;
}
}
void LockCommandRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_enum<enums::LockCommand>(2, this->command);
buffer.encode_bool(3, this->has_code);
buffer.encode_string(4, this->code);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void LockCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("LockCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);
out.append(buffer);
out.append("\n");
out.append(" command: ");
out.append(proto_enum_to_string<enums::LockCommand>(this->command));
out.append("\n");
out.append(" has_code: ");
out.append(YESNO(this->has_code));
out.append("\n");
out.append(" code: ");
out.append("'").append(this->code).append("'");
out.append("\n");
out.append("}");
}
#endif
bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 6: {
@@ -4515,7 +4239,7 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer buffer) const {
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesButtonResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ListEntitiesButtonResponse {\n");
out.append(" object_id: ");
out.append("'").append(this->object_id).append("'");
@@ -4565,7 +4289,7 @@ bool ButtonCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
void ButtonCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void ButtonCommandRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
char buffer[64];
out.append("ButtonCommandRequest {\n");
out.append(" key: ");
sprintf(buffer, "%u", this->key);

View File

@@ -128,19 +128,6 @@ enum NumberMode : uint32_t {
NUMBER_MODE_BOX = 1,
NUMBER_MODE_SLIDER = 2,
};
enum LockState : uint32_t {
LOCK_STATE_NONE = 0,
LOCK_STATE_LOCKED = 1,
LOCK_STATE_UNLOCKED = 2,
LOCK_STATE_JAMMED = 3,
LOCK_STATE_LOCKING = 4,
LOCK_STATE_UNLOCKING = 5,
};
enum LockCommand : uint32_t {
LOCK_UNLOCK = 0,
LOCK_LOCK = 1,
LOCK_OPEN = 2,
};
} // namespace enums
@@ -160,7 +147,6 @@ class HelloResponse : public ProtoMessage {
uint32_t api_version_major{0};
uint32_t api_version_minor{0};
std::string server_info{};
std::string name{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -580,7 +566,6 @@ class ListEntitiesSwitchResponse : public ProtoMessage {
bool assumed_state{false};
bool disabled_by_default{false};
enums::EntityCategory entity_category{};
std::string device_class{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1063,58 +1048,6 @@ class SelectCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
class ListEntitiesLockResponse : public ProtoMessage {
public:
std::string object_id{};
uint32_t key{0};
std::string name{};
std::string unique_id{};
std::string icon{};
bool disabled_by_default{false};
enums::EntityCategory entity_category{};
bool assumed_state{false};
bool supports_open{false};
bool requires_code{false};
std::string code_format{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class LockStateResponse : public ProtoMessage {
public:
uint32_t key{0};
enums::LockState state{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class LockCommandRequest : public ProtoMessage {
public:
uint32_t key{0};
enums::LockCommand command{};
bool has_code{false};
std::string code{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ListEntitiesButtonResponse : public ProtoMessage {
public:
std::string object_id{};

View File

@@ -282,24 +282,6 @@ bool APIServerConnectionBase::send_select_state_response(const SelectStateRespon
#endif
#ifdef USE_SELECT
#endif
#ifdef USE_LOCK
bool APIServerConnectionBase::send_list_entities_lock_response(const ListEntitiesLockResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_list_entities_lock_response: %s", msg.dump().c_str());
#endif
return this->send_message_<ListEntitiesLockResponse>(msg, 58);
}
#endif
#ifdef USE_LOCK
bool APIServerConnectionBase::send_lock_state_response(const LockStateResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_lock_state_response: %s", msg.dump().c_str());
#endif
return this->send_message_<LockStateResponse>(msg, 59);
}
#endif
#ifdef USE_LOCK
#endif
#ifdef USE_BUTTON
bool APIServerConnectionBase::send_list_entities_button_response(const ListEntitiesButtonResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -541,17 +523,6 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str());
#endif
this->on_select_command_request(msg);
#endif
break;
}
case 60: {
#ifdef USE_LOCK
LockCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str());
#endif
this->on_lock_command_request(msg);
#endif
break;
}
@@ -800,19 +771,6 @@ void APIServerConnection::on_button_command_request(const ButtonCommandRequest &
this->button_command(msg);
}
#endif
#ifdef USE_LOCK
void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->lock_command(msg);
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -130,15 +130,6 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_SELECT
virtual void on_select_command_request(const SelectCommandRequest &value){};
#endif
#ifdef USE_LOCK
bool send_list_entities_lock_response(const ListEntitiesLockResponse &msg);
#endif
#ifdef USE_LOCK
bool send_lock_state_response(const LockStateResponse &msg);
#endif
#ifdef USE_LOCK
virtual void on_lock_command_request(const LockCommandRequest &value){};
#endif
#ifdef USE_BUTTON
bool send_list_entities_button_response(const ListEntitiesButtonResponse &msg);
#endif
@@ -189,9 +180,6 @@ class APIServerConnection : public APIServerConnectionBase {
#endif
#ifdef USE_BUTTON
virtual void button_command(const ButtonCommandRequest &msg) = 0;
#endif
#ifdef USE_LOCK
virtual void lock_command(const LockCommandRequest &msg) = 0;
#endif
protected:
void on_hello_request(const HelloRequest &msg) override;
@@ -233,9 +221,6 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BUTTON
void on_button_command_request(const ButtonCommandRequest &msg) override;
#endif
#ifdef USE_LOCK
void on_lock_command_request(const LockCommandRequest &msg) override;
#endif
};
} // namespace api

View File

@@ -24,7 +24,7 @@ static const char *const TAG = "api";
void APIServer::setup() {
ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
this->setup_controller();
socket_ = socket::socket_ip(SOCK_STREAM, 0);
socket_ = socket::socket(AF_INET, SOCK_STREAM, 0);
if (socket_ == nullptr) {
ESP_LOGW(TAG, "Could not create socket.");
this->mark_failed();
@@ -43,16 +43,13 @@ void APIServer::setup() {
return;
}
struct sockaddr_storage server;
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = ESPHOME_INADDR_ANY;
server.sin_port = htons(this->port_);
socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_));
if (sl == 0) {
ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
this->mark_failed();
return;
}
err = socket_->bind((struct sockaddr *) &server, sl);
err = socket_->bind((struct sockaddr *) &server, sizeof(server));
if (err != 0) {
ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
this->mark_failed();
@@ -83,10 +80,9 @@ void APIServer::setup() {
if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
esp32_camera::global_esp32_camera->add_image_callback(
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) {
for (auto &c : this->clients_)
if (!c->remove_)
c->send_camera_state(image);
}
});
}
#endif
@@ -192,7 +188,7 @@ void APIServer::on_cover_update(cover::Cover *obj) {
#endif
#ifdef USE_FAN
void APIServer::on_fan_update(fan::Fan *obj) {
void APIServer::on_fan_update(fan::FanState *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
@@ -263,15 +259,6 @@ void APIServer::on_select_update(select::Select *obj, const std::string &state)
}
#endif
#ifdef USE_LOCK
void APIServer::on_lock_update(lock::Lock *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_lock_state(obj, obj->state);
}
#endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; }
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

View File

@@ -44,7 +44,7 @@ class APIServer : public Component, public Controller {
void on_cover_update(cover::Cover *obj) override;
#endif
#ifdef USE_FAN
void on_fan_update(fan::Fan *obj) override;
void on_fan_update(fan::FanState *obj) override;
#endif
#ifdef USE_LIGHT
void on_light_update(light::LightState *obj) override;
@@ -66,9 +66,6 @@ class APIServer : public Component, public Controller {
#endif
#ifdef USE_SELECT
void on_select_update(select::Select *obj, const std::string &state) override;
#endif
#ifdef USE_LOCK
void on_lock_update(lock::Lock *obj) override;
#endif
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }

View File

@@ -12,10 +12,10 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s
public:
TemplatableStringValue() : TemplatableValue<std::string, X...>() {}
template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0>
template<typename F, enable_if_t<!is_callable<F, X...>::value, int> = 0>
TemplatableStringValue(F value) : TemplatableValue<std::string, X...>(value) {}
template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0>
template<typename F, enable_if_t<is_callable<F, X...>::value, int> = 0>
TemplatableStringValue(F f)
: TemplatableValue<std::string, X...>([f](X... x) -> std::string { return to_string(f(x...)); }) {}
};

View File

@@ -16,7 +16,7 @@ bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_
bool ListEntitiesIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_info(cover); }
#endif
#ifdef USE_FAN
bool ListEntitiesIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_info(fan); }
bool ListEntitiesIterator::on_fan(fan::FanState *fan) { return this->client_->send_fan_info(fan); }
#endif
#ifdef USE_LIGHT
bool ListEntitiesIterator::on_light(light::LightState *light) { return this->client_->send_light_info(light); }
@@ -35,9 +35,6 @@ bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor)
return this->client_->send_text_sensor_info(text_sensor);
}
#endif
#ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_info(a_lock); }
#endif
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client)

View File

@@ -19,7 +19,7 @@ class ListEntitiesIterator : public ComponentIterator {
bool on_cover(cover::Cover *cover) override;
#endif
#ifdef USE_FAN
bool on_fan(fan::Fan *fan) override;
bool on_fan(fan::FanState *fan) override;
#endif
#ifdef USE_LIGHT
bool on_light(light::LightState *light) override;
@@ -48,9 +48,6 @@ class ListEntitiesIterator : public ComponentIterator {
#endif
#ifdef USE_SELECT
bool on_select(select::Select *select) override;
#endif
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
#endif
bool on_end() override;

View File

@@ -55,19 +55,17 @@ class ProtoVarInt {
}
int32_t as_sint32() const {
// with ZigZag encoding
if (this->value_ & 1) {
if (this->value_ & 1)
return static_cast<int32_t>(~(this->value_ >> 1));
} else {
else
return static_cast<int32_t>(this->value_ >> 1);
}
}
int64_t as_sint64() const {
// with ZigZag encoding
if (this->value_ & 1) {
if (this->value_ & 1)
return static_cast<int64_t>(~(this->value_ >> 1));
} else {
else
return static_cast<int64_t>(this->value_ >> 1);
}
}
void encode(std::vector<uint8_t> &out) {
uint32_t val = this->value_;
@@ -222,11 +220,10 @@ class ProtoWriteBuffer {
}
void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
uint32_t uvalue;
if (value < 0) {
if (value < 0)
uvalue = ~(value << 1);
} else {
else
uvalue = value << 1;
}
this->encode_uint32(field_id, uvalue, force);
}
template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) {

View File

@@ -14,7 +14,7 @@ bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_
bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); }
#endif
#ifdef USE_FAN
bool InitialStateIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_state(fan); }
bool InitialStateIterator::on_fan(fan::FanState *fan) { return this->client_->send_fan_state(fan); }
#endif
#ifdef USE_LIGHT
bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); }
@@ -47,9 +47,6 @@ bool InitialStateIterator::on_select(select::Select *select) {
return this->client_->send_select_state(select, select->state);
}
#endif
#ifdef USE_LOCK
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); }
#endif
InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
: ComponentIterator(server), client_(client) {}

View File

@@ -20,7 +20,7 @@ class InitialStateIterator : public ComponentIterator {
bool on_cover(cover::Cover *cover) override;
#endif
#ifdef USE_FAN
bool on_fan(fan::Fan *fan) override;
bool on_fan(fan::FanState *fan) override;
#endif
#ifdef USE_LIGHT
bool on_light(light::LightState *light) override;
@@ -45,9 +45,6 @@ class InitialStateIterator : public ComponentIterator {
#endif
#ifdef USE_SELECT
bool on_select(select::Select *select) override;
#endif
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
#endif
protected:
APIConnection *client_;

View File

@@ -52,7 +52,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
protected:
virtual void execute(Ts... x) = 0;
template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...> type) {
template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...>) {
this->execute((get_execute_arg_value<Ts>(args[S]))...);
}

View File

@@ -212,21 +212,6 @@ void ComponentIterator::advance() {
}
}
break;
#endif
#ifdef USE_LOCK
case IteratorState::LOCK:
if (this->at_ >= App.get_locks().size()) {
advance_platform = true;
} else {
auto *a_lock = App.get_locks()[this->at_];
if (a_lock->is_internal()) {
success = true;
break;
} else {
success = this->on_lock(a_lock);
}
}
break;
#endif
case IteratorState::MAX:
if (this->on_end()) {

View File

@@ -27,7 +27,7 @@ class ComponentIterator {
virtual bool on_cover(cover::Cover *cover) = 0;
#endif
#ifdef USE_FAN
virtual bool on_fan(fan::Fan *fan) = 0;
virtual bool on_fan(fan::FanState *fan) = 0;
#endif
#ifdef USE_LIGHT
virtual bool on_light(light::LightState *light) = 0;
@@ -56,9 +56,6 @@ class ComponentIterator {
#endif
#ifdef USE_SELECT
virtual bool on_select(select::Select *select) = 0;
#endif
#ifdef USE_LOCK
virtual bool on_lock(lock::Lock *a_lock) = 0;
#endif
virtual bool on_end();
@@ -102,9 +99,6 @@ class ComponentIterator {
#endif
#ifdef USE_SELECT
SELECT,
#endif
#ifdef USE_LOCK
LOCK,
#endif
MAX,
} state_{IteratorState::NONE};

View File

@@ -58,11 +58,10 @@ void AS3935Component::loop() {
void AS3935Component::write_indoor(bool indoor) {
ESP_LOGV(TAG, "Setting indoor to %d", indoor);
if (indoor) {
if (indoor)
this->write_register(AFE_GAIN, GAIN_MASK, INDOOR, 1);
} else {
else
this->write_register(AFE_GAIN, GAIN_MASK, OUTDOOR, 1);
}
}
// REG0x01, bits[3:0], manufacturer default: 0010 (2).
// This setting determines the threshold for events that trigger the

View File

@@ -45,8 +45,6 @@ bool ATCMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device
this->battery_voltage_->publish_state(*res->battery_voltage);
success = true;
}
if (this->signal_strength_ != nullptr)
this->signal_strength_->publish_state(device.get_rssi());
return success;
}

View File

@@ -28,7 +28,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_signal_strength(sensor::Sensor *signal_strength) { signal_strength_ = signal_strength; }
protected:
uint64_t address_;
@@ -36,7 +35,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
sensor::Sensor *humidity_{nullptr};
sensor::Sensor *battery_level_{nullptr};
sensor::Sensor *battery_voltage_{nullptr};
sensor::Sensor *signal_strength_{nullptr};
optional<ParseResult> parse_header_(const esp32_ble_tracker::ServiceData &service_data);
bool parse_message_(const std::vector<uint8_t> &message, ParseResult &result);

View File

@@ -6,18 +6,15 @@ from esphome.const import (
CONF_BATTERY_VOLTAGE,
CONF_MAC_ADDRESS,
CONF_HUMIDITY,
CONF_SIGNAL_STRENGTH,
CONF_TEMPERATURE,
CONF_ID,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
ENTITY_CATEGORY_DIAGNOSTIC,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_DECIBEL_MILLIWATT,
UNIT_PERCENT,
UNIT_VOLT,
)
@@ -62,13 +59,6 @@ CONFIG_SCHEMA = (
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
cv.Optional(CONF_SIGNAL_STRENGTH): sensor.sensor_schema(
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
@@ -95,6 +85,3 @@ async def to_code(config):
if CONF_BATTERY_VOLTAGE in config:
sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
cg.add(var.set_battery_voltage(sens))
if CONF_SIGNAL_STRENGTH in config:
sens = await sensor.new_sensor(config[CONF_SIGNAL_STRENGTH])
cg.add(var.set_signal_strength(sens))

View File

@@ -97,7 +97,7 @@ void BalluClimate::transmit_state() {
// Send code
auto transmit = this->transmitter_->transmit();
auto *data = transmit.get_data();
auto data = transmit.get_data();
data->set_carrier_frequency(38000);
@@ -130,10 +130,10 @@ bool BalluClimate::on_receive(remote_base::RemoteReceiveData data) {
for (int i = 0; i < BALLU_STATE_LENGTH; i++) {
// Read bit
for (int j = 0; j < 8; j++) {
if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE)) {
if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE))
remote_state[i] |= 1 << j;
} else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) {
else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) {
ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
return false;
}

View File

@@ -21,13 +21,12 @@ void BangBangClimate::setup() {
restore->to_call(this).perform();
} else {
// restore from defaults, change_away handles those for us
if (supports_cool_ && supports_heat_) {
if (supports_cool_ && supports_heat_)
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
} else if (supports_cool_) {
else if (supports_cool_)
this->mode = climate::CLIMATE_MODE_COOL;
} else if (supports_heat_) {
else if (supports_heat_)
this->mode = climate::CLIMATE_MODE_HEAT;
}
this->change_away_(false);
}
}
@@ -57,12 +56,11 @@ climate::ClimateTraits BangBangClimate::traits() {
if (supports_cool_ && supports_heat_)
traits.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL);
traits.set_supports_two_point_target_temperature(true);
if (supports_away_) {
if (supports_away_)
traits.set_supported_presets({
climate::CLIMATE_PRESET_HOME,
climate::CLIMATE_PRESET_AWAY,
});
}
traits.set_supports_action(true);
return traits;
}
@@ -82,25 +80,21 @@ void BangBangClimate::compute_state_() {
climate::ClimateAction target_action;
if (too_cold) {
// too cold -> enable heating if possible and enabled, else idle
if (this->supports_heat_ &&
(this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_HEAT)) {
// too cold -> enable heating if possible, else idle
if (this->supports_heat_)
target_action = climate::CLIMATE_ACTION_HEATING;
} else {
else
target_action = climate::CLIMATE_ACTION_IDLE;
}
} else if (too_hot) {
// too hot -> enable cooling if possible and enabled, else idle
if (this->supports_cool_ &&
(this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_COOL)) {
// too hot -> enable cooling if possible, else idle
if (this->supports_cool_)
target_action = climate::CLIMATE_ACTION_COOLING;
} else {
else
target_action = climate::CLIMATE_ACTION_IDLE;
}
} else {
// neither too hot nor too cold -> in range
if (this->supports_cool_ && this->supports_heat_ && this->mode == climate::CLIMATE_MODE_HEAT_COOL) {
// if supports both ends and both cooling and heating enabled, go to idle action
if (this->supports_cool_ && this->supports_heat_) {
// if supports both ends, go to idle action
target_action = climate::CLIMATE_ACTION_IDLE;
} else {
// else use current mode and don't change (hysteresis)
@@ -111,10 +105,9 @@ void BangBangClimate::compute_state_() {
this->switch_to_action_(target_action);
}
void BangBangClimate::switch_to_action_(climate::ClimateAction action) {
if (action == this->action) {
if (action == this->action)
// already in target mode
return;
}
if ((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) ||
(action == climate::CLIMATE_ACTION_IDLE && this->action == climate::CLIMATE_ACTION_OFF)) {

View File

@@ -9,7 +9,7 @@ from esphome.const import (
)
from .. import binary_ns
BinaryFan = binary_ns.class_("BinaryFan", fan.Fan, cg.Component)
BinaryFan = binary_ns.class_("BinaryFan", cg.Component)
CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
{
@@ -24,8 +24,9 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
async def to_code(config):
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
await cg.register_component(var, config)
await fan.register_fan(var, config)
fan_ = await fan.create_fan_state(config)
cg.add(var.set_fan(fan_))
output_ = await cg.get_variable(config[CONF_OUTPUT])
cg.add(var.set_output(output_))

View File

@@ -6,35 +6,59 @@ namespace binary {
static const char *const TAG = "binary.fan";
void BinaryFan::setup() {
auto restore = this->restore_state_();
if (restore.has_value()) {
restore->apply(*this);
this->write_state_();
void binary::BinaryFan::dump_config() {
ESP_LOGCONFIG(TAG, "Fan '%s':", this->fan_->get_name().c_str());
if (this->fan_->get_traits().supports_oscillation()) {
ESP_LOGCONFIG(TAG, " Oscillation: YES");
}
if (this->fan_->get_traits().supports_direction()) {
ESP_LOGCONFIG(TAG, " Direction: YES");
}
}
void BinaryFan::dump_config() { LOG_FAN("", "Binary Fan", this); }
fan::FanTraits BinaryFan::get_traits() {
return fan::FanTraits(this->oscillating_ != nullptr, false, this->direction_ != nullptr, 0);
void BinaryFan::setup() {
auto traits = fan::FanTraits(this->oscillating_ != nullptr, false, this->direction_ != nullptr, 0);
this->fan_->set_traits(traits);
this->fan_->add_on_state_callback([this]() { this->next_update_ = true; });
}
void BinaryFan::control(const fan::FanCall &call) {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_oscillating().has_value())
this->oscillating = *call.get_oscillating();
if (call.get_direction().has_value())
this->direction = *call.get_direction();
void BinaryFan::loop() {
if (!this->next_update_) {
return;
}
this->next_update_ = false;
this->write_state_();
this->publish_state();
}
void BinaryFan::write_state_() {
this->output_->set_state(this->state);
if (this->oscillating_ != nullptr)
this->oscillating_->set_state(this->oscillating);
if (this->direction_ != nullptr)
this->direction_->set_state(this->direction == fan::FanDirection::REVERSE);
{
bool enable = this->fan_->state;
if (enable)
this->output_->turn_on();
else
this->output_->turn_off();
ESP_LOGD(TAG, "Setting binary state: %s", ONOFF(enable));
}
if (this->oscillating_ != nullptr) {
bool enable = this->fan_->oscillating;
if (enable) {
this->oscillating_->turn_on();
} else {
this->oscillating_->turn_off();
}
ESP_LOGD(TAG, "Setting oscillation: %s", ONOFF(enable));
}
if (this->direction_ != nullptr) {
bool enable = this->fan_->direction == fan::FAN_DIRECTION_REVERSE;
if (enable) {
this->direction_->turn_on();
} else {
this->direction_->turn_off();
}
ESP_LOGD(TAG, "Setting reverse direction: %s", ONOFF(enable));
}
}
// We need a higher priority than the FanState component to make sure that the traits are set
// when that component sets itself up.
float BinaryFan::get_setup_priority() const { return fan_->get_setup_priority() + 1.0f; }
} // namespace binary
} // namespace esphome

View File

@@ -2,29 +2,28 @@
#include "esphome/core/component.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/fan/fan.h"
#include "esphome/components/fan/fan_state.h"
namespace esphome {
namespace binary {
class BinaryFan : public Component, public fan::Fan {
class BinaryFan : public Component {
public:
void set_fan(fan::FanState *fan) { fan_ = fan; }
void set_output(output::BinaryOutput *output) { output_ = output; }
void setup() override;
void loop() override;
void dump_config() override;
void set_output(output::BinaryOutput *output) { this->output_ = output; }
float get_setup_priority() const override;
void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; }
void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; }
fan::FanTraits get_traits() override;
protected:
void control(const fan::FanCall &call) override;
void write_state_();
fan::FanState *fan_;
output::BinaryOutput *output_;
output::BinaryOutput *oscillating_{nullptr};
output::BinaryOutput *direction_{nullptr};
bool next_update_{true};
};
} // namespace binary

View File

@@ -48,10 +48,7 @@ void BinarySensor::set_device_class(const std::string &device_class) { this->dev
std::string BinarySensor::get_device_class() {
if (this->device_class_.has_value())
return *this->device_class_;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return this->device_class();
#pragma GCC diagnostic pop
}
void BinarySensor::add_filter(Filter *filter) {
filter->parent_ = this;

View File

@@ -74,10 +74,7 @@ class BinarySensor : public EntityBase {
// ========== OVERRIDE METHODS ==========
// (You'll only need this when creating your own custom binary sensor)
/** Override this to set the default device class.
*
* @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
*/
/// Get the default device class for this sensor, or empty string for no default.
virtual std::string device_class();
protected:

View File

@@ -1 +0,0 @@
CODEOWNERS = ["@tobias-"]

View File

@@ -1,137 +0,0 @@
#include "bl0940.h"
#include "esphome/core/log.h"
namespace esphome {
namespace bl0940 {
static const char *const TAG = "bl0940";
static const uint8_t BL0940_READ_COMMAND = 0x50; // 0x58 according to documentation
static const uint8_t BL0940_FULL_PACKET = 0xAA;
static const uint8_t BL0940_PACKET_HEADER = 0x55; // 0x58 according to documentation
static const uint8_t BL0940_WRITE_COMMAND = 0xA0; // 0xA8 according to documentation
static const uint8_t BL0940_REG_I_FAST_RMS_CTRL = 0x10;
static const uint8_t BL0940_REG_MODE = 0x18;
static const uint8_t BL0940_REG_SOFT_RESET = 0x19;
static const uint8_t BL0940_REG_USR_WRPROT = 0x1A;
static const uint8_t BL0940_REG_TPS_CTRL = 0x1B;
const uint8_t BL0940_INIT[5][6] = {
// Reset to default
{BL0940_WRITE_COMMAND, BL0940_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38},
// Enable User Operation Write
{BL0940_WRITE_COMMAND, BL0940_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0},
// 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
{BL0940_WRITE_COMMAND, BL0940_REG_MODE, 0x00, 0x10, 0x00, 0x37},
// 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
{BL0940_WRITE_COMMAND, BL0940_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE},
// 0x181C = Half cycle, Fast RMS threshold 6172
{BL0940_WRITE_COMMAND, BL0940_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
void BL0940::loop() {
DataPacket buffer;
if (!this->available()) {
return;
}
if (read_array((uint8_t *) &buffer, sizeof(buffer))) {
if (validate_checksum(&buffer)) {
received_package_(&buffer);
}
} else {
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
while (read() >= 0)
;
}
}
bool BL0940::validate_checksum(const DataPacket *data) {
uint8_t checksum = BL0940_READ_COMMAND;
// Whole package but checksum
for (uint32_t i = 0; i < sizeof(data->raw) - 1; i++) {
checksum += data->raw[i];
}
checksum ^= 0xFF;
if (checksum != data->checksum) {
ESP_LOGW(TAG, "BL0940 invalid checksum! 0x%02X != 0x%02X", checksum, data->checksum);
}
return checksum == data->checksum;
}
void BL0940::update() {
this->flush();
this->write_byte(BL0940_READ_COMMAND);
this->write_byte(BL0940_FULL_PACKET);
}
void BL0940::setup() {
for (auto *i : BL0940_INIT) {
this->write_array(i, 6);
delay(1);
}
this->flush();
}
float BL0940::update_temp_(sensor::Sensor *sensor, ube16_t temperature) const {
auto tb = (float) (temperature.h << 8 | temperature.l);
float converted_temp = ((float) 170 / 448) * (tb / 2 - 32) - 45;
if (sensor != nullptr) {
if (sensor->has_state() && std::abs(converted_temp - sensor->get_state()) > max_temperature_diff_) {
ESP_LOGD("bl0940", "Invalid temperature change. Sensor: '%s', Old temperature: %f, New temperature: %f",
sensor->get_name().c_str(), sensor->get_state(), converted_temp);
return 0.0f;
}
sensor->publish_state(converted_temp);
}
return converted_temp;
}
void BL0940::received_package_(const DataPacket *data) const {
// Bad header
if (data->frame_header != BL0940_PACKET_HEADER) {
ESP_LOGI("bl0940", "Invalid data. Header mismatch: %d", data->frame_header);
return;
}
float v_rms = (float) to_uint32_t(data->v_rms) / voltage_reference_;
float i_rms = (float) to_uint32_t(data->i_rms) / current_reference_;
float watt = (float) to_int32_t(data->watt) / power_reference_;
uint32_t cf_cnt = to_uint32_t(data->cf_cnt);
float total_energy_consumption = (float) cf_cnt / energy_reference_;
float tps1 = update_temp_(internal_temperature_sensor_, data->tps1);
float tps2 = update_temp_(external_temperature_sensor_, data->tps2);
if (voltage_sensor_ != nullptr) {
voltage_sensor_->publish_state(v_rms);
}
if (current_sensor_ != nullptr) {
current_sensor_->publish_state(i_rms);
}
if (power_sensor_ != nullptr) {
power_sensor_->publish_state(watt);
}
if (energy_sensor_ != nullptr) {
energy_sensor_->publish_state(total_energy_consumption);
}
ESP_LOGV("bl0940", "BL0940: U %fV, I %fA, P %fW, Cnt %d, ∫P %fkWh, T1 %f°C, T2 %f°C", v_rms, i_rms, watt, cf_cnt,
total_energy_consumption, tps1, tps2);
}
void BL0940::dump_config() { // NOLINT(readability-function-cognitive-complexity)
ESP_LOGCONFIG(TAG, "BL0940:");
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_);
LOG_SENSOR("", "Energy", this->energy_sensor_);
LOG_SENSOR("", "Internal temperature", this->internal_temperature_sensor_);
LOG_SENSOR("", "External temperature", this->external_temperature_sensor_);
}
uint32_t BL0940::to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; }
int32_t BL0940::to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; }
} // namespace bl0940
} // namespace esphome

View File

@@ -1,109 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace bl0940 {
static const float BL0940_PREF = 1430;
static const float BL0940_UREF = 33000;
static const float BL0940_IREF = 275000; // 2750 from tasmota. Seems to generate values 100 times too high
// Measured to 297J per click according to power consumption of 5 minutes
// Converted to kWh (3.6MJ per kwH). Used to be 256 * 1638.4
static const float BL0940_EREF = 3.6e6 / 297;
struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t m;
uint8_t h;
} __attribute__((packed));
struct ube16_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t h;
} __attribute__((packed));
struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
uint8_t l;
uint8_t m;
int8_t h;
} __attribute__((packed));
// Caveat: All these values are big endian (low - middle - high)
union DataPacket { // NOLINT(altera-struct-pack-align)
uint8_t raw[35];
struct {
uint8_t frame_header; // value of 0x58 according to docs. 0x55 according to Tasmota real world tests. Reality wins.
ube24_t i_fast_rms; // 0x00
ube24_t i_rms; // 0x04
ube24_t RESERVED0; // reserved
ube24_t v_rms; // 0x06
ube24_t RESERVED1; // reserved
sbe24_t watt; // 0x08
ube24_t RESERVED2; // reserved
ube24_t cf_cnt; // 0x0A
ube24_t RESERVED3; // reserved
ube16_t tps1; // 0x0c
uint8_t RESERVED4; // value of 0x00
ube16_t tps2; // 0x0c
uint8_t RESERVED5; // value of 0x00
uint8_t checksum; // checksum
};
} __attribute__((packed));
class BL0940 : public PollingComponent, public uart::UARTDevice {
public:
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_internal_temperature_sensor(sensor::Sensor *internal_temperature_sensor) {
internal_temperature_sensor_ = internal_temperature_sensor;
}
void set_external_temperature_sensor(sensor::Sensor *external_temperature_sensor) {
external_temperature_sensor_ = external_temperature_sensor;
}
void loop() override;
void update() override;
void setup() override;
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
// NB This may be negative as the circuits is seemingly able to measure
// power in both directions
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *internal_temperature_sensor_;
sensor::Sensor *external_temperature_sensor_;
// Max difference between two measurements of the temperature. Used to avoid noise.
float max_temperature_diff_{0};
// Divide by this to turn into Watt
float power_reference_ = BL0940_PREF;
// Divide by this to turn into Volt
float voltage_reference_ = BL0940_UREF;
// Divide by this to turn into Ampere
float current_reference_ = BL0940_IREF;
// Divide by this to turn into kWh
float energy_reference_ = BL0940_EREF;
float update_temp_(sensor::Sensor *sensor, ube16_t packed_temperature) const;
static uint32_t to_uint32_t(ube24_t input);
static int32_t to_int32_t(sbe24_t input);
static bool validate_checksum(const DataPacket *data);
void received_package_(const DataPacket *data) const;
};
} // namespace bl0940
} // namespace esphome

View File

@@ -1,106 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, uart
from esphome.const import (
CONF_CURRENT,
CONF_ENERGY,
CONF_ID,
CONF_POWER,
CONF_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_TEMPERATURE,
ICON_EMPTY,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_KILOWATT_HOURS,
UNIT_VOLT,
UNIT_WATT,
)
DEPENDENCIES = ["uart"]
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
bl0940_ns = cg.esphome_ns.namespace("bl0940")
BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BL0940),
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
UNIT_AMPERE,
ICON_EMPTY,
2,
DEVICE_CLASS_CURRENT,
STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER): sensor.sensor_schema(
UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
),
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
UNIT_KILOWATT_HOURS,
ICON_EMPTY,
0,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
),
cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
UNIT_CELSIUS,
ICON_EMPTY,
0,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_NONE,
),
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
UNIT_CELSIUS,
ICON_EMPTY,
0,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_NONE,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(uart.UART_DEVICE_SCHEMA)
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
if CONF_VOLTAGE in config:
conf = config[CONF_VOLTAGE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_voltage_sensor(sens))
if CONF_CURRENT in config:
conf = config[CONF_CURRENT]
sens = await sensor.new_sensor(conf)
cg.add(var.set_current_sensor(sens))
if CONF_POWER in config:
conf = config[CONF_POWER]
sens = await sensor.new_sensor(conf)
cg.add(var.set_power_sensor(sens))
if CONF_ENERGY in config:
conf = config[CONF_ENERGY]
sens = await sensor.new_sensor(conf)
cg.add(var.set_energy_sensor(sens))
if CONF_INTERNAL_TEMPERATURE in config:
conf = config[CONF_INTERNAL_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_internal_temperature_sensor(sens))
if CONF_EXTERNAL_TEMPERATURE in config:
conf = config[CONF_EXTERNAL_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_external_temperature_sensor(sens))

View File

@@ -167,7 +167,7 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es
break;
}
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
auto *descr = this->get_config_descriptor(param->reg_for_notify.handle);
auto descr = this->get_config_descriptor(param->reg_for_notify.handle);
if (descr == nullptr) {
ESP_LOGW(TAG, "No descriptor found for notify of handle 0x%x", param->reg_for_notify.handle);
break;
@@ -252,17 +252,16 @@ float BLEClient::parse_char_value(uint8_t *value, uint16_t length) {
}
BLEService *BLEClient::get_service(espbt::ESPBTUUID uuid) {
for (auto *svc : this->services_) {
for (auto svc : this->services_)
if (svc->uuid == uuid)
return svc;
}
return nullptr;
}
BLEService *BLEClient::get_service(uint16_t uuid) { return this->get_service(espbt::ESPBTUUID::from_uint16(uuid)); }
BLECharacteristic *BLEClient::get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr) {
auto *svc = this->get_service(service);
auto svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
return svc->get_characteristic(chr);
@@ -273,24 +272,19 @@ BLECharacteristic *BLEClient::get_characteristic(uint16_t service, uint16_t chr)
}
BLEDescriptor *BLEClient::get_config_descriptor(uint16_t handle) {
for (auto &svc : this->services_) {
for (auto &chr : svc->characteristics) {
if (chr->handle == handle) {
for (auto &desc : chr->descriptors) {
for (auto &svc : this->services_)
for (auto &chr : svc->characteristics)
if (chr->handle == handle)
for (auto &desc : chr->descriptors)
if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902))
return desc;
}
}
}
}
return nullptr;
}
BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) {
for (auto &chr : this->characteristics) {
for (auto &chr : this->characteristics)
if (chr->uuid == uuid)
return chr;
}
return nullptr;
}
@@ -299,10 +293,10 @@ BLECharacteristic *BLEService::get_characteristic(uint16_t uuid) {
}
BLEDescriptor *BLEClient::get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr) {
auto *svc = this->get_service(service);
auto svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
auto *ch = svc->get_characteristic(chr);
auto ch = svc->get_characteristic(chr);
if (ch == nullptr)
return nullptr;
return ch->get_descriptor(descr);
@@ -385,29 +379,24 @@ void BLECharacteristic::parse_descriptors() {
}
BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) {
for (auto &desc : this->descriptors) {
for (auto &desc : this->descriptors)
if (desc->uuid == uuid)
return desc;
}
return nullptr;
}
BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type) {
auto *client = this->service->client;
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) {
auto client = this->service->client;
auto status = esp_ble_gattc_write_char(client->gattc_if, client->conn_id, this->handle, new_val_size, new_val,
write_type, ESP_GATT_AUTH_REQ_NONE);
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status);
}
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) {
write_value(new_val, new_val_size, ESP_GATT_WRITE_TYPE_NO_RSP);
}
} // namespace ble_client
} // namespace esphome

View File

@@ -60,7 +60,6 @@ class BLECharacteristic {
BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid);
BLEDescriptor *get_descriptor(uint16_t uuid);
void write_value(uint8_t *new_val, int16_t new_val_size);
void write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type);
BLEService *service;
};
@@ -127,10 +126,9 @@ class BLEClient : public espbt::ESPBTClient, public Component {
bool all_nodes_established_() {
if (this->state() != espbt::ClientState::ESTABLISHED)
return false;
for (auto &node : nodes_) {
for (auto &node : nodes_)
if (node->node_state != espbt::ClientState::ESTABLISHED)
return false;
}
return true;
}

View File

@@ -1,14 +1,13 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import ble_client, esp32_ble_tracker, output
from esphome.components import output, ble_client, esp32_ble_tracker
from esphome.const import CONF_ID, CONF_SERVICE_UUID
from .. import ble_client_ns
DEPENDENCIES = ["ble_client"]
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
CONF_REQUIRE_RESPONSE = "require_response"
BLEBinaryOutput = ble_client_ns.class_(
"BLEBinaryOutput", output.BinaryOutput, ble_client.BLEClientNode, cg.Component
@@ -20,7 +19,6 @@ CONFIG_SCHEMA = cv.All(
cv.Required(CONF_ID): cv.declare_id(BLEBinaryOutput),
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_REQUIRE_RESPONSE, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
@@ -63,7 +61,7 @@ def to_code(config):
config[CONF_CHARACTERISTIC_UUID]
)
cg.add(var.set_char_uuid128(uuid128))
cg.add(var.set_require_response(config[CONF_REQUIRE_RESPONSE]))
yield output.register_output(var, config)
yield ble_client.register_ble_node(var, config)
yield cg.register_component(var, config)

View File

@@ -32,7 +32,7 @@ void BLEBinaryOutput::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
break;
}
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] Characteristic not found.", this->char_uuid_.to_string().c_str());
break;
@@ -54,7 +54,7 @@ void BLEBinaryOutput::write_state(bool state) {
return;
}
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] Characteristic not found. State update can not be written.",
this->char_uuid_.to_string().c_str());
@@ -63,11 +63,7 @@ void BLEBinaryOutput::write_state(bool state) {
uint8_t state_as_uint = (uint8_t) state;
ESP_LOGV(TAG, "[%s] Write State: %d", this->char_uuid_.to_string().c_str(), state_as_uint);
if (this->require_response_) {
chr->write_value(&state_as_uint, sizeof(state_as_uint), ESP_GATT_WRITE_TYPE_RSP);
} else {
chr->write_value(&state_as_uint, sizeof(state_as_uint), ESP_GATT_WRITE_TYPE_NO_RSP);
}
chr->write_value(&state_as_uint, sizeof(state_as_uint));
}
} // namespace ble_client

View File

@@ -25,11 +25,9 @@ class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, publi
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
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 set_require_response(bool response) { this->require_response_ = response; }
protected:
void write_state(bool state) override;
bool require_response_;
espbt::ESPBTUUID service_uuid_;
espbt::ESPBTUUID char_uuid_;
espbt::ClientState client_state_;

View File

@@ -43,7 +43,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
this->handle = 0;
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
if (chr == nullptr) {
this->status_set_warning();
this->publish_state(NAN);
@@ -53,7 +53,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
}
this->handle = chr->handle;
if (this->descr_uuid_.get_uuid().len > 0) {
auto *descr = chr->get_descriptor(this->descr_uuid_);
auto descr = chr->get_descriptor(this->descr_uuid_);
if (descr == nullptr) {
this->status_set_warning();
this->publish_state(NAN);

View File

@@ -1,6 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor, esp32_ble_tracker
from esphome.const import CONF_ID
DEPENDENCIES = ["esp32_ble_tracker"]
@@ -13,13 +14,18 @@ BLEScanner = ble_scanner_ns.class_(
)
CONFIG_SCHEMA = cv.All(
text_sensor.text_sensor_schema(klass=BLEScanner)
text_sensor.TEXT_SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(BLEScanner),
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
var = await text_sensor.new_text_sensor(config)
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await esp32_ble_tracker.register_ble_device(var, config)
await text_sensor.register_text_sensor(var, config)

View File

@@ -214,10 +214,9 @@ void BME280Component::update() {
float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) {
int32_t adc = ((data[3] & 0xFF) << 16) | ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
adc >>= 4;
if (adc == 0x80000) {
if (adc == 0x80000)
// temperature was disabled
return NAN;
}
const int32_t t1 = this->calibration_.t1;
const int32_t t2 = this->calibration_.t2;
@@ -234,10 +233,9 @@ float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) {
float BME280Component::read_pressure_(const uint8_t *data, int32_t t_fine) {
int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
adc >>= 4;
if (adc == 0x80000) {
if (adc == 0x80000)
// pressure was disabled
return NAN;
}
const int64_t p1 = this->calibration_.p1;
const int64_t p2 = this->calibration_.p2;
const int64_t p3 = this->calibration_.p3;

View File

@@ -95,7 +95,7 @@ void BME680Component::setup() {
this->calibration_.t3 = cal1[3];
this->calibration_.h1 = cal2[2] << 4 | (cal2[1] & 0x0F);
this->calibration_.h2 = cal2[0] << 4 | cal2[1] >> 4;
this->calibration_.h2 = cal2[0] << 4 | cal2[1];
this->calibration_.h3 = cal2[3];
this->calibration_.h4 = cal2[4];
this->calibration_.h5 = cal2[5];
@@ -420,11 +420,10 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) {
calc_hum = var2 + (var3 + var4 * temp_comp) * var2 * var2;
if (calc_hum > 100.0f) {
if (calc_hum > 100.0f)
calc_hum = 100.0f;
} else if (calc_hum < 0.0f) {
else if (calc_hum < 0.0f)
calc_hum = 0.0f;
}
return calc_hum;
}

View File

@@ -1,6 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor
from esphome.const import CONF_ID, CONF_ICON
from . import BME680BSECComponent, CONF_BME680_BSEC_ID
DEPENDENCIES = ["bme680_bsec"]
@@ -13,8 +14,11 @@ TYPES = [CONF_IAQ_ACCURACY]
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent),
cv.Optional(CONF_IAQ_ACCURACY): text_sensor.text_sensor_schema(
icon=ICON_ACCURACY
cv.Optional(CONF_IAQ_ACCURACY): text_sensor.TEXT_SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(text_sensor.TextSensor),
cv.Optional(CONF_ICON, default=ICON_ACCURACY): cv.icon,
}
),
}
)
@@ -23,7 +27,8 @@ CONFIG_SCHEMA = cv.Schema(
async def setup_conf(config, key, hub):
if key in config:
conf = config[key]
sens = await text_sensor.new_text_sensor(conf)
sens = cg.new_Pvariable(conf[CONF_ID])
await text_sensor.register_text_sensor(sens, conf)
cg.add(getattr(hub, f"set_{key}_text_sensor")(sens))

View File

@@ -161,10 +161,9 @@ float BMP280Component::read_temperature_(int32_t *t_fine) {
return NAN;
int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
adc >>= 4;
if (adc == 0x80000) {
if (adc == 0x80000)
// temperature was disabled
return NAN;
}
const int32_t t1 = this->calibration_.t1;
const int32_t t2 = this->calibration_.t2;
@@ -184,10 +183,9 @@ float BMP280Component::read_pressure_(int32_t t_fine) {
return NAN;
int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
adc >>= 4;
if (adc == 0x80000) {
if (adc == 0x80000)
// pressure was disabled
return NAN;
}
const int64_t p1 = this->calibration_.p1;
const int64_t p2 = this->calibration_.p2;
const int64_t p3 = this->calibration_.p3;

View File

@@ -1,388 +0,0 @@
/*
based on BMP388_DEV by Martin Lindupp
under MIT License (MIT)
Copyright (C) Martin Lindupp 2020
http://github.com/MartinL1/BMP388_DEV
*/
#include "bmp3xx.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace bmp3xx {
static const char *const TAG = "bmp3xx.sensor";
static const LogString *chip_type_to_str(uint8_t chip_type) {
switch (chip_type) {
case BMP388_ID:
return LOG_STR("BMP 388");
case BMP390_ID:
return LOG_STR("BMP 390");
default:
return LOG_STR("Unknown Chip Type");
}
}
static const LogString *oversampling_to_str(Oversampling oversampling) {
switch (oversampling) {
case Oversampling::OVERSAMPLING_NONE:
return LOG_STR("None");
case Oversampling::OVERSAMPLING_X2:
return LOG_STR("2x");
case Oversampling::OVERSAMPLING_X4:
return LOG_STR("4x");
case Oversampling::OVERSAMPLING_X8:
return LOG_STR("8x");
case Oversampling::OVERSAMPLING_X16:
return LOG_STR("16x");
case Oversampling::OVERSAMPLING_X32:
return LOG_STR("32x");
default:
return LOG_STR("");
}
}
static const LogString *iir_filter_to_str(IIRFilter filter) {
switch (filter) {
case IIRFilter::IIR_FILTER_OFF:
return LOG_STR("OFF");
case IIRFilter::IIR_FILTER_2:
return LOG_STR("2x");
case IIRFilter::IIR_FILTER_4:
return LOG_STR("4x");
case IIRFilter::IIR_FILTER_8:
return LOG_STR("8x");
case IIRFilter::IIR_FILTER_16:
return LOG_STR("16x");
case IIRFilter::IIR_FILTER_32:
return LOG_STR("32x");
case IIRFilter::IIR_FILTER_64:
return LOG_STR("64x");
case IIRFilter::IIR_FILTER_128:
return LOG_STR("128x");
default:
return LOG_STR("");
}
}
void BMP3XXComponent::setup() {
this->error_code_ = NONE;
ESP_LOGCONFIG(TAG, "Setting up BMP3XX...");
// Call the Device base class "initialise" function
if (!reset()) {
ESP_LOGE(TAG, "Failed to reset BMP3XX...");
this->error_code_ = ERROR_SENSOR_RESET;
this->mark_failed();
}
if (!read_byte(BMP388_CHIP_ID, &this->chip_id_.reg)) {
ESP_LOGE(TAG, "Can't read chip id");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Chip %s Id 0x%X", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
if (chip_id_.reg != BMP388_ID && chip_id_.reg != BMP390_ID) {
ESP_LOGE(TAG, "Unknown chip id - is this really a BMP388 or BMP390?");
this->error_code_ = ERROR_WRONG_CHIP_ID;
this->mark_failed();
return;
}
// set sensor in sleep mode
stop_conversion();
// Read the calibration parameters into the params structure
if (!read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_))) {
ESP_LOGE(TAG, "Can't read calibration data");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
compensation_float_params_.param_T1 =
(float) compensation_params_.param_T1 / powf(2.0f, -8.0f); // Calculate the floating point trim parameters
compensation_float_params_.param_T2 = (float) compensation_params_.param_T2 / powf(2.0f, 30.0f);
compensation_float_params_.param_T3 = (float) compensation_params_.param_T3 / powf(2.0f, 48.0f);
compensation_float_params_.param_P1 = ((float) compensation_params_.param_P1 - powf(2.0f, 14.0f)) / powf(2.0f, 20.0f);
compensation_float_params_.param_P2 = ((float) compensation_params_.param_P2 - powf(2.0f, 14.0f)) / powf(2.0f, 29.0f);
compensation_float_params_.param_P3 = (float) compensation_params_.param_P3 / powf(2.0f, 32.0f);
compensation_float_params_.param_P4 = (float) compensation_params_.param_P4 / powf(2.0f, 37.0f);
compensation_float_params_.param_P5 = (float) compensation_params_.param_P5 / powf(2.0f, -3.0f);
compensation_float_params_.param_P6 = (float) compensation_params_.param_P6 / powf(2.0f, 6.0f);
compensation_float_params_.param_P7 = (float) compensation_params_.param_P7 / powf(2.0f, 8.0f);
compensation_float_params_.param_P8 = (float) compensation_params_.param_P8 / powf(2.0f, 15.0f);
compensation_float_params_.param_P9 = (float) compensation_params_.param_P9 / powf(2.0f, 48.0f);
compensation_float_params_.param_P10 = (float) compensation_params_.param_P10 / powf(2.0f, 48.0f);
compensation_float_params_.param_P11 = (float) compensation_params_.param_P11 / powf(2.0f, 65.0f);
// Initialise the BMP388 IIR filter register
if (!set_iir_filter(this->iir_filter_)) {
ESP_LOGE(TAG, "Failed to set IIR filter");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
// Set power control registers
pwr_ctrl_.bit.press_en = 1;
pwr_ctrl_.bit.temp_en = 1;
// Disable pressure if no sensor defined
// keep temperature enabled since it's needed for compensation
if (this->pressure_sensor_ == nullptr) {
pwr_ctrl_.bit.press_en = 0;
this->pressure_oversampling_ = OVERSAMPLING_NONE;
}
// just disable oeversampling for temp if not used
if (this->temperature_sensor_ == nullptr) {
this->temperature_oversampling_ = OVERSAMPLING_NONE;
}
// Initialise the BMP388 oversampling register
if (!set_oversampling_register(this->pressure_oversampling_, this->temperature_oversampling_)) {
ESP_LOGE(TAG, "Failed to set oversampling register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
}
void BMP3XXComponent::dump_config() {
ESP_LOGCONFIG(TAG, "BMP3XX:");
ESP_LOGCONFIG(TAG, " Type: %s (0x%X)", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
LOG_I2C_DEVICE(this);
switch (this->error_code_) {
case NONE:
break;
case ERROR_COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Communication with BMP3XX failed!");
break;
case ERROR_WRONG_CHIP_ID:
ESP_LOGE(
TAG,
"BMP3XX has wrong chip ID (reported id: 0x%X) - please check if you are really using a BMP 388 or BMP 390",
this->chip_id_.reg);
break;
case ERROR_SENSOR_RESET:
ESP_LOGE(TAG, "BMP3XX failed to reset");
break;
default:
ESP_LOGE(TAG, "BMP3XX error code %d", (int) this->error_code_);
break;
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_filter_)));
LOG_UPDATE_INTERVAL(this);
if (this->temperature_sensor_) {
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_)));
}
if (this->pressure_sensor_) {
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_)));
}
}
float BMP3XXComponent::get_setup_priority() const { return setup_priority::DATA; }
inline uint8_t oversampling_to_time(Oversampling over_sampling) { return (1 << uint8_t(over_sampling)); }
void BMP3XXComponent::update() {
// Enable sensor
ESP_LOGV(TAG, "Sending conversion request...");
float meas_time = 1.0f;
// Ref: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf 3.9.2
meas_time += 2.02f * oversampling_to_time(this->temperature_oversampling_) + 0.163f;
meas_time += 2.02f * oversampling_to_time(this->pressure_oversampling_) + 0.392f;
meas_time += 0.234f;
if (!set_mode(FORCED_MODE)) {
ESP_LOGE(TAG, "Failed start forced mode");
this->mark_failed();
return;
}
ESP_LOGVV(TAG, "measurement time %d", uint32_t(ceilf(meas_time)));
this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
float temperature = 0.0f;
float pressure = 0.0f;
if (this->pressure_sensor_ != nullptr) {
if (!get_measurements(temperature, pressure)) {
ESP_LOGW(TAG, "Failed to read pressure and temperature - skipping update");
this->status_set_warning();
return;
}
ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa", temperature, pressure);
} else {
if (!get_temperature(temperature)) {
ESP_LOGW(TAG, "Failed to read temperature - skipping update");
this->status_set_warning();
return;
}
ESP_LOGD(TAG, "Got temperature=%.1f°C", temperature);
}
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->pressure_sensor_ != nullptr)
this->pressure_sensor_->publish_state(pressure);
this->status_clear_warning();
set_mode(SLEEP_MODE);
});
}
// Reset the BMP3XX
uint8_t BMP3XXComponent::reset() {
write_byte(BMP388_CMD, RESET_CODE); // Write the reset code to the command register
// Wait for 10ms
delay(10);
this->read_byte(BMP388_EVENT, &event_.reg); // Read the BMP388's event register
return event_.bit.por_detected; // Return if device reset is complete
}
// Start a one shot measurement in FORCED_MODE
bool BMP3XXComponent::start_forced_conversion() {
// Only set FORCED_MODE if we're already in SLEEP_MODE
if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
return set_mode(FORCED_MODE);
}
return true;
}
// Stop the conversion and return to SLEEP_MODE
bool BMP3XXComponent::stop_conversion() { return set_mode(SLEEP_MODE); }
// Set the pressure oversampling rate
bool BMP3XXComponent::set_pressure_oversampling(Oversampling oversampling) {
osr_.bit.osr_p = oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Set the temperature oversampling rate
bool BMP3XXComponent::set_temperature_oversampling(Oversampling oversampling) {
osr_.bit.osr_t = oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Set the IIR filter setting
bool BMP3XXComponent::set_iir_filter(IIRFilter iir_filter) {
config_.bit.iir_filter = iir_filter;
return this->write_byte(BMP388_CONFIG, config_.reg);
}
// Get temperature
bool BMP3XXComponent::get_temperature(float &temperature) {
// Check if a measurement is ready
if (!data_ready()) {
return false;
}
uint8_t data[3];
// Read the temperature
if (!this->read_bytes(BMP388_DATA_3, &data[0], 3)) {
ESP_LOGE(TAG, "Failed to read temperature");
return false;
}
// Copy the temperature data into the adc variables
int32_t adc_temp = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0];
// Temperature compensation (function from BMP388 datasheet)
temperature = bmp388_compensate_temperature_((float) adc_temp);
return true;
}
// Get the pressure
bool BMP3XXComponent::get_pressure(float &pressure) {
float temperature;
return get_measurements(temperature, pressure);
}
// Get temperature and pressure
bool BMP3XXComponent::get_measurements(float &temperature, float &pressure) {
// Check if a measurement is ready
if (!data_ready()) {
ESP_LOGD(TAG, "BMP3XX Get measurement - data not ready skipping update");
return false;
}
uint8_t data[6];
// Read the temperature and pressure data
if (!this->read_bytes(BMP388_DATA_0, &data[0], 6)) {
ESP_LOGE(TAG, "Failed to read measurements");
return false;
}
// Copy the temperature and pressure data into the adc variables
int32_t adc_pres = (int32_t) data[2] << 16 | (int32_t) data[1] << 8 | (int32_t) data[0];
int32_t adc_temp = (int32_t) data[5] << 16 | (int32_t) data[4] << 8 | (int32_t) data[3];
// Temperature compensation (function from BMP388 datasheet)
temperature = bmp388_compensate_temperature_((float) adc_temp);
// Pressure compensation (function from BMP388 datasheet)
pressure = bmp388_compensate_pressure_((float) adc_pres, temperature);
// Calculate the pressure in millibar/hPa
pressure /= 100.0f;
return true;
}
// Set the BMP388's mode in the power control register
bool BMP3XXComponent::set_mode(OperationMode mode) {
pwr_ctrl_.bit.mode = mode;
return this->write_byte(BMP388_PWR_CTRL, pwr_ctrl_.reg);
}
// Set the BMP388 oversampling register
bool BMP3XXComponent::set_oversampling_register(Oversampling pressure_oversampling,
Oversampling temperature_oversampling) {
osr_.reg = temperature_oversampling << 3 | pressure_oversampling;
return this->write_byte(BMP388_OSR, osr_.reg);
}
// Check if measurement data is ready
bool BMP3XXComponent::data_ready() {
// If we're in SLEEP_MODE return immediately
if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
ESP_LOGD(TAG, "Not ready - sensor is in sleep mode");
return false;
}
// Read the interrupt status register
uint8_t status;
if (!this->read_byte(BMP388_INT_STATUS, &status)) {
ESP_LOGE(TAG, "Failed to read status register");
return false;
}
int_status_.reg = status;
ESP_LOGVV(TAG, "data ready status %d", status);
// If we're in FORCED_MODE switch back to SLEEP_MODE
if (int_status_.bit.drdy) {
if (pwr_ctrl_.bit.mode == FORCED_MODE) {
pwr_ctrl_.bit.mode = SLEEP_MODE;
}
return true; // The measurement is ready
}
return false; // The measurement is still pending
}
////////////////////////////////////////////////////////////////////////////////
// Bosch BMP3XXComponent (Private) Member Functions
////////////////////////////////////////////////////////////////////////////////
float BMP3XXComponent::bmp388_compensate_temperature_(float uncomp_temp) {
float partial_data1 = uncomp_temp - compensation_float_params_.param_T1;
float partial_data2 = partial_data1 * compensation_float_params_.param_T2;
return partial_data2 + partial_data1 * partial_data1 * compensation_float_params_.param_T3;
}
float BMP3XXComponent::bmp388_compensate_pressure_(float uncomp_press, float t_lin) {
float partial_data1 = compensation_float_params_.param_P6 * t_lin;
float partial_data2 = compensation_float_params_.param_P7 * t_lin * t_lin;
float partial_data3 = compensation_float_params_.param_P8 * t_lin * t_lin * t_lin;
float partial_out1 = compensation_float_params_.param_P5 + partial_data1 + partial_data2 + partial_data3;
partial_data1 = compensation_float_params_.param_P2 * t_lin;
partial_data2 = compensation_float_params_.param_P3 * t_lin * t_lin;
partial_data3 = compensation_float_params_.param_P4 * t_lin * t_lin * t_lin;
float partial_out2 =
uncomp_press * (compensation_float_params_.param_P1 + partial_data1 + partial_data2 + partial_data3);
partial_data1 = uncomp_press * uncomp_press;
partial_data2 = compensation_float_params_.param_P9 + compensation_float_params_.param_P10 * t_lin;
partial_data3 = partial_data1 * partial_data2;
float partial_data4 =
partial_data3 + uncomp_press * uncomp_press * uncomp_press * compensation_float_params_.param_P11;
return partial_out1 + partial_out2 + partial_data4;
}
} // namespace bmp3xx
} // namespace esphome

View File

@@ -1,237 +0,0 @@
/*
based on BMP388_DEV by Martin Lindupp
under MIT License (MIT)
Copyright (C) Martin Lindupp 2020
http://github.com/MartinL1/BMP388_DEV
*/
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace bmp3xx {
static const uint8_t BMP388_ID = 0x50; // The BMP388 device ID
static const uint8_t BMP390_ID = 0x60; // The BMP390 device ID
static const uint8_t RESET_CODE = 0xB6; // The BMP388 reset code
/// BMP388_DEV Registers
enum {
BMP388_CHIP_ID = 0x00, // Chip ID register sub-address
BMP388_ERR_REG = 0x02, // Error register sub-address
BMP388_STATUS = 0x03, // Status register sub-address
BMP388_DATA_0 = 0x04, // Pressure eXtended Least Significant Byte (XLSB) register sub-address
BMP388_DATA_1 = 0x05, // Pressure Least Significant Byte (LSB) register sub-address
BMP388_DATA_2 = 0x06, // Pressure Most Significant Byte (MSB) register sub-address
BMP388_DATA_3 = 0x07, // Temperature eXtended Least Significant Byte (XLSB) register sub-address
BMP388_DATA_4 = 0x08, // Temperature Least Significant Byte (LSB) register sub-address
BMP388_DATA_5 = 0x09, // Temperature Most Significant Byte (MSB) register sub-address
BMP388_SENSORTIME_0 = 0x0C, // Sensor time register 0 sub-address
BMP388_SENSORTIME_1 = 0x0D, // Sensor time register 1 sub-address
BMP388_SENSORTIME_2 = 0x0E, // Sensor time register 2 sub-address
BMP388_EVENT = 0x10, // Event register sub-address
BMP388_INT_STATUS = 0x11, // Interrupt Status register sub-address
BMP388_INT_CTRL = 0x19, // Interrupt Control register sub-address
BMP388_IF_CONFIG = 0x1A, // Interface Configuration register sub-address
BMP388_PWR_CTRL = 0x1B, // Power Control register sub-address
BMP388_OSR = 0x1C, // Oversampling register sub-address
BMP388_ODR = 0x1D, // Output Data Rate register sub-address
BMP388_CONFIG = 0x1F, // Configuration register sub-address
BMP388_TRIM_PARAMS = 0x31, // Trim parameter registers' base sub-address
BMP388_CMD = 0x7E // Command register sub-address
};
/// Device mode bitfield in the control and measurement register
enum OperationMode { SLEEP_MODE = 0x00, FORCED_MODE = 0x01, NORMAL_MODE = 0x03 };
/// Oversampling bit fields in the control and measurement register
enum Oversampling {
OVERSAMPLING_NONE = 0x00,
OVERSAMPLING_X2 = 0x01,
OVERSAMPLING_X4 = 0x02,
OVERSAMPLING_X8 = 0x03,
OVERSAMPLING_X16 = 0x04,
OVERSAMPLING_X32 = 0x05
};
/// Infinite Impulse Response (IIR) filter bit field in the configuration register
enum IIRFilter {
IIR_FILTER_OFF = 0x00,
IIR_FILTER_2 = 0x01,
IIR_FILTER_4 = 0x02,
IIR_FILTER_8 = 0x03,
IIR_FILTER_16 = 0x04,
IIR_FILTER_32 = 0x05,
IIR_FILTER_64 = 0x06,
IIR_FILTER_128 = 0x07
};
/// This class implements support for the BMP3XX Temperature+Pressure i2c sensor.
class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void update() override;
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
/// Set the oversampling value for the temperature sensor. Default is 16x.
void set_temperature_oversampling_config(Oversampling temperature_oversampling) {
this->temperature_oversampling_ = temperature_oversampling;
}
/// Set the oversampling value for the pressure sensor. Default is 16x.
void set_pressure_oversampling_config(Oversampling pressure_oversampling) {
this->pressure_oversampling_ = pressure_oversampling;
}
/// Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
void set_iir_filter_config(IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
/// Soft reset the sensor
uint8_t reset();
/// Start continuous measurement in NORMAL_MODE
bool start_normal_conversion();
/// Start a one shot measurement in FORCED_MODE
bool start_forced_conversion();
/// Stop the conversion and return to SLEEP_MODE
bool stop_conversion();
/// Set the pressure oversampling: OFF, X1, X2, X4, X8, X16, X32
bool set_pressure_oversampling(Oversampling pressure_oversampling);
/// Set the temperature oversampling: OFF, X1, X2, X4, X8, X16, X32
bool set_temperature_oversampling(Oversampling temperature_oversampling);
/// Set the IIR filter setting: OFF, 2, 3, 8, 16, 32
bool set_iir_filter(IIRFilter iir_filter);
/// Get a temperature measurement
bool get_temperature(float &temperature);
/// Get a pressure measurement
bool get_pressure(float &pressure);
/// Get a temperature and pressure measurement
bool get_measurements(float &temperature, float &pressure);
/// Get a temperature and pressure measurement
bool get_measurement();
/// Set the barometer mode
bool set_mode(OperationMode mode);
/// Set the BMP388 oversampling register
bool set_oversampling_register(Oversampling pressure_oversampling, Oversampling temperature_oversampling);
/// Checks if a measurement is ready
bool data_ready();
protected:
Oversampling temperature_oversampling_{OVERSAMPLING_X16};
Oversampling pressure_oversampling_{OVERSAMPLING_X16};
IIRFilter iir_filter_{IIR_FILTER_OFF};
OperationMode operation_mode_{FORCED_MODE};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,
ERROR_WRONG_CHIP_ID,
ERROR_SENSOR_STATUS,
ERROR_SENSOR_RESET,
} error_code_{NONE};
struct { // The BMP388 compensation trim parameters (coefficients)
uint16_t param_T1;
uint16_t param_T2;
int8_t param_T3;
int16_t param_P1;
int16_t param_P2;
int8_t param_P3;
int8_t param_P4;
uint16_t param_P5;
uint16_t param_P6;
int8_t param_P7;
int8_t param_P8;
int16_t param_P9;
int8_t param_P10;
int8_t param_P11;
} __attribute__((packed)) compensation_params_;
struct FloatParams { // The BMP388 float point compensation trim parameters
float param_T1;
float param_T2;
float param_T3;
float param_P1;
float param_P2;
float param_P3;
float param_P4;
float param_P5;
float param_P6;
float param_P7;
float param_P8;
float param_P9;
float param_P10;
float param_P11;
} compensation_float_params_;
union { // Copy of the BMP388's chip id register
struct {
uint8_t chip_id_nvm : 4;
uint8_t chip_id_fixed : 4;
} bit;
uint8_t reg;
} chip_id_ = {.reg = 0};
union { // Copy of the BMP388's event register
struct {
uint8_t por_detected : 1;
} bit;
uint8_t reg;
} event_ = {.reg = 0};
union { // Copy of the BMP388's interrupt status register
struct {
uint8_t fwm_int : 1;
uint8_t ffull_int : 1;
uint8_t : 1;
uint8_t drdy : 1;
} bit;
uint8_t reg;
} int_status_ = {.reg = 0};
union { // Copy of the BMP388's power control register
struct {
uint8_t press_en : 1;
uint8_t temp_en : 1;
uint8_t : 2;
uint8_t mode : 2;
} bit;
uint8_t reg;
} pwr_ctrl_ = {.reg = 0};
union { // Copy of the BMP388's oversampling register
struct {
uint8_t osr_p : 3;
uint8_t osr_t : 3;
} bit;
uint8_t reg;
} osr_ = {.reg = 0};
union { // Copy of the BMP388's output data rate register
struct {
uint8_t odr_sel : 5;
} bit;
uint8_t reg;
} odr_ = {.reg = 0};
union { // Copy of the BMP388's configuration register
struct {
uint8_t : 1;
uint8_t iir_filter : 3;
} bit;
uint8_t reg;
} config_ = {.reg = 0};
// Bosch temperature compensation function
float bmp388_compensate_temperature_(float uncomp_temp);
// Bosch pressure compensation function
float bmp388_compensate_pressure_(float uncomp_press, float t_lin);
};
} // namespace bmp3xx
} // namespace esphome

View File

@@ -1,100 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_IIR_FILTER,
CONF_OVERSAMPLING,
CONF_PRESSURE,
CONF_TEMPERATURE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_HECTOPASCAL,
)
CODEOWNERS = ["@martgras"]
DEPENDENCIES = ["i2c"]
bmp3xx_ns = cg.esphome_ns.namespace("bmp3xx")
Oversampling = bmp3xx_ns.enum("Oversampling")
OVERSAMPLING_OPTIONS = {
"NONE": Oversampling.OVERSAMPLING_NONE,
"2X": Oversampling.OVERSAMPLING_X2,
"4X": Oversampling.OVERSAMPLING_X4,
"8X": Oversampling.OVERSAMPLING_X8,
"16X": Oversampling.OVERSAMPLING_X16,
"32x": Oversampling.OVERSAMPLING_X32,
}
IIRFilter = bmp3xx_ns.enum("IIRFilter")
IIR_FILTER_OPTIONS = {
"OFF": IIRFilter.IIR_FILTER_OFF,
"2X": IIRFilter.IIR_FILTER_2,
"4X": IIRFilter.IIR_FILTER_4,
"8X": IIRFilter.IIR_FILTER_8,
"16X": IIRFilter.IIR_FILTER_16,
"32X": IIRFilter.IIR_FILTER_32,
"64X": IIRFilter.IIR_FILTER_64,
"128X": IIRFilter.IIR_FILTER_128,
}
BMP3XXComponent = bmp3xx_ns.class_(
"BMP3XXComponent", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(BMP3XXComponent),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="2X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement=UNIT_HECTOPASCAL,
accuracy_decimals=1,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum(
OVERSAMPLING_OPTIONS, upper=True
),
}
),
cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum(
IIR_FILTER_OPTIONS, upper=True
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x77))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_iir_filter_config(config[CONF_IIR_FILTER]))
if CONF_TEMPERATURE in config:
conf = config[CONF_TEMPERATURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_temperature_sensor(sens))
cg.add(var.set_temperature_oversampling_config(conf[CONF_OVERSAMPLING]))
if CONF_PRESSURE in config:
conf = config[CONF_PRESSURE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_pressure_sensor(sens))
cg.add(var.set_pressure_oversampling_config(conf[CONF_OVERSAMPLING]))

View File

@@ -14,14 +14,10 @@ CONF_BIT_RATE = "bit_rate"
CONF_ON_FRAME = "on_frame"
def validate_id(config):
if CONF_CAN_ID in config:
id_value = config[CONF_CAN_ID]
id_ext = config[CONF_USE_EXTENDED_ID]
if not id_ext:
if id_value > 0x7FF:
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
return config
def validate_id(id_value, id_ext):
if not id_ext:
if id_value > 0x7FF:
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
def validate_raw_data(value):
@@ -71,18 +67,23 @@ CANBUS_SCHEMA = cv.Schema(
cv.Optional(CONF_ON_FRAME): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF),
cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF),
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
},
validate_id,
cv.Optional(CONF_ON_FRAME): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF),
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
}
),
}
),
},
}
).extend(cv.COMPONENT_SCHEMA)
CANBUS_SCHEMA.add_extra(validate_id)
async def setup_canbus_core_(var, config):
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
await cg.register_component(var, config)
cg.add(var.set_can_id([config[CONF_CAN_ID]]))
cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]]))
@@ -91,6 +92,7 @@ async def setup_canbus_core_(var, config):
for conf in config.get(CONF_ON_FRAME, []):
can_id = conf[CONF_CAN_ID]
ext_id = conf[CONF_USE_EXTENDED_ID]
validate_id(can_id, ext_id)
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id)
await cg.register_component(trigger, conf)
await automation.build_automation(
@@ -115,11 +117,11 @@ async def register_canbus(var, config):
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
},
validate_id,
key=CONF_DATA,
),
)
async def canbus_action_to_code(config, action_id, template_arg, args):
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_CANBUS_ID])

View File

@@ -75,7 +75,7 @@ void Canbus::loop() {
}
// 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)) {
trigger->trigger(data);
}

View File

@@ -39,15 +39,14 @@ void CCS811Component::setup() {
// set MEAS_MODE (page 5)
uint8_t meas_mode = 0;
uint32_t interval = this->get_update_interval();
if (interval >= 60 * 1000) {
if (interval >= 60 * 1000)
meas_mode = 3 << 4; // sensor takes a reading every 60 seconds
} else if (interval >= 10 * 1000) {
else if (interval >= 10 * 1000)
meas_mode = 2 << 4; // sensor takes a reading every 10 seconds
} else if (interval >= 1 * 1000) {
else if (interval >= 1 * 1000)
meas_mode = 1 << 4; // sensor takes a reading every second
} else {
else
meas_mode = 4 << 4; // sensor takes a reading every 250ms
}
CHECKED_IO(this->write_byte(0x01, meas_mode))

View File

@@ -2,6 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor, text_sensor
from esphome.const import (
CONF_ICON,
CONF_ID,
ICON_RADIATOR,
ICON_RESTART,
@@ -46,8 +47,11 @@ CONFIG_SCHEMA = (
device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema(
icon=ICON_RESTART
cv.Optional(CONF_VERSION): text_sensor.TEXT_SENSOR_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(text_sensor.TextSensor),
cv.Optional(CONF_ICON, default=ICON_RESTART): cv.icon,
}
),
cv.Optional(CONF_BASELINE): cv.hex_uint16_t,
cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
@@ -70,7 +74,8 @@ async def to_code(config):
cg.add(var.set_tvoc(sens))
if CONF_VERSION in config:
sens = await text_sensor.new_text_sensor(config[CONF_VERSION])
sens = cg.new_Pvariable(config[CONF_VERSION][CONF_ID])
await text_sensor.register_text_sensor(sens, config[CONF_VERSION])
cg.add(var.set_version(sens))
if CONF_BASELINE in config:

View File

@@ -1,54 +0,0 @@
import esphome.codegen as cg
from esphome import pins
import esphome.config_validation as cv
from esphome.const import (
CONF_DELAY,
CONF_ID,
)
AUTO_LOAD = ["sensor", "voltage_sampler"]
CODEOWNERS = ["@asoehlke"]
MULTI_CONF = True
cd74hc4067_ns = cg.esphome_ns.namespace("cd74hc4067")
CD74HC4067Component = cd74hc4067_ns.class_(
"CD74HC4067Component", cg.Component, cg.PollingComponent
)
CONF_PIN_S0 = "pin_s0"
CONF_PIN_S1 = "pin_s1"
CONF_PIN_S2 = "pin_s2"
CONF_PIN_S3 = "pin_s3"
DEFAULT_DELAY = "2ms"
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CD74HC4067Component),
cv.Required(CONF_PIN_S0): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S1): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S2): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_PIN_S3): pins.internal_gpio_output_pin_schema,
cv.Optional(
CONF_DELAY, default=DEFAULT_DELAY
): cv.positive_time_period_milliseconds,
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
pin_s0 = await cg.gpio_pin_expression(config[CONF_PIN_S0])
cg.add(var.set_pin_s0(pin_s0))
pin_s1 = await cg.gpio_pin_expression(config[CONF_PIN_S1])
cg.add(var.set_pin_s1(pin_s1))
pin_s2 = await cg.gpio_pin_expression(config[CONF_PIN_S2])
cg.add(var.set_pin_s2(pin_s2))
pin_s3 = await cg.gpio_pin_expression(config[CONF_PIN_S3])
cg.add(var.set_pin_s3(pin_s3))
cg.add(var.set_switch_delay(config[CONF_DELAY]))

View File

@@ -1,86 +0,0 @@
#include "cd74hc4067.h"
#include "esphome/core/log.h"
namespace esphome {
namespace cd74hc4067 {
static const char *const TAG = "cd74hc4067";
float CD74HC4067Component::get_setup_priority() const { return setup_priority::DATA; }
void CD74HC4067Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up CD74HC4067...");
this->pin_s0_->setup();
this->pin_s1_->setup();
this->pin_s2_->setup();
this->pin_s3_->setup();
// set other pin, so that activate_pin will really switch
this->active_pin_ = 1;
this->activate_pin(0);
}
void CD74HC4067Component::dump_config() {
ESP_LOGCONFIG(TAG, "CD74HC4067 Multiplexer:");
LOG_PIN(" S0 Pin: ", this->pin_s0_);
LOG_PIN(" S1 Pin: ", this->pin_s1_);
LOG_PIN(" S2 Pin: ", this->pin_s2_);
LOG_PIN(" S3 Pin: ", this->pin_s3_);
ESP_LOGCONFIG(TAG, "switch delay: %d", this->switch_delay_);
}
void CD74HC4067Component::activate_pin(uint8_t pin) {
if (this->active_pin_ != pin) {
ESP_LOGD(TAG, "switch to input %d", pin);
static int mux_channel[16][4] = {
{0, 0, 0, 0}, // channel 0
{1, 0, 0, 0}, // channel 1
{0, 1, 0, 0}, // channel 2
{1, 1, 0, 0}, // channel 3
{0, 0, 1, 0}, // channel 4
{1, 0, 1, 0}, // channel 5
{0, 1, 1, 0}, // channel 6
{1, 1, 1, 0}, // channel 7
{0, 0, 0, 1}, // channel 8
{1, 0, 0, 1}, // channel 9
{0, 1, 0, 1}, // channel 10
{1, 1, 0, 1}, // channel 11
{0, 0, 1, 1}, // channel 12
{1, 0, 1, 1}, // channel 13
{0, 1, 1, 1}, // channel 14
{1, 1, 1, 1} // channel 15
};
this->pin_s0_->digital_write(mux_channel[pin][0]);
this->pin_s1_->digital_write(mux_channel[pin][1]);
this->pin_s2_->digital_write(mux_channel[pin][2]);
this->pin_s3_->digital_write(mux_channel[pin][3]);
// small delay is needed to let the multiplexer switch
delay(this->switch_delay_);
this->active_pin_ = pin;
}
}
CD74HC4067Sensor::CD74HC4067Sensor(CD74HC4067Component *parent) : parent_(parent) {}
void CD74HC4067Sensor::update() {
float value_v = this->sample();
this->publish_state(value_v);
}
float CD74HC4067Sensor::get_setup_priority() const { return this->parent_->get_setup_priority() - 1.0f; }
float CD74HC4067Sensor::sample() {
this->parent_->activate_pin(this->pin_);
return this->source_->sample();
}
void CD74HC4067Sensor::dump_config() {
LOG_SENSOR(TAG, "CD74HC4067 Sensor", this);
ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_);
LOG_UPDATE_INTERVAL(this);
}
} // namespace cd74hc4067
} // namespace esphome

View File

@@ -1,65 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
namespace esphome {
namespace cd74hc4067 {
class CD74HC4067Component : public Component {
public:
/// Set up the internal sensor array.
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
/// setting pin active by setting the right combination of the four multiplexer input pins
void activate_pin(uint8_t pin);
/// set the pin connected to multiplexer control pin 0
void set_pin_s0(InternalGPIOPin *pin) { this->pin_s0_ = pin; }
/// set the pin connected to multiplexer control pin 1
void set_pin_s1(InternalGPIOPin *pin) { this->pin_s1_ = pin; }
/// set the pin connected to multiplexer control pin 2
void set_pin_s2(InternalGPIOPin *pin) { this->pin_s2_ = pin; }
/// set the pin connected to multiplexer control pin 3
void set_pin_s3(InternalGPIOPin *pin) { this->pin_s3_ = pin; }
/// set the delay needed after an input switch
void set_switch_delay(uint32_t switch_delay) { this->switch_delay_ = switch_delay; }
private:
InternalGPIOPin *pin_s0_;
InternalGPIOPin *pin_s1_;
InternalGPIOPin *pin_s2_;
InternalGPIOPin *pin_s3_;
/// the currently active pin
uint8_t active_pin_;
uint32_t switch_delay_;
};
class CD74HC4067Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
public:
CD74HC4067Sensor(CD74HC4067Component *parent);
void update() override;
void dump_config() override;
/// `HARDWARE_LATE` setup priority.
float get_setup_priority() const override;
void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_source(voltage_sampler::VoltageSampler *source) { this->source_ = source; }
float sample() override;
protected:
CD74HC4067Component *parent_;
/// The sampling source to read values from.
voltage_sampler::VoltageSampler *source_;
uint8_t pin_;
};
} // namespace cd74hc4067
} // namespace esphome

View File

@@ -1,55 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, voltage_sampler
from esphome.const import (
CONF_ID,
CONF_SENSOR,
CONF_NUMBER,
ICON_FLASH,
UNIT_VOLT,
STATE_CLASS_MEASUREMENT,
DEVICE_CLASS_VOLTAGE,
)
from . import cd74hc4067_ns, CD74HC4067Component
DEPENDENCIES = ["cd74hc4067"]
CD74HC4067Sensor = cd74hc4067_ns.class_(
"CD74HC4067Sensor",
sensor.Sensor,
cg.PollingComponent,
voltage_sampler.VoltageSampler,
)
CONF_CD74HC4067_ID = "cd74hc4067_id"
CONFIG_SCHEMA = (
sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=3,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_FLASH,
)
.extend(
{
cv.GenerateID(): cv.declare_id(CD74HC4067Sensor),
cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component),
cv.Required(CONF_NUMBER): cv.int_range(0, 15),
cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
}
)
.extend(cv.polling_component_schema("60s"))
)
async def to_code(config):
parent = await cg.get_variable(config[CONF_CD74HC4067_ID])
var = cg.new_Pvariable(config[CONF_ID], parent)
await cg.register_component(var, config)
await sensor.register_sensor(var, config)
cg.add(var.set_pin(config[CONF_NUMBER]))
sens = await cg.get_variable(config[CONF_SENSOR])
cg.add(var.set_source(sens))

View File

@@ -65,7 +65,7 @@ class ClimateTraits {
ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20")
void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); }
bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); }
std::set<ClimateMode> get_supported_modes() const { return supported_modes_; }
const std::set<ClimateMode> get_supported_modes() const { return supported_modes_; }
void set_supports_action(bool supports_action) { supports_action_ = supports_action; }
bool get_supports_action() const { return supports_action_; }
@@ -93,7 +93,7 @@ class ClimateTraits {
void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); }
bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); }
bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); }
std::set<ClimateFanMode> get_supported_fan_modes() const { return supported_fan_modes_; }
const std::set<ClimateFanMode> get_supported_fan_modes() const { return supported_fan_modes_; }
void set_supported_custom_fan_modes(std::set<std::string> supported_custom_fan_modes) {
supported_custom_fan_modes_ = std::move(supported_custom_fan_modes);
@@ -141,7 +141,7 @@ class ClimateTraits {
}
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(); }
std::set<ClimateSwingMode> get_supported_swing_modes() { return supported_swing_modes_; }
const std::set<ClimateSwingMode> get_supported_swing_modes() { return supported_swing_modes_; }
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; }

View File

@@ -10,22 +10,21 @@ climate::ClimateTraits ClimateIR::traits() {
auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(this->sensor_ != nullptr);
traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT_COOL});
if (this->supports_cool_)
if (supports_cool_)
traits.add_supported_mode(climate::CLIMATE_MODE_COOL);
if (this->supports_heat_)
if (supports_heat_)
traits.add_supported_mode(climate::CLIMATE_MODE_HEAT);
if (this->supports_dry_)
if (supports_dry_)
traits.add_supported_mode(climate::CLIMATE_MODE_DRY);
if (this->supports_fan_only_)
if (supports_fan_only_)
traits.add_supported_mode(climate::CLIMATE_MODE_FAN_ONLY);
traits.set_supports_two_point_target_temperature(false);
traits.set_visual_min_temperature(this->minimum_temperature_);
traits.set_visual_max_temperature(this->maximum_temperature_);
traits.set_visual_temperature_step(this->temperature_step_);
traits.set_supported_fan_modes(this->fan_modes_);
traits.set_supported_swing_modes(this->swing_modes_);
traits.set_supported_presets(this->presets_);
traits.set_supported_fan_modes(fan_modes_);
traits.set_supported_swing_modes(swing_modes_);
return traits;
}
@@ -51,7 +50,6 @@ void ClimateIR::setup() {
roundf(clamp(this->current_temperature, this->minimum_temperature_, this->maximum_temperature_));
this->fan_mode = climate::CLIMATE_FAN_AUTO;
this->swing_mode = climate::CLIMATE_SWING_OFF;
this->preset = climate::CLIMATE_PRESET_NONE;
}
// Never send nan to HA
if (std::isnan(this->target_temperature))
@@ -67,8 +65,6 @@ void ClimateIR::control(const climate::ClimateCall &call) {
this->fan_mode = *call.get_fan_mode();
if (call.get_swing_mode().has_value())
this->swing_mode = *call.get_swing_mode();
if (call.get_preset().has_value())
this->preset = *call.get_preset();
this->transmit_state();
this->publish_state();
}

View File

@@ -22,7 +22,7 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
public:
ClimateIR(float minimum_temperature, float maximum_temperature, float temperature_step = 1.0f,
bool supports_dry = false, bool supports_fan_only = false, std::set<climate::ClimateFanMode> fan_modes = {},
std::set<climate::ClimateSwingMode> swing_modes = {}, std::set<climate::ClimatePreset> presets = {}) {
std::set<climate::ClimateSwingMode> swing_modes = {}) {
this->minimum_temperature_ = minimum_temperature;
this->maximum_temperature_ = maximum_temperature;
this->temperature_step_ = temperature_step;
@@ -30,7 +30,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
this->supports_fan_only_ = supports_fan_only;
this->fan_modes_ = std::move(fan_modes);
this->swing_modes_ = std::move(swing_modes);
this->presets_ = std::move(presets);
}
void setup() override;
@@ -62,7 +61,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
bool supports_fan_only_{false};
std::set<climate::ClimateFanMode> fan_modes_ = {};
std::set<climate::ClimateSwingMode> swing_modes_ = {};
std::set<climate::ClimatePreset> presets_ = {};
remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};

View File

@@ -137,11 +137,11 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
this->swing_mode =
this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
} else {
if ((remote_state & COMMAND_MASK) == COMMAND_AUTO) {
if ((remote_state & COMMAND_MASK) == COMMAND_AUTO)
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
} else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN) {
else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN)
this->mode = climate::CLIMATE_MODE_DRY;
} else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) {
else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) {
this->mode = climate::CLIMATE_MODE_HEAT;
} else {
this->mode = climate::CLIMATE_MODE_COOL;
@@ -156,15 +156,14 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) {
this->fan_mode = climate::CLIMATE_FAN_AUTO;
} else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT ||
this->mode == climate::CLIMATE_MODE_DRY) {
if ((remote_state & FAN_MASK) == FAN_AUTO) {
if ((remote_state & FAN_MASK) == FAN_AUTO)
this->fan_mode = climate::CLIMATE_FAN_AUTO;
} else if ((remote_state & FAN_MASK) == FAN_MIN) {
else if ((remote_state & FAN_MASK) == FAN_MIN)
this->fan_mode = climate::CLIMATE_FAN_LOW;
} else if ((remote_state & FAN_MASK) == FAN_MED) {
else if ((remote_state & FAN_MASK) == FAN_MED)
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
} else if ((remote_state & FAN_MASK) == FAN_MAX) {
else if ((remote_state & FAN_MASK) == FAN_MAX)
this->fan_mode = climate::CLIMATE_FAN_HIGH;
}
}
}
this->publish_state();
@@ -176,7 +175,7 @@ void LgIrClimate::transmit_(uint32_t value) {
ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02X", value);
auto transmit = this->transmitter_->transmit();
auto *data = transmit.get_data();
auto data = transmit.get_data();
data->set_carrier_frequency(38000);
data->reserve(2 + BITS * 2u);

View File

@@ -1,5 +1,4 @@
#include "coolix.h"
#include "esphome/components/remote_base/coolix_protocol.h"
#include "esphome/core/log.h"
namespace esphome {
@@ -7,29 +6,29 @@ namespace coolix {
static const char *const TAG = "coolix.climate";
static const uint32_t COOLIX_OFF = 0xB27BE0;
static const uint32_t COOLIX_SWING = 0xB26BE0;
static const uint32_t COOLIX_LED = 0xB5F5A5;
static const uint32_t COOLIX_SILENCE_FP = 0xB5F5B6;
const uint32_t COOLIX_OFF = 0xB27BE0;
const uint32_t COOLIX_SWING = 0xB26BE0;
const uint32_t COOLIX_LED = 0xB5F5A5;
const uint32_t COOLIX_SILENCE_FP = 0xB5F5B6;
// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore.
static const uint8_t COOLIX_COOL = 0b0000;
static const uint8_t COOLIX_DRY_FAN = 0b0100;
static const uint8_t COOLIX_AUTO = 0b1000;
static const uint8_t COOLIX_HEAT = 0b1100;
static const uint32_t COOLIX_MODE_MASK = 0b1100;
static const uint32_t COOLIX_FAN_MASK = 0xF000;
static const uint32_t COOLIX_FAN_MODE_AUTO_DRY = 0x1000;
static const uint32_t COOLIX_FAN_AUTO = 0xB000;
static const uint32_t COOLIX_FAN_MIN = 0x9000;
static const uint32_t COOLIX_FAN_MED = 0x5000;
static const uint32_t COOLIX_FAN_MAX = 0x3000;
const uint8_t COOLIX_COOL = 0b0000;
const uint8_t COOLIX_DRY_FAN = 0b0100;
const uint8_t COOLIX_AUTO = 0b1000;
const uint8_t COOLIX_HEAT = 0b1100;
const uint32_t COOLIX_MODE_MASK = 0b1100;
const uint32_t COOLIX_FAN_MASK = 0xF000;
const uint32_t COOLIX_FAN_MODE_AUTO_DRY = 0x1000;
const uint32_t COOLIX_FAN_AUTO = 0xB000;
const uint32_t COOLIX_FAN_MIN = 0x9000;
const uint32_t COOLIX_FAN_MED = 0x5000;
const uint32_t COOLIX_FAN_MAX = 0x3000;
// Temperature
static const uint8_t COOLIX_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
static const uint8_t COOLIX_FAN_TEMP_CODE = 0b11100000; // Part of Fan Mode.
static const uint32_t COOLIX_TEMP_MASK = 0b11110000;
static const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
const uint8_t COOLIX_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
const uint8_t COOLIX_FAN_TEMP_CODE = 0b11100000; // Part of Fan Mode.
const uint32_t COOLIX_TEMP_MASK = 0b11110000;
const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
0b00000000, // 17C
0b00010000, // 18c
0b00110000, // 19C
@@ -46,6 +45,17 @@ static const uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE] = {
0b10110000 // 30C
};
// Constants
static const uint32_t BIT_MARK_US = 660;
static const uint32_t HEADER_MARK_US = 560 * 8;
static const uint32_t HEADER_SPACE_US = 560 * 8;
static const uint32_t BIT_ONE_SPACE_US = 1500;
static const uint32_t BIT_ZERO_SPACE_US = 450;
static const uint32_t FOOTER_MARK_US = BIT_MARK_US;
static const uint32_t FOOTER_SPACE_US = HEADER_SPACE_US;
const uint16_t COOLIX_BITS = 24;
void CoolixClimate::transmit_state() {
uint32_t remote_state = 0xB20F00;
@@ -101,63 +111,119 @@ void CoolixClimate::transmit_state() {
}
}
}
ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state);
ESP_LOGV(TAG, "Sending coolix code: 0x%02X", remote_state);
auto transmit = this->transmitter_->transmit();
auto *data = transmit.get_data();
remote_base::CoolixProtocol().encode(data, remote_state);
auto data = transmit.get_data();
data->set_carrier_frequency(38000);
uint16_t repeat = 1;
for (uint16_t r = 0; r <= repeat; r++) {
// Header
data->mark(HEADER_MARK_US);
data->space(HEADER_SPACE_US);
// Data
// Break data into bytes, starting at the Most Significant
// Byte. Each byte then being sent normal, then followed inverted.
for (uint16_t i = 8; i <= COOLIX_BITS; i += 8) {
// Grab a bytes worth of data.
uint8_t byte = (remote_state >> (COOLIX_BITS - i)) & 0xFF;
// Normal
for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
data->mark(BIT_MARK_US);
data->space((byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
}
// Inverted
for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
data->mark(BIT_MARK_US);
data->space(!(byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
}
}
// Footer
data->mark(BIT_MARK_US);
data->space(FOOTER_SPACE_US); // Pause before repeating
}
transmit.perform();
}
bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteReceiveData data) {
auto decoded = remote_base::CoolixProtocol().decode(data);
if (!decoded.has_value())
return false;
bool CoolixClimate::on_receive(remote_base::RemoteReceiveData data) {
// Decoded remote state y 3 bytes long code.
uint32_t remote_state = *decoded;
ESP_LOGV(TAG, "Decoded 0x%06X", remote_state);
if ((remote_state & 0xFF0000) != 0xB20000)
uint32_t remote_state = 0;
// The protocol sends the data twice, read here
uint32_t loop_read;
for (uint16_t loop = 1; loop <= 2; loop++) {
if (!data.expect_item(HEADER_MARK_US, HEADER_SPACE_US))
return false;
loop_read = 0;
for (uint8_t a_byte = 0; a_byte < 3; a_byte++) {
uint8_t byte = 0;
for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
if (data.expect_item(BIT_MARK_US, BIT_ONE_SPACE_US))
byte |= 1 << a_bit;
else if (!data.expect_item(BIT_MARK_US, BIT_ZERO_SPACE_US))
return false;
}
// Need to see this segment inverted
for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
bool bit = byte & (1 << a_bit);
if (!data.expect_item(BIT_MARK_US, bit ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US))
return false;
}
// Receiving MSB first: reorder bytes
loop_read |= byte << ((2 - a_byte) * 8);
}
// Footer Mark
if (!data.expect_mark(BIT_MARK_US))
return false;
if (loop == 1) {
// Back up state on first loop
remote_state = loop_read;
if (!data.expect_space(FOOTER_SPACE_US))
return false;
}
}
ESP_LOGV(TAG, "Decoded 0x%02X", remote_state);
if (remote_state != loop_read || (remote_state & 0xFF0000) != 0xB20000)
return false;
if (remote_state == COOLIX_OFF) {
parent->mode = climate::CLIMATE_MODE_OFF;
this->mode = climate::CLIMATE_MODE_OFF;
} else if (remote_state == COOLIX_SWING) {
parent->swing_mode =
parent->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
this->swing_mode =
this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF;
} else {
if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT) {
parent->mode = climate::CLIMATE_MODE_HEAT;
} else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO) {
parent->mode = climate::CLIMATE_MODE_HEAT_COOL;
} else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) {
if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY) {
parent->mode = climate::CLIMATE_MODE_DRY;
} else {
parent->mode = climate::CLIMATE_MODE_FAN_ONLY;
}
if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT)
this->mode = climate::CLIMATE_MODE_HEAT;
else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO)
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) {
if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY)
this->mode = climate::CLIMATE_MODE_DRY;
else
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
} else
parent->mode = climate::CLIMATE_MODE_COOL;
this->mode = climate::CLIMATE_MODE_COOL;
// Fan Speed
if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || parent->mode == climate::CLIMATE_MODE_HEAT_COOL ||
parent->mode == climate::CLIMATE_MODE_DRY) {
parent->fan_mode = climate::CLIMATE_FAN_AUTO;
} else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN) {
parent->fan_mode = climate::CLIMATE_FAN_LOW;
} else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED) {
parent->fan_mode = climate::CLIMATE_FAN_MEDIUM;
} else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX) {
parent->fan_mode = climate::CLIMATE_FAN_HIGH;
}
if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || this->mode == climate::CLIMATE_MODE_HEAT_COOL ||
this->mode == climate::CLIMATE_MODE_DRY)
this->fan_mode = climate::CLIMATE_FAN_AUTO;
else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN)
this->fan_mode = climate::CLIMATE_FAN_LOW;
else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED)
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX)
this->fan_mode = climate::CLIMATE_FAN_HIGH;
// Temperature
uint8_t temperature_code = remote_state & COOLIX_TEMP_MASK;
for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++) {
for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++)
if (COOLIX_TEMP_MAP[i] == temperature_code)
parent->target_temperature = i + COOLIX_TEMP_MIN;
}
this->target_temperature = i + COOLIX_TEMP_MIN;
}
parent->publish_state();
this->publish_state();
return true;
}

Some files were not shown because too many files have changed in this diff Show More