mirror of
https://github.com/esphome/esphome.git
synced 2024-12-26 23:41:45 +01:00
Merge branch 'esphome:dev' into nvds-new-espnow
This commit is contained in:
commit
dfdc9db2d5
40 changed files with 476 additions and 115 deletions
|
@ -1107,6 +1107,19 @@ enum MediaPlayerCommand {
|
||||||
MEDIA_PLAYER_COMMAND_MUTE = 3;
|
MEDIA_PLAYER_COMMAND_MUTE = 3;
|
||||||
MEDIA_PLAYER_COMMAND_UNMUTE = 4;
|
MEDIA_PLAYER_COMMAND_UNMUTE = 4;
|
||||||
}
|
}
|
||||||
|
enum MediaPlayerFormatPurpose {
|
||||||
|
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0;
|
||||||
|
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1;
|
||||||
|
}
|
||||||
|
message MediaPlayerSupportedFormat {
|
||||||
|
option (id) = 119;
|
||||||
|
option (ifdef) = "USE_MEDIA_PLAYER";
|
||||||
|
|
||||||
|
string format = 1;
|
||||||
|
uint32 sample_rate = 2;
|
||||||
|
uint32 num_channels = 3;
|
||||||
|
MediaPlayerFormatPurpose purpose = 4;
|
||||||
|
}
|
||||||
message ListEntitiesMediaPlayerResponse {
|
message ListEntitiesMediaPlayerResponse {
|
||||||
option (id) = 63;
|
option (id) = 63;
|
||||||
option (source) = SOURCE_SERVER;
|
option (source) = SOURCE_SERVER;
|
||||||
|
@ -1122,6 +1135,8 @@ message ListEntitiesMediaPlayerResponse {
|
||||||
EntityCategory entity_category = 7;
|
EntityCategory entity_category = 7;
|
||||||
|
|
||||||
bool supports_pause = 8;
|
bool supports_pause = 8;
|
||||||
|
|
||||||
|
repeated MediaPlayerSupportedFormat supported_formats = 9;
|
||||||
}
|
}
|
||||||
message MediaPlayerStateResponse {
|
message MediaPlayerStateResponse {
|
||||||
option (id) = 64;
|
option (id) = 64;
|
||||||
|
|
|
@ -179,6 +179,7 @@ void APIConnection::loop() {
|
||||||
SubscribeHomeAssistantStateResponse resp;
|
SubscribeHomeAssistantStateResponse resp;
|
||||||
resp.entity_id = it.entity_id;
|
resp.entity_id = it.entity_id;
|
||||||
resp.attribute = it.attribute.value();
|
resp.attribute = it.attribute.value();
|
||||||
|
resp.once = it.once;
|
||||||
if (this->send_subscribe_home_assistant_state_response(resp)) {
|
if (this->send_subscribe_home_assistant_state_response(resp)) {
|
||||||
state_subs_at_++;
|
state_subs_at_++;
|
||||||
}
|
}
|
||||||
|
@ -1025,6 +1026,15 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
|
||||||
auto traits = media_player->get_traits();
|
auto traits = media_player->get_traits();
|
||||||
msg.supports_pause = traits.get_supports_pause();
|
msg.supports_pause = traits.get_supports_pause();
|
||||||
|
|
||||||
|
for (auto &supported_format : traits.get_supported_formats()) {
|
||||||
|
MediaPlayerSupportedFormat media_format;
|
||||||
|
media_format.format = supported_format.format;
|
||||||
|
media_format.sample_rate = supported_format.sample_rate;
|
||||||
|
media_format.num_channels = supported_format.num_channels;
|
||||||
|
media_format.purpose = static_cast<enums::MediaPlayerFormatPurpose>(supported_format.purpose);
|
||||||
|
msg.supported_formats.push_back(media_format);
|
||||||
|
}
|
||||||
|
|
||||||
return this->send_list_entities_media_player_response(msg);
|
return this->send_list_entities_media_player_response(msg);
|
||||||
}
|
}
|
||||||
void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
|
void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
|
||||||
|
|
|
@ -387,6 +387,18 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
template<> const char *proto_enum_to_string<enums::MediaPlayerFormatPurpose>(enums::MediaPlayerFormatPurpose value) {
|
||||||
|
switch (value) {
|
||||||
|
case enums::MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT:
|
||||||
|
return "MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT";
|
||||||
|
case enums::MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT:
|
||||||
|
return "MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
template<>
|
template<>
|
||||||
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
|
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
|
@ -5123,6 +5135,64 @@ void ButtonCommandRequest::dump_to(std::string &out) const {
|
||||||
out.append("}");
|
out.append("}");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
bool MediaPlayerSupportedFormat::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 2: {
|
||||||
|
this->sample_rate = value.as_uint32();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
this->num_channels = value.as_uint32();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
this->purpose = value.as_enum<enums::MediaPlayerFormatPurpose>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool MediaPlayerSupportedFormat::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 1: {
|
||||||
|
this->format = value.as_string();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const {
|
||||||
|
buffer.encode_string(1, this->format);
|
||||||
|
buffer.encode_uint32(2, this->sample_rate);
|
||||||
|
buffer.encode_uint32(3, this->num_channels);
|
||||||
|
buffer.encode_enum<enums::MediaPlayerFormatPurpose>(4, this->purpose);
|
||||||
|
}
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void MediaPlayerSupportedFormat::dump_to(std::string &out) const {
|
||||||
|
__attribute__((unused)) char buffer[64];
|
||||||
|
out.append("MediaPlayerSupportedFormat {\n");
|
||||||
|
out.append(" format: ");
|
||||||
|
out.append("'").append(this->format).append("'");
|
||||||
|
out.append("\n");
|
||||||
|
|
||||||
|
out.append(" sample_rate: ");
|
||||||
|
sprintf(buffer, "%" PRIu32, this->sample_rate);
|
||||||
|
out.append(buffer);
|
||||||
|
out.append("\n");
|
||||||
|
|
||||||
|
out.append(" num_channels: ");
|
||||||
|
sprintf(buffer, "%" PRIu32, this->num_channels);
|
||||||
|
out.append(buffer);
|
||||||
|
out.append("\n");
|
||||||
|
|
||||||
|
out.append(" purpose: ");
|
||||||
|
out.append(proto_enum_to_string<enums::MediaPlayerFormatPurpose>(this->purpose));
|
||||||
|
out.append("\n");
|
||||||
|
out.append("}");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 6: {
|
case 6: {
|
||||||
|
@ -5159,6 +5229,10 @@ bool ListEntitiesMediaPlayerResponse::decode_length(uint32_t field_id, ProtoLeng
|
||||||
this->icon = value.as_string();
|
this->icon = value.as_string();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case 9: {
|
||||||
|
this->supported_formats.push_back(value.as_message<MediaPlayerSupportedFormat>());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -5182,6 +5256,9 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_bool(6, this->disabled_by_default);
|
buffer.encode_bool(6, this->disabled_by_default);
|
||||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||||
buffer.encode_bool(8, this->supports_pause);
|
buffer.encode_bool(8, this->supports_pause);
|
||||||
|
for (auto &it : this->supported_formats) {
|
||||||
|
buffer.encode_message<MediaPlayerSupportedFormat>(9, it, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
||||||
|
@ -5219,6 +5296,12 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
||||||
out.append(" supports_pause: ");
|
out.append(" supports_pause: ");
|
||||||
out.append(YESNO(this->supports_pause));
|
out.append(YESNO(this->supports_pause));
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
|
|
||||||
|
for (const auto &it : this->supported_formats) {
|
||||||
|
out.append(" supported_formats: ");
|
||||||
|
it.dump_to(out);
|
||||||
|
out.append("\n");
|
||||||
|
}
|
||||||
out.append("}");
|
out.append("}");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -156,6 +156,10 @@ enum MediaPlayerCommand : uint32_t {
|
||||||
MEDIA_PLAYER_COMMAND_MUTE = 3,
|
MEDIA_PLAYER_COMMAND_MUTE = 3,
|
||||||
MEDIA_PLAYER_COMMAND_UNMUTE = 4,
|
MEDIA_PLAYER_COMMAND_UNMUTE = 4,
|
||||||
};
|
};
|
||||||
|
enum MediaPlayerFormatPurpose : uint32_t {
|
||||||
|
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
|
||||||
|
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1,
|
||||||
|
};
|
||||||
enum BluetoothDeviceRequestType : uint32_t {
|
enum BluetoothDeviceRequestType : uint32_t {
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
||||||
|
@ -1267,6 +1271,21 @@ class ButtonCommandRequest : public ProtoMessage {
|
||||||
protected:
|
protected:
|
||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
};
|
};
|
||||||
|
class MediaPlayerSupportedFormat : public ProtoMessage {
|
||||||
|
public:
|
||||||
|
std::string format{};
|
||||||
|
uint32_t sample_rate{0};
|
||||||
|
uint32_t num_channels{0};
|
||||||
|
enums::MediaPlayerFormatPurpose purpose{};
|
||||||
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
|
};
|
||||||
class ListEntitiesMediaPlayerResponse : public ProtoMessage {
|
class ListEntitiesMediaPlayerResponse : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
std::string object_id{};
|
std::string object_id{};
|
||||||
|
@ -1277,6 +1296,7 @@ class ListEntitiesMediaPlayerResponse : public ProtoMessage {
|
||||||
bool disabled_by_default{false};
|
bool disabled_by_default{false};
|
||||||
enums::EntityCategory entity_category{};
|
enums::EntityCategory entity_category{};
|
||||||
bool supports_pause{false};
|
bool supports_pause{false};
|
||||||
|
std::vector<MediaPlayerSupportedFormat> supported_formats{};
|
||||||
void encode(ProtoWriteBuffer buffer) const override;
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
|
|
|
@ -311,6 +311,14 @@ bool APIServerConnectionBase::send_list_entities_button_response(const ListEntit
|
||||||
#ifdef USE_BUTTON
|
#ifdef USE_BUTTON
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_MEDIA_PLAYER
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
bool APIServerConnectionBase::send_media_player_supported_format(const MediaPlayerSupportedFormat &msg) {
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
ESP_LOGVV(TAG, "send_media_player_supported_format: %s", msg.dump().c_str());
|
||||||
|
#endif
|
||||||
|
return this->send_message_<MediaPlayerSupportedFormat>(msg, 119);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
bool APIServerConnectionBase::send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg) {
|
bool APIServerConnectionBase::send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg) {
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
ESP_LOGVV(TAG, "send_list_entities_media_player_response: %s", msg.dump().c_str());
|
ESP_LOGVV(TAG, "send_list_entities_media_player_response: %s", msg.dump().c_str());
|
||||||
|
@ -1135,6 +1143,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
||||||
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
|
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
|
||||||
#endif
|
#endif
|
||||||
this->on_update_command_request(msg);
|
this->on_update_command_request(msg);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 119: {
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
MediaPlayerSupportedFormat msg;
|
||||||
|
msg.decode(msg_data, msg_size);
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
ESP_LOGVV(TAG, "on_media_player_supported_format: %s", msg.dump().c_str());
|
||||||
|
#endif
|
||||||
|
this->on_media_player_supported_format(msg);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,10 @@ class APIServerConnectionBase : public ProtoService {
|
||||||
#ifdef USE_BUTTON
|
#ifdef USE_BUTTON
|
||||||
virtual void on_button_command_request(const ButtonCommandRequest &value){};
|
virtual void on_button_command_request(const ButtonCommandRequest &value){};
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
bool send_media_player_supported_format(const MediaPlayerSupportedFormat &msg);
|
||||||
|
virtual void on_media_player_supported_format(const MediaPlayerSupportedFormat &value){};
|
||||||
|
#endif
|
||||||
#ifdef USE_MEDIA_PLAYER
|
#ifdef USE_MEDIA_PLAYER
|
||||||
bool send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg);
|
bool send_list_entities_media_player_response(const ListEntitiesMediaPlayerResponse &msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
|
||||||
from esphome.components import sensor, spi
|
from esphome.components import sensor, spi
|
||||||
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
|
||||||
CONF_REACTIVE_POWER,
|
|
||||||
CONF_VOLTAGE,
|
|
||||||
CONF_CURRENT,
|
CONF_CURRENT,
|
||||||
|
CONF_FORWARD_ACTIVE_ENERGY,
|
||||||
|
CONF_FREQUENCY,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_LINE_FREQUENCY,
|
||||||
CONF_POWER,
|
CONF_POWER,
|
||||||
CONF_POWER_FACTOR,
|
CONF_POWER_FACTOR,
|
||||||
CONF_FREQUENCY,
|
CONF_REACTIVE_POWER,
|
||||||
CONF_FORWARD_ACTIVE_ENERGY,
|
|
||||||
CONF_REVERSE_ACTIVE_ENERGY,
|
CONF_REVERSE_ACTIVE_ENERGY,
|
||||||
|
CONF_VOLTAGE,
|
||||||
DEVICE_CLASS_CURRENT,
|
DEVICE_CLASS_CURRENT,
|
||||||
DEVICE_CLASS_ENERGY,
|
DEVICE_CLASS_ENERGY,
|
||||||
DEVICE_CLASS_POWER,
|
DEVICE_CLASS_POWER,
|
||||||
DEVICE_CLASS_POWER_FACTOR,
|
DEVICE_CLASS_POWER_FACTOR,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
ICON_LIGHTBULB,
|
|
||||||
ICON_CURRENT_AC,
|
ICON_CURRENT_AC,
|
||||||
|
ICON_LIGHTBULB,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
STATE_CLASS_TOTAL_INCREASING,
|
STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
UNIT_AMPERE,
|
||||||
UNIT_HERTZ,
|
UNIT_HERTZ,
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
UNIT_AMPERE,
|
|
||||||
UNIT_WATT,
|
|
||||||
UNIT_VOLT_AMPS_REACTIVE,
|
UNIT_VOLT_AMPS_REACTIVE,
|
||||||
|
UNIT_WATT,
|
||||||
UNIT_WATT_HOURS,
|
UNIT_WATT_HOURS,
|
||||||
)
|
)
|
||||||
|
|
||||||
CONF_LINE_FREQUENCY = "line_frequency"
|
|
||||||
CONF_METER_CONSTANT = "meter_constant"
|
CONF_METER_CONSTANT = "meter_constant"
|
||||||
CONF_PL_CONST = "pl_const"
|
CONF_PL_CONST = "pl_const"
|
||||||
CONF_GAIN_PGA = "gain_pga"
|
CONF_GAIN_PGA = "gain_pga"
|
||||||
|
|
|
@ -7,6 +7,7 @@ from esphome.const import (
|
||||||
CONF_FORWARD_ACTIVE_ENERGY,
|
CONF_FORWARD_ACTIVE_ENERGY,
|
||||||
CONF_FREQUENCY,
|
CONF_FREQUENCY,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_LINE_FREQUENCY,
|
||||||
CONF_PHASE_A,
|
CONF_PHASE_A,
|
||||||
CONF_PHASE_ANGLE,
|
CONF_PHASE_ANGLE,
|
||||||
CONF_PHASE_B,
|
CONF_PHASE_B,
|
||||||
|
@ -39,7 +40,6 @@ from esphome.const import (
|
||||||
|
|
||||||
from . import atm90e32_ns
|
from . import atm90e32_ns
|
||||||
|
|
||||||
CONF_LINE_FREQUENCY = "line_frequency"
|
|
||||||
CONF_CHIP_TEMPERATURE = "chip_temperature"
|
CONF_CHIP_TEMPERATURE = "chip_temperature"
|
||||||
CONF_GAIN_PGA = "gain_pga"
|
CONF_GAIN_PGA = "gain_pga"
|
||||||
CONF_CURRENT_PHASES = "current_phases"
|
CONF_CURRENT_PHASES = "current_phases"
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
|
// Datasheet: https://www.belling.com.cn/media/file_object/bel_product/BL0942/datasheet/BL0942_V1.06_en.pdf
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace bl0942 {
|
namespace bl0942 {
|
||||||
|
|
||||||
|
@ -12,33 +14,41 @@ static const uint8_t BL0942_FULL_PACKET = 0xAA;
|
||||||
static const uint8_t BL0942_PACKET_HEADER = 0x55;
|
static const uint8_t BL0942_PACKET_HEADER = 0x55;
|
||||||
|
|
||||||
static const uint8_t BL0942_WRITE_COMMAND = 0xA8;
|
static const uint8_t BL0942_WRITE_COMMAND = 0xA8;
|
||||||
static const uint8_t BL0942_REG_I_FAST_RMS_CTRL = 0x10;
|
|
||||||
static const uint8_t BL0942_REG_MODE = 0x18;
|
static const uint8_t BL0942_REG_I_RMSOS = 0x12;
|
||||||
static const uint8_t BL0942_REG_SOFT_RESET = 0x19;
|
static const uint8_t BL0942_REG_WA_CREEP = 0x14;
|
||||||
static const uint8_t BL0942_REG_USR_WRPROT = 0x1A;
|
static const uint8_t BL0942_REG_I_FAST_RMS_TH = 0x15;
|
||||||
|
static const uint8_t BL0942_REG_I_FAST_RMS_CYC = 0x16;
|
||||||
|
static const uint8_t BL0942_REG_FREQ_CYC = 0x17;
|
||||||
|
static const uint8_t BL0942_REG_OT_FUNX = 0x18;
|
||||||
|
static const uint8_t BL0942_REG_MODE = 0x19;
|
||||||
|
static const uint8_t BL0942_REG_SOFT_RESET = 0x1C;
|
||||||
|
static const uint8_t BL0942_REG_USR_WRPROT = 0x1D;
|
||||||
static const uint8_t BL0942_REG_TPS_CTRL = 0x1B;
|
static const uint8_t BL0942_REG_TPS_CTRL = 0x1B;
|
||||||
|
|
||||||
// TODO: Confirm insialisation works as intended
|
static const uint32_t BL0942_REG_MODE_RESV = 0x03;
|
||||||
const uint8_t BL0942_INIT[5][6] = {
|
static const uint32_t BL0942_REG_MODE_CF_EN = 0x04;
|
||||||
// Reset to default
|
static const uint32_t BL0942_REG_MODE_RMS_UPDATE_SEL = 0x08;
|
||||||
{BL0942_WRITE_COMMAND, BL0942_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38},
|
static const uint32_t BL0942_REG_MODE_FAST_RMS_SEL = 0x10;
|
||||||
// Enable User Operation Write
|
static const uint32_t BL0942_REG_MODE_AC_FREQ_SEL = 0x20;
|
||||||
{BL0942_WRITE_COMMAND, BL0942_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0},
|
static const uint32_t BL0942_REG_MODE_CF_CNT_CLR_SEL = 0x40;
|
||||||
// 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
|
static const uint32_t BL0942_REG_MODE_CF_CNT_ADD_SEL = 0x80;
|
||||||
{BL0942_WRITE_COMMAND, BL0942_REG_MODE, 0x00, 0x10, 0x00, 0x37},
|
static const uint32_t BL0942_REG_MODE_UART_RATE_19200 = 0x200;
|
||||||
// 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
|
static const uint32_t BL0942_REG_MODE_UART_RATE_38400 = 0x300;
|
||||||
{BL0942_WRITE_COMMAND, BL0942_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE},
|
static const uint32_t BL0942_REG_MODE_DEFAULT =
|
||||||
// 0x181C = Half cycle, Fast RMS threshold 6172
|
BL0942_REG_MODE_RESV | BL0942_REG_MODE_CF_EN | BL0942_REG_MODE_CF_CNT_ADD_SEL;
|
||||||
{BL0942_WRITE_COMMAND, BL0942_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
|
|
||||||
|
static const uint32_t BL0942_REG_SOFT_RESET_MAGIC = 0x5a5a5a;
|
||||||
|
static const uint32_t BL0942_REG_USR_WRPROT_MAGIC = 0x55;
|
||||||
|
|
||||||
void BL0942::loop() {
|
void BL0942::loop() {
|
||||||
DataPacket buffer;
|
DataPacket buffer;
|
||||||
if (!this->available()) {
|
if (!this->available()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (read_array((uint8_t *) &buffer, sizeof(buffer))) {
|
if (this->read_array((uint8_t *) &buffer, sizeof(buffer))) {
|
||||||
if (validate_checksum(&buffer)) {
|
if (this->validate_checksum_(&buffer)) {
|
||||||
received_package_(&buffer);
|
this->received_package_(&buffer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
|
ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
|
||||||
|
@ -47,8 +57,8 @@ void BL0942::loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BL0942::validate_checksum(DataPacket *data) {
|
bool BL0942::validate_checksum_(DataPacket *data) {
|
||||||
uint8_t checksum = BL0942_READ_COMMAND;
|
uint8_t checksum = BL0942_READ_COMMAND | this->address_;
|
||||||
// Whole package but checksum
|
// Whole package but checksum
|
||||||
uint8_t *raw = (uint8_t *) data;
|
uint8_t *raw = (uint8_t *) data;
|
||||||
for (uint32_t i = 0; i < sizeof(*data) - 1; i++) {
|
for (uint32_t i = 0; i < sizeof(*data) - 1; i++) {
|
||||||
|
@ -61,17 +71,58 @@ bool BL0942::validate_checksum(DataPacket *data) {
|
||||||
return checksum == data->checksum;
|
return checksum == data->checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BL0942::update() {
|
void BL0942::write_reg_(uint8_t reg, uint32_t val) {
|
||||||
|
uint8_t pkt[6];
|
||||||
|
|
||||||
this->flush();
|
this->flush();
|
||||||
this->write_byte(BL0942_READ_COMMAND);
|
pkt[0] = BL0942_WRITE_COMMAND | this->address_;
|
||||||
|
pkt[1] = reg;
|
||||||
|
pkt[2] = (val & 0xff);
|
||||||
|
pkt[3] = (val >> 8) & 0xff;
|
||||||
|
pkt[4] = (val >> 16) & 0xff;
|
||||||
|
pkt[5] = (pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4]) ^ 0xff;
|
||||||
|
this->write_array(pkt, 6);
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BL0942::read_reg_(uint8_t reg) {
|
||||||
|
union {
|
||||||
|
uint8_t b[4];
|
||||||
|
uint32_le_t le32;
|
||||||
|
} resp;
|
||||||
|
|
||||||
|
this->write_byte(BL0942_READ_COMMAND | this->address_);
|
||||||
|
this->write_byte(reg);
|
||||||
|
this->flush();
|
||||||
|
if (this->read_array(resp.b, 4) &&
|
||||||
|
resp.b[3] ==
|
||||||
|
(uint8_t) ((BL0942_READ_COMMAND + this->address_ + reg + resp.b[0] + resp.b[1] + resp.b[2]) ^ 0xff)) {
|
||||||
|
resp.b[3] = 0;
|
||||||
|
return resp.le32;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BL0942::update() {
|
||||||
|
this->write_byte(BL0942_READ_COMMAND | this->address_);
|
||||||
this->write_byte(BL0942_FULL_PACKET);
|
this->write_byte(BL0942_FULL_PACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BL0942::setup() {
|
void BL0942::setup() {
|
||||||
for (auto *i : BL0942_INIT) {
|
this->write_reg_(BL0942_REG_USR_WRPROT, BL0942_REG_USR_WRPROT_MAGIC);
|
||||||
this->write_array(i, 6);
|
this->write_reg_(BL0942_REG_SOFT_RESET, BL0942_REG_SOFT_RESET_MAGIC);
|
||||||
delay(1);
|
|
||||||
}
|
uint32_t mode = BL0942_REG_MODE_DEFAULT;
|
||||||
|
mode |= BL0942_REG_MODE_RMS_UPDATE_SEL; /* 800ms refresh time */
|
||||||
|
if (this->line_freq_ == LINE_FREQUENCY_60HZ)
|
||||||
|
mode |= BL0942_REG_MODE_AC_FREQ_SEL;
|
||||||
|
this->write_reg_(BL0942_REG_MODE, mode);
|
||||||
|
|
||||||
|
this->write_reg_(BL0942_REG_USR_WRPROT, 0);
|
||||||
|
|
||||||
|
if (this->read_reg_(BL0942_REG_MODE) != mode)
|
||||||
|
this->status_set_warning("BL0942 setup failed!");
|
||||||
|
|
||||||
this->flush();
|
this->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +155,15 @@ void BL0942::received_package_(DataPacket *data) {
|
||||||
if (frequency_sensor_ != nullptr) {
|
if (frequency_sensor_ != nullptr) {
|
||||||
frequency_sensor_->publish_state(frequency);
|
frequency_sensor_->publish_state(frequency);
|
||||||
}
|
}
|
||||||
|
this->status_clear_warning();
|
||||||
ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms,
|
ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms,
|
||||||
watt, cf_cnt, total_energy_consumption, frequency, data->status);
|
watt, cf_cnt, total_energy_consumption, frequency, data->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity)
|
void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity)
|
||||||
ESP_LOGCONFIG(TAG, "BL0942:");
|
ESP_LOGCONFIG(TAG, "BL0942:");
|
||||||
|
ESP_LOGCONFIG(TAG, " Address: %d", this->address_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Nominal line frequency: %d Hz", this->line_freq_);
|
||||||
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
|
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
|
||||||
LOG_SENSOR("", "Current", this->current_sensor_);
|
LOG_SENSOR("", "Current", this->current_sensor_);
|
||||||
LOG_SENSOR("", "Power", this->power_sensor_);
|
LOG_SENSOR("", "Power", this->power_sensor_);
|
||||||
|
|
|
@ -28,6 +28,11 @@ struct DataPacket {
|
||||||
uint8_t checksum;
|
uint8_t checksum;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
enum LineFrequency : uint8_t {
|
||||||
|
LINE_FREQUENCY_50HZ = 50,
|
||||||
|
LINE_FREQUENCY_60HZ = 60,
|
||||||
|
};
|
||||||
|
|
||||||
class BL0942 : public PollingComponent, public uart::UARTDevice {
|
class BL0942 : public PollingComponent, public uart::UARTDevice {
|
||||||
public:
|
public:
|
||||||
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
||||||
|
@ -35,9 +40,10 @@ class BL0942 : public PollingComponent, public uart::UARTDevice {
|
||||||
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
|
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
|
||||||
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
|
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
|
||||||
void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; }
|
void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; }
|
||||||
|
void set_line_freq(LineFrequency freq) { this->line_freq_ = freq; }
|
||||||
|
void set_address(uint8_t address) { this->address_ = address; }
|
||||||
|
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
@ -59,9 +65,12 @@ class BL0942 : public PollingComponent, public uart::UARTDevice {
|
||||||
float current_reference_ = BL0942_IREF;
|
float current_reference_ = BL0942_IREF;
|
||||||
// Divide by this to turn into kWh
|
// Divide by this to turn into kWh
|
||||||
float energy_reference_ = BL0942_EREF;
|
float energy_reference_ = BL0942_EREF;
|
||||||
|
uint8_t address_ = 0;
|
||||||
|
LineFrequency line_freq_ = LINE_FREQUENCY_50HZ;
|
||||||
|
|
||||||
static bool validate_checksum(DataPacket *data);
|
bool validate_checksum_(DataPacket *data);
|
||||||
|
int read_reg_(uint8_t reg);
|
||||||
|
void write_reg_(uint8_t reg, uint32_t val);
|
||||||
void received_package_(DataPacket *data);
|
void received_package_(DataPacket *data);
|
||||||
};
|
};
|
||||||
} // namespace bl0942
|
} // namespace bl0942
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
|
||||||
from esphome.components import sensor, uart
|
from esphome.components import sensor, uart
|
||||||
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_ADDRESS,
|
||||||
CONF_CURRENT,
|
CONF_CURRENT,
|
||||||
CONF_ENERGY,
|
CONF_ENERGY,
|
||||||
|
CONF_FREQUENCY,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_LINE_FREQUENCY,
|
||||||
CONF_POWER,
|
CONF_POWER,
|
||||||
CONF_VOLTAGE,
|
CONF_VOLTAGE,
|
||||||
CONF_FREQUENCY,
|
|
||||||
DEVICE_CLASS_CURRENT,
|
DEVICE_CLASS_CURRENT,
|
||||||
DEVICE_CLASS_ENERGY,
|
DEVICE_CLASS_ENERGY,
|
||||||
|
DEVICE_CLASS_FREQUENCY,
|
||||||
DEVICE_CLASS_POWER,
|
DEVICE_CLASS_POWER,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
DEVICE_CLASS_FREQUENCY,
|
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
STATE_CLASS_TOTAL_INCREASING,
|
||||||
UNIT_AMPERE,
|
UNIT_AMPERE,
|
||||||
|
UNIT_HERTZ,
|
||||||
UNIT_KILOWATT_HOURS,
|
UNIT_KILOWATT_HOURS,
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
UNIT_WATT,
|
UNIT_WATT,
|
||||||
UNIT_HERTZ,
|
|
||||||
STATE_CLASS_TOTAL_INCREASING,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
DEPENDENCIES = ["uart"]
|
DEPENDENCIES = ["uart"]
|
||||||
|
@ -27,6 +29,12 @@ DEPENDENCIES = ["uart"]
|
||||||
bl0942_ns = cg.esphome_ns.namespace("bl0942")
|
bl0942_ns = cg.esphome_ns.namespace("bl0942")
|
||||||
BL0942 = bl0942_ns.class_("BL0942", cg.PollingComponent, uart.UARTDevice)
|
BL0942 = bl0942_ns.class_("BL0942", cg.PollingComponent, uart.UARTDevice)
|
||||||
|
|
||||||
|
LineFrequency = bl0942_ns.enum("LineFrequency")
|
||||||
|
LINE_FREQS = {
|
||||||
|
50: LineFrequency.LINE_FREQUENCY_50HZ,
|
||||||
|
60: LineFrequency.LINE_FREQUENCY_60HZ,
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
|
@ -61,6 +69,14 @@ CONFIG_SCHEMA = (
|
||||||
device_class=DEVICE_CLASS_FREQUENCY,
|
device_class=DEVICE_CLASS_FREQUENCY,
|
||||||
state_class=STATE_CLASS_MEASUREMENT,
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_LINE_FREQUENCY, default="50HZ"): cv.All(
|
||||||
|
cv.frequency,
|
||||||
|
cv.enum(
|
||||||
|
LINE_FREQS,
|
||||||
|
int=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_ADDRESS, default=0): cv.int_range(min=0, max=3),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("60s"))
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
@ -88,3 +104,5 @@ async def to_code(config):
|
||||||
if frequency_config := config.get(CONF_FREQUENCY):
|
if frequency_config := config.get(CONF_FREQUENCY):
|
||||||
sens = await sensor.new_sensor(frequency_config)
|
sens = await sensor.new_sensor(frequency_config)
|
||||||
cg.add(var.set_frequency_sensor(sens))
|
cg.add(var.set_frequency_sensor(sens))
|
||||||
|
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
|
||||||
|
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||||
|
|
|
@ -38,7 +38,8 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalRAMAllocator<rmt_item32_t> rmt_allocator(ExternalRAMAllocator<rmt_item32_t>::ALLOW_FAILURE);
|
ExternalRAMAllocator<rmt_item32_t> rmt_allocator(ExternalRAMAllocator<rmt_item32_t>::ALLOW_FAILURE);
|
||||||
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8); // 8 bits per byte, 1 rmt_item32_t per bit
|
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 +
|
||||||
|
1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset
|
||||||
|
|
||||||
rmt_config_t config;
|
rmt_config_t config;
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
|
@ -66,7 +67,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high,
|
void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high,
|
||||||
uint32_t bit1_low) {
|
uint32_t bit1_low, uint32_t reset_time_high, uint32_t reset_time_low) {
|
||||||
float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f;
|
float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f;
|
||||||
|
|
||||||
// 0-bit
|
// 0-bit
|
||||||
|
@ -79,6 +80,11 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
|
||||||
this->bit1_.level0 = 1;
|
this->bit1_.level0 = 1;
|
||||||
this->bit1_.duration1 = (uint32_t) (ratio * bit1_low);
|
this->bit1_.duration1 = (uint32_t) (ratio * bit1_low);
|
||||||
this->bit1_.level1 = 0;
|
this->bit1_.level1 = 0;
|
||||||
|
// reset
|
||||||
|
this->reset_.duration0 = (uint32_t) (ratio * reset_time_high);
|
||||||
|
this->reset_.level0 = 1;
|
||||||
|
this->reset_.duration1 = (uint32_t) (ratio * reset_time_low);
|
||||||
|
this->reset_.level1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||||
|
@ -118,6 +124,12 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||||
psrc++;
|
psrc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) {
|
||||||
|
pdest->val = this->reset_.val;
|
||||||
|
pdest++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
if (rmt_write_items(this->channel_, this->rmt_buf_, len, false) != ESP_OK) {
|
if (rmt_write_items(this->channel_, this->rmt_buf_, len, false) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "RMT TX error");
|
ESP_LOGE(TAG, "RMT TX error");
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
|
|
|
@ -49,7 +49,8 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||||
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
||||||
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
||||||
|
|
||||||
void set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, uint32_t bit1_low);
|
void set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, uint32_t bit1_low,
|
||||||
|
uint32_t reset_time_high, uint32_t reset_time_low);
|
||||||
|
|
||||||
void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; }
|
void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; }
|
||||||
void set_rmt_channel(rmt_channel_t channel) { this->channel_ = channel; }
|
void set_rmt_channel(rmt_channel_t channel) { this->channel_ = channel; }
|
||||||
|
@ -75,7 +76,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||||
bool is_rgbw_;
|
bool is_rgbw_;
|
||||||
bool is_wrgb_;
|
bool is_wrgb_;
|
||||||
|
|
||||||
rmt_item32_t bit0_, bit1_;
|
rmt_item32_t bit0_, bit1_, reset_;
|
||||||
RGBOrder rgb_order_;
|
RGBOrder rgb_order_;
|
||||||
rmt_channel_t channel_;
|
rmt_channel_t channel_;
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,15 @@ class LEDStripTimings:
|
||||||
bit0_low: int
|
bit0_low: int
|
||||||
bit1_high: int
|
bit1_high: int
|
||||||
bit1_low: int
|
bit1_low: int
|
||||||
|
reset_high: int
|
||||||
|
reset_low: int
|
||||||
|
|
||||||
|
|
||||||
CHIPSETS = {
|
CHIPSETS = {
|
||||||
"WS2812": LEDStripTimings(400, 1000, 1000, 400),
|
"WS2812": LEDStripTimings(400, 1000, 1000, 400, 0, 0),
|
||||||
"SK6812": LEDStripTimings(300, 900, 600, 600),
|
"SK6812": LEDStripTimings(300, 900, 600, 600, 0, 0),
|
||||||
"APA106": LEDStripTimings(350, 1360, 1360, 350),
|
"APA106": LEDStripTimings(350, 1360, 1360, 350, 0, 0),
|
||||||
"SM16703": LEDStripTimings(300, 900, 900, 300),
|
"SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,6 +60,8 @@ CONF_BIT0_HIGH = "bit0_high"
|
||||||
CONF_BIT0_LOW = "bit0_low"
|
CONF_BIT0_LOW = "bit0_low"
|
||||||
CONF_BIT1_HIGH = "bit1_high"
|
CONF_BIT1_HIGH = "bit1_high"
|
||||||
CONF_BIT1_LOW = "bit1_low"
|
CONF_BIT1_LOW = "bit1_low"
|
||||||
|
CONF_RESET_HIGH = "reset_high"
|
||||||
|
CONF_RESET_LOW = "reset_low"
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
@ -88,6 +92,14 @@ CONFIG_SCHEMA = cv.All(
|
||||||
CONF_BIT1_LOW,
|
CONF_BIT1_LOW,
|
||||||
"custom",
|
"custom",
|
||||||
): cv.positive_time_period_nanoseconds,
|
): cv.positive_time_period_nanoseconds,
|
||||||
|
cv.Optional(
|
||||||
|
CONF_RESET_HIGH,
|
||||||
|
default="0 us",
|
||||||
|
): cv.positive_time_period_nanoseconds,
|
||||||
|
cv.Optional(
|
||||||
|
CONF_RESET_LOW,
|
||||||
|
default="0 us",
|
||||||
|
): cv.positive_time_period_nanoseconds,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH),
|
cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH),
|
||||||
|
@ -113,6 +125,8 @@ async def to_code(config):
|
||||||
chipset.bit0_low,
|
chipset.bit0_low,
|
||||||
chipset.bit1_high,
|
chipset.bit1_high,
|
||||||
chipset.bit1_low,
|
chipset.bit1_low,
|
||||||
|
chipset.reset_high,
|
||||||
|
chipset.reset_low,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -122,6 +136,8 @@ async def to_code(config):
|
||||||
config[CONF_BIT0_LOW],
|
config[CONF_BIT0_LOW],
|
||||||
config[CONF_BIT1_HIGH],
|
config[CONF_BIT1_HIGH],
|
||||||
config[CONF_BIT1_LOW],
|
config[CONF_BIT1_LOW],
|
||||||
|
config[CONF_RESET_HIGH],
|
||||||
|
config[CONF_RESET_LOW],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
import esphome.codegen as cg
|
|
||||||
import esphome.config_validation as cv
|
|
||||||
from esphome import core, pins
|
from esphome import core, pins
|
||||||
from esphome.components import display, spi, font
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import display, font, spi
|
||||||
from esphome.components.display import validate_rotation
|
from esphome.components.display import validate_rotation
|
||||||
from esphome.core import CORE, HexInt
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_COLOR_ORDER,
|
||||||
CONF_COLOR_PALETTE,
|
CONF_COLOR_PALETTE,
|
||||||
CONF_DC_PIN,
|
CONF_DC_PIN,
|
||||||
CONF_ID,
|
|
||||||
CONF_LAMBDA,
|
|
||||||
CONF_MODEL,
|
|
||||||
CONF_RAW_DATA_ID,
|
|
||||||
CONF_PAGES,
|
|
||||||
CONF_RESET_PIN,
|
|
||||||
CONF_DIMENSIONS,
|
CONF_DIMENSIONS,
|
||||||
CONF_WIDTH,
|
|
||||||
CONF_HEIGHT,
|
CONF_HEIGHT,
|
||||||
CONF_ROTATION,
|
CONF_ID,
|
||||||
|
CONF_INVERT_COLORS,
|
||||||
|
CONF_LAMBDA,
|
||||||
CONF_MIRROR_X,
|
CONF_MIRROR_X,
|
||||||
CONF_MIRROR_Y,
|
CONF_MIRROR_Y,
|
||||||
CONF_SWAP_XY,
|
CONF_MODEL,
|
||||||
CONF_COLOR_ORDER,
|
|
||||||
CONF_OFFSET_HEIGHT,
|
CONF_OFFSET_HEIGHT,
|
||||||
CONF_OFFSET_WIDTH,
|
CONF_OFFSET_WIDTH,
|
||||||
|
CONF_PAGES,
|
||||||
|
CONF_RAW_DATA_ID,
|
||||||
|
CONF_RESET_PIN,
|
||||||
|
CONF_ROTATION,
|
||||||
|
CONF_SWAP_XY,
|
||||||
CONF_TRANSFORM,
|
CONF_TRANSFORM,
|
||||||
CONF_INVERT_COLORS,
|
CONF_WIDTH,
|
||||||
)
|
)
|
||||||
|
from esphome.core import CORE, HexInt
|
||||||
|
|
||||||
DEPENDENCIES = ["spi"]
|
DEPENDENCIES = ["spi"]
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Optional(CONF_INVERT_DISPLAY): cv.invalid(
|
cv.Optional(CONF_INVERT_DISPLAY): cv.invalid(
|
||||||
"'invert_display' has been replaced by 'invert_colors'"
|
"'invert_display' has been replaced by 'invert_colors'"
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_INVERT_COLORS): cv.boolean,
|
cv.Required(CONF_INVERT_COLORS): cv.boolean,
|
||||||
cv.Optional(CONF_COLOR_ORDER): cv.one_of(*COLOR_ORDERS.keys(), upper=True),
|
cv.Optional(CONF_COLOR_ORDER): cv.one_of(*COLOR_ORDERS.keys(), upper=True),
|
||||||
cv.Exclusive(CONF_ROTATION, CONF_ROTATION): validate_rotation,
|
cv.Exclusive(CONF_ROTATION, CONF_ROTATION): validate_rotation,
|
||||||
cv.Exclusive(CONF_TRANSFORM, CONF_ROTATION): cv.Schema(
|
cv.Exclusive(CONF_TRANSFORM, CONF_ROTATION): cv.Schema(
|
||||||
|
@ -287,5 +287,4 @@ async def to_code(config):
|
||||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||||
cg.add(var.set_palette(prog_arr))
|
cg.add(var.set_palette(prog_arr))
|
||||||
|
|
||||||
if CONF_INVERT_COLORS in config:
|
cg.add(var.invert_colors(config[CONF_INVERT_COLORS]))
|
||||||
cg.add(var.invert_colors(config[CONF_INVERT_COLORS]))
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ void ILI9XXXDisplay::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, " Swap_xy: %s", YESNO(this->swap_xy_));
|
ESP_LOGCONFIG(TAG, " Swap_xy: %s", YESNO(this->swap_xy_));
|
||||||
ESP_LOGCONFIG(TAG, " Mirror_x: %s", YESNO(this->mirror_x_));
|
ESP_LOGCONFIG(TAG, " Mirror_x: %s", YESNO(this->mirror_x_));
|
||||||
ESP_LOGCONFIG(TAG, " Mirror_y: %s", YESNO(this->mirror_y_));
|
ESP_LOGCONFIG(TAG, " Mirror_y: %s", YESNO(this->mirror_y_));
|
||||||
|
ESP_LOGCONFIG(TAG, " Invert colors: %s", YESNO(this->pre_invertcolors_));
|
||||||
|
|
||||||
if (this->is_failed()) {
|
if (this->is_failed()) {
|
||||||
ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!");
|
ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!");
|
||||||
|
@ -154,7 +155,6 @@ void ILI9XXXDisplay::fill(Color color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -28,8 +28,8 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
||||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> {
|
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> {
|
||||||
public:
|
public:
|
||||||
ILI9XXXDisplay() = default;
|
ILI9XXXDisplay() = default;
|
||||||
ILI9XXXDisplay(uint8_t const *init_sequence, int16_t width, int16_t height, bool invert_colors)
|
ILI9XXXDisplay(uint8_t const *init_sequence, int16_t width, int16_t height)
|
||||||
: init_sequence_{init_sequence}, width_{width}, height_{height}, pre_invertcolors_{invert_colors} {
|
: init_sequence_{init_sequence}, width_{width}, height_{height} {
|
||||||
uint8_t cmd, num_args, bits;
|
uint8_t cmd, num_args, bits;
|
||||||
const uint8_t *addr = init_sequence;
|
const uint8_t *addr = init_sequence;
|
||||||
while ((cmd = *addr++) != 0) {
|
while ((cmd = *addr++) != 0) {
|
||||||
|
@ -144,7 +144,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
||||||
bool need_update_ = false;
|
bool need_update_ = false;
|
||||||
bool is_18bitdisplay_ = false;
|
bool is_18bitdisplay_ = false;
|
||||||
PixelMode pixel_mode_{};
|
PixelMode pixel_mode_{};
|
||||||
bool pre_invertcolors_ = false;
|
bool pre_invertcolors_{};
|
||||||
display::ColorOrder color_order_{display::COLOR_ORDER_BGR};
|
display::ColorOrder color_order_{display::COLOR_ORDER_BGR};
|
||||||
bool swap_xy_{};
|
bool swap_xy_{};
|
||||||
bool mirror_x_{};
|
bool mirror_x_{};
|
||||||
|
@ -154,54 +154,54 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
||||||
//----------- M5Stack display --------------
|
//----------- M5Stack display --------------
|
||||||
class ILI9XXXM5Stack : public ILI9XXXDisplay {
|
class ILI9XXXM5Stack : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXM5Stack() : ILI9XXXDisplay(INITCMD_M5STACK, 320, 240, true) {}
|
ILI9XXXM5Stack() : ILI9XXXDisplay(INITCMD_M5STACK, 320, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- M5Stack display --------------
|
//----------- M5Stack display --------------
|
||||||
class ILI9XXXM5CORE : public ILI9XXXDisplay {
|
class ILI9XXXM5CORE : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXM5CORE() : ILI9XXXDisplay(INITCMD_M5CORE, 320, 240, true) {}
|
ILI9XXXM5CORE() : ILI9XXXDisplay(INITCMD_M5CORE, 320, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ST7789V display --------------
|
//----------- ST7789V display --------------
|
||||||
class ILI9XXXST7789V : public ILI9XXXDisplay {
|
class ILI9XXXST7789V : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXST7789V() : ILI9XXXDisplay(INITCMD_ST7789V, 240, 320, false) {}
|
ILI9XXXST7789V() : ILI9XXXDisplay(INITCMD_ST7789V, 240, 320) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_24_TFT display --------------
|
//----------- ILI9XXX_24_TFT display --------------
|
||||||
class ILI9XXXILI9341 : public ILI9XXXDisplay {
|
class ILI9XXXILI9341 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9341() : ILI9XXXDisplay(INITCMD_ILI9341, 240, 320, false) {}
|
ILI9XXXILI9341() : ILI9XXXDisplay(INITCMD_ILI9341, 240, 320) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_24_TFT rotated display --------------
|
//----------- ILI9XXX_24_TFT rotated display --------------
|
||||||
class ILI9XXXILI9342 : public ILI9XXXDisplay {
|
class ILI9XXXILI9342 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9342() : ILI9XXXDisplay(INITCMD_ILI9341, 320, 240, false) {}
|
ILI9XXXILI9342() : ILI9XXXDisplay(INITCMD_ILI9341, 320, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_??_TFT rotated display --------------
|
//----------- ILI9XXX_??_TFT rotated display --------------
|
||||||
class ILI9XXXILI9481 : public ILI9XXXDisplay {
|
class ILI9XXXILI9481 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9481() : ILI9XXXDisplay(INITCMD_ILI9481, 480, 320, false) {}
|
ILI9XXXILI9481() : ILI9XXXDisplay(INITCMD_ILI9481, 480, 320) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9481 in 18 bit mode --------------
|
//----------- ILI9481 in 18 bit mode --------------
|
||||||
class ILI9XXXILI948118 : public ILI9XXXDisplay {
|
class ILI9XXXILI948118 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI948118() : ILI9XXXDisplay(INITCMD_ILI9481_18, 320, 480, true) {}
|
ILI9XXXILI948118() : ILI9XXXDisplay(INITCMD_ILI9481_18, 320, 480) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||||
class ILI9XXXILI9486 : public ILI9XXXDisplay {
|
class ILI9XXXILI9486 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320, false) {}
|
ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ILI9XXXILI9488 : public ILI9XXXDisplay {
|
class ILI9XXXILI9488 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9488(const uint8_t *seq = INITCMD_ILI9488) : ILI9XXXDisplay(seq, 480, 320, true) {}
|
ILI9XXXILI9488(const uint8_t *seq = INITCMD_ILI9488) : ILI9XXXDisplay(seq, 480, 320) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_madctl() override {
|
void set_madctl() override {
|
||||||
|
@ -246,34 +246,34 @@ class WAVESHARERES35 : public ILI9XXXILI9488 {
|
||||||
//----------- ILI9XXX_35_TFT origin colors rotated display --------------
|
//----------- ILI9XXX_35_TFT origin colors rotated display --------------
|
||||||
class ILI9XXXILI9488A : public ILI9XXXDisplay {
|
class ILI9XXXILI9488A : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXILI9488A() : ILI9XXXDisplay(INITCMD_ILI9488_A, 480, 320, true) {}
|
ILI9XXXILI9488A() : ILI9XXXDisplay(INITCMD_ILI9488_A, 480, 320) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||||
class ILI9XXXST7796 : public ILI9XXXDisplay {
|
class ILI9XXXST7796 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXST7796() : ILI9XXXDisplay(INITCMD_ST7796, 320, 480, false) {}
|
ILI9XXXST7796() : ILI9XXXDisplay(INITCMD_ST7796, 320, 480) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ILI9XXXS3Box : public ILI9XXXDisplay {
|
class ILI9XXXS3Box : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXS3Box() : ILI9XXXDisplay(INITCMD_S3BOX, 320, 240, false) {}
|
ILI9XXXS3Box() : ILI9XXXDisplay(INITCMD_S3BOX, 320, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ILI9XXXS3BoxLite : public ILI9XXXDisplay {
|
class ILI9XXXS3BoxLite : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXS3BoxLite() : ILI9XXXDisplay(INITCMD_S3BOXLITE, 320, 240, true) {}
|
ILI9XXXS3BoxLite() : ILI9XXXDisplay(INITCMD_S3BOXLITE, 320, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ILI9XXXGC9A01A : public ILI9XXXDisplay {
|
class ILI9XXXGC9A01A : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240, true) {}
|
ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------- ILI9XXX_24_TFT display --------------
|
//----------- ILI9XXX_24_TFT display --------------
|
||||||
class ILI9XXXST7735 : public ILI9XXXDisplay {
|
class ILI9XXXST7735 : public ILI9XXXDisplay {
|
||||||
public:
|
public:
|
||||||
ILI9XXXST7735() : ILI9XXXDisplay(INITCMD_ST7735, 128, 160, false) {}
|
ILI9XXXST7735() : ILI9XXXDisplay(INITCMD_ST7735, 128, 160) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ili9xxx
|
} // namespace ili9xxx
|
||||||
|
|
|
@ -101,7 +101,6 @@ static const uint8_t PROGMEM INITCMD_ILI9481[] = {
|
||||||
ILI9XXX_MADCTL , 1, MADCTL_MV | MADCTL_BGR, // Memory Access Control
|
ILI9XXX_MADCTL , 1, MADCTL_MV | MADCTL_BGR, // Memory Access Control
|
||||||
ILI9XXX_CSCON , 1, 0x01,
|
ILI9XXX_CSCON , 1, 0x01,
|
||||||
ILI9XXX_PIXFMT, 1, 0x55, // 16 bit mode
|
ILI9XXX_PIXFMT, 1, 0x55, // 16 bit mode
|
||||||
ILI9XXX_INVON, 0,
|
|
||||||
ILI9XXX_DISPON, 0x80, // Set display on
|
ILI9XXX_DISPON, 0x80, // Set display on
|
||||||
0x00 // end
|
0x00 // end
|
||||||
};
|
};
|
||||||
|
@ -121,7 +120,6 @@ static const uint8_t PROGMEM INITCMD_ILI9481_18[] = {
|
||||||
ILI9XXX_MADCTL , 1, MADCTL_MX| MADCTL_BGR, // Memory Access Control
|
ILI9XXX_MADCTL , 1, MADCTL_MX| MADCTL_BGR, // Memory Access Control
|
||||||
ILI9XXX_CSCON , 1, 0x01,
|
ILI9XXX_CSCON , 1, 0x01,
|
||||||
ILI9XXX_PIXFMT, 1, 0x66, // 18 bit mode
|
ILI9XXX_PIXFMT, 1, 0x66, // 18 bit mode
|
||||||
ILI9XXX_INVON, 0,
|
|
||||||
ILI9XXX_DISPON, 0x80, // Set display on
|
ILI9XXX_DISPON, 0x80, // Set display on
|
||||||
0x00 // end
|
0x00 // end
|
||||||
};
|
};
|
||||||
|
@ -204,7 +202,6 @@ static const uint8_t PROGMEM INITCMD_ILI9488_A[] = {
|
||||||
|
|
||||||
|
|
||||||
ILI9XXX_SLPOUT, 0x80, // Exit sleep mode
|
ILI9XXX_SLPOUT, 0x80, // Exit sleep mode
|
||||||
//ILI9XXX_INVON , 0,
|
|
||||||
ILI9XXX_DISPON, 0x80, // Set display on
|
ILI9XXX_DISPON, 0x80, // Set display on
|
||||||
0x00 // end
|
0x00 // end
|
||||||
};
|
};
|
||||||
|
|
|
@ -266,7 +266,10 @@ async def to_code(config):
|
||||||
await add_top_layer(config)
|
await add_top_layer(config)
|
||||||
await msgboxes_to_code(config)
|
await msgboxes_to_code(config)
|
||||||
await disp_update(f"{lv_component}->get_disp()", config)
|
await disp_update(f"{lv_component}->get_disp()", config)
|
||||||
Widget.set_completed()
|
# At this point only the setup code should be generated
|
||||||
|
assert LvContext.added_lambda_count == 1
|
||||||
|
Widget.set_completed()
|
||||||
|
async with LvContext(lv_component):
|
||||||
await generate_triggers(lv_component)
|
await generate_triggers(lv_component)
|
||||||
for conf in config.get(CONF_ON_IDLE, ()):
|
for conf in config.get(CONF_ON_IDLE, ()):
|
||||||
templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32)
|
templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32)
|
||||||
|
|
|
@ -157,7 +157,7 @@ async def lvgl_update_to_code(config, action_id, template_arg, args):
|
||||||
widgets = await get_widgets(config)
|
widgets = await get_widgets(config)
|
||||||
w = widgets[0]
|
w = widgets[0]
|
||||||
disp = f"{w.obj}->get_disp()"
|
disp = f"{w.obj}->get_disp()"
|
||||||
async with LambdaContext(parameters=args, where=action_id) as context:
|
async with LambdaContext(LVGL_COMP_ARG, where=action_id) as context:
|
||||||
await disp_update(disp, config)
|
await disp_update(disp, config)
|
||||||
var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
|
var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
|
||||||
await cg.register_parented(var, w.var)
|
await cg.register_parented(var, w.var)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET
|
||||||
from ..lvcode import EVENT_ARG, LambdaContext, LvContext
|
from ..lvcode import EVENT_ARG, LambdaContext, LvContext
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, lv_pseudo_button_t
|
from ..types import LV_EVENT, lv_pseudo_button_t
|
||||||
from ..widgets import Widget, get_widgets
|
from ..widgets import Widget, get_widgets, wait_for_widgets
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
binary_sensor_schema(BinarySensor)
|
binary_sensor_schema(BinarySensor)
|
||||||
|
@ -29,6 +29,7 @@ async def to_code(config):
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
assert isinstance(widget, Widget)
|
assert isinstance(widget, Widget)
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext(EVENT_ARG) as pressed_ctx:
|
async with LambdaContext(EVENT_ARG) as pressed_ctx:
|
||||||
pressed_ctx.add(sensor.publish_state(widget.is_pressed()))
|
pressed_ctx.add(sensor.publish_state(widget.is_pressed()))
|
||||||
async with LvContext(paren) as ctx:
|
async with LvContext(paren) as ctx:
|
||||||
|
|
|
@ -505,4 +505,10 @@ DEFAULT_ESPHOME_FONT = "esphome_lv_default_font"
|
||||||
|
|
||||||
|
|
||||||
def join_enums(enums, prefix=""):
|
def join_enums(enums, prefix=""):
|
||||||
return literal("|".join(f"(int){prefix}{e.upper()}" for e in enums))
|
enums = list(enums)
|
||||||
|
enums.sort()
|
||||||
|
# If a prefix is provided, prepend each constant with the prefix, and assume that all the constants are within the
|
||||||
|
# same namespace, otherwise cast to int to avoid triggering warnings about mixing enum types.
|
||||||
|
if prefix:
|
||||||
|
return literal("|".join(f"{prefix}{e.upper()}" for e in enums))
|
||||||
|
return literal("|".join(f"(int){e.upper()}" for e in enums))
|
||||||
|
|
|
@ -8,7 +8,7 @@ from ..defines import CONF_LVGL_ID
|
||||||
from ..lvcode import LvContext
|
from ..lvcode import LvContext
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LvType, lvgl_ns
|
from ..types import LvType, lvgl_ns
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
lv_led_t = LvType("lv_led_t")
|
lv_led_t = LvType("lv_led_t")
|
||||||
LVLight = lvgl_ns.class_("LVLight", LightOutput)
|
LVLight = lvgl_ns.class_("LVLight", LightOutput)
|
||||||
|
@ -28,5 +28,6 @@ async def to_code(config):
|
||||||
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
||||||
widget = await get_widgets(config, CONF_LED)
|
widget = await get_widgets(config, CONF_LED)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
|
await wait_for_widgets()
|
||||||
async with LvContext(paren) as ctx:
|
async with LvContext(paren) as ctx:
|
||||||
ctx.add(var.set_obj(widget.obj))
|
ctx.add(var.set_obj(widget.obj))
|
||||||
|
|
|
@ -176,6 +176,8 @@ class LvContext(LambdaContext):
|
||||||
Code generation into the LVGL initialisation code (called in `setup()`)
|
Code generation into the LVGL initialisation code (called in `setup()`)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
added_lambda_count = 0
|
||||||
|
|
||||||
def __init__(self, lv_component, args=None):
|
def __init__(self, lv_component, args=None):
|
||||||
self.args = args or LVGL_COMP_ARG
|
self.args = args or LVGL_COMP_ARG
|
||||||
super().__init__(parameters=self.args)
|
super().__init__(parameters=self.args)
|
||||||
|
@ -183,6 +185,7 @@ class LvContext(LambdaContext):
|
||||||
|
|
||||||
async def add_init_lambda(self):
|
async def add_init_lambda(self):
|
||||||
cg.add(self.lv_component.add_init_lambda(await self.get_lambda()))
|
cg.add(self.lv_component.add_init_lambda(await self.get_lambda()))
|
||||||
|
LvContext.added_lambda_count += 1
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||||
await super().__aexit__(exc_type, exc_val, exc_tb)
|
await super().__aexit__(exc_type, exc_val, exc_tb)
|
||||||
|
|
|
@ -16,7 +16,7 @@ from ..lvcode import (
|
||||||
)
|
)
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LvNumber, lvgl_ns
|
from ..types import LV_EVENT, LvNumber, lvgl_ns
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
|
LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
|
||||||
|
|
||||||
|
@ -44,11 +44,13 @@ async def to_code(config):
|
||||||
step=widget.get_step(),
|
step=widget.get_step(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext([(cg.float_, "v")]) as control:
|
async with LambdaContext([(cg.float_, "v")]) as control:
|
||||||
await widget.set_property(
|
await widget.set_property(
|
||||||
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
||||||
)
|
)
|
||||||
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
||||||
|
control.add(var.publish_state(widget.get_value()))
|
||||||
async with LambdaContext(EVENT_ARG) as event:
|
async with LambdaContext(EVENT_ARG) as event:
|
||||||
event.add(var.publish_state(widget.get_value()))
|
event.add(var.publish_state(widget.get_value()))
|
||||||
event_code = (
|
event_code = (
|
||||||
|
|
|
@ -15,7 +15,7 @@ from ..lvcode import (
|
||||||
)
|
)
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LvSelect, lvgl_ns
|
from ..types import LV_EVENT, LvSelect, lvgl_ns
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
|
LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
|
||||||
|
|
||||||
|
@ -37,11 +37,13 @@ async def to_code(config):
|
||||||
options = widget.config.get(CONF_OPTIONS, [])
|
options = widget.config.get(CONF_OPTIONS, [])
|
||||||
selector = await select.new_select(config, options=options)
|
selector = await select.new_select(config, options=options)
|
||||||
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext(EVENT_ARG) as pub_ctx:
|
async with LambdaContext(EVENT_ARG) as pub_ctx:
|
||||||
pub_ctx.add(selector.publish_index(widget.get_value()))
|
pub_ctx.add(selector.publish_index(widget.get_value()))
|
||||||
async with LambdaContext([(cg.uint16, "v")]) as control:
|
async with LambdaContext([(cg.uint16, "v")]) as control:
|
||||||
await widget.set_property("selected", "v", animated=config[CONF_ANIMATED])
|
await widget.set_property("selected", "v", animated=config[CONF_ANIMATED])
|
||||||
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
||||||
|
control.add(selector.publish_index(widget.get_value()))
|
||||||
async with LvContext(paren) as ctx:
|
async with LvContext(paren) as ctx:
|
||||||
lv_add(selector.set_control_lambda(await control.get_lambda()))
|
lv_add(selector.set_control_lambda(await control.get_lambda()))
|
||||||
ctx.add(
|
ctx.add(
|
||||||
|
|
|
@ -14,7 +14,7 @@ from ..lvcode import (
|
||||||
)
|
)
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LvNumber
|
from ..types import LV_EVENT, LvNumber
|
||||||
from ..widgets import Widget, get_widgets
|
from ..widgets import Widget, get_widgets, wait_for_widgets
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
sensor_schema(Sensor)
|
sensor_schema(Sensor)
|
||||||
|
@ -33,6 +33,7 @@ async def to_code(config):
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
assert isinstance(widget, Widget)
|
assert isinstance(widget, Widget)
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext(EVENT_ARG) as lamb:
|
async with LambdaContext(EVENT_ARG) as lamb:
|
||||||
lv_add(sensor.publish_state(widget.get_value()))
|
lv_add(sensor.publish_state(widget.get_value()))
|
||||||
async with LvContext(paren, LVGL_COMP_ARG):
|
async with LvContext(paren, LVGL_COMP_ARG):
|
||||||
|
|
|
@ -3,7 +3,7 @@ from esphome.components.switch import Switch, new_switch, switch_schema
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.cpp_generator import MockObj
|
from esphome.cpp_generator import MockObj
|
||||||
|
|
||||||
from ..defines import CONF_LVGL_ID, CONF_WIDGET
|
from ..defines import CONF_LVGL_ID, CONF_WIDGET, literal
|
||||||
from ..lvcode import (
|
from ..lvcode import (
|
||||||
API_EVENT,
|
API_EVENT,
|
||||||
EVENT_ARG,
|
EVENT_ARG,
|
||||||
|
@ -16,7 +16,7 @@ from ..lvcode import (
|
||||||
)
|
)
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns
|
from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch)
|
LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch)
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
|
@ -35,6 +35,7 @@ async def to_code(config):
|
||||||
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext(EVENT_ARG) as checked_ctx:
|
async with LambdaContext(EVENT_ARG) as checked_ctx:
|
||||||
checked_ctx.add(switch.publish_state(widget.get_value()))
|
checked_ctx.add(switch.publish_state(widget.get_value()))
|
||||||
async with LambdaContext([(cg.bool_, "v")]) as control:
|
async with LambdaContext([(cg.bool_, "v")]) as control:
|
||||||
|
@ -43,6 +44,7 @@ async def to_code(config):
|
||||||
cond.else_()
|
cond.else_()
|
||||||
widget.clear_state(LV_STATE.CHECKED)
|
widget.clear_state(LV_STATE.CHECKED)
|
||||||
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
||||||
|
control.add(switch.publish_state(literal("v")))
|
||||||
async with LvContext(paren) as ctx:
|
async with LvContext(paren) as ctx:
|
||||||
lv_add(switch.set_control_lambda(await control.get_lambda()))
|
lv_add(switch.set_control_lambda(await control.get_lambda()))
|
||||||
ctx.add(
|
ctx.add(
|
||||||
|
|
|
@ -15,7 +15,7 @@ from ..lvcode import (
|
||||||
)
|
)
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LvText, lvgl_ns
|
from ..types import LV_EVENT, LvText, lvgl_ns
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
LVGLText = lvgl_ns.class_("LVGLText", text.Text)
|
LVGLText = lvgl_ns.class_("LVGLText", text.Text)
|
||||||
|
|
||||||
|
@ -32,9 +32,11 @@ async def to_code(config):
|
||||||
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext([(cg.std_string, "text_value")]) as control:
|
async with LambdaContext([(cg.std_string, "text_value")]) as control:
|
||||||
await widget.set_property("text", "text_value.c_str())")
|
await widget.set_property("text", "text_value.c_str())")
|
||||||
lv.event_send(widget.obj, API_EVENT, None)
|
lv.event_send(widget.obj, API_EVENT, None)
|
||||||
|
control.add(textvar.publish_state(widget.get_value()))
|
||||||
async with LambdaContext(EVENT_ARG) as lamb:
|
async with LambdaContext(EVENT_ARG) as lamb:
|
||||||
lv_add(textvar.publish_state(widget.get_value()))
|
lv_add(textvar.publish_state(widget.get_value()))
|
||||||
async with LvContext(paren):
|
async with LvContext(paren):
|
||||||
|
|
|
@ -10,7 +10,7 @@ from ..defines import CONF_LVGL_ID, CONF_WIDGET
|
||||||
from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext
|
from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext
|
||||||
from ..schemas import LVGL_SCHEMA
|
from ..schemas import LVGL_SCHEMA
|
||||||
from ..types import LV_EVENT, LvText
|
from ..types import LV_EVENT, LvText
|
||||||
from ..widgets import get_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
text_sensor_schema(TextSensor)
|
text_sensor_schema(TextSensor)
|
||||||
|
@ -28,6 +28,7 @@ async def to_code(config):
|
||||||
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
|
await wait_for_widgets()
|
||||||
async with LambdaContext(EVENT_ARG) as pressed_ctx:
|
async with LambdaContext(EVENT_ARG) as pressed_ctx:
|
||||||
pressed_ctx.add(sensor.publish_state(widget.get_value()))
|
pressed_ctx.add(sensor.publish_state(widget.get_value()))
|
||||||
async with LvContext(paren) as ctx:
|
async with LvContext(paren) as ctx:
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
|
@ -119,7 +118,14 @@ class Widget:
|
||||||
def clear_flag(self, flag):
|
def clear_flag(self, flag):
|
||||||
return lv_obj.clear_flag(self.obj, literal(flag))
|
return lv_obj.clear_flag(self.obj, literal(flag))
|
||||||
|
|
||||||
async def set_property(self, prop, value, animated: bool = None):
|
async def set_property(self, prop, value, animated: bool = None, lv_name=None):
|
||||||
|
"""
|
||||||
|
Set a property of the widget.
|
||||||
|
:param prop: The property name
|
||||||
|
:param value: The value
|
||||||
|
:param animated: If the change should be animated
|
||||||
|
:param lv_name: The base type of the widget e.g. "obj"
|
||||||
|
"""
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
value = value.get(prop)
|
value = value.get(prop)
|
||||||
if isinstance(ALL_STYLES.get(prop), LValidator):
|
if isinstance(ALL_STYLES.get(prop), LValidator):
|
||||||
|
@ -132,11 +138,12 @@ class Widget:
|
||||||
value = value.total_milliseconds
|
value = value.total_milliseconds
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = literal(value)
|
value = literal(value)
|
||||||
|
lv_name = lv_name or self.type.lv_name
|
||||||
if animated is None or self.type.animated is not True:
|
if animated is None or self.type.animated is not True:
|
||||||
lv.call(f"{self.type.lv_name}_set_{prop}", self.obj, value)
|
lv.call(f"{lv_name}_set_{prop}", self.obj, value)
|
||||||
else:
|
else:
|
||||||
lv.call(
|
lv.call(
|
||||||
f"{self.type.lv_name}_set_{prop}",
|
f"{lv_name}_set_{prop}",
|
||||||
self.obj,
|
self.obj,
|
||||||
value,
|
value,
|
||||||
literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"),
|
literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"),
|
||||||
|
@ -224,9 +231,17 @@ async def get_widget_(wid: Widget):
|
||||||
return await FakeAwaitable(get_widget_generator(wid))
|
return await FakeAwaitable(get_widget_generator(wid))
|
||||||
|
|
||||||
|
|
||||||
|
def widgets_wait_generator():
|
||||||
|
while True:
|
||||||
|
if Widget.widgets_completed:
|
||||||
|
return
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
async def wait_for_widgets():
|
async def wait_for_widgets():
|
||||||
while not Widget.widgets_completed:
|
if Widget.widgets_completed:
|
||||||
await asyncio.sleep(0)
|
return
|
||||||
|
await FakeAwaitable(widgets_wait_generator())
|
||||||
|
|
||||||
|
|
||||||
async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]:
|
async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]:
|
||||||
|
@ -312,8 +327,15 @@ async def set_obj_properties(w: Widget, config):
|
||||||
lv_obj.set_flex_align(w.obj, main, cross, track)
|
lv_obj.set_flex_align(w.obj, main, cross, track)
|
||||||
parts = collect_parts(config)
|
parts = collect_parts(config)
|
||||||
for part, states in parts.items():
|
for part, states in parts.items():
|
||||||
|
part = "LV_PART_" + part.upper()
|
||||||
for state, props in states.items():
|
for state, props in states.items():
|
||||||
lv_state = join_enums((f"LV_STATE_{state}", f"LV_PART_{part}"))
|
state = "LV_STATE_" + state.upper()
|
||||||
|
if state == "LV_STATE_DEFAULT":
|
||||||
|
lv_state = literal(part)
|
||||||
|
elif part == "LV_PART_MAIN":
|
||||||
|
lv_state = literal(state)
|
||||||
|
else:
|
||||||
|
lv_state = join_enums((state, part))
|
||||||
for style_id in props.get(CONF_STYLES, ()):
|
for style_id in props.get(CONF_STYLES, ()):
|
||||||
lv_obj.add_style(w.obj, MockObj(style_id), lv_state)
|
lv_obj.add_style(w.obj, MockObj(style_id), lv_state)
|
||||||
for prop, value in {
|
for prop, value in {
|
||||||
|
@ -377,7 +399,7 @@ async def set_obj_properties(w: Widget, config):
|
||||||
w.add_state(state)
|
w.add_state(state)
|
||||||
cond.else_()
|
cond.else_()
|
||||||
w.clear_state(state)
|
w.clear_state(state)
|
||||||
await w.set_property(CONF_SCROLLBAR_MODE, config)
|
await w.set_property(CONF_SCROLLBAR_MODE, config, lv_name="obj")
|
||||||
|
|
||||||
|
|
||||||
async def add_widgets(parent: Widget, config: dict):
|
async def add_widgets(parent: Widget, config: dict):
|
||||||
|
|
|
@ -27,6 +27,18 @@ enum MediaPlayerCommand : uint8_t {
|
||||||
};
|
};
|
||||||
const char *media_player_command_to_string(MediaPlayerCommand command);
|
const char *media_player_command_to_string(MediaPlayerCommand command);
|
||||||
|
|
||||||
|
enum class MediaPlayerFormatPurpose : uint8_t {
|
||||||
|
PURPOSE_DEFAULT = 0,
|
||||||
|
PURPOSE_ANNOUNCEMENT = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MediaPlayerSupportedFormat {
|
||||||
|
std::string format;
|
||||||
|
uint32_t sample_rate;
|
||||||
|
uint32_t num_channels;
|
||||||
|
MediaPlayerFormatPurpose purpose;
|
||||||
|
};
|
||||||
|
|
||||||
class MediaPlayer;
|
class MediaPlayer;
|
||||||
|
|
||||||
class MediaPlayerTraits {
|
class MediaPlayerTraits {
|
||||||
|
@ -37,8 +49,11 @@ class MediaPlayerTraits {
|
||||||
|
|
||||||
bool get_supports_pause() const { return this->supports_pause_; }
|
bool get_supports_pause() const { return this->supports_pause_; }
|
||||||
|
|
||||||
|
std::vector<MediaPlayerSupportedFormat> &get_supported_formats() { return this->supported_formats_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool supports_pause_{false};
|
bool supports_pause_{false};
|
||||||
|
std::vector<MediaPlayerSupportedFormat> supported_formats_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class MediaPlayerCall {
|
class MediaPlayerCall {
|
||||||
|
|
|
@ -431,6 +431,7 @@ CONF_LIGHT_ID = "light_id"
|
||||||
CONF_LIGHTNING_ENERGY = "lightning_energy"
|
CONF_LIGHTNING_ENERGY = "lightning_energy"
|
||||||
CONF_LIGHTNING_THRESHOLD = "lightning_threshold"
|
CONF_LIGHTNING_THRESHOLD = "lightning_threshold"
|
||||||
CONF_LIMIT_MODE = "limit_mode"
|
CONF_LIMIT_MODE = "limit_mode"
|
||||||
|
CONF_LINE_FREQUENCY = "line_frequency"
|
||||||
CONF_LINE_THICKNESS = "line_thickness"
|
CONF_LINE_THICKNESS = "line_thickness"
|
||||||
CONF_LINE_TYPE = "line_type"
|
CONF_LINE_TYPE = "line_type"
|
||||||
CONF_LOADED_INTEGRATIONS = "loaded_integrations"
|
CONF_LOADED_INTEGRATIONS = "loaded_integrations"
|
||||||
|
|
22
tests/components/bl0942/test.bk72xx-ard.yaml
Normal file
22
tests/components/bl0942/test.bk72xx-ard.yaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
uart:
|
||||||
|
- id: uart_bl0942
|
||||||
|
tx_pin:
|
||||||
|
number: TX1
|
||||||
|
rx_pin:
|
||||||
|
number: RX1
|
||||||
|
baud_rate: 2400
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: bl0942
|
||||||
|
address: 0
|
||||||
|
line_frequency: 50Hz
|
||||||
|
voltage:
|
||||||
|
name: BL0942 Voltage
|
||||||
|
current:
|
||||||
|
name: BL0942 Current
|
||||||
|
power:
|
||||||
|
name: BL0942 Power
|
||||||
|
energy:
|
||||||
|
name: BL0942 Energy
|
||||||
|
frequency:
|
||||||
|
name: BL0942 Frequency
|
|
@ -19,6 +19,7 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- platform: ili9xxx
|
- platform: ili9xxx
|
||||||
|
invert_colors: false
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 240
|
height: 240
|
||||||
|
|
|
@ -20,6 +20,7 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- platform: ili9xxx
|
- platform: ili9xxx
|
||||||
|
invert_colors: false
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 240
|
height: 240
|
||||||
|
|
|
@ -20,6 +20,7 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- platform: ili9xxx
|
- platform: ili9xxx
|
||||||
|
invert_colors: false
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 240
|
height: 240
|
||||||
|
|
|
@ -20,6 +20,7 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- platform: ili9xxx
|
- platform: ili9xxx
|
||||||
|
invert_colors: false
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 240
|
height: 240
|
||||||
|
|
|
@ -20,6 +20,7 @@ display:
|
||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- platform: ili9xxx
|
- platform: ili9xxx
|
||||||
|
invert_colors: false
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 240
|
height: 240
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
lvgl:
|
lvgl:
|
||||||
log_level: TRACE
|
log_level: TRACE
|
||||||
bg_color: light_blue
|
bg_color: light_blue
|
||||||
|
disp_bg_color: 0xffff00
|
||||||
|
disp_bg_image: cat_image
|
||||||
theme:
|
theme:
|
||||||
obj:
|
obj:
|
||||||
border_width: 1
|
border_width: 1
|
||||||
|
@ -78,6 +80,9 @@ lvgl:
|
||||||
on_click:
|
on_click:
|
||||||
then:
|
then:
|
||||||
- lvgl.animimg.stop: anim_img
|
- lvgl.animimg.stop: anim_img
|
||||||
|
- lvgl.update:
|
||||||
|
disp_bg_color: 0xffff00
|
||||||
|
disp_bg_image: cat_image
|
||||||
- label:
|
- label:
|
||||||
text: "Hello shiny day"
|
text: "Hello shiny day"
|
||||||
text_color: 0xFFFFFF
|
text_color: 0xFFFFFF
|
||||||
|
@ -304,6 +309,17 @@ lvgl:
|
||||||
src: cat_image
|
src: cat_image
|
||||||
align: top_left
|
align: top_left
|
||||||
y: 50
|
y: 50
|
||||||
|
- tileview:
|
||||||
|
id: tileview_id
|
||||||
|
scrollbar_mode: active
|
||||||
|
tiles:
|
||||||
|
- id: page_1
|
||||||
|
row: 0
|
||||||
|
column: 0
|
||||||
|
dir: HOR
|
||||||
|
widgets:
|
||||||
|
- obj:
|
||||||
|
bg_color: 0x000000
|
||||||
|
|
||||||
- id: page2
|
- id: page2
|
||||||
widgets:
|
widgets:
|
||||||
|
|
Loading…
Reference in a new issue