mirror of
https://github.com/esphome/esphome.git
synced 2025-11-01 15:41:52 +00:00
Compare commits
279 Commits
jesserockz
...
2022.5.0b4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5069edc78 | ||
|
|
282d9e138c | ||
|
|
72fcf2cbe1 | ||
|
|
6f49f5465b | ||
|
|
17b8bd8316 | ||
|
|
7e88938932 | ||
|
|
c707e64685 | ||
|
|
a639690716 | ||
|
|
01222dbab7 | ||
|
|
ff72d6a146 | ||
|
|
603d0d0c7c | ||
|
|
28883f711b | ||
|
|
e914828add | ||
|
|
c1480029fb | ||
|
|
40f622949e | ||
|
|
63096ac2bc | ||
|
|
c2a59cb476 | ||
|
|
d6e039a1d1 | ||
|
|
0f1a7c2b69 | ||
|
|
41d9059a2f | ||
|
|
e26e0d7c01 | ||
|
|
ad41c07a1f | ||
|
|
5732f3b044 | ||
|
|
712115b6ce | ||
|
|
9283559c6b | ||
|
|
6b393438e9 | ||
|
|
343b9ab455 | ||
|
|
dcb226b202 | ||
|
|
2243021b58 | ||
|
|
d5134e88b1 | ||
|
|
c59adf612f | ||
|
|
a82d8ea0c3 | ||
|
|
ad57faa9a9 | ||
|
|
a9b5e8d036 | ||
|
|
59e6e798dd | ||
|
|
e5c2dbc7ec | ||
|
|
756f71c382 | ||
|
|
b7535693fa | ||
|
|
06a3505698 | ||
|
|
efa8f0730d | ||
|
|
023d26f521 | ||
|
|
5068619f1b | ||
|
|
b528f48417 | ||
|
|
ec7a79049a | ||
|
|
6ddad6b299 | ||
|
|
16dc7762f9 | ||
|
|
dc0ed8857f | ||
|
|
bb6b77bd98 | ||
|
|
dcc80f9032 | ||
|
|
dd554bcdf4 | ||
|
|
f376a39e55 | ||
|
|
8dcc9d6b66 | ||
|
|
a576c9f21f | ||
|
|
71a438e2cb | ||
|
|
272d6f2a8b | ||
|
|
5dc776e55f | ||
|
|
72d60f30f7 | ||
|
|
869743a742 | ||
|
|
7b03e07908 | ||
|
|
348f880e15 | ||
|
|
ead597d0fb | ||
|
|
afbf989715 | ||
|
|
01b62a16c3 | ||
|
|
c5eba04517 | ||
|
|
282313ab52 | ||
|
|
d274545e77 | ||
|
|
d3fda37615 | ||
|
|
cbe3092404 | ||
|
|
6dfe3039d0 | ||
|
|
d6009453df | ||
|
|
c81323ef91 | ||
|
|
961c27f1c2 | ||
|
|
fe4a14e6cc | ||
|
|
50848c2f4d | ||
|
|
d32633b3c7 | ||
|
|
b37739eec2 | ||
|
|
28f87dc804 | ||
|
|
41879e41e6 | ||
|
|
fc0a6546a2 | ||
|
|
ffd4280d6c | ||
|
|
db3b955b0f | ||
|
|
5516f65971 | ||
|
|
9471df0a1b | ||
|
|
6d39f64be7 | ||
|
|
b89d0a9a73 | ||
|
|
4bb779d9a5 | ||
|
|
386a5b6362 | ||
|
|
e32a999cd0 | ||
|
|
bfbc6a4bad | ||
|
|
8c9e0e552d | ||
|
|
8aaf9fd83f | ||
|
|
08057720b8 | ||
|
|
bfaa648837 | ||
|
|
d504daef91 | ||
|
|
b8d3ef2f49 | ||
|
|
3bf6320030 | ||
|
|
708b928c73 | ||
|
|
649366ff44 | ||
|
|
e5c9e87fad | ||
|
|
f3d9d707b6 | ||
|
|
090e10730c | ||
|
|
fbc84861c7 | ||
|
|
e763469af8 | ||
|
|
3c0c514e44 | ||
|
|
ed5e2dd332 | ||
|
|
09b7c6f550 | ||
|
|
df315a1f51 | ||
|
|
7ee4bb621c | ||
|
|
24874f4c3c | ||
|
|
c128880033 | ||
|
|
a66e94a0b0 | ||
|
|
56870ed4a8 | ||
|
|
3ac720df47 | ||
|
|
1bc757ad06 | ||
|
|
f72abc6f3d | ||
|
|
5ac88de985 | ||
|
|
0826b367d6 | ||
|
|
329bf861d6 | ||
|
|
9dcd3d18a0 | ||
|
|
db66cd88b6 | ||
|
|
86c205fe43 | ||
|
|
c6414138c7 | ||
|
|
36b355eb82 | ||
|
|
7be9291b13 | ||
|
|
ea9e75039b | ||
|
|
a5fb036011 | ||
|
|
e55506f9db | ||
|
|
50ec1d0445 | ||
|
|
3d5e1d8d91 | ||
|
|
db2128a344 | ||
|
|
21db43db06 | ||
|
|
5009b3029f | ||
|
|
57a029189c | ||
|
|
0cb715bb76 | ||
|
|
7d03823afd | ||
|
|
8e1c9f5042 | ||
|
|
980b7cda8f | ||
|
|
3a72dd5cb6 | ||
|
|
3178243811 | ||
|
|
d30e2f2a4f | ||
|
|
6226dae05c | ||
|
|
9c6a475a6e | ||
|
|
8294d10d5b | ||
|
|
67558bec47 | ||
|
|
84873d4074 | ||
|
|
58a0b28a39 | ||
|
|
b37d3a66cc | ||
|
|
7e495a5e27 | ||
|
|
c41547fd4a | ||
|
|
0d47d41c85 | ||
|
|
41a3a17456 | ||
|
|
cbbafbcca2 | ||
|
|
c75566b374 | ||
|
|
7279f1fcc1 | ||
|
|
d7432f7c10 | ||
|
|
b0a0a153f3 | ||
|
|
024632dbd0 | ||
|
|
0a545a28b9 | ||
|
|
0f2df59998 | ||
|
|
29a7d32f77 | ||
|
|
687a7e9b2f | ||
|
|
09e8782318 | ||
|
|
f2aea02210 | ||
|
|
194f922312 | ||
|
|
fea3c48098 | ||
|
|
c2f57baec2 | ||
|
|
f4a140e126 | ||
|
|
ab506b09fe | ||
|
|
87e1cdeedb | ||
|
|
81a36146ef | ||
|
|
7fa4a68a27 | ||
|
|
f1c5e2ef81 | ||
|
|
b526155cce | ||
|
|
62c3f301e7 | ||
|
|
38cb988809 | ||
|
|
b976ac54c8 | ||
|
|
78026e766f | ||
|
|
b4cd8d21a5 | ||
|
|
7552893311 | ||
|
|
21c896d8f8 | ||
|
|
4b7fe202ec | ||
|
|
9f4519210f | ||
|
|
b0506afa5b | ||
|
|
8cbb379898 | ||
|
|
b226215593 | ||
|
|
19970729a9 | ||
|
|
d2ebfd2833 | ||
|
|
bd782fc828 | ||
|
|
23560e608c | ||
|
|
f1377b560e | ||
|
|
72108684ea | ||
|
|
c6adaaea97 | ||
|
|
91999a38ca | ||
|
|
b34eed125d | ||
|
|
2abe09529a | ||
|
|
9aaaf4dd4b | ||
|
|
cbfbcf7f1b | ||
|
|
c7651dc40d | ||
|
|
eda1c471ad | ||
|
|
c7ef18fbc4 | ||
|
|
901ec918b1 | ||
|
|
6bdae55ee1 | ||
|
|
dfb96e4b7f | ||
|
|
ff2c316b18 | ||
|
|
5be52f71f9 | ||
|
|
42873dd37c | ||
|
|
f93e7d4e3a | ||
|
|
bbcd523967 | ||
|
|
68cbe58d00 | ||
|
|
115bca98f1 | ||
|
|
ed0b34b2fe | ||
|
|
ab34401421 | ||
|
|
eed0c18d65 | ||
|
|
e5a38ce748 | ||
|
|
7d9d9fcf36 | ||
|
|
f0aba6ceb2 | ||
|
|
ab07ee57c6 | ||
|
|
eae3d72a4d | ||
|
|
7b8d826704 | ||
|
|
e7baa42e63 | ||
|
|
2f32833a22 | ||
|
|
f6935a4b4b | ||
|
|
332c9e891b | ||
|
|
b91ee4847f | ||
|
|
625463d871 | ||
|
|
6433a01e07 | ||
|
|
56cc31e8e7 | ||
|
|
3af297aa76 | ||
|
|
996ec59d28 | ||
|
|
95593eeeab | ||
|
|
dad244fb7a | ||
|
|
adb5d27d95 | ||
|
|
8456a8cecb | ||
|
|
b9f66373c1 | ||
|
|
9ac365feef | ||
|
|
43bbd58a44 | ||
|
|
7feffa64f3 | ||
|
|
ea0977abb4 | ||
|
|
4c83dc7c28 | ||
|
|
e10ab1da78 | ||
|
|
1b0e60374b | ||
|
|
3a760fbb44 | ||
|
|
6ef57a2973 | ||
|
|
3e9c7f2e9f | ||
|
|
430598b7a1 | ||
|
|
91611b09b4 | ||
|
|
ecd115851f | ||
|
|
4a1e50fed1 | ||
|
|
d6d037047b | ||
|
|
b5734c2b20 | ||
|
|
723fb7eaac | ||
|
|
63a9acaa19 | ||
|
|
0524f8c677 | ||
|
|
70b62f272e | ||
|
|
f0089b7940 | ||
|
|
4b44280d53 | ||
|
|
f045382d20 | ||
|
|
db3fa1ade7 | ||
|
|
f83950fd75 | ||
|
|
4dd1bf920d | ||
|
|
98755f3621 | ||
|
|
c3a8a044b9 | ||
|
|
15b5ea43a7 | ||
|
|
ec683fc227 | ||
|
|
d4e65eb82a | ||
|
|
10c6601b0a | ||
|
|
73940bc1bd | ||
|
|
9b7fb829f9 | ||
|
|
c51d8c9021 | ||
|
|
d8a6dfe5ce | ||
|
|
5f7cef0b06 | ||
|
|
48ff2ffc68 | ||
|
|
b3b9ccd314 | ||
|
|
e63c7b483b | ||
|
|
f57980b069 | ||
|
|
7006aa0d2a | ||
|
|
8051c1ca99 | ||
|
|
a779592414 | ||
|
|
112215848d |
@@ -76,6 +76,8 @@ async def to_code(config):
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
if CONF_RESIZE in config:
|
||||
image.thumbnail(config[CONF_RESIZE])
|
||||
frame = image.convert("RGB")
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
|
||||
@@ -117,7 +117,7 @@ void Bedjet::control(const ClimateCall &call) {
|
||||
pkt = this->codec_->get_button_request(BTN_OFF);
|
||||
break;
|
||||
case climate::CLIMATE_MODE_HEAT:
|
||||
pkt = this->codec_->get_button_request(BTN_EXTHT);
|
||||
pkt = this->codec_->get_button_request(BTN_HEAT);
|
||||
break;
|
||||
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||
pkt = this->codec_->get_button_request(BTN_COOL);
|
||||
@@ -137,7 +137,7 @@ void Bedjet::control(const ClimateCall &call) {
|
||||
} else {
|
||||
this->force_refresh_ = true;
|
||||
this->mode = mode;
|
||||
// We're using (custom) preset for Turbo & M1-3 presets, so changing climate mode will clear those
|
||||
// We're using (custom) preset for Turbo, EXT HT, & M1-3 presets, so changing climate mode will clear those
|
||||
this->custom_preset.reset();
|
||||
this->preset.reset();
|
||||
}
|
||||
@@ -186,6 +186,8 @@ void Bedjet::control(const ClimateCall &call) {
|
||||
pkt = this->codec_->get_button_request(BTN_M2);
|
||||
} else if (preset == "M3") {
|
||||
pkt = this->codec_->get_button_request(BTN_M3);
|
||||
} else if (preset == "EXT HT") {
|
||||
pkt = this->codec_->get_button_request(BTN_EXTHT);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Unsupported preset: %s", preset.c_str());
|
||||
return;
|
||||
|
||||
@@ -67,6 +67,8 @@ class Bedjet : public climate::Climate, public esphome::ble_client::BLEClientNod
|
||||
// We could fetch biodata from bedjet and set these names that way.
|
||||
// But then we have to invert the lookup in order to send the right preset.
|
||||
// For now, we can leave them as M1-3 to match the remote buttons.
|
||||
// EXT HT added to match remote button.
|
||||
"EXT HT",
|
||||
"M1",
|
||||
"M2",
|
||||
"M3",
|
||||
|
||||
@@ -39,17 +39,7 @@ class CaptivePortal : public AsyncWebHandler, public Component {
|
||||
if (request->method() == HTTP_GET) {
|
||||
if (request->url() == "/")
|
||||
return true;
|
||||
if (request->url() == "/stylesheet.css")
|
||||
return true;
|
||||
if (request->url() == "/wifi-strength-1.svg")
|
||||
return true;
|
||||
if (request->url() == "/wifi-strength-2.svg")
|
||||
return true;
|
||||
if (request->url() == "/wifi-strength-3.svg")
|
||||
return true;
|
||||
if (request->url() == "/wifi-strength-4.svg")
|
||||
return true;
|
||||
if (request->url() == "/lock.svg")
|
||||
if (request->url() == "/config.json")
|
||||
return true;
|
||||
if (request->url() == "/wifisave")
|
||||
return true;
|
||||
|
||||
@@ -287,9 +287,11 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
cv.Exclusive(CONF_FAN_MODE, "fan_mode"): cv.templatable(
|
||||
validate_climate_fan_mode
|
||||
),
|
||||
cv.Exclusive(CONF_CUSTOM_FAN_MODE, "fan_mode"): cv.string_strict,
|
||||
cv.Exclusive(CONF_CUSTOM_FAN_MODE, "fan_mode"): cv.templatable(
|
||||
cv.string_strict
|
||||
),
|
||||
cv.Exclusive(CONF_PRESET, "preset"): cv.templatable(validate_climate_preset),
|
||||
cv.Exclusive(CONF_CUSTOM_PRESET, "preset"): cv.string_strict,
|
||||
cv.Exclusive(CONF_CUSTOM_PRESET, "preset"): cv.templatable(cv.string_strict),
|
||||
cv.Optional(CONF_SWING_MODE): cv.templatable(validate_climate_swing_mode),
|
||||
}
|
||||
)
|
||||
@@ -324,13 +326,17 @@ async def climate_control_to_code(config, action_id, template_arg, args):
|
||||
template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode)
|
||||
cg.add(var.set_fan_mode(template_))
|
||||
if CONF_CUSTOM_FAN_MODE in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_FAN_MODE], args, str)
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_CUSTOM_FAN_MODE], args, cg.std_string
|
||||
)
|
||||
cg.add(var.set_custom_fan_mode(template_))
|
||||
if CONF_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_PRESET], args, ClimatePreset)
|
||||
cg.add(var.set_preset(template_))
|
||||
if CONF_CUSTOM_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_PRESET], args, str)
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_CUSTOM_PRESET], args, cg.std_string
|
||||
)
|
||||
cg.add(var.set_custom_preset(template_))
|
||||
if CONF_SWING_MODE in config:
|
||||
template_ = await cg.templatable(
|
||||
|
||||
@@ -118,12 +118,17 @@ class ESP32Preferences : public ESPPreferences {
|
||||
// go through vector from back to front (makes erase easier/more efficient)
|
||||
for (ssize_t i = s_pending_save.size() - 1; i >= 0; i--) {
|
||||
const auto &save = s_pending_save[i];
|
||||
esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.data(), save.data.size());
|
||||
if (err != 0) {
|
||||
ESP_LOGV(TAG, "nvs_set_blob('%s', len=%u) failed: %s", save.key.c_str(), save.data.size(),
|
||||
esp_err_to_name(err));
|
||||
any_failed = true;
|
||||
continue;
|
||||
ESP_LOGVV(TAG, "Checking if NVS data %s has changed", save.key.c_str());
|
||||
if (is_changed(nvs_handle, save)) {
|
||||
esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.data(), save.data.size());
|
||||
if (err != 0) {
|
||||
ESP_LOGV(TAG, "nvs_set_blob('%s', len=%u) failed: %s", save.key.c_str(), save.data.size(),
|
||||
esp_err_to_name(err));
|
||||
any_failed = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "NVS data not changed skipping %s len=%u", save.key.c_str(), save.data.size());
|
||||
}
|
||||
s_pending_save.erase(s_pending_save.begin() + i);
|
||||
}
|
||||
@@ -137,6 +142,22 @@ class ESP32Preferences : public ESPPreferences {
|
||||
|
||||
return !any_failed;
|
||||
}
|
||||
bool is_changed(const uint32_t nvs_handle, const NVSData &to_save) {
|
||||
NVSData stored_data{};
|
||||
size_t actual_len;
|
||||
esp_err_t err = nvs_get_blob(nvs_handle, to_save.key.c_str(), nullptr, &actual_len);
|
||||
if (err != 0) {
|
||||
ESP_LOGV(TAG, "nvs_get_blob('%s'): %s - the key might not be set yet", to_save.key.c_str(), esp_err_to_name(err));
|
||||
return true;
|
||||
}
|
||||
stored_data.data.reserve(actual_len);
|
||||
err = nvs_get_blob(nvs_handle, to_save.key.c_str(), stored_data.data.data(), &actual_len);
|
||||
if (err != 0) {
|
||||
ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", to_save.key.c_str(), esp_err_to_name(err));
|
||||
return true;
|
||||
}
|
||||
return to_save.data == stored_data.data;
|
||||
}
|
||||
};
|
||||
|
||||
void setup_preferences() {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from esphome.const import CONF_BAUD_RATE, CONF_ID, CONF_LOGGER
|
||||
from esphome.components.logger import USB_CDC, USB_SERIAL_JTAG
|
||||
from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import CORE
|
||||
import esphome.final_validate as fv
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
@@ -17,14 +19,19 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def validate_logger_baud_rate(config):
|
||||
def validate_logger(config):
|
||||
logger_conf = fv.full_config.get()[CONF_LOGGER]
|
||||
if logger_conf[CONF_BAUD_RATE] == 0:
|
||||
raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0")
|
||||
if CORE.using_esp_idf:
|
||||
if logger_conf[CONF_HARDWARE_UART] in [USB_SERIAL_JTAG, USB_CDC]:
|
||||
raise cv.Invalid(
|
||||
"improv_serial does not support the selected logger hardware_uart"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = validate_logger_baud_rate
|
||||
FINAL_VALIDATE_SCHEMA = validate_logger
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
|
||||
@@ -26,21 +26,33 @@ std::string build_json(const json_build_t &f) {
|
||||
const size_t free_heap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
|
||||
#endif
|
||||
|
||||
const size_t request_size = std::min(free_heap, (size_t) 512);
|
||||
|
||||
DynamicJsonDocument json_document(request_size);
|
||||
if (json_document.capacity() == 0) {
|
||||
ESP_LOGE(TAG, "Could not allocate memory for JSON document! Requested %u bytes, largest free heap block: %u bytes",
|
||||
request_size, free_heap);
|
||||
return "{}";
|
||||
size_t request_size = std::min(free_heap, (size_t) 512);
|
||||
while (true) {
|
||||
ESP_LOGV(TAG, "Attempting to allocate %u bytes for JSON serialization", request_size);
|
||||
DynamicJsonDocument json_document(request_size);
|
||||
if (json_document.capacity() == 0) {
|
||||
ESP_LOGE(TAG,
|
||||
"Could not allocate memory for JSON document! Requested %u bytes, largest free heap block: %u bytes",
|
||||
request_size, free_heap);
|
||||
return "{}";
|
||||
}
|
||||
JsonObject root = json_document.to<JsonObject>();
|
||||
f(root);
|
||||
if (json_document.overflowed()) {
|
||||
if (request_size == free_heap) {
|
||||
ESP_LOGE(TAG, "Could not allocate memory for JSON document! Overflowed largest free heap block: %u bytes",
|
||||
free_heap);
|
||||
return "{}";
|
||||
}
|
||||
request_size = std::min(request_size * 2, free_heap);
|
||||
continue;
|
||||
}
|
||||
json_document.shrinkToFit();
|
||||
ESP_LOGV(TAG, "Size after shrink %u bytes", json_document.capacity());
|
||||
std::string output;
|
||||
serializeJson(json_document, output);
|
||||
return output;
|
||||
}
|
||||
JsonObject root = json_document.to<JsonObject>();
|
||||
f(root);
|
||||
json_document.shrinkToFit();
|
||||
ESP_LOGV(TAG, "Size after shrink %u bytes", json_document.capacity());
|
||||
std::string output;
|
||||
serializeJson(json_document, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
void parse_json(const std::string &data, const json_parse_t &f) {
|
||||
|
||||
@@ -158,11 +158,8 @@ bool ShellyDimmer::upgrade_firmware_() {
|
||||
ESP_LOGW(TAG, "Starting STM32 firmware upgrade");
|
||||
this->reset_dfu_boot_();
|
||||
|
||||
// Could be constexpr in c++17
|
||||
static const auto CLOSE = [](stm32_t *stm32) { stm32_close(stm32); };
|
||||
|
||||
// Cleanup with RAII
|
||||
std::unique_ptr<stm32_t, decltype(CLOSE)> stm32{stm32_init(this, STREAM_SERIAL, 1), CLOSE};
|
||||
auto stm32 = stm32_init(this, STREAM_SERIAL, 1);
|
||||
|
||||
if (!stm32) {
|
||||
ESP_LOGW(TAG, "Failed to initialize STM32");
|
||||
@@ -170,7 +167,7 @@ bool ShellyDimmer::upgrade_firmware_() {
|
||||
}
|
||||
|
||||
// Erase STM32 flash.
|
||||
if (stm32_erase_memory(stm32.get(), 0, STM32_MASS_ERASE) != STM32_ERR_OK) {
|
||||
if (stm32_erase_memory(stm32, 0, STM32_MASS_ERASE) != STM32_ERR_OK) {
|
||||
ESP_LOGW(TAG, "Failed to erase STM32 flash memory");
|
||||
return false;
|
||||
}
|
||||
@@ -196,7 +193,7 @@ bool ShellyDimmer::upgrade_firmware_() {
|
||||
std::memcpy(buffer, p, BUFFER_SIZE);
|
||||
p += BUFFER_SIZE;
|
||||
|
||||
if (stm32_write_memory(stm32.get(), addr, buffer, len) != STM32_ERR_OK) {
|
||||
if (stm32_write_memory(stm32, addr, buffer, len) != STM32_ERR_OK) {
|
||||
ESP_LOGW(TAG, "Failed to write to STM32 flash memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace shelly_dimmer {
|
||||
|
||||
namespace {
|
||||
|
||||
int flash_addr_to_page_ceil(const stm32_t *stm, uint32_t addr) {
|
||||
int flash_addr_to_page_ceil(const stm32_unique_ptr &stm, uint32_t addr) {
|
||||
if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
|
||||
return 0;
|
||||
|
||||
@@ -135,7 +135,7 @@ int flash_addr_to_page_ceil(const stm32_t *stm, uint32_t addr) {
|
||||
return addr ? page + 1 : page;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, uint32_t timeout) {
|
||||
stm32_err_t stm32_get_ack_timeout(const stm32_unique_ptr &stm, uint32_t timeout) {
|
||||
auto *stream = stm->stream;
|
||||
uint8_t rxbyte;
|
||||
|
||||
@@ -168,9 +168,9 @@ stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, uint32_t timeout) {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
stm32_err_t stm32_get_ack(const stm32_t *stm) { return stm32_get_ack_timeout(stm, 0); }
|
||||
stm32_err_t stm32_get_ack(const stm32_unique_ptr &stm) { return stm32_get_ack_timeout(stm, 0); }
|
||||
|
||||
stm32_err_t stm32_send_command_timeout(const stm32_t *stm, const uint8_t cmd, const uint32_t timeout) {
|
||||
stm32_err_t stm32_send_command_timeout(const stm32_unique_ptr &stm, const uint8_t cmd, const uint32_t timeout) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
static constexpr auto BUFFER_SIZE = 2;
|
||||
@@ -194,12 +194,12 @@ stm32_err_t stm32_send_command_timeout(const stm32_t *stm, const uint8_t cmd, co
|
||||
return STM32_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd) {
|
||||
stm32_err_t stm32_send_command(const stm32_unique_ptr &stm, const uint8_t cmd) {
|
||||
return stm32_send_command_timeout(stm, cmd, 0);
|
||||
}
|
||||
|
||||
/* if we have lost sync, send a wrong command and expect a NACK */
|
||||
stm32_err_t stm32_resync(const stm32_t *stm) {
|
||||
stm32_err_t stm32_resync(const stm32_unique_ptr &stm) {
|
||||
auto *const stream = stm->stream;
|
||||
uint32_t t0 = millis();
|
||||
auto t1 = t0;
|
||||
@@ -238,7 +238,7 @@ stm32_err_t stm32_resync(const stm32_t *stm) {
|
||||
*
|
||||
* len is value of the first byte in the frame.
|
||||
*/
|
||||
stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, const uint8_t cmd, uint8_t *const data, unsigned int len) {
|
||||
stm32_err_t stm32_guess_len_cmd(const stm32_unique_ptr &stm, const uint8_t cmd, uint8_t *const data, unsigned int len) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
|
||||
@@ -286,7 +286,7 @@ stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, const uint8_t cmd, uint8_t *
|
||||
* This function sends the init sequence and, in case of timeout, recovers
|
||||
* the interface.
|
||||
*/
|
||||
stm32_err_t stm32_send_init_seq(const stm32_t *stm) {
|
||||
stm32_err_t stm32_send_init_seq(const stm32_unique_ptr &stm) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
stream->write_array(&STM32_CMD_INIT, 1);
|
||||
@@ -320,7 +320,7 @@ stm32_err_t stm32_send_init_seq(const stm32_t *stm) {
|
||||
return STM32_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_mass_erase(const stm32_t *stm) {
|
||||
stm32_err_t stm32_mass_erase(const stm32_unique_ptr &stm) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
|
||||
@@ -364,7 +364,7 @@ template<typename T> std::unique_ptr<T[], void (*)(T *memory)> malloc_array_raii
|
||||
DELETOR};
|
||||
}
|
||||
|
||||
stm32_err_t stm32_pages_erase(const stm32_t *stm, const uint32_t spage, const uint32_t pages) {
|
||||
stm32_err_t stm32_pages_erase(const stm32_unique_ptr &stm, const uint32_t spage, const uint32_t pages) {
|
||||
auto *const stream = stm->stream;
|
||||
uint8_t cs = 0;
|
||||
int i = 0;
|
||||
@@ -474,6 +474,18 @@ template<size_t N> void populate_buffer_with_address(uint8_t (&buffer)[N], uint3
|
||||
buffer[4] = static_cast<uint8_t>(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]);
|
||||
}
|
||||
|
||||
template<typename T> stm32_unique_ptr make_stm32_with_deletor(T ptr) {
|
||||
static const auto CLOSE = [](stm32_t *stm32) {
|
||||
if (stm32) {
|
||||
free(stm32->cmd); // NOLINT
|
||||
}
|
||||
free(stm32); // NOLINT
|
||||
};
|
||||
|
||||
// Cleanup with RAII
|
||||
return std::unique_ptr<stm32_t, decltype(CLOSE)>{ptr, CLOSE};
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
} // namespace shelly_dimmer
|
||||
@@ -485,48 +497,44 @@ namespace shelly_dimmer {
|
||||
/* find newer command by higher code */
|
||||
#define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a)))
|
||||
|
||||
stm32_t *stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init) {
|
||||
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init) {
|
||||
uint8_t buf[257];
|
||||
|
||||
// Could be constexpr in c++17
|
||||
static const auto CLOSE = [](stm32_t *stm32) { stm32_close(stm32); };
|
||||
|
||||
// Cleanup with RAII
|
||||
std::unique_ptr<stm32_t, decltype(CLOSE)> stm{static_cast<stm32_t *>(calloc(sizeof(stm32_t), 1)), // NOLINT
|
||||
CLOSE};
|
||||
auto stm = make_stm32_with_deletor(static_cast<stm32_t *>(calloc(sizeof(stm32_t), 1))); // NOLINT
|
||||
|
||||
if (!stm) {
|
||||
return nullptr;
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
stm->stream = stream;
|
||||
stm->flags = flags;
|
||||
|
||||
stm->cmd = static_cast<stm32_cmd_t *>(malloc(sizeof(stm32_cmd_t))); // NOLINT
|
||||
if (!stm->cmd) {
|
||||
return nullptr;
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t));
|
||||
|
||||
if ((stm->flags & STREAM_OPT_CMD_INIT) && init) {
|
||||
if (stm32_send_init_seq(stm.get()) != STM32_ERR_OK)
|
||||
return nullptr; // NOLINT
|
||||
if (stm32_send_init_seq(stm) != STM32_ERR_OK)
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
/* get the version and read protection status */
|
||||
if (stm32_send_command(stm.get(), STM32_CMD_GVR) != STM32_ERR_OK) {
|
||||
return nullptr; // NOLINT
|
||||
if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
/* From AN, only UART bootloader returns 3 bytes */
|
||||
{
|
||||
const auto len = (stm->flags & STREAM_OPT_GVR_ETX) ? 3 : 1;
|
||||
if (!stream->read_array(buf, len))
|
||||
return nullptr; // NOLINT
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
|
||||
stm->version = buf[0];
|
||||
stm->option1 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[1] : 0;
|
||||
stm->option2 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[2] : 0;
|
||||
if (stm32_get_ack(stm.get()) != STM32_ERR_OK) {
|
||||
return nullptr;
|
||||
if (stm32_get_ack(stm) != STM32_ERR_OK) {
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,8 +552,8 @@ stm32_t *stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char in
|
||||
return STM32_CMD_GET_LENGTH;
|
||||
})();
|
||||
|
||||
if (stm32_guess_len_cmd(stm.get(), STM32_CMD_GET, buf, len) != STM32_ERR_OK)
|
||||
return nullptr;
|
||||
if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK)
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
const auto stop = buf[0] + 1;
|
||||
@@ -607,23 +615,23 @@ stm32_t *stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char in
|
||||
}
|
||||
if (new_cmds)
|
||||
ESP_LOGD(TAG, ")");
|
||||
if (stm32_get_ack(stm.get()) != STM32_ERR_OK) {
|
||||
return nullptr;
|
||||
if (stm32_get_ack(stm) != STM32_ERR_OK) {
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
if (stm->cmd->get == STM32_CMD_ERR || stm->cmd->gvr == STM32_CMD_ERR || stm->cmd->gid == STM32_CMD_ERR) {
|
||||
ESP_LOGD(TAG, "Error: bootloader did not returned correct information from GET command");
|
||||
return nullptr;
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
/* get the device ID */
|
||||
if (stm32_guess_len_cmd(stm.get(), stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
|
||||
return nullptr;
|
||||
if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
const auto returned = buf[0] + 1;
|
||||
if (returned < 2) {
|
||||
ESP_LOGD(TAG, "Only %d bytes sent in the PID, unknown/unsupported device", returned);
|
||||
return nullptr;
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
stm->pid = (buf[1] << 8) | buf[2];
|
||||
if (returned > 2) {
|
||||
@@ -631,8 +639,8 @@ stm32_t *stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char in
|
||||
for (auto i = 2; i <= returned; i++)
|
||||
ESP_LOGD(TAG, " %02x", buf[i]);
|
||||
}
|
||||
if (stm32_get_ack(stm.get()) != STM32_ERR_OK) {
|
||||
return nullptr;
|
||||
if (stm32_get_ack(stm) != STM32_ERR_OK) {
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
stm->dev = DEVICES;
|
||||
@@ -641,21 +649,14 @@ stm32_t *stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char in
|
||||
|
||||
if (!stm->dev->id) {
|
||||
ESP_LOGD(TAG, "Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
|
||||
return nullptr;
|
||||
return make_stm32_with_deletor(nullptr);
|
||||
}
|
||||
|
||||
// TODO: Would be much better if the unique_ptr was returned from this function
|
||||
// Release ownership of unique_ptr
|
||||
return stm.release(); // NOLINT
|
||||
return stm;
|
||||
}
|
||||
|
||||
void stm32_close(stm32_t *stm) {
|
||||
if (stm)
|
||||
free(stm->cmd); // NOLINT
|
||||
free(stm); // NOLINT
|
||||
}
|
||||
|
||||
stm32_err_t stm32_read_memory(const stm32_t *stm, const uint32_t address, uint8_t *data, const unsigned int len) {
|
||||
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data,
|
||||
const unsigned int len) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
if (!len)
|
||||
@@ -693,7 +694,8 @@ stm32_err_t stm32_read_memory(const stm32_t *stm, const uint32_t address, uint8_
|
||||
return STM32_ERR_OK;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, const uint8_t *data, const unsigned int len) {
|
||||
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data,
|
||||
const unsigned int len) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
if (!len)
|
||||
@@ -753,7 +755,7 @@ stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, const uint8
|
||||
return STM32_ERR_OK;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_wunprot_memory(const stm32_t *stm) {
|
||||
stm32_err_t stm32_wunprot_memory(const stm32_unique_ptr &stm) {
|
||||
if (stm->cmd->uw == STM32_CMD_ERR) {
|
||||
ESP_LOGD(TAG, "Error: WRITE UNPROTECT command not implemented in bootloader.");
|
||||
return STM32_ERR_NO_CMD;
|
||||
@@ -766,7 +768,7 @@ stm32_err_t stm32_wunprot_memory(const stm32_t *stm) {
|
||||
[]() { ESP_LOGD(TAG, "Error: Failed to WRITE UNPROTECT"); });
|
||||
}
|
||||
|
||||
stm32_err_t stm32_wprot_memory(const stm32_t *stm) {
|
||||
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm) {
|
||||
if (stm->cmd->wp == STM32_CMD_ERR) {
|
||||
ESP_LOGD(TAG, "Error: WRITE PROTECT command not implemented in bootloader.");
|
||||
return STM32_ERR_NO_CMD;
|
||||
@@ -779,7 +781,7 @@ stm32_err_t stm32_wprot_memory(const stm32_t *stm) {
|
||||
[]() { ESP_LOGD(TAG, "Error: Failed to WRITE PROTECT"); });
|
||||
}
|
||||
|
||||
stm32_err_t stm32_runprot_memory(const stm32_t *stm) {
|
||||
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm) {
|
||||
if (stm->cmd->ur == STM32_CMD_ERR) {
|
||||
ESP_LOGD(TAG, "Error: READOUT UNPROTECT command not implemented in bootloader.");
|
||||
return STM32_ERR_NO_CMD;
|
||||
@@ -792,7 +794,7 @@ stm32_err_t stm32_runprot_memory(const stm32_t *stm) {
|
||||
[]() { ESP_LOGD(TAG, "Error: Failed to READOUT UNPROTECT"); });
|
||||
}
|
||||
|
||||
stm32_err_t stm32_readprot_memory(const stm32_t *stm) {
|
||||
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm) {
|
||||
if (stm->cmd->rp == STM32_CMD_ERR) {
|
||||
ESP_LOGD(TAG, "Error: READOUT PROTECT command not implemented in bootloader.");
|
||||
return STM32_ERR_NO_CMD;
|
||||
@@ -805,7 +807,7 @@ stm32_err_t stm32_readprot_memory(const stm32_t *stm) {
|
||||
[]() { ESP_LOGD(TAG, "Error: Failed to READOUT PROTECT"); });
|
||||
}
|
||||
|
||||
stm32_err_t stm32_erase_memory(const stm32_t *stm, uint32_t spage, uint32_t pages) {
|
||||
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages) {
|
||||
if (!pages || spage > STM32_MAX_PAGES || ((pages != STM32_MASS_ERASE) && ((spage + pages) > STM32_MAX_PAGES)))
|
||||
return STM32_ERR_OK;
|
||||
|
||||
@@ -847,7 +849,7 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint32_t spage, uint32_t page
|
||||
return STM32_ERR_OK;
|
||||
}
|
||||
|
||||
static stm32_err_t stm32_run_raw_code(const stm32_t *stm, uint32_t target_address, const uint8_t *code,
|
||||
static stm32_err_t stm32_run_raw_code(const stm32_unique_ptr &stm, uint32_t target_address, const uint8_t *code,
|
||||
uint32_t code_size) {
|
||||
static constexpr uint32_t BUFFER_SIZE = 256;
|
||||
|
||||
@@ -893,7 +895,7 @@ static stm32_err_t stm32_run_raw_code(const stm32_t *stm, uint32_t target_addres
|
||||
return stm32_go(stm, target_address);
|
||||
}
|
||||
|
||||
stm32_err_t stm32_go(const stm32_t *stm, const uint32_t address) {
|
||||
stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address) {
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
if (stm->cmd->go == STM32_CMD_ERR) {
|
||||
@@ -916,7 +918,7 @@ stm32_err_t stm32_go(const stm32_t *stm, const uint32_t address) {
|
||||
return STM32_ERR_OK;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_reset_device(const stm32_t *stm) {
|
||||
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm) {
|
||||
const auto target_address = stm->dev->ram_start;
|
||||
|
||||
if (stm->dev->flags & F_OBLL) {
|
||||
@@ -927,7 +929,8 @@ stm32_err_t stm32_reset_device(const stm32_t *stm) {
|
||||
}
|
||||
}
|
||||
|
||||
stm32_err_t stm32_crc_memory(const stm32_t *stm, const uint32_t address, const uint32_t length, uint32_t *const crc) {
|
||||
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length,
|
||||
uint32_t *const crc) {
|
||||
static constexpr auto BUFFER_SIZE = 5;
|
||||
auto *const stream = stm->stream;
|
||||
|
||||
@@ -1022,7 +1025,7 @@ uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, uint32_t length, uint32_t *crc) {
|
||||
stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc) {
|
||||
static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
|
||||
static constexpr uint32_t BUFFER_SIZE = 256;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifdef USE_SHD_FIRMWARE_DATA
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -108,19 +109,20 @@ struct VarlenCmd {
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
stm32_t *stm32_init(uart::UARTDevice *stream, uint8_t flags, char init);
|
||||
void stm32_close(stm32_t *stm);
|
||||
stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, uint8_t *data, unsigned int len);
|
||||
stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, const uint8_t *data, unsigned int len);
|
||||
stm32_err_t stm32_wunprot_memory(const stm32_t *stm);
|
||||
stm32_err_t stm32_wprot_memory(const stm32_t *stm);
|
||||
stm32_err_t stm32_erase_memory(const stm32_t *stm, uint32_t spage, uint32_t pages);
|
||||
stm32_err_t stm32_go(const stm32_t *stm, uint32_t address);
|
||||
stm32_err_t stm32_reset_device(const stm32_t *stm);
|
||||
stm32_err_t stm32_readprot_memory(const stm32_t *stm);
|
||||
stm32_err_t stm32_runprot_memory(const stm32_t *stm);
|
||||
stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, uint32_t length, uint32_t *crc);
|
||||
stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, uint32_t length, uint32_t *crc);
|
||||
using stm32_unique_ptr = std::unique_ptr<stm32_t, void (*)(stm32_t *)>;
|
||||
|
||||
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, uint8_t flags, char init);
|
||||
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, uint32_t address, uint8_t *data, unsigned int len);
|
||||
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data, unsigned int len);
|
||||
stm32_err_t stm32_wunprot_memory(const stm32_unique_ptr &stm);
|
||||
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm);
|
||||
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages);
|
||||
stm32_err_t stm32_go(const stm32_unique_ptr &stm, uint32_t address);
|
||||
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm);
|
||||
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm);
|
||||
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm);
|
||||
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc);
|
||||
stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc);
|
||||
uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len);
|
||||
|
||||
} // namespace shelly_dimmer
|
||||
|
||||
@@ -13,11 +13,11 @@ static const char *const TAG = "time";
|
||||
|
||||
RealTimeClock::RealTimeClock() = default;
|
||||
void RealTimeClock::call_setup() {
|
||||
setenv("TZ", this->timezone_.c_str(), 1);
|
||||
tzset();
|
||||
this->apply_timezone_();
|
||||
PollingComponent::call_setup();
|
||||
}
|
||||
void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
||||
// Update UTC epoch time.
|
||||
struct timeval timev {
|
||||
.tv_sec = static_cast<time_t>(epoch), .tv_usec = 0,
|
||||
};
|
||||
@@ -30,6 +30,9 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
||||
ret = settimeofday(&timev, nullptr);
|
||||
}
|
||||
|
||||
// Move timezone back to local timezone.
|
||||
this->apply_timezone_();
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGW(TAG, "setimeofday() failed with code %d", ret);
|
||||
}
|
||||
@@ -41,6 +44,11 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
||||
this->time_sync_callback_.call();
|
||||
}
|
||||
|
||||
void RealTimeClock::apply_timezone_() {
|
||||
setenv("TZ", this->timezone_.c_str(), 1);
|
||||
tzset();
|
||||
}
|
||||
|
||||
size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) {
|
||||
struct tm c_tm = this->to_c_tm();
|
||||
return ::strftime(buffer, buffer_len, format, &c_tm);
|
||||
|
||||
@@ -137,6 +137,7 @@ class RealTimeClock : public PollingComponent {
|
||||
void synchronize_epoch_(uint32_t epoch);
|
||||
|
||||
std::string timezone_{};
|
||||
void apply_timezone_();
|
||||
|
||||
CallbackManager<void()> time_sync_callback_;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "tuya.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -10,6 +10,7 @@ namespace tuya {
|
||||
static const char *const TAG = "tuya";
|
||||
static const int COMMAND_DELAY = 10;
|
||||
static const int RECEIVE_TIMEOUT = 300;
|
||||
static const int MAX_RETRIES = 5;
|
||||
|
||||
void Tuya::setup() {
|
||||
this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
|
||||
@@ -27,8 +28,12 @@ void Tuya::loop() {
|
||||
void Tuya::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Tuya:");
|
||||
if (this->init_state_ != TuyaInitState::INIT_DONE) {
|
||||
ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u",
|
||||
static_cast<uint8_t>(this->init_state_));
|
||||
if (this->init_failed_) {
|
||||
ESP_LOGCONFIG(TAG, " Initialization failed. Current init_state: %u", static_cast<uint8_t>(this->init_state_));
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u",
|
||||
static_cast<uint8_t>(this->init_state_));
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " If no further output is received, confirm that this is a supported Tuya device.");
|
||||
return;
|
||||
}
|
||||
@@ -127,6 +132,8 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
|
||||
|
||||
if (this->expected_response_.has_value() && this->expected_response_ == command_type) {
|
||||
this->expected_response_.reset();
|
||||
this->command_queue_.erase(command_queue_.begin());
|
||||
this->init_retries_ = 0;
|
||||
}
|
||||
|
||||
switch (command_type) {
|
||||
@@ -378,13 +385,24 @@ void Tuya::process_command_queue_() {
|
||||
|
||||
if (this->expected_response_.has_value() && delay > RECEIVE_TIMEOUT) {
|
||||
this->expected_response_.reset();
|
||||
if (init_state_ != TuyaInitState::INIT_DONE) {
|
||||
if (++this->init_retries_ >= MAX_RETRIES) {
|
||||
this->init_failed_ = true;
|
||||
ESP_LOGE(TAG, "Initialization failed at init_state %u", static_cast<uint8_t>(this->init_state_));
|
||||
this->command_queue_.erase(command_queue_.begin());
|
||||
this->init_retries_ = 0;
|
||||
}
|
||||
} else {
|
||||
this->command_queue_.erase(command_queue_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
// Left check of delay since last command in case there's ever a command sent by calling send_raw_command_ directly
|
||||
if (delay > COMMAND_DELAY && !this->command_queue_.empty() && this->rx_message_.empty() &&
|
||||
!this->expected_response_.has_value()) {
|
||||
this->send_raw_command_(command_queue_.front());
|
||||
this->command_queue_.erase(command_queue_.begin());
|
||||
if (!this->expected_response_.has_value())
|
||||
this->command_queue_.erase(command_queue_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,8 @@ class Tuya : public Component, public uart::UARTDevice {
|
||||
optional<time::RealTimeClock *> time_id_{};
|
||||
#endif
|
||||
TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT;
|
||||
bool init_failed_{false};
|
||||
int init_retries_{0};
|
||||
uint8_t protocol_version_ = -1;
|
||||
int gpio_status_ = -1;
|
||||
int gpio_reset_ = -1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2022.5.0-dev"
|
||||
__version__ = "2022.5.0b4"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user