Merge branch 'dev' into nrf52_core

This commit is contained in:
tomaszduda23 2024-08-30 08:58:48 +02:00 committed by GitHub
commit 34563d9db3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 273 additions and 248 deletions

View file

@ -17,7 +17,7 @@ runs:
steps: steps:
- name: Set up Python ${{ inputs.python-version }} - name: Set up Python ${{ inputs.python-version }}
id: python id: python
uses: actions/setup-python@v5.1.1 uses: actions/setup-python@v5.2.0
with: with:
python-version: ${{ inputs.python-version }} python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment - name: Restore Python virtual environment

View file

@ -23,7 +23,7 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.11" python-version: "3.11"

View file

@ -42,7 +42,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4.1.7 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.9" python-version: "3.9"
- name: Set up Docker Buildx - name: Set up Docker Buildx

View file

@ -41,7 +41,7 @@ jobs:
run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
- name: Set up Python ${{ env.DEFAULT_PYTHON }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python id: python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment - name: Restore Python virtual environment

View file

@ -53,7 +53,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4.1.7 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- name: Set up python environment - name: Set up python environment
@ -85,7 +85,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4.1.7 - uses: actions/checkout@v4.1.7
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: "3.9" python-version: "3.9"

View file

@ -22,7 +22,7 @@ jobs:
path: lib/home-assistant path: lib/home-assistant
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v5.1.0 uses: actions/setup-python@v5.2.0
with: with:
python-version: 3.12 python-version: 3.12

View file

@ -1,18 +1,23 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins from esphome import pins
import esphome.codegen as cg
from esphome.components import canbus from esphome.components import canbus
from esphome.const import CONF_ID, CONF_RX_PIN, CONF_TX_PIN from esphome.components.canbus import CONF_BIT_RATE, CanbusComponent, CanSpeed
from esphome.components.canbus import CanbusComponent, CanSpeed, CONF_BIT_RATE
from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import ( from esphome.components.esp32.const import (
VARIANT_ESP32, VARIANT_ESP32,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32C3, VARIANT_ESP32C3,
VARIANT_ESP32C6, VARIANT_ESP32C6,
VARIANT_ESP32H2, VARIANT_ESP32H2,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
)
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
CONF_RX_PIN,
CONF_RX_QUEUE_LEN,
CONF_TX_PIN,
CONF_TX_QUEUE_LEN,
) )
CODEOWNERS = ["@Sympatron"] CODEOWNERS = ["@Sympatron"]
@ -77,6 +82,8 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend(
cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate, cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate,
cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number, cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number,
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number, cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t,
cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t,
} }
) )
@ -87,3 +94,7 @@ async def to_code(config):
cg.add(var.set_rx(config[CONF_RX_PIN])) cg.add(var.set_rx(config[CONF_RX_PIN]))
cg.add(var.set_tx(config[CONF_TX_PIN])) cg.add(var.set_tx(config[CONF_TX_PIN]))
if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None:
cg.add(var.set_rx_queue_len(rx_queue_len))
if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None:
cg.add(var.set_tx_queue_len(tx_queue_len))

View file

@ -69,6 +69,13 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config
bool ESP32Can::setup_internal() { bool ESP32Can::setup_internal() {
twai_general_config_t g_config = twai_general_config_t g_config =
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL); TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL);
if (this->tx_queue_len_.has_value()) {
g_config.tx_queue_len = this->tx_queue_len_.value();
}
if (this->rx_queue_len_.has_value()) {
g_config.rx_queue_len = this->rx_queue_len_.value();
}
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
twai_timing_config_t t_config; twai_timing_config_t t_config;

View file

@ -12,6 +12,8 @@ class ESP32Can : public canbus::Canbus {
public: public:
void set_rx(int rx) { rx_ = rx; } void set_rx(int rx) { rx_ = rx; }
void set_tx(int tx) { tx_ = tx; } void set_tx(int tx) { tx_ = tx; }
void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; }
void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; }
ESP32Can(){}; ESP32Can(){};
protected: protected:
@ -21,6 +23,8 @@ class ESP32Can : public canbus::Canbus {
int rx_{-1}; int rx_{-1};
int tx_{-1}; int tx_{-1};
optional<uint32_t> tx_queue_len_{};
optional<uint32_t> rx_queue_len_{};
}; };
} // namespace esp32_can } // namespace esp32_can

View file

@ -1,11 +1,10 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins from esphome import pins
import esphome.codegen as cg
from esphome.components import i2c, touchscreen from esphome.components import i2c, touchscreen
from esphome.const import CONF_INTERRUPT_PIN, CONF_ID import esphome.config_validation as cv
from .. import gt911_ns from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN
from .. import gt911_ns
GT911ButtonListener = gt911_ns.class_("GT911ButtonListener") GT911ButtonListener = gt911_ns.class_("GT911ButtonListener")
GT911Touchscreen = gt911_ns.class_( GT911Touchscreen = gt911_ns.class_(
@ -18,6 +17,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
{ {
cv.GenerateID(): cv.declare_id(GT911Touchscreen), cv.GenerateID(): cv.declare_id(GT911Touchscreen),
cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema,
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
} }
).extend(i2c.i2c_device_schema(0x5D)) ).extend(i2c.i2c_device_schema(0x5D))
@ -29,3 +29,5 @@ async def to_code(config):
if interrupt_pin := config.get(CONF_INTERRUPT_PIN): if interrupt_pin := config.get(CONF_INTERRUPT_PIN):
cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin)))
if reset_pin := config.get(CONF_RESET_PIN):
cg.add(var.set_reset_pin(await cg.gpio_pin_expression(reset_pin)))

View file

@ -26,6 +26,23 @@ static const size_t MAX_BUTTONS = 4; // max number of buttons scanned
void GT911Touchscreen::setup() { void GT911Touchscreen::setup() {
i2c::ErrorCode err; i2c::ErrorCode err;
ESP_LOGCONFIG(TAG, "Setting up GT911 Touchscreen..."); ESP_LOGCONFIG(TAG, "Setting up GT911 Touchscreen...");
if (this->reset_pin_ != nullptr) {
this->reset_pin_->setup();
this->reset_pin_->digital_write(false);
if (this->interrupt_pin_ != nullptr) {
// The interrupt pin is used as an input during reset to select the I2C address.
this->interrupt_pin_->pin_mode(gpio::FLAG_OUTPUT);
this->interrupt_pin_->setup();
this->interrupt_pin_->digital_write(false);
}
delay(2);
this->reset_pin_->digital_write(true);
delay(50); // NOLINT
if (this->interrupt_pin_ != nullptr) {
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT);
this->interrupt_pin_->setup();
}
}
// check the configuration of the int line. // check the configuration of the int line.
uint8_t data[4]; uint8_t data[4];

View file

@ -19,12 +19,14 @@ class GT911Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice
void dump_config() override; void dump_config() override;
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; }
void register_button_listener(GT911ButtonListener *listener) { this->button_listeners_.push_back(listener); } void register_button_listener(GT911ButtonListener *listener) { this->button_listeners_.push_back(listener); }
protected: protected:
void update_touches() override; void update_touches() override;
InternalGPIOPin *interrupt_pin_{}; InternalGPIOPin *interrupt_pin_{};
GPIOPin *reset_pin_{};
std::vector<GT911ButtonListener *> button_listeners_; std::vector<GT911ButtonListener *> button_listeners_;
uint8_t button_state_{0xFF}; // last button state. Initial FF guarantees first update. uint8_t button_state_{0xFF}; // last button state. Initial FF guarantees first update.
}; };

View file

@ -70,72 +70,62 @@ void MICS4514Component::update() {
if (this->carbon_monoxide_sensor_ != nullptr) { if (this->carbon_monoxide_sensor_ != nullptr) {
float co = 0.0f; float co = 0.0f;
if (red_f <= 0.425f) { if (red_f > 3.4f) {
co = (0.425f - red_f) / 0.000405f; co = 0.0;
if (co < 1.0f) } else if (red_f < 0.01) {
co = 0.0f; co = 1000.0;
if (co > 1000.0f) } else {
co = 1000.0f; co = 4.2 / pow(red_f, 1.2);
} }
this->carbon_monoxide_sensor_->publish_state(co); this->carbon_monoxide_sensor_->publish_state(co);
} }
if (this->nitrogen_dioxide_sensor_ != nullptr) { if (this->nitrogen_dioxide_sensor_ != nullptr) {
float nitrogendioxide = 0.0f; float nitrogendioxide = 0.0f;
if (ox_f >= 1.1f) { if (ox_f < 0.3f) {
nitrogendioxide = (ox_f - 0.045f) / 6.13f; nitrogendioxide = 0.0;
if (nitrogendioxide < 0.1f) } else {
nitrogendioxide = 0.0f; nitrogendioxide = 0.164 * pow(ox_f, 0.975);
if (nitrogendioxide > 10.0f)
nitrogendioxide = 10.0f;
} }
this->nitrogen_dioxide_sensor_->publish_state(nitrogendioxide); this->nitrogen_dioxide_sensor_->publish_state(nitrogendioxide);
} }
if (this->methane_sensor_ != nullptr) { if (this->methane_sensor_ != nullptr) {
float methane = 0.0f; float methane = 0.0f;
if (red_f <= 0.786f) { if (red_f > 0.9f || red_f < 0.5) { // outside the range->unlikely
methane = (0.786f - red_f) / 0.000023f; methane = 0.0;
if (methane < 1000.0f) } else {
methane = 0.0f; methane = 630 / pow(red_f, 4.4);
if (methane > 25000.0f)
methane = 25000.0f;
} }
this->methane_sensor_->publish_state(methane); this->methane_sensor_->publish_state(methane);
} }
if (this->ethanol_sensor_ != nullptr) { if (this->ethanol_sensor_ != nullptr) {
float ethanol = 0.0f; float ethanol = 0.0f;
if (red_f <= 0.306f) { if (red_f > 1.0f || red_f < 0.02) { // outside the range->unlikely
ethanol = (0.306f - red_f) / 0.00057f; ethanol = 0.0;
if (ethanol < 10.0f) } else {
ethanol = 0.0f; ethanol = 1.52 / pow(red_f, 1.55);
if (ethanol > 500.0f)
ethanol = 500.0f;
} }
this->ethanol_sensor_->publish_state(ethanol); this->ethanol_sensor_->publish_state(ethanol);
} }
if (this->hydrogen_sensor_ != nullptr) { if (this->hydrogen_sensor_ != nullptr) {
float hydrogen = 0.0f; float hydrogen = 0.0f;
if (red_f <= 0.279f) { if (red_f > 0.9f || red_f < 0.02) { // outside the range->unlikely
hydrogen = (0.279f - red_f) / 0.00026f; hydrogen = 0.0;
if (hydrogen < 1.0f) } else {
hydrogen = 0.0f; hydrogen = 0.85 / pow(red_f, 1.75);
if (hydrogen > 1000.0f)
hydrogen = 1000.0f;
} }
this->hydrogen_sensor_->publish_state(hydrogen); this->hydrogen_sensor_->publish_state(hydrogen);
} }
if (this->ammonia_sensor_ != nullptr) { if (this->ammonia_sensor_ != nullptr) {
float ammonia = 0.0f; float ammonia = 0.0f;
if (red_f <= 0.8f) { if (red_f > 0.98f || red_f < 0.2532) { // outside the ammonia range->unlikely
ammonia = (0.8f - red_f) / 0.0015f; ammonia = 0.0;
if (ammonia < 1.0f) } else {
ammonia = 0.0f; ammonia = 0.9 / pow(red_f, 4.6);
if (ammonia > 500.0f)
ammonia = 500.0f;
} }
this->ammonia_sensor_->publish_state(ammonia); this->ammonia_sensor_->publish_state(ammonia);
} }

View file

@ -1,47 +1,39 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins from esphome import pins
from esphome.components import ( import esphome.codegen as cg
spi, from esphome.components import display, spi
display, from esphome.components.esp32 import const, only_on_variant
)
from esphome.const import (
CONF_DC_PIN,
CONF_HSYNC_PIN,
CONF_RESET_PIN,
CONF_DATA_PINS,
CONF_ID,
CONF_DIMENSIONS,
CONF_VSYNC_PIN,
CONF_WIDTH,
CONF_HEIGHT,
CONF_LAMBDA,
CONF_MIRROR_X,
CONF_MIRROR_Y,
CONF_COLOR_ORDER,
CONF_TRANSFORM,
CONF_OFFSET_HEIGHT,
CONF_OFFSET_WIDTH,
CONF_INVERT_COLORS,
CONF_RED,
CONF_GREEN,
CONF_BLUE,
CONF_NUMBER,
CONF_IGNORE_STRAPPING_WARNING,
)
from esphome.components.esp32 import (
only_on_variant,
const,
)
from esphome.components.rpi_dpi_rgb.display import ( from esphome.components.rpi_dpi_rgb.display import (
CONF_PCLK_FREQUENCY, CONF_PCLK_FREQUENCY,
CONF_PCLK_INVERTED, CONF_PCLK_INVERTED,
) )
from .init_sequences import ( import esphome.config_validation as cv
ST7701S_INITS, from esphome.const import (
cmd, CONF_BLUE,
CONF_COLOR_ORDER,
CONF_DATA_PINS,
CONF_DC_PIN,
CONF_DIMENSIONS,
CONF_GREEN,
CONF_HEIGHT,
CONF_HSYNC_PIN,
CONF_ID,
CONF_IGNORE_STRAPPING_WARNING,
CONF_INVERT_COLORS,
CONF_LAMBDA,
CONF_MIRROR_X,
CONF_MIRROR_Y,
CONF_NUMBER,
CONF_OFFSET_HEIGHT,
CONF_OFFSET_WIDTH,
CONF_RED,
CONF_RESET_PIN,
CONF_TRANSFORM,
CONF_VSYNC_PIN,
CONF_WIDTH,
) )
from esphome.core import TimePeriod
from .init_sequences import ST7701S_INITS, cmd
CONF_INIT_SEQUENCE = "init_sequence" CONF_INIT_SEQUENCE = "init_sequence"
CONF_DE_PIN = "de_pin" CONF_DE_PIN = "de_pin"
@ -59,6 +51,7 @@ DEPENDENCIES = ["spi", "esp32"]
st7701s_ns = cg.esphome_ns.namespace("st7701s") st7701s_ns = cg.esphome_ns.namespace("st7701s")
ST7701S = st7701s_ns.class_("ST7701S", display.Display, cg.Component, spi.SPIDevice) ST7701S = st7701s_ns.class_("ST7701S", display.Display, cg.Component, spi.SPIDevice)
ColorOrder = display.display_ns.enum("ColorMode") ColorOrder = display.display_ns.enum("ColorMode")
ST7701S_DELAY_FLAG = 0xFF
COLOR_ORDERS = { COLOR_ORDERS = {
"RGB": ColorOrder.COLOR_ORDER_RGB, "RGB": ColorOrder.COLOR_ORDER_RGB,
@ -93,18 +86,23 @@ def map_sequence(value):
""" """
An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py, An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py,
or can be a literal array of data bytes. or can be a literal array of data bytes.
The format is a repeated sequence of [CMD, LEN, <data>] where <data> is LEN bytes. The format is a repeated sequence of [CMD, <data>] where <data> is s a sequence of bytes. The length is inferred
from the length of the sequence and should not be explicit.
A delay can be inserted by specifying "- delay N" where N is in ms
""" """
if isinstance(value, str) and value.lower().startswith("delay "):
value = value.lower()[6:]
delay = cv.All(
cv.positive_time_period_milliseconds,
cv.Range(TimePeriod(milliseconds=1), TimePeriod(milliseconds=255)),
)(value)
return [delay, ST7701S_DELAY_FLAG]
if not isinstance(value, list): if not isinstance(value, list):
value = cv.int_(value) value = cv.int_(value)
value = cv.one_of(*ST7701S_INITS)(value) value = cv.one_of(*ST7701S_INITS)(value)
return ST7701S_INITS[value] return ST7701S_INITS[value]
# value = cv.ensure_list(cv.uint8_t)(value) value = cv.Length(min=1, max=254)(value)
data_length = len(value) return cmd(*value)
if data_length == 0:
raise cv.Invalid("Empty sequence")
value = cmd(*value)
return value
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(

View file

@ -138,12 +138,17 @@ void ST7701S::write_init_sequence_() {
for (size_t i = 0; i != this->init_sequence_.size();) { for (size_t i = 0; i != this->init_sequence_.size();) {
uint8_t cmd = this->init_sequence_[i++]; uint8_t cmd = this->init_sequence_[i++];
size_t len = this->init_sequence_[i++]; size_t len = this->init_sequence_[i++];
if (len == ST7701S_DELAY_FLAG) {
ESP_LOGV(TAG, "Delay %dms", cmd);
delay(cmd);
} else {
this->write_sequence_(cmd, len, &this->init_sequence_[i]); this->write_sequence_(cmd, len, &this->init_sequence_[i]);
i += len; i += len;
esph_log_v(TAG, "Command %X, %d bytes", cmd, len); ESP_LOGV(TAG, "Command %X, %d bytes", cmd, len);
if (cmd == SW_RESET_CMD) if (cmd == SW_RESET_CMD)
delay(6); delay(6);
} }
}
// st7701 does not appear to support axis swapping // st7701 does not appear to support axis swapping
this->write_sequence_(CMD2_BKSEL, sizeof(CMD2_BK0), CMD2_BK0); this->write_sequence_(CMD2_BKSEL, sizeof(CMD2_BK0), CMD2_BK0);
this->write_command_(SDIR_CMD); // this is in the BK0 command set this->write_command_(SDIR_CMD); // this is in the BK0 command set
@ -153,7 +158,7 @@ void ST7701S::write_init_sequence_() {
val |= 0x10; val |= 0x10;
this->write_command_(MADCTL_CMD); this->write_command_(MADCTL_CMD);
this->write_data_(val); this->write_data_(val);
esph_log_d(TAG, "write MADCTL %X", val); ESP_LOGD(TAG, "write MADCTL %X", val);
this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF); this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF);
this->set_timeout(120, [this] { this->set_timeout(120, [this] {
this->write_command_(SLEEP_OUT); this->write_command_(SLEEP_OUT);

View file

@ -25,6 +25,7 @@ const uint8_t INVERT_ON = 0x21;
const uint8_t DISPLAY_ON = 0x29; const uint8_t DISPLAY_ON = 0x29;
const uint8_t CMD2_BKSEL = 0xFF; const uint8_t CMD2_BKSEL = 0xFF;
const uint8_t CMD2_BK0[5] = {0x77, 0x01, 0x00, 0x00, 0x10}; const uint8_t CMD2_BK0[5] = {0x77, 0x01, 0x00, 0x00, 0x10};
const uint8_t ST7701S_DELAY_FLAG = 0xFF;
class ST7701S : public display::Display, class ST7701S : public display::Display,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,

View file

@ -9,6 +9,7 @@ from esphome.const import (
CONF_MULTIPLY, CONF_MULTIPLY,
CONF_STEP, CONF_STEP,
CONF_INITIAL_VALUE, CONF_INITIAL_VALUE,
CONF_RESTORE_VALUE,
) )
from .. import tuya_ns, CONF_TUYA_ID, Tuya, TuyaDatapointType from .. import tuya_ns, CONF_TUYA_ID, Tuya, TuyaDatapointType
@ -58,6 +59,7 @@ CONFIG_SCHEMA = cv.All(
DATAPOINT_TYPES, lower=True DATAPOINT_TYPES, lower=True
), ),
cv.Optional(CONF_INITIAL_VALUE): cv.float_, cv.Optional(CONF_INITIAL_VALUE): cv.float_,
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
} }
) )
), ),
@ -90,3 +92,4 @@ async def to_code(config):
hidden_init_value := hidden_config.get(CONF_INITIAL_VALUE, None) hidden_init_value := hidden_config.get(CONF_INITIAL_VALUE, None)
) is not None: ) is not None:
cg.add(var.set_datapoint_initial_value(hidden_init_value)) cg.add(var.set_datapoint_initial_value(hidden_init_value))
cg.add(var.set_restore_value(hidden_config[CONF_RESTORE_VALUE]))

View file

@ -7,14 +7,28 @@ namespace tuya {
static const char *const TAG = "tuya.number"; static const char *const TAG = "tuya.number";
void TuyaNumber::setup() { void TuyaNumber::setup() {
if (this->restore_value_) {
this->pref_ = global_preferences->make_preference<float>(this->get_object_id_hash());
}
this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) { this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) {
if (datapoint.type == TuyaDatapointType::INTEGER) { if (datapoint.type == TuyaDatapointType::INTEGER) {
ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int); ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int);
this->publish_state(datapoint.value_int / multiply_by_); float value = datapoint.value_int / multiply_by_;
this->publish_state(value);
if (this->restore_value_)
this->pref_.save(&value);
} else if (datapoint.type == TuyaDatapointType::ENUM) { } else if (datapoint.type == TuyaDatapointType::ENUM) {
ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum); ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum);
this->publish_state(datapoint.value_enum); float value = datapoint.value_enum;
this->publish_state(value);
if (this->restore_value_)
this->pref_.save(&value);
} else {
ESP_LOGW(TAG, "Reported type (%d) is not a number!", static_cast<int>(datapoint.type));
return;
} }
if ((this->type_) && (this->type_ != datapoint.type)) { if ((this->type_) && (this->type_ != datapoint.type)) {
ESP_LOGW(TAG, "Reported type (%d) different than previously set (%d)!", static_cast<int>(datapoint.type), ESP_LOGW(TAG, "Reported type (%d) different than previously set (%d)!", static_cast<int>(datapoint.type),
static_cast<int>(*this->type_)); static_cast<int>(*this->type_));
@ -23,8 +37,26 @@ void TuyaNumber::setup() {
}); });
this->parent_->add_on_initialized_callback([this] { this->parent_->add_on_initialized_callback([this] {
if ((this->initial_value_) && (this->type_)) { if (this->type_) {
this->control(*this->initial_value_); float value;
if (!this->restore_value_) {
if (this->initial_value_) {
value = *this->initial_value_;
} else {
return;
}
} else {
if (!this->pref_.load(&value)) {
if (this->initial_value_) {
value = *this->initial_value_;
} else {
value = this->traits.get_min_value();
ESP_LOGW(TAG, "Failed to restore and there is no initial value defined. Setting min_value (%f)", value);
}
}
}
this->control(value);
} }
}); });
} }
@ -38,6 +70,9 @@ void TuyaNumber::control(float value) {
this->parent_->set_enum_datapoint_value(this->number_id_, value); this->parent_->set_enum_datapoint_value(this->number_id_, value);
} }
this->publish_state(value); this->publish_state(value);
if (this->restore_value_)
this->pref_.save(&value);
} }
void TuyaNumber::dump_config() { void TuyaNumber::dump_config() {
@ -52,6 +87,8 @@ void TuyaNumber::dump_config() {
if (this->initial_value_) { if (this->initial_value_) {
ESP_LOGCONFIG(TAG, " Initial Value: %f", *this->initial_value_); ESP_LOGCONFIG(TAG, " Initial Value: %f", *this->initial_value_);
} }
ESP_LOGCONFIG(TAG, " Restore Value: %s", YESNO(this->restore_value_));
} }
} // namespace tuya } // namespace tuya

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "esphome/core/component.h"
#include "esphome/components/tuya/tuya.h"
#include "esphome/components/number/number.h" #include "esphome/components/number/number.h"
#include "esphome/components/tuya/tuya.h"
#include "esphome/core/component.h"
#include "esphome/core/optional.h" #include "esphome/core/optional.h"
#include "esphome/core/preferences.h"
namespace esphome { namespace esphome {
namespace tuya { namespace tuya {
@ -16,6 +17,7 @@ class TuyaNumber : public number::Number, public Component {
void set_write_multiply(float factor) { multiply_by_ = factor; } void set_write_multiply(float factor) { multiply_by_ = factor; }
void set_datapoint_type(TuyaDatapointType type) { type_ = type; } void set_datapoint_type(TuyaDatapointType type) { type_ = type; }
void set_datapoint_initial_value(float value) { this->initial_value_ = value; } void set_datapoint_initial_value(float value) { this->initial_value_ = value; }
void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; }
void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
@ -27,6 +29,9 @@ class TuyaNumber : public number::Number, public Component {
float multiply_by_{1.0}; float multiply_by_{1.0};
optional<TuyaDatapointType> type_{}; optional<TuyaDatapointType> type_{};
optional<float> initial_value_{}; optional<float> initial_value_{};
bool restore_value_{false};
ESPPreferenceObject pref_;
}; };
} // namespace tuya } // namespace tuya

View file

@ -732,6 +732,7 @@ CONF_RW_PIN = "rw_pin"
CONF_RX_BUFFER_SIZE = "rx_buffer_size" CONF_RX_BUFFER_SIZE = "rx_buffer_size"
CONF_RX_ONLY = "rx_only" CONF_RX_ONLY = "rx_only"
CONF_RX_PIN = "rx_pin" CONF_RX_PIN = "rx_pin"
CONF_RX_QUEUE_LEN = "rx_queue_len"
CONF_SAFE_MODE = "safe_mode" CONF_SAFE_MODE = "safe_mode"
CONF_SAMPLE_RATE = "sample_rate" CONF_SAMPLE_RATE = "sample_rate"
CONF_SAMSUNG = "samsung" CONF_SAMSUNG = "samsung"
@ -883,6 +884,7 @@ CONF_TVOC = "tvoc"
CONF_TX_BUFFER_SIZE = "tx_buffer_size" CONF_TX_BUFFER_SIZE = "tx_buffer_size"
CONF_TX_PIN = "tx_pin" CONF_TX_PIN = "tx_pin"
CONF_TX_POWER = "tx_power" CONF_TX_POWER = "tx_power"
CONF_TX_QUEUE_LEN = "tx_queue_len"
CONF_TYPE = "type" CONF_TYPE = "type"
CONF_TYPE_ID = "type_id" CONF_TYPE_ID = "type_id"
CONF_UART_ID = "uart_id" CONF_UART_ID = "uart_id"

View file

@ -1,6 +1,9 @@
#include "bytebuffer.h" #include "bytebuffer.h"
#include <cassert> #include <cassert>
#include <cstring> #include "esphome/core/helpers.h"
#include <list>
#include <vector>
namespace esphome { namespace esphome {
@ -110,18 +113,13 @@ uint32_t ByteBuffer::get_int24() {
} }
float ByteBuffer::get_float() { float ByteBuffer::get_float() {
assert(this->get_remaining() >= sizeof(float)); assert(this->get_remaining() >= sizeof(float));
auto ui_value = this->get_uint32(); return bit_cast<float>(this->get_uint32());
float value;
memcpy(&value, &ui_value, sizeof(float));
return value;
} }
double ByteBuffer::get_double() { double ByteBuffer::get_double() {
assert(this->get_remaining() >= sizeof(double)); assert(this->get_remaining() >= sizeof(double));
auto ui_value = this->get_uint64(); return bit_cast<double>(this->get_uint64());
double value;
memcpy(&value, &ui_value, sizeof(double));
return value;
} }
std::vector<uint8_t> ByteBuffer::get_vector(size_t length) { std::vector<uint8_t> ByteBuffer::get_vector(size_t length) {
assert(this->get_remaining() >= length); assert(this->get_remaining() >= length);
auto start = this->data_.begin() + this->position_; auto start = this->data_.begin() + this->position_;
@ -154,16 +152,12 @@ void ByteBuffer::put_uint(uint64_t value, size_t length) {
void ByteBuffer::put_float(float value) { void ByteBuffer::put_float(float value) {
static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported");
assert(this->get_remaining() >= sizeof(float)); assert(this->get_remaining() >= sizeof(float));
uint32_t ui_value; this->put_uint32(bit_cast<uint32_t>(value));
memcpy(&ui_value, &value, sizeof(float)); // this work-around required to silence compiler warnings
this->put_uint32(ui_value);
} }
void ByteBuffer::put_double(double value) { void ByteBuffer::put_double(double value) {
static_assert(sizeof(double) == sizeof(uint64_t), "Double sizes other than 64 bit not supported"); static_assert(sizeof(double) == sizeof(uint64_t), "Double sizes other than 64 bit not supported");
assert(this->get_remaining() >= sizeof(double)); assert(this->get_remaining() >= sizeof(double));
uint64_t ui_value; this->put_uint64(bit_cast<uint64_t>(value));
memcpy(&ui_value, &value, sizeof(double));
this->put_uint64(ui_value);
} }
void ByteBuffer::put_vector(const std::vector<uint8_t> &value) { void ByteBuffer::put_vector(const std::vector<uint8_t> &value) {
assert(this->get_remaining() >= value.size()); assert(this->get_remaining() >= value.size());

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -11,6 +11,7 @@ display:
cs_pin: 5 cs_pin: 5
dc_pin: 15 dc_pin: 15
reset_pin: 16 reset_pin: 16
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -11,6 +11,7 @@ display:
cs_pin: 20 cs_pin: 20
dc_pin: 21 dc_pin: 21
reset_pin: 22 reset_pin: 22
invert_colors: false
# Purposely test that `animation:` does auto-load `image:` # Purposely test that `animation:` does auto-load `image:`
# Keep the `image:` undefined. # Keep the `image:` undefined.

View file

@ -12,6 +12,7 @@ display:
dc_pin: GPIO4 dc_pin: GPIO4
reset_pin: reset_pin:
number: GPIO21 number: GPIO21
invert_colors: false
i2c: i2c:
scl: GPIO18 scl: GPIO18

View file

@ -26,6 +26,7 @@ display:
mirror_x: true mirror_x: true
mirror_y: true mirror_y: true
auto_clear_enabled: false auto_clear_enabled: false
invert_colors: false
spi: spi:
clk_pin: 14 clk_pin: 14

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: false
lambda: |- lambda: |-
// Draw an analog clock in the center of the screen // Draw an analog clock in the center of the screen
int centerX = it.get_width() / 2; int centerX = it.get_width() / 2;

View file

@ -19,6 +19,7 @@ display:
mirror_x: true mirror_x: true
mirror_y: true mirror_y: true
auto_clear_enabled: false auto_clear_enabled: false
invert_colors: false
touchscreen: touchscreen:
- platform: ft63x6 - platform: ft63x6

View file

@ -0,0 +1,25 @@
i2c:
- id: i2c_gt911
scl: 5
sda: 4
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 10
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 20
reset_pin: 21
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -1,24 +1 @@
i2c: <<: !include common.yaml
- id: i2c_gt911
scl: 16
sda: 17
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 13
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 14
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -1,24 +1 @@
i2c: <<: !include common.yaml
- id: i2c_gt911
scl: 5
sda: 4
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 3
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 6
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -1,24 +1 @@
i2c: <<: !include common.yaml
- id: i2c_gt911
scl: 5
sda: 4
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 3
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 6
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -1,24 +1 @@
i2c: <<: !include common.yaml
- id: i2c_gt911
scl: 16
sda: 17
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 13
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 14
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -1,24 +1 @@
i2c: <<: !include common.yaml
- id: i2c_gt911
scl: 5
sda: 4
display:
- platform: ssd1306_i2c
id: ssd1306_display
model: SSD1306_128X64
reset_pin: 3
pages:
- id: page1
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
touchscreen:
- platform: gt911
display: ssd1306_display
interrupt_pin: 6
binary_sensor:
- platform: gt911
id: touch_key_911
index: 0

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -11,6 +11,7 @@ display:
cs_pin: 5 cs_pin: 5
dc_pin: 15 dc_pin: 15
reset_pin: 16 reset_pin: 16
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -11,6 +11,7 @@ display:
cs_pin: 20 cs_pin: 20
dc_pin: 21 dc_pin: 21
reset_pin: 22 reset_pin: 22
invert_colors: true
image: image:
- id: binary_image - id: binary_image

View file

@ -13,6 +13,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: true
lambda: |- lambda: |-
it.fill(Color(0, 0, 0)); it.fill(Color(0, 0, 0));
it.image(0, 0, id(online_rgba_image)); it.image(0, 0, id(online_rgba_image));

View file

@ -13,6 +13,7 @@ display:
cs_pin: 15 cs_pin: 15
dc_pin: 3 dc_pin: 3
reset_pin: 1 reset_pin: 1
invert_colors: true
lambda: |- lambda: |-
it.fill(Color(0, 0, 0)); it.fill(Color(0, 0, 0));
it.image(0, 0, id(online_rgba_image)); it.image(0, 0, id(online_rgba_image));

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -11,6 +11,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -11,6 +11,7 @@ display:
cs_pin: 12 cs_pin: 12
dc_pin: 13 dc_pin: 13
reset_pin: 21 reset_pin: 21
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -11,6 +11,7 @@ display:
cs_pin: 5 cs_pin: 5
dc_pin: 15 dc_pin: 15
reset_pin: 16 reset_pin: 16
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -11,6 +11,7 @@ display:
cs_pin: 20 cs_pin: 20
dc_pin: 21 dc_pin: 21
reset_pin: 22 reset_pin: 22
invert_colors: false
lambda: |- lambda: |-
// Draw a QR code in the center of the screen // Draw a QR code in the center of the screen
auto scale = 2; auto scale = 2;

View file

@ -38,7 +38,12 @@ display:
hsync_pin: 16 hsync_pin: 16
vsync_pin: 17 vsync_pin: 17
pclk_pin: 21 pclk_pin: 21
init_sequence: 1 init_sequence:
- 1
- [0x23, 0xA, 0xB]
- delay 20ms
- [0x23, 0xA, 0xB]
- delay 0.2s
data_pins: data_pins:
- number: 0 - number: 0
ignore_strapping_warning: true ignore_strapping_warning: true

View file

@ -18,6 +18,7 @@ display:
data_rate: 40MHz data_rate: 40MHz
dimensions: 320x240 dimensions: 320x240
update_interval: never update_interval: never
invert_colors: false
transform: transform:
mirror_y: false mirror_y: false
mirror_x: false mirror_x: false

View file

@ -12,6 +12,7 @@ display:
cs_pin: 13 cs_pin: 13
dc_pin: 14 dc_pin: 14
reset_pin: 21 reset_pin: 21
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());

View file

@ -12,6 +12,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());

View file

@ -12,6 +12,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());

View file

@ -12,6 +12,7 @@ display:
cs_pin: 13 cs_pin: 13
dc_pin: 14 dc_pin: 14
reset_pin: 21 reset_pin: 21
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());

View file

@ -14,6 +14,7 @@ display:
data_rate: 40MHz data_rate: 40MHz
dimensions: 320x240 dimensions: 320x240
update_interval: never update_interval: never
invert_colors: false
transform: transform:
mirror_y: false mirror_y: false
mirror_x: false mirror_x: false

View file

@ -12,6 +12,7 @@ display:
cs_pin: 15 cs_pin: 15
dc_pin: 4 dc_pin: 4
reset_pin: 5 reset_pin: 5
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());

View file

@ -12,6 +12,7 @@ display:
cs_pin: 8 cs_pin: 8
dc_pin: 9 dc_pin: 9
reset_pin: 10 reset_pin: 10
invert_colors: false
lambda: |- lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height()); it.rectangle(0, 0, it.get_width(), it.get_height());