mirror of
https://github.com/esphome/esphome.git
synced 2024-12-28 00:11:43 +01:00
Merge branch 'dev' into optolink
This commit is contained in:
commit
28236c9db4
34 changed files with 410 additions and 128 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -129,4 +129,6 @@ tests/.esphome/
|
|||
sdkconfig.*
|
||||
!sdkconfig.defaults
|
||||
|
||||
.tests/
|
||||
.tests/
|
||||
|
||||
/components
|
||||
|
|
|
@ -22,16 +22,22 @@ RUN \
|
|||
python3=3.9.2-3 \
|
||||
python3-pip=20.3.4-4+deb11u1 \
|
||||
python3-setuptools=52.0.0-4 \
|
||||
python3-pil=8.1.2+dfsg-0.3+deb11u1 \
|
||||
python3-cryptography=3.3.2-1 \
|
||||
python3-venv=3.9.2-3 \
|
||||
iputils-ping=3:20210202-1 \
|
||||
git=1:2.30.2-1+deb11u2 \
|
||||
curl=7.74.0-1.3+deb11u7 \
|
||||
openssh-client=1:8.4p1-5+deb11u1 \
|
||||
libcairo2=1.16.0-5 \
|
||||
python3-cffi=1.14.5-1 \
|
||||
&& rm -rf \
|
||||
python3-cffi=1.14.5-1; \
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential=12.9 \
|
||||
python3-dev=3.9.2-3 \
|
||||
zlib1g-dev=1:1.2.11.dfsg-2+deb11u2 \
|
||||
libjpeg-dev=1:2.0.6-4 \
|
||||
libcairo2=1.16.0-5; \
|
||||
fi; \
|
||||
rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
/var/lib/apt/lists/*
|
||||
|
|
|
@ -365,10 +365,16 @@ def command_wizard(args):
|
|||
|
||||
|
||||
def command_config(args, config):
|
||||
_LOGGER.info("Configuration is valid!")
|
||||
if not CORE.verbose:
|
||||
config = strip_default_ids(config)
|
||||
safe_print(yaml_util.dump(config, args.show_secrets))
|
||||
output = yaml_util.dump(config, args.show_secrets)
|
||||
# add the console decoration so the front-end can hide the secrets
|
||||
if not args.show_secrets:
|
||||
output = re.sub(
|
||||
r"(password|key|psk|ssid)\:\s(.*)", r"\1: \\033[5m\2\\033[6m", output
|
||||
)
|
||||
safe_print(output)
|
||||
_LOGGER.info("Configuration is valid!")
|
||||
return 0
|
||||
|
||||
|
||||
|
|
|
@ -1420,6 +1420,7 @@ message VoiceAssistantRequest {
|
|||
|
||||
bool start = 1;
|
||||
string conversation_id = 2;
|
||||
bool use_vad = 3;
|
||||
}
|
||||
|
||||
message VoiceAssistantResponse {
|
||||
|
|
|
@ -907,12 +907,13 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
|
|||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id) {
|
||||
bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) {
|
||||
if (!this->voice_assistant_subscription_)
|
||||
return false;
|
||||
VoiceAssistantRequest msg;
|
||||
msg.start = start;
|
||||
msg.conversation_id = conversation_id;
|
||||
msg.use_vad = use_vad;
|
||||
return this->send_voice_assistant_request(msg);
|
||||
}
|
||||
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
|
||||
|
|
|
@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection {
|
|||
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
|
||||
this->voice_assistant_subscription_ = msg.subscribe;
|
||||
}
|
||||
bool request_voice_assistant(bool start, const std::string &conversation_id);
|
||||
bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad);
|
||||
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
|
||||
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
|
||||
#endif
|
||||
|
|
|
@ -6348,6 +6348,10 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
|||
this->start = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->use_vad = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -6365,6 +6369,7 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite
|
|||
void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(1, this->start);
|
||||
buffer.encode_string(2, this->conversation_id);
|
||||
buffer.encode_bool(3, this->use_vad);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void VoiceAssistantRequest::dump_to(std::string &out) const {
|
||||
|
@ -6377,6 +6382,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const {
|
|||
out.append(" conversation_id: ");
|
||||
out.append("'").append(this->conversation_id).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" use_vad: ");
|
||||
out.append(YESNO(this->use_vad));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1655,6 +1655,7 @@ class VoiceAssistantRequest : public ProtoMessage {
|
|||
public:
|
||||
bool start{false};
|
||||
std::string conversation_id{};
|
||||
bool use_vad{false};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
|
|
|
@ -323,16 +323,16 @@ void APIServer::on_shutdown() {
|
|||
}
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
bool APIServer::start_voice_assistant(const std::string &conversation_id) {
|
||||
bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) {
|
||||
for (auto &c : this->clients_) {
|
||||
if (c->request_voice_assistant(true, conversation_id))
|
||||
if (c->request_voice_assistant(true, conversation_id, use_vad))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void APIServer::stop_voice_assistant() {
|
||||
for (auto &c : this->clients_) {
|
||||
if (c->request_voice_assistant(false, ""))
|
||||
if (c->request_voice_assistant(false, "", false))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class APIServer : public Component, public Controller {
|
|||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
bool start_voice_assistant(const std::string &conversation_id);
|
||||
bool start_voice_assistant(const std::string &conversation_id, bool use_vad);
|
||||
void stop_voice_assistant();
|
||||
#endif
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteRecei
|
|||
if (!decoded.has_value())
|
||||
return false;
|
||||
// Decoded remote state y 3 bytes long code.
|
||||
uint32_t remote_state = *decoded;
|
||||
uint32_t remote_state = (*decoded).second;
|
||||
ESP_LOGV(TAG, "Decoded 0x%06X", remote_state);
|
||||
if ((remote_state & 0xFF0000) != 0xB20000)
|
||||
return false;
|
||||
|
|
|
@ -51,7 +51,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet
|
|||
if (universe < first_universe_ || universe > get_last_universe())
|
||||
return false;
|
||||
|
||||
int output_offset = (universe - first_universe_) * get_lights_per_universe();
|
||||
int32_t output_offset = (universe - first_universe_) * get_lights_per_universe();
|
||||
// limit amount of lights per universe and received
|
||||
int output_end =
|
||||
std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Union
|
||||
from typing import Union, Optional
|
||||
from pathlib import Path
|
||||
import logging
|
||||
import os
|
||||
|
@ -42,6 +42,7 @@ from .const import ( # noqa
|
|||
KEY_REFRESH,
|
||||
KEY_REPO,
|
||||
KEY_SDKCONFIG_OPTIONS,
|
||||
KEY_SUBMODULES,
|
||||
KEY_VARIANT,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_FRIENDLY,
|
||||
|
@ -120,17 +121,28 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType):
|
|||
|
||||
|
||||
def add_idf_component(
|
||||
name: str, repo: str, ref: str = None, path: str = None, refresh: TimePeriod = None
|
||||
*,
|
||||
name: str,
|
||||
repo: str,
|
||||
ref: str = None,
|
||||
path: str = None,
|
||||
refresh: TimePeriod = None,
|
||||
components: Optional[list[str]] = None,
|
||||
submodules: Optional[list[str]] = None,
|
||||
):
|
||||
"""Add an esp-idf component to the project."""
|
||||
if not CORE.using_esp_idf:
|
||||
raise ValueError("Not an esp-idf project")
|
||||
if components is None:
|
||||
components = []
|
||||
if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]:
|
||||
CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = {
|
||||
KEY_REPO: repo,
|
||||
KEY_REF: ref,
|
||||
KEY_PATH: path,
|
||||
KEY_REFRESH: refresh,
|
||||
KEY_COMPONENTS: components,
|
||||
KEY_SUBMODULES: submodules,
|
||||
}
|
||||
|
||||
|
||||
|
@ -163,23 +175,23 @@ RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5)
|
|||
# The platformio/espressif32 version to use for arduino frameworks
|
||||
# - https://github.com/platformio/platform-espressif32/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
|
||||
ARDUINO_PLATFORM_VERSION = cv.Version(5, 3, 0)
|
||||
ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
||||
|
||||
# The default/recommended esp-idf framework version
|
||||
# - https://github.com/espressif/esp-idf/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
||||
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 4)
|
||||
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 5)
|
||||
# The platformio/espressif32 version to use for esp-idf frameworks
|
||||
# - https://github.com/platformio/platform-espressif32/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
|
||||
ESP_IDF_PLATFORM_VERSION = cv.Version(5, 3, 0)
|
||||
ESP_IDF_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
||||
|
||||
|
||||
def _arduino_check_versions(value):
|
||||
value = value.copy()
|
||||
lookups = {
|
||||
"dev": (cv.Version(2, 1, 0), "https://github.com/espressif/arduino-esp32.git"),
|
||||
"latest": (cv.Version(2, 0, 7), None),
|
||||
"latest": (cv.Version(2, 0, 9), None),
|
||||
"recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None),
|
||||
}
|
||||
|
||||
|
@ -214,7 +226,7 @@ def _esp_idf_check_versions(value):
|
|||
value = value.copy()
|
||||
lookups = {
|
||||
"dev": (cv.Version(5, 1, 0), "https://github.com/espressif/esp-idf.git"),
|
||||
"latest": (cv.Version(5, 0, 1), None),
|
||||
"latest": (cv.Version(5, 1, 0), None),
|
||||
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
|
||||
}
|
||||
|
||||
|
@ -536,20 +548,41 @@ def copy_files():
|
|||
ref=component[KEY_REF],
|
||||
refresh=component[KEY_REFRESH],
|
||||
domain="idf_components",
|
||||
submodules=component[KEY_SUBMODULES],
|
||||
)
|
||||
mkdir_p(CORE.relative_build_path("components"))
|
||||
component_dir = repo_dir
|
||||
if component[KEY_PATH] is not None:
|
||||
component_dir = component_dir / component[KEY_PATH]
|
||||
|
||||
shutil.copytree(
|
||||
component_dir,
|
||||
CORE.relative_build_path(f"components/{name}"),
|
||||
dirs_exist_ok=True,
|
||||
ignore=shutil.ignore_patterns(".git", ".github"),
|
||||
symlinks=True,
|
||||
ignore_dangling_symlinks=True,
|
||||
)
|
||||
if component[KEY_COMPONENTS] == ["*"]:
|
||||
shutil.copytree(
|
||||
component_dir,
|
||||
CORE.relative_build_path("components"),
|
||||
dirs_exist_ok=True,
|
||||
ignore=shutil.ignore_patterns(".git*"),
|
||||
symlinks=True,
|
||||
ignore_dangling_symlinks=True,
|
||||
)
|
||||
elif len(component[KEY_COMPONENTS]) > 0:
|
||||
for comp in component[KEY_COMPONENTS]:
|
||||
shutil.copytree(
|
||||
component_dir / comp,
|
||||
CORE.relative_build_path(f"components/{comp}"),
|
||||
dirs_exist_ok=True,
|
||||
ignore=shutil.ignore_patterns(".git*"),
|
||||
symlinks=True,
|
||||
ignore_dangling_symlinks=True,
|
||||
)
|
||||
else:
|
||||
shutil.copytree(
|
||||
component_dir,
|
||||
CORE.relative_build_path(f"components/{name}"),
|
||||
dirs_exist_ok=True,
|
||||
ignore=shutil.ignore_patterns(".git*"),
|
||||
symlinks=True,
|
||||
ignore_dangling_symlinks=True,
|
||||
)
|
||||
|
||||
dir = os.path.dirname(__file__)
|
||||
post_build_file = os.path.join(dir, "post_build.py.script")
|
||||
|
|
|
@ -1201,6 +1201,10 @@ BOARDS = {
|
|||
"name": "BPI-Bit",
|
||||
"variant": VARIANT_ESP32,
|
||||
},
|
||||
"bpi_leaf_s3": {
|
||||
"name": "BPI-Leaf-S3",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"briki_abc_esp32": {
|
||||
"name": "Briki ABC (MBC-WB) - ESP32",
|
||||
"variant": VARIANT_ESP32,
|
||||
|
@ -1217,6 +1221,10 @@ BOARDS = {
|
|||
"name": "Connaxio's Espoir",
|
||||
"variant": VARIANT_ESP32,
|
||||
},
|
||||
"cytron_maker_feather_aiot_s3": {
|
||||
"name": "Cytron Maker Feather AIoT S3",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"d-duino-32": {
|
||||
"name": "D-duino-32",
|
||||
"variant": VARIANT_ESP32,
|
||||
|
@ -1225,6 +1233,10 @@ BOARDS = {
|
|||
"name": "Deneyap Kart 1A",
|
||||
"variant": VARIANT_ESP32,
|
||||
},
|
||||
"deneyapkart1Av2": {
|
||||
"name": "Deneyap Kart 1A v2",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"deneyapkartg": {
|
||||
"name": "Deneyap Kart G",
|
||||
"variant": VARIANT_ESP32C3,
|
||||
|
@ -1237,6 +1249,10 @@ BOARDS = {
|
|||
"name": "Deneyap Mini",
|
||||
"variant": VARIANT_ESP32S2,
|
||||
},
|
||||
"deneyapminiv2": {
|
||||
"name": "Deneyap Mini v2",
|
||||
"variant": VARIANT_ESP32S2,
|
||||
},
|
||||
"denky32": {
|
||||
"name": "Denky32 (WROOM32)",
|
||||
"variant": VARIANT_ESP32,
|
||||
|
@ -1265,6 +1281,10 @@ BOARDS = {
|
|||
"name": "Espressif ESP32-C3-DevKitM-1",
|
||||
"variant": VARIANT_ESP32C3,
|
||||
},
|
||||
"esp32-c3-m1i-kit": {
|
||||
"name": "Ai-Thinker ESP-C3-M1-I-Kit",
|
||||
"variant": VARIANT_ESP32C3,
|
||||
},
|
||||
"esp32cam": {
|
||||
"name": "AI Thinker ESP32-CAM",
|
||||
"variant": VARIANT_ESP32,
|
||||
|
@ -1329,6 +1349,10 @@ BOARDS = {
|
|||
"name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"esp32-s3-korvo-2": {
|
||||
"name": "Espressif ESP32-S3-Korvo-2",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"esp32thing": {
|
||||
"name": "SparkFun ESP32 Thing",
|
||||
"variant": VARIANT_ESP32,
|
||||
|
@ -1637,6 +1661,10 @@ BOARDS = {
|
|||
"name": "Noduino Quantum",
|
||||
"variant": VARIANT_ESP32,
|
||||
},
|
||||
"redpill_esp32s3": {
|
||||
"name": "Munich Labs RedPill ESP32-S3",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"seeed_xiao_esp32c3": {
|
||||
"name": "Seeed Studio XIAO ESP32C3",
|
||||
"variant": VARIANT_ESP32C3,
|
||||
|
|
|
@ -9,6 +9,7 @@ KEY_REPO = "repo"
|
|||
KEY_REF = "ref"
|
||||
KEY_REFRESH = "refresh"
|
||||
KEY_PATH = "path"
|
||||
KEY_SUBMODULES = "submodules"
|
||||
|
||||
VARIANT_ESP32 = "ESP32"
|
||||
VARIANT_ESP32S2 = "ESP32S2"
|
||||
|
|
|
@ -112,7 +112,6 @@ CONFIG_SCHEMA = cv.All(
|
|||
|
||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||
"ld2410",
|
||||
baud_rate=256000,
|
||||
require_tx=True,
|
||||
require_rx=True,
|
||||
parity="NONE",
|
||||
|
|
|
@ -86,10 +86,10 @@ async def to_code(config):
|
|||
5, 0, 0
|
||||
):
|
||||
add_idf_component(
|
||||
"mdns",
|
||||
"https://github.com/espressif/esp-protocols.git",
|
||||
"mdns-v1.0.9",
|
||||
"components/mdns",
|
||||
name="mdns",
|
||||
repo="https://github.com/espressif/esp-protocols.git",
|
||||
ref="mdns-v1.0.9",
|
||||
path="components/mdns",
|
||||
)
|
||||
|
||||
if config[CONF_DISABLED]:
|
||||
|
|
|
@ -28,6 +28,7 @@ from esphome.const import (
|
|||
DEVICE_CLASS_DATA_RATE,
|
||||
DEVICE_CLASS_DATA_SIZE,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
DEVICE_CLASS_DURATION,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_ENERGY_STORAGE,
|
||||
|
@ -42,6 +43,7 @@ from esphome.const import (
|
|||
DEVICE_CLASS_NITROGEN_MONOXIDE,
|
||||
DEVICE_CLASS_NITROUS_OXIDE,
|
||||
DEVICE_CLASS_OZONE,
|
||||
DEVICE_CLASS_PH,
|
||||
DEVICE_CLASS_PM1,
|
||||
DEVICE_CLASS_PM10,
|
||||
DEVICE_CLASS_PM25,
|
||||
|
@ -81,6 +83,7 @@ DEVICE_CLASSES = [
|
|||
DEVICE_CLASS_DATA_RATE,
|
||||
DEVICE_CLASS_DATA_SIZE,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
DEVICE_CLASS_DURATION,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
DEVICE_CLASS_ENERGY,
|
||||
DEVICE_CLASS_ENERGY_STORAGE,
|
||||
|
@ -95,6 +98,7 @@ DEVICE_CLASSES = [
|
|||
DEVICE_CLASS_NITROGEN_MONOXIDE,
|
||||
DEVICE_CLASS_NITROUS_OXIDE,
|
||||
DEVICE_CLASS_OZONE,
|
||||
DEVICE_CLASS_PH,
|
||||
DEVICE_CLASS_PM1,
|
||||
DEVICE_CLASS_PM10,
|
||||
DEVICE_CLASS_PM25,
|
||||
|
|
|
@ -17,6 +17,7 @@ from esphome.const import (
|
|||
CONF_PROTOCOL,
|
||||
CONF_GROUP,
|
||||
CONF_DEVICE,
|
||||
CONF_SECOND,
|
||||
CONF_STATE,
|
||||
CONF_CHANNEL,
|
||||
CONF_FAMILY,
|
||||
|
@ -39,6 +40,7 @@ AUTO_LOAD = ["binary_sensor"]
|
|||
|
||||
CONF_RECEIVER_ID = "receiver_id"
|
||||
CONF_TRANSMITTER_ID = "transmitter_id"
|
||||
CONF_FIRST = "first"
|
||||
|
||||
ns = remote_base_ns = cg.esphome_ns.namespace("remote_base")
|
||||
RemoteProtocol = ns.class_("RemoteProtocol")
|
||||
|
@ -349,19 +351,48 @@ async def canalsatld_action(var, config, args):
|
|||
CoolixAction,
|
||||
CoolixDumper,
|
||||
) = declare_protocol("Coolix")
|
||||
COOLIX_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t})
|
||||
|
||||
|
||||
@register_binary_sensor("coolix", CoolixBinarySensor, COOLIX_SCHEMA)
|
||||
COOLIX_BASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_FIRST): cv.hex_int_range(0, 16777215),
|
||||
cv.Optional(CONF_SECOND, default=0): cv.hex_int_range(0, 16777215),
|
||||
cv.Optional(CONF_DATA): cv.invalid(
|
||||
"'data' option has been removed in ESPHome 2023.8. "
|
||||
"Use the 'first' and 'second' options instead."
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
COOLIX_SENSOR_SCHEMA = cv.Any(cv.hex_int_range(0, 16777215), COOLIX_BASE_SCHEMA)
|
||||
|
||||
|
||||
@register_binary_sensor("coolix", CoolixBinarySensor, COOLIX_SENSOR_SCHEMA)
|
||||
def coolix_binary_sensor(var, config):
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(
|
||||
CoolixData,
|
||||
("data", config[CONF_DATA]),
|
||||
if isinstance(config, dict):
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(
|
||||
CoolixData,
|
||||
("first", config[CONF_FIRST]),
|
||||
("second", config[CONF_SECOND]),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(CoolixData, ("first", 0), ("second", config))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@register_action("coolix", CoolixAction, COOLIX_BASE_SCHEMA)
|
||||
async def coolix_action(var, config, args):
|
||||
template_ = await cg.templatable(config[CONF_FIRST], args, cg.uint32)
|
||||
cg.add(var.set_first(template_))
|
||||
template_ = await cg.templatable(config[CONF_SECOND], args, cg.uint32)
|
||||
cg.add(var.set_second(template_))
|
||||
|
||||
|
||||
@register_trigger("coolix", CoolixTrigger, CoolixData)
|
||||
|
@ -374,12 +405,6 @@ def coolix_dumper(var, config):
|
|||
pass
|
||||
|
||||
|
||||
@register_action("coolix", CoolixAction, COOLIX_SCHEMA)
|
||||
async def coolix_action(var, config, args):
|
||||
template_ = await cg.templatable(config[CONF_DATA], args, cg.uint32)
|
||||
cg.add(var.set_data(template_))
|
||||
|
||||
|
||||
# Dish
|
||||
DishData, DishBinarySensor, DishTrigger, DishAction, DishDumper = declare_protocol(
|
||||
"Dish"
|
||||
|
|
|
@ -15,11 +15,21 @@ static const int32_t BIT_ZERO_SPACE_US = 1 * TICK_US;
|
|||
static const int32_t FOOTER_MARK_US = 1 * TICK_US;
|
||||
static const int32_t FOOTER_SPACE_US = 10 * TICK_US;
|
||||
|
||||
static void encode_data(RemoteTransmitData *dst, const CoolixData &src) {
|
||||
// Break data into bytes, starting at the Most Significant
|
||||
// Byte. Each byte then being sent normal, then followed inverted.
|
||||
bool CoolixData::operator==(const CoolixData &other) const {
|
||||
if (this->first == 0)
|
||||
return this->second == other.first || this->second == other.second;
|
||||
if (other.first == 0)
|
||||
return other.second == this->first || other.second == this->second;
|
||||
return this->first == other.first && this->second == other.second;
|
||||
}
|
||||
|
||||
static void encode_frame(RemoteTransmitData *dst, const uint32_t &src) {
|
||||
// Append header
|
||||
dst->item(HEADER_MARK_US, HEADER_SPACE_US);
|
||||
// Break data into bytes, starting at the Most Significant
|
||||
// Byte. Each byte then being sent normal, then followed inverted.
|
||||
for (unsigned shift = 16;; shift -= 8) {
|
||||
// Grab a bytes worth of data.
|
||||
// Grab a bytes worth of data
|
||||
const uint8_t byte = src >> shift;
|
||||
// Normal
|
||||
for (uint8_t mask = 1 << 7; mask; mask >>= 1)
|
||||
|
@ -27,27 +37,33 @@ static void encode_data(RemoteTransmitData *dst, const CoolixData &src) {
|
|||
// Inverted
|
||||
for (uint8_t mask = 1 << 7; mask; mask >>= 1)
|
||||
dst->item(BIT_MARK_US, (byte & mask) ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US);
|
||||
// Data end
|
||||
if (shift == 0)
|
||||
// End of frame
|
||||
if (shift == 0) {
|
||||
// Append footer
|
||||
dst->mark(FOOTER_MARK_US);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoolixProtocol::encode(RemoteTransmitData *dst, const CoolixData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
dst->reserve(2 + 2 * 48 + 2 + 2 + 2 * 48 + 1);
|
||||
dst->item(HEADER_MARK_US, HEADER_SPACE_US);
|
||||
encode_data(dst, data);
|
||||
dst->item(FOOTER_MARK_US, FOOTER_SPACE_US);
|
||||
dst->item(HEADER_MARK_US, HEADER_SPACE_US);
|
||||
encode_data(dst, data);
|
||||
dst->mark(FOOTER_MARK_US);
|
||||
dst->reserve(100 + 100 * data.has_second());
|
||||
encode_frame(dst, data.first);
|
||||
if (data.has_second()) {
|
||||
dst->space(FOOTER_SPACE_US);
|
||||
encode_frame(dst, data.second);
|
||||
}
|
||||
}
|
||||
|
||||
static bool decode_data(RemoteReceiveData &src, CoolixData &dst) {
|
||||
static bool decode_frame(RemoteReceiveData &src, uint32_t &dst) {
|
||||
// Checking for header
|
||||
if (!src.expect_item(HEADER_MARK_US, HEADER_SPACE_US))
|
||||
return false;
|
||||
// Reading data
|
||||
uint32_t data = 0;
|
||||
for (unsigned n = 3;; data <<= 8) {
|
||||
// Read byte
|
||||
// Reading byte
|
||||
for (uint32_t mask = 1 << 7; mask; mask >>= 1) {
|
||||
if (!src.expect_mark(BIT_MARK_US))
|
||||
return false;
|
||||
|
@ -57,13 +73,16 @@ static bool decode_data(RemoteReceiveData &src, CoolixData &dst) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// Check for inverse byte
|
||||
// Checking for inverted byte
|
||||
for (uint32_t mask = 1 << 7; mask; mask >>= 1) {
|
||||
if (!src.expect_item(BIT_MARK_US, (data & mask) ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US))
|
||||
return false;
|
||||
}
|
||||
// Checking the end of reading
|
||||
// End of frame
|
||||
if (--n == 0) {
|
||||
// Checking for footer
|
||||
if (!src.expect_mark(FOOTER_MARK_US))
|
||||
return false;
|
||||
dst = data;
|
||||
return true;
|
||||
}
|
||||
|
@ -71,15 +90,24 @@ static bool decode_data(RemoteReceiveData &src, CoolixData &dst) {
|
|||
}
|
||||
|
||||
optional<CoolixData> CoolixProtocol::decode(RemoteReceiveData data) {
|
||||
CoolixData first, second;
|
||||
if (data.expect_item(HEADER_MARK_US, HEADER_SPACE_US) && decode_data(data, first) &&
|
||||
data.expect_item(FOOTER_MARK_US, FOOTER_SPACE_US) && data.expect_item(HEADER_MARK_US, HEADER_SPACE_US) &&
|
||||
decode_data(data, second) && data.expect_mark(FOOTER_MARK_US) && first == second)
|
||||
return first;
|
||||
return {};
|
||||
CoolixData result;
|
||||
const auto size = data.size();
|
||||
if ((size != 200 && size != 100) || !decode_frame(data, result.first))
|
||||
return {};
|
||||
if (size == 100 || !data.expect_space(FOOTER_SPACE_US) || !decode_frame(data, result.second))
|
||||
result.second = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void CoolixProtocol::dump(const CoolixData &data) { ESP_LOGD(TAG, "Received Coolix: 0x%06X", data); }
|
||||
void CoolixProtocol::dump(const CoolixData &data) {
|
||||
if (data.is_strict()) {
|
||||
ESP_LOGD(TAG, "Received Coolix: 0x%06X", data.first);
|
||||
} else if (data.has_second()) {
|
||||
ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X, 0x%06X]", data.first, data.second);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Received unstrict Coolix: [0x%06X]", data.first);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace remote_base
|
||||
} // namespace esphome
|
||||
|
|
|
@ -7,7 +7,16 @@
|
|||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
using CoolixData = uint32_t;
|
||||
struct CoolixData {
|
||||
CoolixData() {}
|
||||
CoolixData(uint32_t a) : first(a), second(a) {}
|
||||
CoolixData(uint32_t a, uint32_t b) : first(a), second(b) {}
|
||||
bool operator==(const CoolixData &other) const;
|
||||
bool is_strict() const { return this->first == this->second; }
|
||||
bool has_second() const { return this->second != 0; }
|
||||
uint32_t first;
|
||||
uint32_t second;
|
||||
};
|
||||
|
||||
class CoolixProtocol : public RemoteProtocol<CoolixData> {
|
||||
public:
|
||||
|
@ -19,10 +28,10 @@ class CoolixProtocol : public RemoteProtocol<CoolixData> {
|
|||
DECLARE_REMOTE_PROTOCOL(Coolix)
|
||||
|
||||
template<typename... Ts> class CoolixAction : public RemoteTransmitterActionBase<Ts...> {
|
||||
TEMPLATABLE_VALUE(CoolixData, data)
|
||||
TEMPLATABLE_VALUE(uint32_t, first)
|
||||
TEMPLATABLE_VALUE(uint32_t, second)
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
CoolixData data = this->data_.value(x...);
|
||||
CoolixProtocol().encode(dst, data);
|
||||
CoolixProtocol().encode(dst, {this->first_.value(x...), this->second_.value(x...)});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ from esphome.const import (
|
|||
DEVICE_CLASS_NITROGEN_MONOXIDE,
|
||||
DEVICE_CLASS_NITROUS_OXIDE,
|
||||
DEVICE_CLASS_OZONE,
|
||||
DEVICE_CLASS_PH,
|
||||
DEVICE_CLASS_PM1,
|
||||
DEVICE_CLASS_PM10,
|
||||
DEVICE_CLASS_PM25,
|
||||
|
@ -114,6 +115,7 @@ DEVICE_CLASSES = [
|
|||
DEVICE_CLASS_NITROGEN_MONOXIDE,
|
||||
DEVICE_CLASS_NITROUS_OXIDE,
|
||||
DEVICE_CLASS_OZONE,
|
||||
DEVICE_CLASS_PH,
|
||||
DEVICE_CLASS_PM1,
|
||||
DEVICE_CLASS_PM10,
|
||||
DEVICE_CLASS_PM25,
|
||||
|
|
57
esphome/components/sigma_delta_output/sigma_delta_output.cpp
Normal file
57
esphome/components/sigma_delta_output/sigma_delta_output.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "sigma_delta_output.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sigma_delta_output {
|
||||
|
||||
static const char *const TAG = "output.sigma_delta";
|
||||
|
||||
void SigmaDeltaOutput::setup() {
|
||||
if (this->pin_)
|
||||
this->pin_->setup();
|
||||
}
|
||||
|
||||
void SigmaDeltaOutput::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Sigma Delta Output:");
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
if (this->state_change_trigger_) {
|
||||
ESP_LOGCONFIG(TAG, " State change automation configured");
|
||||
}
|
||||
if (this->turn_on_trigger_) {
|
||||
ESP_LOGCONFIG(TAG, " Turn on automation configured");
|
||||
}
|
||||
if (this->turn_off_trigger_) {
|
||||
ESP_LOGCONFIG(TAG, " Turn off automation configured");
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_FLOAT_OUTPUT(this);
|
||||
}
|
||||
|
||||
void SigmaDeltaOutput::update() {
|
||||
this->accum_ += this->state_;
|
||||
const bool next_value = this->accum_ > 0;
|
||||
|
||||
if (next_value) {
|
||||
this->accum_ -= 1.;
|
||||
}
|
||||
|
||||
if (next_value != this->value_) {
|
||||
this->value_ = next_value;
|
||||
if (this->pin_) {
|
||||
this->pin_->digital_write(next_value);
|
||||
}
|
||||
|
||||
if (this->state_change_trigger_) {
|
||||
this->state_change_trigger_->trigger(next_value);
|
||||
}
|
||||
|
||||
if (next_value && this->turn_on_trigger_) {
|
||||
this->turn_on_trigger_->trigger();
|
||||
} else if (!next_value && this->turn_off_trigger_) {
|
||||
this->turn_off_trigger_->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sigma_delta_output
|
||||
} // namespace esphome
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/output/float_output.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sigma_delta_output {
|
||||
|
||||
class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput {
|
||||
public:
|
||||
Trigger<> *get_turn_on_trigger() {
|
||||
|
@ -25,31 +28,9 @@ class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput {
|
|||
|
||||
void set_pin(GPIOPin *pin) { this->pin_ = pin; };
|
||||
void write_state(float state) override { this->state_ = state; }
|
||||
void update() override {
|
||||
this->accum_ += this->state_;
|
||||
const bool next_value = this->accum_ > 0;
|
||||
|
||||
if (next_value) {
|
||||
this->accum_ -= 1.;
|
||||
}
|
||||
|
||||
if (next_value != this->value_) {
|
||||
this->value_ = next_value;
|
||||
if (this->pin_) {
|
||||
this->pin_->digital_write(next_value);
|
||||
}
|
||||
|
||||
if (this->state_change_trigger_) {
|
||||
this->state_change_trigger_->trigger(next_value);
|
||||
}
|
||||
|
||||
if (next_value && this->turn_on_trigger_) {
|
||||
this->turn_on_trigger_->trigger();
|
||||
} else if (!next_value && this->turn_off_trigger_) {
|
||||
this->turn_off_trigger_->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
GPIOPin *pin_{nullptr};
|
||||
|
|
|
@ -130,7 +130,7 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) {
|
|||
|
||||
void VoiceAssistant::request_start(bool continuous) {
|
||||
ESP_LOGD(TAG, "Requesting start...");
|
||||
if (!api::global_api_server->start_voice_assistant(this->conversation_id_)) {
|
||||
if (!api::global_api_server->start_voice_assistant(this->conversation_id_, this->silence_detection_)) {
|
||||
ESP_LOGW(TAG, "Could not request start.");
|
||||
this->error_trigger_->trigger("not-connected", "Could not request start.");
|
||||
this->continuous_ = false;
|
||||
|
|
|
@ -25,10 +25,9 @@ namespace voice_assistant {
|
|||
|
||||
// Version 1: Initial version
|
||||
// Version 2: Adds raw speaker support
|
||||
// Version 3: Adds continuous support
|
||||
// Version 3: Unused/skip
|
||||
static const uint32_t INITIAL_VERSION = 1;
|
||||
static const uint32_t SPEAKER_SUPPORT = 2;
|
||||
static const uint32_t SILENCE_DETECTION_SUPPORT = 3;
|
||||
|
||||
class VoiceAssistant : public Component {
|
||||
public:
|
||||
|
@ -48,9 +47,6 @@ class VoiceAssistant : public Component {
|
|||
uint32_t get_version() const {
|
||||
#ifdef USE_SPEAKER
|
||||
if (this->speaker_ != nullptr) {
|
||||
if (this->silence_detection_) {
|
||||
return SILENCE_DETECTION_SUPPORT;
|
||||
}
|
||||
return SPEAKER_SUPPORT;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -988,6 +988,7 @@ DEVICE_CLASS_OCCUPANCY = "occupancy"
|
|||
DEVICE_CLASS_OPENING = "opening"
|
||||
DEVICE_CLASS_OUTLET = "outlet"
|
||||
DEVICE_CLASS_OZONE = "ozone"
|
||||
DEVICE_CLASS_PH = "ph"
|
||||
DEVICE_CLASS_PLUG = "plug"
|
||||
DEVICE_CLASS_PM1 = "pm1"
|
||||
DEVICE_CLASS_PM10 = "pm10"
|
||||
|
|
|
@ -475,6 +475,7 @@ template<typename... Ts> class CallbackManager<void(Ts...)> {
|
|||
for (auto &cb : this->callbacks_)
|
||||
cb(args...);
|
||||
}
|
||||
size_t size() const { return this->callbacks_.size(); }
|
||||
|
||||
/// Call all callbacks in this manager.
|
||||
void operator()(Ts... args) { call(args...); }
|
||||
|
|
|
@ -25,6 +25,7 @@ import tornado.ioloop
|
|||
import tornado.iostream
|
||||
import tornado.netutil
|
||||
import tornado.process
|
||||
import tornado.queues
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import yaml
|
||||
|
@ -92,6 +93,10 @@ class DashboardSettings:
|
|||
def using_auth(self):
|
||||
return self.using_password or self.using_ha_addon_auth
|
||||
|
||||
@property
|
||||
def streamer_mode(self):
|
||||
return get_bool_env("ESPHOME_STREAMER_MODE")
|
||||
|
||||
def check_password(self, username, password):
|
||||
if not self.using_auth:
|
||||
return True
|
||||
|
@ -130,7 +135,7 @@ def template_args():
|
|||
"docs_link": docs_link,
|
||||
"get_static_file_url": get_static_file_url,
|
||||
"relative_url": settings.relative_url,
|
||||
"streamer_mode": get_bool_env("ESPHOME_STREAMER_MODE"),
|
||||
"streamer_mode": settings.streamer_mode,
|
||||
"config_dir": settings.config_dir,
|
||||
}
|
||||
|
||||
|
@ -202,7 +207,11 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
def __init__(self, application, request, **kwargs):
|
||||
super().__init__(application, request, **kwargs)
|
||||
self._proc = None
|
||||
self._queue = None
|
||||
self._is_closed = False
|
||||
# Windows doesn't support non-blocking pipes,
|
||||
# use Popen() with a reading thread instead
|
||||
self._use_popen = os.name == "nt"
|
||||
|
||||
@authenticated
|
||||
def on_message(self, message):
|
||||
|
@ -224,13 +233,28 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
return
|
||||
command = self.build_command(json_message)
|
||||
_LOGGER.info("Running command '%s'", " ".join(shlex_quote(x) for x in command))
|
||||
self._proc = tornado.process.Subprocess(
|
||||
command,
|
||||
stdout=tornado.process.Subprocess.STREAM,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=tornado.process.Subprocess.STREAM,
|
||||
)
|
||||
self._proc.set_exit_callback(self._proc_on_exit)
|
||||
|
||||
if self._use_popen:
|
||||
self._queue = tornado.queues.Queue()
|
||||
# pylint: disable=consider-using-with
|
||||
self._proc = subprocess.Popen(
|
||||
command,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
stdout_thread = threading.Thread(target=self._stdout_thread)
|
||||
stdout_thread.daemon = True
|
||||
stdout_thread.start()
|
||||
else:
|
||||
self._proc = tornado.process.Subprocess(
|
||||
command,
|
||||
stdout=tornado.process.Subprocess.STREAM,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=tornado.process.Subprocess.STREAM,
|
||||
)
|
||||
self._proc.set_exit_callback(self._proc_on_exit)
|
||||
|
||||
tornado.ioloop.IOLoop.current().spawn_callback(self._redirect_stdout)
|
||||
|
||||
@property
|
||||
|
@ -252,7 +276,13 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
|
||||
while True:
|
||||
try:
|
||||
data = yield self._proc.stdout.read_until_regex(reg)
|
||||
if self._use_popen:
|
||||
data = yield self._queue.get()
|
||||
if data is None:
|
||||
self._proc_on_exit(self._proc.poll())
|
||||
break
|
||||
else:
|
||||
data = yield self._proc.stdout.read_until_regex(reg)
|
||||
except tornado.iostream.StreamClosedError:
|
||||
break
|
||||
data = codecs.decode(data, "utf8", "replace")
|
||||
|
@ -260,6 +290,19 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
_LOGGER.debug("> stdout: %s", data)
|
||||
self.write_message({"event": "line", "data": data})
|
||||
|
||||
def _stdout_thread(self):
|
||||
if not self._use_popen:
|
||||
return
|
||||
while True:
|
||||
data = self._proc.stdout.readline()
|
||||
if data:
|
||||
data = data.replace(b"\r", b"")
|
||||
self._queue.put_nowait(data)
|
||||
if self._proc.poll() is not None:
|
||||
break
|
||||
self._proc.wait(1.0)
|
||||
self._queue.put_nowait(None)
|
||||
|
||||
def _proc_on_exit(self, returncode):
|
||||
if not self._is_closed:
|
||||
# Check if the proc was not forcibly closed
|
||||
|
@ -270,7 +313,10 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||
# Check if proc exists (if 'start' has been run)
|
||||
if self.is_process_active:
|
||||
_LOGGER.debug("Terminating process")
|
||||
self._proc.proc.terminate()
|
||||
if self._use_popen:
|
||||
self._proc.terminate()
|
||||
else:
|
||||
self._proc.proc.terminate()
|
||||
# Shutdown proc on WS close
|
||||
self._is_closed = True
|
||||
|
||||
|
@ -354,7 +400,10 @@ class EsphomeCompileHandler(EsphomeCommandWebSocket):
|
|||
class EsphomeValidateHandler(EsphomeCommandWebSocket):
|
||||
def build_command(self, json_message):
|
||||
config_file = settings.rel_path(json_message["configuration"])
|
||||
return ["esphome", "--dashboard", "config", config_file]
|
||||
command = ["esphome", "--dashboard", "config", config_file]
|
||||
if not settings.streamer_mode:
|
||||
command.append("--show-secrets")
|
||||
return command
|
||||
|
||||
|
||||
class EsphomeCleanMqttHandler(EsphomeCommandWebSocket):
|
||||
|
@ -1105,7 +1154,7 @@ class JsonConfigRequestHandler(BaseHandler):
|
|||
self.send_error(404)
|
||||
return
|
||||
|
||||
args = ["esphome", "config", settings.rel_path(configuration), "--show-secrets"]
|
||||
args = ["esphome", "config", filename, "--show-secrets"]
|
||||
|
||||
rc, stdout, _ = run_system_command(*args)
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def run_git_command(cmd, cwd=None) -> str:
|
||||
_LOGGER.debug("Running git command: %s", " ".join(cmd))
|
||||
try:
|
||||
ret = subprocess.run(cmd, cwd=cwd, capture_output=True, check=False)
|
||||
except FileNotFoundError as err:
|
||||
|
@ -48,6 +49,7 @@ def clone_or_update(
|
|||
domain: str,
|
||||
username: str = None,
|
||||
password: str = None,
|
||||
submodules: Optional[list[str]] = None,
|
||||
) -> tuple[Path, Optional[Callable[[], None]]]:
|
||||
key = f"{url}@{ref}"
|
||||
|
||||
|
@ -74,6 +76,14 @@ def clone_or_update(
|
|||
run_git_command(["git", "fetch", "--", "origin", ref], str(repo_dir))
|
||||
run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir))
|
||||
|
||||
if submodules is not None:
|
||||
_LOGGER.info(
|
||||
"Initialising submodules (%s) for %s", ", ".join(submodules), key
|
||||
)
|
||||
run_git_command(
|
||||
["git", "submodule", "update", "--init"] + submodules, str(repo_dir)
|
||||
)
|
||||
|
||||
else:
|
||||
# Check refresh needed
|
||||
file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD")
|
||||
|
@ -97,6 +107,14 @@ def clone_or_update(
|
|||
# Hard reset to FETCH_HEAD (short-lived git ref corresponding to most recent fetch)
|
||||
run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir))
|
||||
|
||||
if submodules is not None:
|
||||
_LOGGER.info(
|
||||
"Updating submodules (%s) for %s", ", ".join(submodules), key
|
||||
)
|
||||
run_git_command(
|
||||
["git", "submodule", "update", "--init"] + submodules, str(repo_dir)
|
||||
)
|
||||
|
||||
def revert():
|
||||
_LOGGER.info("Reverting changes to %s -> %s", key, old_sha)
|
||||
run_git_command(["git", "reset", "--hard", old_sha], str(repo_dir))
|
||||
|
|
|
@ -71,6 +71,8 @@ def setup_log(
|
|||
) -> None:
|
||||
import colorama
|
||||
|
||||
colorama.init()
|
||||
|
||||
if debug:
|
||||
log_level = logging.DEBUG
|
||||
CORE.verbose = True
|
||||
|
@ -82,7 +84,6 @@ def setup_log(
|
|||
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
|
||||
colorama.init()
|
||||
logging.getLogger().handlers[0].setFormatter(
|
||||
ESPHomeLogFormatter(include_timestamp=include_timestamp)
|
||||
)
|
||||
|
|
|
@ -105,7 +105,7 @@ extra_scripts = post:esphome/components/esp8266/post_build.py.script
|
|||
; This are common settings for the ESP32 (all variants) using Arduino.
|
||||
[common:esp32-arduino]
|
||||
extends = common:arduino
|
||||
platform = platformio/espressif32@5.3.0
|
||||
platform = platformio/espressif32@5.4.0
|
||||
platform_packages =
|
||||
platformio/framework-arduinoespressif32@~3.20005.0
|
||||
|
||||
|
@ -134,9 +134,9 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script
|
|||
; This are common settings for the ESP32 (all variants) using IDF.
|
||||
[common:esp32-idf]
|
||||
extends = common:idf
|
||||
platform = platformio/espressif32@5.3.0
|
||||
platform = platformio/espressif32@5.4.0
|
||||
platform_packages =
|
||||
platformio/framework-espidf@~3.40404.0
|
||||
platformio/framework-espidf@~3.40405.0
|
||||
|
||||
framework = espidf
|
||||
lib_deps =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
voluptuous==0.13.1
|
||||
PyYAML==6.0
|
||||
PyYAML==6.0.1
|
||||
paho-mqtt==1.6.1
|
||||
colorama==0.4.6
|
||||
tornado==6.3.2
|
||||
|
@ -8,7 +8,7 @@ tzdata>=2021.1 # from time
|
|||
pyserial==3.5
|
||||
platformio==6.1.7 # When updating platformio, also update Dockerfile
|
||||
esptool==4.6.2
|
||||
click==8.1.3
|
||||
click==8.1.5
|
||||
esphome-dashboard==20230711.0
|
||||
aioesphomeapi==15.0.0
|
||||
zeroconf==0.69.0
|
||||
|
|
|
@ -1609,6 +1609,18 @@ binary_sensor:
|
|||
-2267,
|
||||
1709,
|
||||
]
|
||||
- platform: remote_receiver
|
||||
name: Coolix Test 1
|
||||
coolix: 0xB21F98
|
||||
- platform: remote_receiver
|
||||
name: Coolix Test 2
|
||||
coolix:
|
||||
first: 0xB2E003
|
||||
- platform: remote_receiver
|
||||
name: Coolix Test 3
|
||||
coolix:
|
||||
first: 0xB2E003
|
||||
second: 0xB21F98
|
||||
- platform: as3935
|
||||
name: Storm Alert
|
||||
- platform: analog_threshold
|
||||
|
@ -2283,8 +2295,16 @@ switch:
|
|||
- platform: template
|
||||
name: MIDEA_RAW
|
||||
turn_on_action:
|
||||
remote_transmitter.transmit_midea:
|
||||
code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF]
|
||||
- remote_transmitter.transmit_coolix:
|
||||
first: 0xB21F98
|
||||
- remote_transmitter.transmit_coolix:
|
||||
first: 0xB21F98
|
||||
second: 0xB21F98
|
||||
- remote_transmitter.transmit_coolix:
|
||||
first: !lambda "return 0xB21F98;"
|
||||
second: !lambda "return 0xB21F98;"
|
||||
- remote_transmitter.transmit_midea:
|
||||
code: [0xA2, 0x08, 0xFF, 0xFF, 0xFF]
|
||||
- platform: gpio
|
||||
name: "MCP23S08 Pin #0"
|
||||
pin:
|
||||
|
@ -2868,6 +2888,9 @@ tm1651:
|
|||
remote_receiver:
|
||||
pin: GPIO32
|
||||
dump: all
|
||||
on_coolix:
|
||||
then:
|
||||
delay: !lambda "return x.first + x.second;"
|
||||
|
||||
status_led:
|
||||
pin: GPIO2
|
||||
|
|
Loading…
Reference in a new issue