1
0
mirror of https://github.com/esphome/esphome.git synced 2025-02-28 07:48:15 +00:00

Merge remote-tracking branch 'origin/dev' into jesserockz-2024-416

This commit is contained in:
Jesse Hills 2024-09-03 16:15:08 +12:00
commit 81720db1c9
No known key found for this signature in database
GPG Key ID: BEAAE804EFD8E83A
18 changed files with 200 additions and 36 deletions

View File

@ -16,6 +16,8 @@
#include <esp32s2/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32S3)
#include <esp32s3/rom/rtc.h>
#elif defined(USE_ESP32_VARIANT_ESP32H2)
#include <esp32h2/rom/rtc.h>
#endif
#ifdef USE_ARDUINO
#include <Esp.h>
@ -61,7 +63,7 @@ std::string DebugComponent::get_reset_reason_() {
case RTCWDT_SYS_RESET:
reset_reason = "RTC Watch Dog Reset Digital Core";
break;
#if !defined(USE_ESP32_VARIANT_ESP32C6)
#if !defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32H2)
case INTRUSION_RESET:
reset_reason = "Intrusion Reset CPU";
break;

View File

@ -1,6 +1,6 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate_ir
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MODEL
CODEOWNERS = ["@orestismers"]
@ -17,6 +17,7 @@ MODELS = {
"yaa": Model.GREE_YAA,
"yac": Model.GREE_YAC,
"yac1fb9": Model.GREE_YAC1FB9,
"yx1ff": Model.GREE_YX1FF,
}
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(

View File

@ -6,7 +6,15 @@ namespace gree {
static const char *const TAG = "gree.climate";
void GreeClimate::set_model(Model model) { this->model_ = model; }
void GreeClimate::set_model(Model model) {
if (model == GREE_YX1FF) {
this->fan_modes_.insert(climate::CLIMATE_FAN_QUIET); // YX1FF 4 speed
this->presets_.insert(climate::CLIMATE_PRESET_NONE); // YX1FF sleep mode
this->presets_.insert(climate::CLIMATE_PRESET_SLEEP); // YX1FF sleep mode
}
this->model_ = model;
}
void GreeClimate::transmit_state() {
uint8_t remote_state[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00};
@ -14,7 +22,7 @@ void GreeClimate::transmit_state() {
remote_state[0] = this->fan_speed_() | this->operation_mode_();
remote_state[1] = this->temperature_();
if (this->model_ == GREE_YAN) {
if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF) {
remote_state[2] = 0x60;
remote_state[3] = 0x50;
remote_state[4] = this->vertical_swing_();
@ -36,8 +44,18 @@ void GreeClimate::transmit_state() {
}
}
if (this->model_ == GREE_YX1FF) {
if (this->fan_speed_() == GREE_FAN_TURBO) {
remote_state[2] |= GREE_FAN_TURBO_BIT;
}
if (this->preset_() == GREE_PRESET_SLEEP) {
remote_state[0] |= GREE_PRESET_SLEEP_BIT;
}
}
// Calculate the checksum
if (this->model_ == GREE_YAN) {
if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF) {
remote_state[7] = ((remote_state[0] << 4) + (remote_state[1] << 4) + 0xC0);
} else {
remote_state[7] =
@ -124,6 +142,23 @@ uint8_t GreeClimate::operation_mode_() {
}
uint8_t GreeClimate::fan_speed_() {
// YX1FF has 4 fan speeds -- we treat low as quiet and turbo as high
if (this->model_ == GREE_YX1FF) {
switch (this->fan_mode.value()) {
case climate::CLIMATE_FAN_QUIET:
return GREE_FAN_1;
case climate::CLIMATE_FAN_LOW:
return GREE_FAN_2;
case climate::CLIMATE_FAN_MEDIUM:
return GREE_FAN_3;
case climate::CLIMATE_FAN_HIGH:
return GREE_FAN_TURBO;
case climate::CLIMATE_FAN_AUTO:
default:
return GREE_FAN_AUTO;
}
}
switch (this->fan_mode.value()) {
case climate::CLIMATE_FAN_LOW:
return GREE_FAN_1;
@ -161,5 +196,21 @@ uint8_t GreeClimate::temperature_() {
return (uint8_t) roundf(clamp<float>(this->target_temperature, GREE_TEMP_MIN, GREE_TEMP_MAX));
}
uint8_t GreeClimate::preset_() {
// YX1FF has sleep preset
if (this->model_ == GREE_YX1FF) {
switch (this->preset.value()) {
case climate::CLIMATE_PRESET_NONE:
return GREE_PRESET_NONE;
case climate::CLIMATE_PRESET_SLEEP:
return GREE_PRESET_SLEEP;
default:
return GREE_PRESET_NONE;
}
}
return GREE_PRESET_NONE;
}
} // namespace gree
} // namespace esphome

View File

@ -25,7 +25,6 @@ const uint8_t GREE_FAN_AUTO = 0x00;
const uint8_t GREE_FAN_1 = 0x10;
const uint8_t GREE_FAN_2 = 0x20;
const uint8_t GREE_FAN_3 = 0x30;
const uint8_t GREE_FAN_TURBO = 0x80;
// IR Transmission
const uint32_t GREE_IR_FREQUENCY = 38000;
@ -70,8 +69,16 @@ const uint8_t GREE_HDIR_MIDDLE = 0x04;
const uint8_t GREE_HDIR_MRIGHT = 0x05;
const uint8_t GREE_HDIR_RIGHT = 0x06;
// Only available on YX1FF
// Turbo (high) fan mode + sleep preset mode
const uint8_t GREE_FAN_TURBO = 0x80;
const uint8_t GREE_FAN_TURBO_BIT = 0x10;
const uint8_t GREE_PRESET_NONE = 0x00;
const uint8_t GREE_PRESET_SLEEP = 0x01;
const uint8_t GREE_PRESET_SLEEP_BIT = 0x80;
// Model codes
enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9 };
enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9, GREE_YX1FF };
class GreeClimate : public climate_ir::ClimateIR {
public:
@ -93,6 +100,7 @@ class GreeClimate : public climate_ir::ClimateIR {
uint8_t horizontal_swing_();
uint8_t vertical_swing_();
uint8_t temperature_();
uint8_t preset_();
Model model_{};
};

View File

@ -1,17 +1,17 @@
import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component
import esphome.config_validation as cv
from esphome.const import (
CONF_DISABLED,
CONF_ID,
CONF_PORT,
CONF_PROTOCOL,
CONF_SERVICES,
CONF_SERVICE,
CONF_SERVICES,
KEY_CORE,
KEY_FRAMEWORK_VERSION,
CONF_DISABLED,
)
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.core import CORE, coroutine_with_priority
from esphome.components.esp32 import add_idf_component
CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network"]
@ -91,7 +91,7 @@ async def to_code(config):
add_idf_component(
name="mdns",
repo="https://github.com/espressif/esp-protocols.git",
ref="mdns-v1.2.5",
ref="mdns-v1.3.2",
path="components/mdns",
)

View File

@ -13,6 +13,7 @@ from esphome.const import (
)
from esphome.cpp_helpers import logging
from .const import (
CONF_ALLOW_DUPLICATE_COMMANDS,
CONF_BITMASK,
CONF_BYTE_OFFSET,
CONF_COMMAND_THROTTLE,
@ -126,6 +127,7 @@ CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ModbusController),
cv.Optional(CONF_ALLOW_DUPLICATE_COMMANDS, default=False): cv.boolean,
cv.Optional(
CONF_COMMAND_THROTTLE, default="0ms"
): cv.positive_time_period_milliseconds,
@ -253,6 +255,7 @@ async def add_modbus_base_properties(
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS]))
cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
if CONF_SERVER_REGISTERS in config:

View File

@ -1,3 +1,4 @@
CONF_ALLOW_DUPLICATE_COMMANDS = "allow_duplicate_commands"
CONF_BITMASK = "bitmask"
CONF_BYTE_OFFSET = "byte_offset"
CONF_COMMAND_THROTTLE = "command_throttle"

View File

@ -175,16 +175,18 @@ void ModbusController::on_register_data(ModbusRegisterType register_type, uint16
}
void ModbusController::queue_command(const ModbusCommandItem &command) {
// check if this command is already qeued.
// not very effective but the queue is never really large
for (auto &item : command_queue_) {
if (item->is_equal(command)) {
ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u",
static_cast<uint8_t>(command.register_type), command.register_address, command.register_count);
// update the payload of the queued command
// replaces a previous command
item->payload = command.payload;
return;
if (!this->allow_duplicate_commands_) {
// check if this command is already qeued.
// not very effective but the queue is never really large
for (auto &item : command_queue_) {
if (item->is_equal(command)) {
ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u",
static_cast<uint8_t>(command.register_type), command.register_address, command.register_count);
// update the payload of the queued command
// replaces a previous command
item->payload = command.payload;
return;
}
}
}
command_queue_.push_back(make_unique<ModbusCommandItem>(command));

View File

@ -448,6 +448,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
/// incoming queue
void on_write_register_response(ModbusRegisterType register_type, uint16_t start_address,
const std::vector<uint8_t> &data);
/// Allow a duplicate command to be sent
void set_allow_duplicate_commands(bool allow_duplicate_commands) {
this->allow_duplicate_commands_ = allow_duplicate_commands;
}
/// get if a duplicate command can be sent
bool get_allow_duplicate_commands() { return this->allow_duplicate_commands_; }
/// called by esphome generated code to set the command_throttle period
void set_command_throttle(uint16_t command_throttle) { this->command_throttle_ = command_throttle; }
/// called by esphome generated code to set the offline_skip_updates
@ -482,6 +488,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
std::list<std::unique_ptr<ModbusCommandItem>> command_queue_;
/// modbus response data waiting to get processed
std::queue<std::unique_ptr<ModbusCommandItem>> incoming_queue_;
/// if duplicate commands can be sent
bool allow_duplicate_commands_;
/// when was the last send operation
uint32_t last_command_timestamp_;
/// min time in ms between sending modbus commands

View File

@ -1,6 +1,5 @@
import logging
import os
from string import ascii_letters, digits
import esphome.codegen as cg
@ -8,6 +7,7 @@ import esphome.config_validation as cv
from esphome.const import (
CONF_BOARD,
CONF_FRAMEWORK,
CONF_PLATFORM_VERSION,
CONF_SOURCE,
CONF_VERSION,
KEY_CORE,
@ -15,10 +15,9 @@ from esphome.const import (
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PLATFORM_RP2040,
CONF_PLATFORM_VERSION,
)
from esphome.core import CORE, coroutine_with_priority, EsphomeError
from esphome.helpers import mkdir_p, write_file, copy_file_if_changed
from esphome.core import CORE, EsphomeError, coroutine_with_priority
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file
from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns
@ -81,19 +80,19 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
# The default/recommended arduino framework version
# - https://github.com/earlephilhower/arduino-pico/releases
# - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 7, 2)
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4)
# The platformio/raspberrypi version to use for arduino frameworks
# - https://github.com/platformio/platform-raspberrypi/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi
ARDUINO_PLATFORM_VERSION = cv.Version(1, 12, 0)
ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0)
def _arduino_check_versions(value):
value = value.copy()
lookups = {
"dev": (cv.Version(3, 4, 0), "https://github.com/earlephilhower/arduino-pico"),
"latest": (cv.Version(3, 4, 0), None),
"dev": (cv.Version(3, 9, 4), "https://github.com/earlephilhower/arduino-pico"),
"latest": (cv.Version(3, 9, 4), None),
"recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None),
}

View File

@ -20,13 +20,20 @@ std::unique_ptr<RingBuffer> RingBuffer::create(size_t len) {
return nullptr;
}
rb->handle_ = xStreamBufferCreateStatic(len + 1, 0, rb->storage_, &rb->structure_);
rb->handle_ = xStreamBufferCreateStatic(len + 1, 1, rb->storage_, &rb->structure_);
ESP_LOGD(TAG, "Created ring buffer with size %u", len);
return rb;
}
size_t RingBuffer::read(void *data, size_t len, TickType_t ticks_to_wait) {
return xStreamBufferReceive(this->handle_, data, len, ticks_to_wait);
if (ticks_to_wait > 0)
xStreamBufferSetTriggerLevel(this->handle_, len);
size_t bytes_read = xStreamBufferReceive(this->handle_, data, len, ticks_to_wait);
xStreamBufferSetTriggerLevel(this->handle_, 1);
return bytes_read;
}
size_t RingBuffer::write(void *data, size_t len) {
@ -39,6 +46,10 @@ size_t RingBuffer::write(void *data, size_t len) {
return xStreamBufferSend(this->handle_, data, len, 0);
}
size_t RingBuffer::write_without_replacement(void *data, size_t len, TickType_t ticks_to_wait) {
return xStreamBufferSend(this->handle_, data, len, ticks_to_wait);
}
size_t RingBuffer::available() const { return xStreamBufferBytesAvailable(this->handle_); }
size_t RingBuffer::free() const { return xStreamBufferSpacesAvailable(this->handle_); }

View File

@ -12,13 +12,69 @@ namespace esphome {
class RingBuffer {
public:
/**
* @brief Reads from the ring buffer, waiting up to a specified number of ticks if necessary.
*
* Available bytes are read into the provided data pointer. If not enough bytes are available,
* the function will wait up to `ticks_to_wait` FreeRTOS ticks before reading what is available.
*
* @param data Pointer to copy read data into
* @param len Number of bytes to read
* @param ticks_to_wait Maximum number of FreeRTOS ticks to wait (default: 0)
* @return Number of bytes read
*/
size_t read(void *data, size_t len, TickType_t ticks_to_wait = 0);
/**
* @brief Writes to the ring buffer, overwriting oldest data if necessary.
*
* The provided data is written to the ring buffer. If not enough space is available,
* the function will overwrite the oldest data in the ring buffer.
*
* @param data Pointer to data for writing
* @param len Number of bytes to write
* @return Number of bytes written
*/
size_t write(void *data, size_t len);
/**
* @brief Writes to the ring buffer without overwriting oldest data.
*
* The provided data is written to the ring buffer. If not enough space is available,
* the function will wait up to `ticks_to_wait` FreeRTOS ticks before writing as much as possible.
*
* @param data Pointer to data for writing
* @param len Number of bytes to write
* @param ticks_to_wait Maximum number of FreeRTOS ticks to wait (default: 0)
* @return Number of bytes written
*/
size_t write_without_replacement(void *data, size_t len, TickType_t ticks_to_wait = 0);
/**
* @brief Returns the number of available bytes in the ring buffer.
*
* This function provides the number of bytes that can be read from the ring buffer
* without blocking the calling FreeRTOS task.
*
* @return Number of available bytes
*/
size_t available() const;
/**
* @brief Returns the number of free bytes in the ring buffer.
*
* This function provides the number of bytes that can be written to the ring buffer
* without overwriting data or blocking the calling FreeRTOS task.
*
* @return Number of free bytes
*/
size_t free() const;
/**
* @brief Resets the ring buffer, discarding all stored data.
*
* @return pdPASS if successful, pdFAIL otherwise
*/
BaseType_t reset();
static std::unique_ptr<RingBuffer> create(size_t len);

View File

@ -7,7 +7,7 @@ dependencies:
version: v2.0.9
mdns:
git: https://github.com/espressif/esp-protocols.git
version: mdns-v1.2.5
version: mdns-v1.3.2
path: components/mdns
rules:
- if: "idf_version >=5.0"

View File

@ -48,6 +48,8 @@ class StorageJSON:
firmware_bin_path: str,
loaded_integrations: set[str],
no_mdns: bool,
framework: str | None = None,
core_platform: str | None = None,
) -> None:
# Version of the storage JSON schema
assert storage_version is None or isinstance(storage_version, int)
@ -78,6 +80,10 @@ class StorageJSON:
self.loaded_integrations = loaded_integrations
# Is mDNS disabled
self.no_mdns = no_mdns
# The framework used to compile the firmware
self.framework = framework
# The core platform of this firmware. Like "esp32", "rp2040", "host" etc.
self.core_platform = core_platform
def as_dict(self):
return {
@ -94,6 +100,8 @@ class StorageJSON:
"firmware_bin_path": self.firmware_bin_path,
"loaded_integrations": sorted(self.loaded_integrations),
"no_mdns": self.no_mdns,
"framework": self.framework,
"core_platform": self.core_platform,
}
def to_json(self):
@ -127,6 +135,8 @@ class StorageJSON:
and CONF_DISABLED in esph.config[CONF_MDNS]
and esph.config[CONF_MDNS][CONF_DISABLED] is True
),
framework=esph.target_framework,
core_platform=esph.target_platform,
)
@staticmethod
@ -147,6 +157,8 @@ class StorageJSON:
firmware_bin_path=None,
loaded_integrations=set(),
no_mdns=False,
framework=None,
core_platform=platform.lower(),
)
@staticmethod
@ -168,6 +180,8 @@ class StorageJSON:
firmware_bin_path = storage.get("firmware_bin_path")
loaded_integrations = set(storage.get("loaded_integrations", []))
no_mdns = storage.get("no_mdns", False)
framework = storage.get("framework")
core_platform = storage.get("core_platform")
return StorageJSON(
storage_version,
name,
@ -182,6 +196,8 @@ class StorageJSON:
firmware_bin_path,
loaded_integrations,
no_mdns,
framework,
core_platform,
)
@staticmethod

View File

@ -9,6 +9,7 @@ from esphome.config import iter_component_configs, iter_components
from esphome.const import (
ENV_NOGITIGNORE,
HEADER_FILE_EXTENSIONS,
PLATFORM_ESP32,
SOURCE_FILE_EXTENSIONS,
__version__,
)
@ -107,7 +108,10 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool:
if old.build_path != new.build_path:
return True
if old.loaded_integrations != new.loaded_integrations:
return True
if new.core_platform == PLATFORM_ESP32:
from esphome.components.esp32 import FRAMEWORK_ESP_IDF
return new.framework == FRAMEWORK_ESP_IDF
return False

View File

@ -168,7 +168,7 @@ board_build.filesystem_size = 0.5m
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
platform_packages =
; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.7.2/rp2040-3.7.2.zip
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip
framework = arduino
lib_deps =

View File

@ -20,6 +20,7 @@ modbus_controller:
- id: modbus_controller1
address: 0x2
modbus_id: mod_bus1
allow_duplicate_commands: false
- id: modbus_controller2
address: 0x2
modbus_id: mod_bus2

View File

@ -12,3 +12,4 @@ modbus_controller:
- id: modbus_controller1
address: 0x2
modbus_id: mod_bus1
allow_duplicate_commands: true