mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 23:14:54 +01:00
si4713 commands, properties
This commit is contained in:
parent
0c7c84011a
commit
8033ef48a8
20 changed files with 2415 additions and 0 deletions
131
esphome/components/si4713_i2c/__init__.py
Normal file
131
esphome/components/si4713_i2c/__init__.py
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import automation, pins
|
||||||
|
from esphome.components import i2c, sensor, text_sensor
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_FREQUENCY,
|
||||||
|
UNIT_EMPTY,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
ICON_CHIP,
|
||||||
|
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODEOWNERS = ["@gabest11"]
|
||||||
|
DEPENDENCIES = ["i2c"]
|
||||||
|
AUTO_LOAD = ["sensor", "text_sensor", "number", "switch", "select", "text"]
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
|
UNIT_MEGA_HERTZ = "MHz"
|
||||||
|
UNIT_KILO_HERTZ = "kHz"
|
||||||
|
UNIT_MILLI_VOLT = "mV"
|
||||||
|
UNIT_MICRO_AMPERE = "mA"
|
||||||
|
UNIT_DECIBEL_MICRO_VOLT = "dBµV"
|
||||||
|
|
||||||
|
ICON_VOLUME_MUTE = "mdi:volume-mute"
|
||||||
|
ICON_EAR_HEARING = "mdi:ear-hearing"
|
||||||
|
ICON_RADIO_TOWER = "mdi:radio-tower"
|
||||||
|
ICON_SLEEP = "mdi:sleep"
|
||||||
|
ICON_SINE_WAVE = "mdi:sine-wave"
|
||||||
|
ICON_RESISTOR = "mdi:resistor"
|
||||||
|
ICON_FORMAT_TEXT = "mdi:format-text"
|
||||||
|
|
||||||
|
si4713_ns = cg.esphome_ns.namespace("si4713")
|
||||||
|
Si4713Component = si4713_ns.class_(
|
||||||
|
"Si4713Component", cg.PollingComponent, i2c.I2CDevice
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_SI4713_ID = "si4713_id"
|
||||||
|
CONF_RESET_PIN = "reset_pin"
|
||||||
|
CONF_FREQUENCY_DEVIATION = "frequency_deviation"
|
||||||
|
CONF_MUTE = "mute"
|
||||||
|
CONF_MONO = "mono"
|
||||||
|
CONF_TX_ENABLE = "tx_enable"
|
||||||
|
CONF_TX_PILOT = "tx_pilot"
|
||||||
|
CONF_T1M_SEL = "t1m_sel"
|
||||||
|
CONF_PRIV_EN = "priv_en"
|
||||||
|
CONF_PRE_EMPHASIS = "pre_emphasis"
|
||||||
|
CONF_XTAL_SOURCE = "xtal_source"
|
||||||
|
CONF_XTAL_CURRENT = "xtal_current"
|
||||||
|
CONF_XTAL_FREQUENCY = "xtal_frequency"
|
||||||
|
CONF_INPUT_IMPEDANCE = "input_impedance"
|
||||||
|
CONF_INPUT_GAIN = "input_gain"
|
||||||
|
CONF_DIGITAL_GAIN = "digital_gain"
|
||||||
|
CONF_POWER_TARGET = "power_target"
|
||||||
|
CONF_RDS_ENABLE = "rds_enable"
|
||||||
|
CONF_RDS_FREQUENCY_DEVIATION = "rds_frequency_deviation"
|
||||||
|
CONF_RDS_STATION = "rds_station"
|
||||||
|
CONF_RDS_TEXT = "rds_text"
|
||||||
|
CONF_AUD_PK = "aud_pk"
|
||||||
|
CONF_FSM = "fsm"
|
||||||
|
CONF_CHIP_ID = "chip_id"
|
||||||
|
CONF_REG30 = "reg30"
|
||||||
|
|
||||||
|
SetFrequencyAction = si4713_ns.class_(
|
||||||
|
"SetFrequencyAction", automation.Action, cg.Parented.template(Si4713Component)
|
||||||
|
)
|
||||||
|
|
||||||
|
#T1mSel = si4713_ns.enum("T1mSel", True)
|
||||||
|
#T1M_SEL = {
|
||||||
|
# "58s": T1mSel.T1M_SEL_58S,
|
||||||
|
# "59s": T1mSel.T1M_SEL_59S,
|
||||||
|
# "60s": T1mSel.T1M_SEL_60S,
|
||||||
|
# "Never": T1mSel.T1M_SEL_NEVER,
|
||||||
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(Si4713Component),
|
||||||
|
cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Optional(CONF_FREQUENCY, default=87.50): cv.float_range(76, 108),
|
||||||
|
cv.Optional(CONF_MUTE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_MONO, default=False): cv.boolean,
|
||||||
|
# cv.Optional(CONF_T1M_SEL, default="60s"): cv.enum(T1M_SEL),
|
||||||
|
cv.Optional(CONF_RDS_ENABLE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_RDS_STATION): cv.string,
|
||||||
|
cv.Optional(CONF_RDS_TEXT): cv.string,
|
||||||
|
cv.Optional(CONF_CHIP_ID): text_sensor.text_sensor_schema(
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
icon=ICON_CHIP,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
.extend(i2c.i2c_device_schema(0x63))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def set_var(config, id, setter):
|
||||||
|
if c := config.get(id):
|
||||||
|
cg.add(setter(c))
|
||||||
|
|
||||||
|
|
||||||
|
async def set_sensor(config, id, setter):
|
||||||
|
if c := config.get(id):
|
||||||
|
s = await sensor.new_sensor(c)
|
||||||
|
cg.add(setter(s))
|
||||||
|
|
||||||
|
|
||||||
|
async def set_text_sensor(config, id, setter):
|
||||||
|
if c := config.get(id):
|
||||||
|
s = await text_sensor.new_text_sensor(c)
|
||||||
|
cg.add(setter(s))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await i2c.register_i2c_device(var, config)
|
||||||
|
reset_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
|
||||||
|
cg.add(var.set_reset_pin(reset_pin))
|
||||||
|
await set_var(config, CONF_FREQUENCY, var.set_frequency)
|
||||||
|
await set_var(config, CONF_MUTE, var.set_mute)
|
||||||
|
await set_var(config, CONF_MONO, var.set_mono)
|
||||||
|
# await set_var(config, CONF_T1M_SEL, var.set_t1m_sel)
|
||||||
|
await set_var(config, CONF_RDS_ENABLE, var.set_rds_enable)
|
||||||
|
await set_var(config, CONF_RDS_STATION, var.set_rds_station)
|
||||||
|
await set_var(config, CONF_RDS_TEXT, var.set_rds_text)
|
||||||
|
await set_text_sensor(config, CONF_CHIP_ID, var.set_chip_id_text_sensor)
|
51
esphome/components/si4713_i2c/number/__init__.py
Normal file
51
esphome/components/si4713_i2c/number/__init__.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import number
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_FREQUENCY,
|
||||||
|
UNIT_PERCENT,
|
||||||
|
UNIT_DECIBEL,
|
||||||
|
DEVICE_CLASS_FREQUENCY,
|
||||||
|
DEVICE_CLASS_CURRENT,
|
||||||
|
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||||
|
DEVICE_CLASS_EMPTY,
|
||||||
|
ENTITY_CATEGORY_CONFIG,
|
||||||
|
)
|
||||||
|
from .. import (
|
||||||
|
CONF_SI4713_ID,
|
||||||
|
Si4713Component,
|
||||||
|
si4713_ns,
|
||||||
|
# CONF_,
|
||||||
|
UNIT_MEGA_HERTZ,
|
||||||
|
UNIT_KILO_HERTZ,
|
||||||
|
UNIT_MICRO_AMPERE,
|
||||||
|
UNIT_DECIBEL_MICRO_VOLT,
|
||||||
|
)
|
||||||
|
|
||||||
|
FrequencyNumber = si4713_ns.class_("FrequencyNumber", number.Number)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
|
||||||
|
cv.Optional(CONF_FREQUENCY): number.number_schema(
|
||||||
|
FrequencyNumber,
|
||||||
|
unit_of_measurement=UNIT_MEGA_HERTZ,
|
||||||
|
device_class=DEVICE_CLASS_FREQUENCY,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_number(config, id, setter, min_value, max_value, step, *args):
|
||||||
|
if c := config.get(id):
|
||||||
|
n = await number.new_number(
|
||||||
|
c, *args, min_value=min_value, max_value=max_value, step=step
|
||||||
|
)
|
||||||
|
await cg.register_parented(n, config[CONF_SI4713_ID])
|
||||||
|
cg.add(setter(n))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
c = await cg.get_variable(config[CONF_SI4713_ID])
|
||||||
|
await new_number(config, CONF_FREQUENCY, c.set_frequency_number, 76, 108, 0.05)
|
12
esphome/components/si4713_i2c/number/frequency_number.cpp
Normal file
12
esphome/components/si4713_i2c/number/frequency_number.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "frequency_number.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void FrequencyNumber::control(float value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_frequency(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/number/frequency_number.h
Normal file
18
esphome/components/si4713_i2c/number/frequency_number.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/number/number.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class FrequencyNumber : public number::Number, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
FrequencyNumber() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(float value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
42
esphome/components/si4713_i2c/select/__init__.py
Normal file
42
esphome/components/si4713_i2c/select/__init__.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import select
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
ENTITY_CATEGORY_CONFIG,
|
||||||
|
ICON_PULSE,
|
||||||
|
)
|
||||||
|
from .. import (
|
||||||
|
CONF_SI4713_ID,
|
||||||
|
Si4713Component,
|
||||||
|
si4713_ns,
|
||||||
|
CONF_,
|
||||||
|
ICON_SLEEP,
|
||||||
|
ICON_SINE_WAVE,
|
||||||
|
ICON_RESISTOR,
|
||||||
|
# T1M_SEL,
|
||||||
|
)
|
||||||
|
|
||||||
|
#T1mSelSelect = si4713_ns.class_("T1mSelSelect", select.Select)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
|
||||||
|
# cv.Optional(CONF_T1M_SEL): select.select_schema(
|
||||||
|
# T1mSelSelect,
|
||||||
|
# entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
# icon=ICON_SLEEP,
|
||||||
|
# ),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_select(config, id, setter, options):
|
||||||
|
if c := config.get(id):
|
||||||
|
s = await select.new_select(c, options=list(options.keys()))
|
||||||
|
await cg.register_parented(s, config[CONF_SI4713_ID])
|
||||||
|
cg.add(setter(s))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
c = await cg.get_variable(config[CONF_SI4713_ID])
|
||||||
|
# await new_select(config, CONF_T1M_SEL, c.set_t1m_sel_select, T1M_SEL)
|
400
esphome/components/si4713_i2c/si4713.cpp
Normal file
400
esphome/components/si4713_i2c/si4713.cpp
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
#include "si4713.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
// TODO: std::clamp isn't here yet
|
||||||
|
#define clamp(v, lo, hi) std::max(std::min(v, hi), lo)
|
||||||
|
|
||||||
|
static const char *const TAG = "si4713";
|
||||||
|
|
||||||
|
Si4713Component::Si4713Component() {
|
||||||
|
this->reset_pin_ = nullptr;
|
||||||
|
this->reset_ = false;
|
||||||
|
// memset(&this->state_, 0, sizeof(this->state_));
|
||||||
|
this->rds_station_pos_ = 0;
|
||||||
|
this->rds_text_pos_ = 0;
|
||||||
|
// this->state_. = ;
|
||||||
|
// our defaults
|
||||||
|
// this->state_. = ; // start with tx enabled
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void Si4713Component::write_reg_(uint8_t addr) {
|
||||||
|
switch (addr) {
|
||||||
|
case 0x00: // REG_..
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "write_reg_(0x%02X) invalid register address", addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->reset_) {
|
||||||
|
uint8_t value = this->regs_[addr];
|
||||||
|
ESP_LOGV(TAG, "write_reg_(0x%02X) = 0x%02X", addr, value);
|
||||||
|
this->write_byte(addr, value);
|
||||||
|
} else {
|
||||||
|
if (this->get_component_state() & COMPONENT_STATE_LOOP) {
|
||||||
|
ESP_LOGE(TAG, "write_reg_(0x%02X) device was not reset", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::read_reg_(uint8_t addr) {
|
||||||
|
switch (addr) {
|
||||||
|
case 0x00: // REG_..
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "read_reg_(0x%02X) trying to read invalid register", addr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto b = this->read_byte(addr)) {
|
||||||
|
this->regs_[addr] = *b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGE(TAG, "read_reg_(0x%02X) cannot read register", addr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size) {
|
||||||
|
const uint8_t *buff = (const uint8_t *) cmd;
|
||||||
|
|
||||||
|
if (!this->reset_) {
|
||||||
|
if (this->get_component_state() & COMPONENT_STATE_LOOP) {
|
||||||
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) device was not reset", buff[0], cmd_size);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c::ErrorCode err = this->write(buff, cmd_size);
|
||||||
|
if (err != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) write error", buff[0], cmd_size);
|
||||||
|
this->mark_failed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t status = 0;
|
||||||
|
while (!(status & SI4710_STATUS_CTS)) {
|
||||||
|
err = this->read(&status, 1); // TODO: read res_size into res here?
|
||||||
|
if (err != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read status error", buff[0], cmd_size);
|
||||||
|
this->mark_failed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != nullptr) {
|
||||||
|
//((uint8_t*) res)[0] = status;
|
||||||
|
err = this->read((uint8_t *) res, res_size);
|
||||||
|
if (err != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "send_cmd(0x%02X, %d) read response error", buff[0], cmd_size);
|
||||||
|
this->mark_failed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::power_up() {
|
||||||
|
// Note: In FMTX component 1.0 and 2.0, a reset is required when the system controller writes a command other than
|
||||||
|
// POWER_UP when in powerdown mode
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
delay_microseconds_safe(10);
|
||||||
|
this->reset_pin_->digital_write(false);
|
||||||
|
delay_microseconds_safe(10);
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
|
||||||
|
CmdPowerUp cmd;
|
||||||
|
cmd.FUNC = 2;
|
||||||
|
cmd.XOSCEN = 1; // TODO: external oscillator
|
||||||
|
cmd.OPMODE = 0x50; // TODO: digital
|
||||||
|
cmd.GPO2OEN = 0; // TODO: GPIO2 enable
|
||||||
|
return this->send_cmd(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::power_down() { return this->send_cmd(CmdPowerDown()); }
|
||||||
|
|
||||||
|
bool Si4713Component::detect_chip_id() {
|
||||||
|
ResGetRev res;
|
||||||
|
if (!this->send_cmd(CmdGetRev(), res)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buff[32] = {0};
|
||||||
|
snprintf(buff, sizeof(buff), "Si47%02d Rev %d", res.PN, res.CHIPREV);
|
||||||
|
this->chip_id_ = buff;
|
||||||
|
|
||||||
|
// TODO: support all transmitters 10/11/12/13/20/21
|
||||||
|
|
||||||
|
if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) {
|
||||||
|
ESP_LOGE(TAG, "Si47%02d is not supported", res.PN);
|
||||||
|
this->mark_failed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_power(uint8_t power, uint8_t antcap) {
|
||||||
|
if (!this->send_cmd(CmdTxTunePower(power, antcap))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->tune_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_freq(uint16_t freq) {
|
||||||
|
if (!this->send_cmd(CmdTxTuneFreq(freq))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->tune_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::tune_ready() {
|
||||||
|
ResGetIntStatus res;
|
||||||
|
while (res.CTS != 1 || res.STCINT != 1) {
|
||||||
|
if (!this->send_cmd(CmdGetIntStatus(), res)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::rds_update_() {}
|
||||||
|
|
||||||
|
// overrides
|
||||||
|
|
||||||
|
void Si4713Component::setup() {
|
||||||
|
if (this->reset_pin_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "setup cannot reset device, reset pin is not set");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset
|
||||||
|
|
||||||
|
this->reset_ = true;
|
||||||
|
this->reset_pin_->setup();
|
||||||
|
|
||||||
|
if (!this->power_up()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->detect_chip_id()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->set_prop(PropRefClkFreq(32768));
|
||||||
|
this->set_prop(PropTxPreEmphasis());
|
||||||
|
/*
|
||||||
|
// configuration! see page 254
|
||||||
|
setProperty(SI4713_PROP_REFCLK_FREQ, 32768); // crystal is 32.768
|
||||||
|
setProperty(SI4713_PROP_TX_PREEMPHASIS, 0); // 74uS pre-emph (USA std)
|
||||||
|
setProperty(SI4713_PROP_TX_ACOMP_GAIN, 10); // max gain?
|
||||||
|
// setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x02); // turn on limiter, but no
|
||||||
|
// dynamic ranging
|
||||||
|
setProperty(SI4713_PROP_TX_ACOMP_ENABLE, 0x0); // turn on limiter and AGC
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: set properties
|
||||||
|
|
||||||
|
this->tune_power(115);
|
||||||
|
this->tune_freq(8750);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
this->publish_frequency();
|
||||||
|
this->publish_mute();
|
||||||
|
this->publish_mono();
|
||||||
|
this->publish_rds_enable();
|
||||||
|
this->publish_rds_station();
|
||||||
|
this->publish_rds_text();
|
||||||
|
|
||||||
|
this->set_interval(1000, [this]() { this->rds_update_(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Si4713:");
|
||||||
|
LOG_I2C_DEVICE(this);
|
||||||
|
if (this->is_failed()) {
|
||||||
|
ESP_LOGE(TAG, "failed!");
|
||||||
|
}
|
||||||
|
ESP_LOGCONFIG(TAG, " Chip: %s", this->chip_id_.c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Frequency: %.2f MHz", this->get_frequency());
|
||||||
|
ESP_LOGCONFIG(TAG, " RDS station: %s", this->rds_station_.c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " RDS text: %s", this->rds_text_.c_str());
|
||||||
|
// TODO: ...and everything else...
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::update() {
|
||||||
|
/*
|
||||||
|
if (this->read_reg_(REG_)) {
|
||||||
|
this->publish_();
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "update cannot read the status register");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::loop() {}
|
||||||
|
|
||||||
|
// config
|
||||||
|
|
||||||
|
void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
|
||||||
|
|
||||||
|
void Si4713Component::set_frequency(float value) {
|
||||||
|
if (!(CH_FREQ_MIN <= value && value <= CH_FREQ_MAX)) {
|
||||||
|
ESP_LOGE(TAG, "set_frequency(%.2f) invalid (%.2f - %.2f)", value, CH_FREQ_MIN, CH_FREQ_MAX);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int f = clamp((int) std::lround((value - 76) * 20), CH_FREQ_RAW_MIN, CH_FREQ_RAW_MAX);
|
||||||
|
// this->state_.CH_UPPER = (uint8_t) (f >> 8);
|
||||||
|
// this->state_.CH_LOWER = (uint8_t) (f & 0xff);
|
||||||
|
// this->write_reg_(REG_SYSTEM_ADDR);
|
||||||
|
// this->write_reg_(REG_CH1_ADDR);
|
||||||
|
|
||||||
|
this->publish_frequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Si4713Component::get_frequency() {
|
||||||
|
// uint16_t ch = ((uint16_t) this->state_.CH_UPPER << 8) | this->state_.CH_LOWER;
|
||||||
|
// return (float) ch / 20 + 76;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_mute(bool value) {
|
||||||
|
// this->state_.MUTE = value ? 1 : 0;
|
||||||
|
// this->write_reg_(REG_SYSTEM_ADDR);
|
||||||
|
|
||||||
|
this->publish_mute();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::get_mute() {
|
||||||
|
// return this->state_.MUTE == 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_mono(bool value) {
|
||||||
|
// this->state_.MONO = value ? 1 : 0;
|
||||||
|
// this->write_reg_(REG_SYSTEM_ADDR);
|
||||||
|
|
||||||
|
this->publish_mono();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::get_mono() {
|
||||||
|
// return this->state_.MONO == 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_rds_enable(bool value) {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
this->publish_rds_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si4713Component::get_rds_enable() {
|
||||||
|
// return this->state_.RDSEN == 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_rds_station(const std::string &value) {
|
||||||
|
this->rds_station_ = value;
|
||||||
|
this->rds_station_pos_ = 0;
|
||||||
|
if (this->rds_station_.size() > RDS_STATION_MAX) {
|
||||||
|
ESP_LOGW(TAG, "rds station too long '%s' (max %d characters)", value.c_str(), RDS_STATION_MAX);
|
||||||
|
this->rds_station_.resize(RDS_STATION_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->publish_rds_station();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::set_rds_text(const std::string &value) {
|
||||||
|
this->rds_text_ = value;
|
||||||
|
this->rds_text_pos_ = 0;
|
||||||
|
if (this->rds_text_.size() > RDS_TEXT_MAX) {
|
||||||
|
ESP_LOGW(TAG, "rds text to long '%s' (max %d characters)", value.c_str(), RDS_TEXT_MAX);
|
||||||
|
this->rds_text_.resize(RDS_TEXT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->publish_rds_text();
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish
|
||||||
|
|
||||||
|
void Si4713Component::publish_() {
|
||||||
|
// this->publish(this->_sensor_, this->state_.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish_chip_id() { this->publish(this->chip_id_text_sensor_, this->chip_id_); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_frequency() { this->publish(this->frequency_number_, this->get_frequency()); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_mute() { this->publish(this->mute_switch_, this->get_mute()); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_mono() { this->publish(this->mono_switch_, this->get_mono()); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_rds_enable() { this->publish(this->rds_enable_switch_, this->get_rds_enable()); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_rds_station() { this->publish(this->rds_station_text_, this->rds_station_); }
|
||||||
|
|
||||||
|
void Si4713Component::publish_rds_text() { this->publish(this->rds_text_text_, this->rds_text_); }
|
||||||
|
|
||||||
|
void Si4713Component::publish(text_sensor::TextSensor *s, const std::string &state) {
|
||||||
|
if (s != nullptr) {
|
||||||
|
if (!s->has_state() || s->state != state) {
|
||||||
|
s->publish_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish(sensor::Sensor *s, float state) {
|
||||||
|
if (s != nullptr) {
|
||||||
|
if (!s->has_state() || s->state != state) {
|
||||||
|
s->publish_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish(number::Number *n, float state) {
|
||||||
|
if (n != nullptr) {
|
||||||
|
if (!n->has_state() || n->state != state) {
|
||||||
|
n->publish_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish(switch_::Switch *s, bool state) {
|
||||||
|
if (s != nullptr) {
|
||||||
|
if (s->state != state) { // ?
|
||||||
|
s->publish_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish(select::Select *s, size_t index) {
|
||||||
|
if (s != nullptr) {
|
||||||
|
if (auto state = s->at(index)) {
|
||||||
|
if (!s->has_state() || s->state != *state) {
|
||||||
|
s->publish_state(*state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Si4713Component::publish(text::Text *t, const std::string &state) {
|
||||||
|
if (t != nullptr) {
|
||||||
|
if (!t->has_state() || t->state != state) {
|
||||||
|
t->publish_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
130
esphome/components/si4713_i2c/si4713.h
Normal file
130
esphome/components/si4713_i2c/si4713.h
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/gpio.h"
|
||||||
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/text_sensor/text_sensor.h"
|
||||||
|
#include "esphome/components/number/number.h"
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "esphome/components/select/select.h"
|
||||||
|
#include "esphome/components/text/text.h"
|
||||||
|
#include <string>
|
||||||
|
#include "si4713defs.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
#ifndef SUB_TEXT
|
||||||
|
#define SUB_TEXT(name) \
|
||||||
|
protected: \
|
||||||
|
text::Text *name##_text_{nullptr}; \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
void set_##name##_text(text::Text *text) { this->name##_text_ = text; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Si4713Component : public PollingComponent, public i2c::I2CDevice {
|
||||||
|
std::string chip_id_;
|
||||||
|
InternalGPIOPin *reset_pin_;
|
||||||
|
bool reset_;
|
||||||
|
/*
|
||||||
|
union {
|
||||||
|
struct Si4713State state_;
|
||||||
|
uint8_t regs_[sizeof(struct Si4713State)];
|
||||||
|
};
|
||||||
|
|
||||||
|
void write_reg_(uint8_t addr);
|
||||||
|
bool read_reg_(uint8_t addr);
|
||||||
|
*/
|
||||||
|
bool send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size);
|
||||||
|
|
||||||
|
template<typename CMD> bool send_cmd(const CMD &cmd) {
|
||||||
|
return this->send_cmd((const void *) &cmd, sizeof(cmd), nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename CMD, typename RES> bool send_cmd(CMD cmd, RES &res) {
|
||||||
|
return this->send_cmd((const void *) &cmd, sizeof(cmd), (void *) &res, sizeof(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P> bool set_prop(P p) {
|
||||||
|
CmdSetProperty cmd = CmdSetProperty(p.PROP, p.PROPD);
|
||||||
|
return this->send_cmd(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P> bool get_prop(P &p) {
|
||||||
|
ResGetProperty res;
|
||||||
|
if (this->send_cmd(CmdGetProperty(p.PROP), res)) {
|
||||||
|
p.PROPD = ((uint16_t) res.PROPDH << 8) | res.PROPDL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool power_up();
|
||||||
|
bool power_down();
|
||||||
|
bool detect_chip_id();
|
||||||
|
bool tune_power(uint8_t power = 0, uint8_t antcap = 0);
|
||||||
|
bool tune_freq(uint16_t freq);
|
||||||
|
bool tune_ready();
|
||||||
|
|
||||||
|
std::string rds_station_;
|
||||||
|
std::string rds_text_;
|
||||||
|
uint8_t rds_station_pos_;
|
||||||
|
uint8_t rds_text_pos_;
|
||||||
|
uint8_t rds_upd_;
|
||||||
|
|
||||||
|
void rds_update_();
|
||||||
|
|
||||||
|
SUB_TEXT_SENSOR(chip_id)
|
||||||
|
// TODO: sensors TX_TUNE_STATUS / FREQ, RFuV, ANTCAP, NL
|
||||||
|
// TODO: sensors TX_ASQ_STATUS / OVERMOD, IALH, IALL, INLEVEL
|
||||||
|
SUB_NUMBER(frequency)
|
||||||
|
SUB_SWITCH(mute)
|
||||||
|
SUB_SWITCH(mono)
|
||||||
|
SUB_SWITCH(rds_enable)
|
||||||
|
SUB_TEXT(rds_station)
|
||||||
|
SUB_TEXT(rds_text)
|
||||||
|
// TODO: GPIO switches
|
||||||
|
|
||||||
|
void publish_();
|
||||||
|
void publish_chip_id();
|
||||||
|
void publish_frequency();
|
||||||
|
void publish_mute();
|
||||||
|
void publish_mono();
|
||||||
|
void publish_rds_enable();
|
||||||
|
void publish_rds_station();
|
||||||
|
void publish_rds_text();
|
||||||
|
void publish(sensor::Sensor *s, float state);
|
||||||
|
void publish(text_sensor::TextSensor *s, const std::string &state);
|
||||||
|
void publish(number::Number *n, float state);
|
||||||
|
void publish(switch_::Switch *s, bool state);
|
||||||
|
void publish(select::Select *s, size_t index);
|
||||||
|
void publish(text::Text *t, const std::string &state);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Si4713Component();
|
||||||
|
|
||||||
|
// float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void update() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
void set_reset_pin(InternalGPIOPin *pin);
|
||||||
|
void set_frequency(float value);
|
||||||
|
float get_frequency();
|
||||||
|
void set_mute(bool value);
|
||||||
|
bool get_mute();
|
||||||
|
void set_mono(bool value);
|
||||||
|
bool get_mono();
|
||||||
|
void set_rds_enable(bool value);
|
||||||
|
bool get_rds_enable();
|
||||||
|
void set_rds_station(const std::string &value);
|
||||||
|
void set_rds_text(const std::string &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
1266
esphome/components/si4713_i2c/si4713defs.h
Normal file
1266
esphome/components/si4713_i2c/si4713defs.h
Normal file
File diff suppressed because it is too large
Load diff
61
esphome/components/si4713_i2c/switch/__init__.py
Normal file
61
esphome/components/si4713_i2c/switch/__init__.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import switch
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
DEVICE_CLASS_SWITCH,
|
||||||
|
ENTITY_CATEGORY_CONFIG,
|
||||||
|
ICON_SECURITY,
|
||||||
|
)
|
||||||
|
from .. import (
|
||||||
|
CONF_SI4713_ID,
|
||||||
|
Si4713Component,
|
||||||
|
si4713_ns,
|
||||||
|
CONF_MUTE,
|
||||||
|
CONF_MONO,
|
||||||
|
CONF_RDS_ENABLE,
|
||||||
|
ICON_VOLUME_MUTE,
|
||||||
|
ICON_EAR_HEARING,
|
||||||
|
ICON_FORMAT_TEXT,
|
||||||
|
)
|
||||||
|
|
||||||
|
MuteSwitch = si4713_ns.class_("MuteSwitch", switch.Switch)
|
||||||
|
MonoSwitch = si4713_ns.class_("MonoSwitch", switch.Switch)
|
||||||
|
RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
|
||||||
|
cv.Optional(CONF_MUTE): switch.switch_schema(
|
||||||
|
MuteSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon=ICON_VOLUME_MUTE,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_MONO): switch.switch_schema(
|
||||||
|
MonoSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon=ICON_EAR_HEARING,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_RDS_ENABLE): switch.switch_schema(
|
||||||
|
RDSEnableSwitch,
|
||||||
|
device_class=DEVICE_CLASS_SWITCH,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon=ICON_FORMAT_TEXT,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_switch(config, id, setter):
|
||||||
|
if c := config.get(id):
|
||||||
|
s = await switch.new_switch(c)
|
||||||
|
await cg.register_parented(s, config[CONF_SI4713_ID])
|
||||||
|
cg.add(setter(s))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
c = await cg.get_variable(config[CONF_SI4713_ID])
|
||||||
|
await new_switch(config, CONF_MUTE, c.set_mute_switch)
|
||||||
|
await new_switch(config, CONF_MONO, c.set_mono_switch)
|
||||||
|
await new_switch(config, CONF_RDS_ENABLE, c.set_rds_enable_switch)
|
12
esphome/components/si4713_i2c/switch/mono_switch.cpp
Normal file
12
esphome/components/si4713_i2c/switch/mono_switch.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "mono_switch.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void MonoSwitch::write_state(bool value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_mono(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/switch/mono_switch.h
Normal file
18
esphome/components/si4713_i2c/switch/mono_switch.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class MonoSwitch : public switch_::Switch, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
MonoSwitch() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
12
esphome/components/si4713_i2c/switch/mute_switch.cpp
Normal file
12
esphome/components/si4713_i2c/switch/mute_switch.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "mute_switch.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void MuteSwitch::write_state(bool value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_mute(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/switch/mute_switch.h
Normal file
18
esphome/components/si4713_i2c/switch/mute_switch.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class MuteSwitch : public switch_::Switch, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
MuteSwitch() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
12
esphome/components/si4713_i2c/switch/rds_enable_switch.cpp
Normal file
12
esphome/components/si4713_i2c/switch/rds_enable_switch.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "rds_enable_switch.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void RDSEnableSwitch::write_state(bool value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_rds_enable(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/switch/rds_enable_switch.h
Normal file
18
esphome/components/si4713_i2c/switch/rds_enable_switch.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class RDSEnableSwitch : public switch_::Switch, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
RDSEnableSwitch() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
154
esphome/components/si4713_i2c/text/__init__.py
Normal file
154
esphome/components/si4713_i2c/text/__init__.py
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
from typing import Optional
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import text
|
||||||
|
from esphome.components import mqtt, web_server
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_ENTITY_CATEGORY,
|
||||||
|
CONF_ICON,
|
||||||
|
CONF_MQTT_ID,
|
||||||
|
CONF_WEB_SERVER,
|
||||||
|
ENTITY_CATEGORY_CONFIG,
|
||||||
|
)
|
||||||
|
from esphome.core import CORE
|
||||||
|
from esphome.cpp_generator import MockObjClass
|
||||||
|
from esphome.cpp_helpers import setup_entity
|
||||||
|
from .. import (
|
||||||
|
CONF_SI4713_ID,
|
||||||
|
Si4713Component,
|
||||||
|
si4713_ns,
|
||||||
|
CONF_RDS_STATION,
|
||||||
|
CONF_RDS_TEXT,
|
||||||
|
ICON_FORMAT_TEXT,
|
||||||
|
)
|
||||||
|
|
||||||
|
RDSStationText = si4713_ns.class_("RDSStationText", text.Text)
|
||||||
|
RDSTextText = si4713_ns.class_("RDSTextText", text.Text)
|
||||||
|
|
||||||
|
# The text component isn't implemented the same way as switch, select, number.
|
||||||
|
# It is not possible to create our own text platform as it is now, so I adopted
|
||||||
|
# the necessary code from those.
|
||||||
|
|
||||||
|
_TEXT_SCHEMA = (
|
||||||
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||||
|
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextComponent),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
_UNDEF = object()
|
||||||
|
|
||||||
|
|
||||||
|
def text_schema(
|
||||||
|
class_: MockObjClass = _UNDEF,
|
||||||
|
*,
|
||||||
|
entity_category: str = _UNDEF,
|
||||||
|
device_class: str = _UNDEF,
|
||||||
|
icon: str = _UNDEF,
|
||||||
|
):
|
||||||
|
schema = _TEXT_SCHEMA
|
||||||
|
if class_ is not _UNDEF:
|
||||||
|
schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
|
||||||
|
if entity_category is not _UNDEF:
|
||||||
|
schema = schema.extend(
|
||||||
|
{
|
||||||
|
cv.Optional(
|
||||||
|
CONF_ENTITY_CATEGORY, default=entity_category
|
||||||
|
): cv.entity_category
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if icon is not _UNDEF:
|
||||||
|
schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
|
||||||
|
return schema
|
||||||
|
|
||||||
|
|
||||||
|
TEXT_SCHEMA = text_schema() # for compatibility
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_text_core_(
|
||||||
|
var,
|
||||||
|
config,
|
||||||
|
*,
|
||||||
|
min_length: Optional[int],
|
||||||
|
max_length: Optional[int],
|
||||||
|
pattern: Optional[str],
|
||||||
|
):
|
||||||
|
await setup_entity(var, config)
|
||||||
|
cg.add(var.traits.set_min_length(min_length))
|
||||||
|
cg.add(var.traits.set_max_length(max_length))
|
||||||
|
if pattern is not None:
|
||||||
|
cg.add(var.traits.set_pattern(pattern))
|
||||||
|
|
||||||
|
if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
|
||||||
|
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||||
|
await mqtt.register_mqtt_component(mqtt_, config)
|
||||||
|
|
||||||
|
if web_server_config := config.get(CONF_WEB_SERVER):
|
||||||
|
await web_server.add_entity_config(var, web_server_config)
|
||||||
|
|
||||||
|
|
||||||
|
async def register_text(
|
||||||
|
var,
|
||||||
|
config,
|
||||||
|
min_length: Optional[int] = 0,
|
||||||
|
max_length: Optional[int] = 255,
|
||||||
|
pattern: Optional[str] = None,
|
||||||
|
):
|
||||||
|
if not CORE.has_id(config[CONF_ID]):
|
||||||
|
var = cg.Pvariable(config[CONF_ID], var)
|
||||||
|
cg.add(cg.App.register_text(var))
|
||||||
|
await setup_text_core_(
|
||||||
|
var, config, min_length=min_length, max_length=max_length, pattern=pattern
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_text(
|
||||||
|
config,
|
||||||
|
*args,
|
||||||
|
min_length: Optional[int] = 0,
|
||||||
|
max_length: Optional[int] = 255,
|
||||||
|
pattern: Optional[str] = None,
|
||||||
|
):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID], *args)
|
||||||
|
await register_text(
|
||||||
|
var, config, min_length=min_length, max_length=max_length, pattern=pattern
|
||||||
|
)
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_SI4713_ID): cv.use_id(Si4713Component),
|
||||||
|
cv.Optional(CONF_RDS_STATION): text_schema(
|
||||||
|
RDSStationText,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon=ICON_FORMAT_TEXT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_RDS_TEXT): text_schema(
|
||||||
|
RDSTextText,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon=ICON_FORMAT_TEXT,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_text_simple(config, id, setter, min_length, max_length, *args):
|
||||||
|
if c := config.get(id):
|
||||||
|
t = await new_text(c, *args, min_length=min_length, max_length=max_length)
|
||||||
|
await cg.register_parented(t, config[CONF_SI4713_ID])
|
||||||
|
cg.add(setter(t))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
c = await cg.get_variable(config[CONF_SI4713_ID])
|
||||||
|
await new_text_simple(
|
||||||
|
config, CONF_RDS_STATION, c.set_rds_station_text, 0, si4713_ns.RDS_STATION_MAX
|
||||||
|
)
|
||||||
|
await new_text_simple(
|
||||||
|
config, CONF_RDS_TEXT, c.set_rds_text_text, 0, si4713_ns.RDS_TEXT_MAX
|
||||||
|
)
|
12
esphome/components/si4713_i2c/text/rds_station_text.cpp
Normal file
12
esphome/components/si4713_i2c/text/rds_station_text.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "rds_station_text.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void RDSStationText::control(const std::string &value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_rds_station(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/text/rds_station_text.h
Normal file
18
esphome/components/si4713_i2c/text/rds_station_text.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/text/text.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class RDSStationText : public text::Text, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
RDSStationText() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const std::string &value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
12
esphome/components/si4713_i2c/text/rds_text_text.cpp
Normal file
12
esphome/components/si4713_i2c/text/rds_text_text.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "rds_text_text.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
void RDSTextText::control(const std::string &value) {
|
||||||
|
this->publish_state(value);
|
||||||
|
this->parent_->set_rds_text(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
18
esphome/components/si4713_i2c/text/rds_text_text.h
Normal file
18
esphome/components/si4713_i2c/text/rds_text_text.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/text/text.h"
|
||||||
|
#include "../si4713.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace si4713 {
|
||||||
|
|
||||||
|
class RDSTextText : public text::Text, public Parented<Si4713Component> {
|
||||||
|
public:
|
||||||
|
RDSTextText() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void control(const std::string &value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace si4713
|
||||||
|
} // namespace esphome
|
Loading…
Reference in a new issue