From 7bfbf720925122b71c115dee02a15fb64eacc6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Poczkodi?= Date: Wed, 16 Oct 2024 17:38:00 +0200 Subject: [PATCH] config done --- esphome/components/si4713_i2c/__init__.py | 416 +++++++- .../components/si4713_i2c/number/__init__.py | 238 ++++- .../si4713_i2c/number/acomp_gain_number.cpp | 12 + .../si4713_i2c/number/acomp_gain_number.h | 18 + .../number/acomp_threshold_number.cpp | 12 + .../number/acomp_threshold_number.h | 18 + .../si4713_i2c/number/analog_level_number.cpp | 12 + .../si4713_i2c/number/analog_level_number.h | 18 + .../si4713_i2c/number/antcap_number.cpp | 12 + .../si4713_i2c/number/antcap_number.h | 18 + .../number/asq_duration_high_number.cpp | 12 + .../number/asq_duration_high_number.h | 18 + .../number/asq_duration_low_number.cpp | 12 + .../number/asq_duration_low_number.h | 18 + .../number/asq_level_high_number.cpp | 12 + .../si4713_i2c/number/asq_level_high_number.h | 18 + .../number/asq_level_low_number.cpp | 12 + .../si4713_i2c/number/asq_level_low_number.h | 18 + .../number/audio_deviation_number.cpp | 12 + .../number/audio_deviation_number.h | 18 + .../number/digital_sample_rate_number.cpp | 12 + .../number/digital_sample_rate_number.h | 18 + .../number/limiter_release_time_number.cpp | 12 + .../number/limiter_release_time_number.h | 18 + .../number/pilot_deviation_number.cpp | 12 + .../number/pilot_deviation_number.h | 18 + .../number/pilot_frequency_number.cpp | 12 + .../number/pilot_frequency_number.h | 18 + .../si4713_i2c/number/power_number.cpp | 12 + .../si4713_i2c/number/power_number.h | 18 + .../number/rds_deviation_number.cpp | 12 + .../si4713_i2c/number/rds_deviation_number.h | 18 + .../number/refclk_frequency_number.cpp | 12 + .../number/refclk_frequency_number.h | 18 + .../number/refclk_prescaler_number.cpp | 12 + .../number/refclk_prescaler_number.h | 18 + .../si4713_i2c/output/binary_output.cpp | 2 +- .../components/si4713_i2c/select/__init__.py | 132 ++- .../si4713_i2c/select/acomp_attack_select.cpp | 14 + .../si4713_i2c/select/acomp_attack_select.h | 18 + .../si4713_i2c/select/acomp_preset_select.cpp | 14 + .../si4713_i2c/select/acomp_preset_select.h | 18 + .../select/acomp_release_select.cpp | 14 + .../si4713_i2c/select/acomp_release_select.h | 18 + .../select/analog_attenuation_select.cpp | 14 + .../select/analog_attenuation_select.h | 18 + .../select/digital_channels_select.cpp | 14 + .../select/digital_channels_select.h | 18 + .../select/digital_clock_edge_select.cpp | 14 + .../select/digital_clock_edge_select.h | 18 + .../si4713_i2c/select/digital_mode_select.cpp | 14 + .../si4713_i2c/select/digital_mode_select.h | 18 + .../select/digital_sample_bits_select.cpp | 14 + .../select/digital_sample_bits_select.h | 18 + .../si4713_i2c/select/pre_emphasis_select.cpp | 14 + .../si4713_i2c/select/pre_emphasis_select.h | 18 + .../select/refclk_source_select.cpp | 14 + .../si4713_i2c/select/refclk_source_select.h | 18 + esphome/components/si4713_i2c/si4713.cpp | 905 ++++++++++++------ esphome/components/si4713_i2c/si4713.h | 302 ++++-- esphome/components/si4713_i2c/si4713defs.h | 192 +++- .../components/si4713_i2c/switch/__init__.py | 162 +++- .../si4713_i2c/switch/acomp_enable_switch.cpp | 12 + .../si4713_i2c/switch/acomp_enable_switch.h | 18 + .../switch/asq_ialh_enable_switch.cpp | 12 + .../switch/asq_ialh_enable_switch.h | 18 + .../switch/asq_iall_enable_switch.cpp | 12 + .../switch/asq_iall_enable_switch.h | 18 + .../switch/asq_overmod_enable_switch.cpp | 12 + .../switch/asq_overmod_enable_switch.h | 18 + .../switch/limiter_enable_switch.cpp | 12 + .../si4713_i2c/switch/limiter_enable_switch.h | 18 + .../si4713_i2c/switch/pilot_enable_switch.cpp | 12 + .../si4713_i2c/switch/pilot_enable_switch.h | 18 + .../components/si4713_i2c/text/__init__.py | 47 +- 75 files changed, 2902 insertions(+), 504 deletions(-) create mode 100644 esphome/components/si4713_i2c/number/acomp_gain_number.cpp create mode 100644 esphome/components/si4713_i2c/number/acomp_gain_number.h create mode 100644 esphome/components/si4713_i2c/number/acomp_threshold_number.cpp create mode 100644 esphome/components/si4713_i2c/number/acomp_threshold_number.h create mode 100644 esphome/components/si4713_i2c/number/analog_level_number.cpp create mode 100644 esphome/components/si4713_i2c/number/analog_level_number.h create mode 100644 esphome/components/si4713_i2c/number/antcap_number.cpp create mode 100644 esphome/components/si4713_i2c/number/antcap_number.h create mode 100644 esphome/components/si4713_i2c/number/asq_duration_high_number.cpp create mode 100644 esphome/components/si4713_i2c/number/asq_duration_high_number.h create mode 100644 esphome/components/si4713_i2c/number/asq_duration_low_number.cpp create mode 100644 esphome/components/si4713_i2c/number/asq_duration_low_number.h create mode 100644 esphome/components/si4713_i2c/number/asq_level_high_number.cpp create mode 100644 esphome/components/si4713_i2c/number/asq_level_high_number.h create mode 100644 esphome/components/si4713_i2c/number/asq_level_low_number.cpp create mode 100644 esphome/components/si4713_i2c/number/asq_level_low_number.h create mode 100644 esphome/components/si4713_i2c/number/audio_deviation_number.cpp create mode 100644 esphome/components/si4713_i2c/number/audio_deviation_number.h create mode 100644 esphome/components/si4713_i2c/number/digital_sample_rate_number.cpp create mode 100644 esphome/components/si4713_i2c/number/digital_sample_rate_number.h create mode 100644 esphome/components/si4713_i2c/number/limiter_release_time_number.cpp create mode 100644 esphome/components/si4713_i2c/number/limiter_release_time_number.h create mode 100644 esphome/components/si4713_i2c/number/pilot_deviation_number.cpp create mode 100644 esphome/components/si4713_i2c/number/pilot_deviation_number.h create mode 100644 esphome/components/si4713_i2c/number/pilot_frequency_number.cpp create mode 100644 esphome/components/si4713_i2c/number/pilot_frequency_number.h create mode 100644 esphome/components/si4713_i2c/number/power_number.cpp create mode 100644 esphome/components/si4713_i2c/number/power_number.h create mode 100644 esphome/components/si4713_i2c/number/rds_deviation_number.cpp create mode 100644 esphome/components/si4713_i2c/number/rds_deviation_number.h create mode 100644 esphome/components/si4713_i2c/number/refclk_frequency_number.cpp create mode 100644 esphome/components/si4713_i2c/number/refclk_frequency_number.h create mode 100644 esphome/components/si4713_i2c/number/refclk_prescaler_number.cpp create mode 100644 esphome/components/si4713_i2c/number/refclk_prescaler_number.h create mode 100644 esphome/components/si4713_i2c/select/acomp_attack_select.cpp create mode 100644 esphome/components/si4713_i2c/select/acomp_attack_select.h create mode 100644 esphome/components/si4713_i2c/select/acomp_preset_select.cpp create mode 100644 esphome/components/si4713_i2c/select/acomp_preset_select.h create mode 100644 esphome/components/si4713_i2c/select/acomp_release_select.cpp create mode 100644 esphome/components/si4713_i2c/select/acomp_release_select.h create mode 100644 esphome/components/si4713_i2c/select/analog_attenuation_select.cpp create mode 100644 esphome/components/si4713_i2c/select/analog_attenuation_select.h create mode 100644 esphome/components/si4713_i2c/select/digital_channels_select.cpp create mode 100644 esphome/components/si4713_i2c/select/digital_channels_select.h create mode 100644 esphome/components/si4713_i2c/select/digital_clock_edge_select.cpp create mode 100644 esphome/components/si4713_i2c/select/digital_clock_edge_select.h create mode 100644 esphome/components/si4713_i2c/select/digital_mode_select.cpp create mode 100644 esphome/components/si4713_i2c/select/digital_mode_select.h create mode 100644 esphome/components/si4713_i2c/select/digital_sample_bits_select.cpp create mode 100644 esphome/components/si4713_i2c/select/digital_sample_bits_select.h create mode 100644 esphome/components/si4713_i2c/select/pre_emphasis_select.cpp create mode 100644 esphome/components/si4713_i2c/select/pre_emphasis_select.h create mode 100644 esphome/components/si4713_i2c/select/refclk_source_select.cpp create mode 100644 esphome/components/si4713_i2c/select/refclk_source_select.h create mode 100644 esphome/components/si4713_i2c/switch/acomp_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/acomp_enable_switch.h create mode 100644 esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.h create mode 100644 esphome/components/si4713_i2c/switch/asq_iall_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/asq_iall_enable_switch.h create mode 100644 esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.h create mode 100644 esphome/components/si4713_i2c/switch/limiter_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/limiter_enable_switch.h create mode 100644 esphome/components/si4713_i2c/switch/pilot_enable_switch.cpp create mode 100644 esphome/components/si4713_i2c/switch/pilot_enable_switch.h diff --git a/esphome/components/si4713_i2c/__init__.py b/esphome/components/si4713_i2c/__init__.py index 6be0a3fd31..8a21fba1d8 100644 --- a/esphome/components/si4713_i2c/__init__.py +++ b/esphome/components/si4713_i2c/__init__.py @@ -1,10 +1,11 @@ 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.components import i2c, sensor, binary_sensor, text_sensor from esphome.const import ( CONF_ID, CONF_FREQUENCY, + UNIT_DECIBEL, UNIT_EMPTY, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT, @@ -22,6 +23,9 @@ UNIT_KILO_HERTZ = "kHz" UNIT_MILLI_VOLT = "mV" UNIT_MICRO_AMPERE = "mA" UNIT_DECIBEL_MICRO_VOLT = "dBµV" +UNIT_PICO_FARAD = "pF" +UNIT_KILO_OHM = "kOhm" +UNIT_DECIBEL_FS = "dBfs" ICON_VOLUME_MUTE = "mdi:volume-mute" ICON_EAR_HEARING = "mdi:ear-hearing" @@ -38,58 +42,308 @@ Si4713Component = si4713_ns.class_( CONF_SI4713_ID = "si4713_id" CONF_RESET_PIN = "reset_pin" -CONF_FREQUENCY_DEVIATION = "frequency_deviation" +CONF_SECTION_TUNER = "tuner" +CONF_SECTION_ANALOG = "analog" +CONF_SECTION_DIGITAL = "digital" +CONF_SECTION_PILOT = "pilot" +CONF_SECTION_REFCLK = "refclk" +CONF_SECTION_COMPRESSOR = "compressor" +CONF_SECTION_LIMITER = "limiter" +CONF_SECTION_ASQ = "asq" +CONF_SECTION_RDS = "rds" +CONF_SECTION_OUTPUT = "output" +CONF_SECTION_SENSOR = "sensor" +# general config +CONF_OP_MODE = "op_mode" 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" +# tuner +CONF_FREQUENCY = "frequency" +CONF_DEVIATION = "deviation" +CONF_POWER = "power" +CONF_ANTCAP = "antcap" +# analog +CONF_LEVEL = "level" +CONF_ATTENUATION = "attenuation" +# digital +CONF_SAMPLE_RATE = "sample_rate" +CONF_SAMPLE_BITS = "sample_bits" +CONF_CHANNELS = "channels" +CONF_MODE = "mode" +CONF_CLOCK_EDGE = "clock_edge" +# pilot +CONF_ENABLE = "enable" +CONF_FREQUENCY = "frequency" +CONF_DEVIATION = "deviation" +# refclk +CONF_FREQUENCY = "frequency" +CONF_SOURCE = "source" +CONF_PRESCALER = "prescaler" +# compressor +CONF_ENABLE = "enable" +CONF_THRESHOLD = "threshold" +CONF_ATTACK = "attack" +CONF_RELEASE = "release" +CONF_GAIN = "gain" +CONF_PRESET = "preset" +# limiter +CONF_ENABLE = "enable" +CONF_RELEASE_TIME = "release_time" +# asq +CONF_IALL = "iall" +CONF_IALH = "ialh" +CONF_OVERMOD = "overmod" +CONF_LEVEL_LOW = "level_low" +CONF_DURATION_LOW = "duration_low" +CONF_LEVEL_HIGH = "level_high" +CONF_DURATION_HIGH = "duration_high" +# rds +CONF_ENABLE = "enable" +CONF_DEVIATION = "deviation" +CONF_STATION = "station" +CONF_TEXT = "text" +# output +CONF_GPIO1="gpio1" +CONF_GPIO2="gpio2" +CONF_GPIO3="gpio3" +# sensor CONF_CHIP_ID = "chip_id" -CONF_REG30 = "reg30" +CONF_READ_FREQUENCY = "frequency" +CONF_READ_POWER = "power" +CONF_READ_ANTCAP = "antcap" +CONF_READ_NOISE_LEVEL = "noise_level" +CONF_IALL = "iall" +CONF_IALH = "ialh" +CONF_OVERMOD = "overmod" +CONF_INLEVEL = "inlevel" 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, -#} +MeasureFrequencyAction = si4713_ns.class_( + "MeasureFrequencyAction", automation.Action, cg.Parented.template(Si4713Component) +) +OpMode = si4713_ns.enum("OpMode", True) +OP_MODE = { + "Analog": OpMode.OPMODE_ANALOG, + "Digital": OpMode.OPMODE_Digital, +} + +PreEmphasis = si4713_ns.enum("PreEmphasis", True) +PRE_EMPHASIS = { + "75us": PreEmphasis.FMPE_75US, + "50us": PreEmphasis.FMPE_50US, + "Disabled": PreEmphasis.FMPE_DISABLED, +} + +LineAttenuation = si4713_ns.enum("LineAttenuation", True) +LINE_ATTENUATION = { + "396kOhm": LineAttenuation.LIATTEN_396KOHM, + "100kOhm": LineAttenuation.LIATTEN_100KOHM, + "74kOhm": LineAttenuation.LIATTEN_74KOHM, + "60kOhm": LineAttenuation.LIATTEN_60KOHM, +} + +SampleBits = si4713_ns.enum("SampleBits", True) +SAMPLE_BITS = { + "16": SampleBits.ISIZE_16BITS, + "20": SampleBits.ISIZE_20BITS, + "24": SampleBits.ISIZE_24BITS, + "8": SampleBits.ISIZE_8BITS, +} + +SampleChannels = si4713_ns.enum("SampleChannels", True) +SAMPLE_CHANNELS = { + "Stereo": SampleChannels.IMONO_STEREO, + "Mono": SampleChannels.IMONO_MONO, +} + +DigitalMode = si4713_ns.enum("DigitalMode", True) +DIGITAL_MODE = { + "Default": DigitalMode.IMODE_DEFAULT, + "I2S": DigitalMode.IMODE_I2S, + "Left Justified": DigitalMode.IMODE_LEFT_JUSTIFIED, + "MSB at 1st": DigitalMode.IMODE_MSB_AT_1ST, + "MSB at 2nd": DigitalMode.IMODE_MSB_AT_2ND, +} + +DigitalClockEdge = si4713_ns.enum("DigitalClockEdge", True) +DIGITAL_CLOCK_EDGE = { + "Rising": DigitalClockEdge.IFALL_DCLK_RISING_EDGE, + "Falling": DigitalClockEdge.IFALL_DCLK_FALLING_EDGE, +} + +RefClkSource = si4713_ns.enum("RefClkSource", True) +REFCLK_SOURCE = { + "RCLK": RefClkSource.RCLKSEL_RCLK, + "DCLK": RefClkSource.RCLKSEL_DCLK, +} + +AcompAttack = si4713_ns.enum("AcompAttack", True) +ACOMP_ATTACK = { + "0.5ms": AcompAttack.ATTACK_05MS, + "1.0ms": AcompAttack.ATTACK_10MS, + "1.5ms": AcompAttack.ATTACK_15MS, + "2.0ms": AcompAttack.ATTACK_20MS, + "2.5ms": AcompAttack.ATTACK_25MS, + "3.0ms": AcompAttack.ATTACK_30MS, + "3.5ms": AcompAttack.ATTACK_35MS, + "4.0ms": AcompAttack.ATTACK_40MS, + "4.5ms": AcompAttack.ATTACK_45MS, + "5.0ms": AcompAttack.ATTACK_50MS, +} + +AcompRelease = si4713_ns.enum("AcompRelease", True) +ACOMP_RELEASE = { + "100ms": AcompRelease.RELEASE_100MS, + "200ms": AcompRelease.RELEASE_200MS, + "350ms": AcompRelease.RELEASE_350MS, + "525ms": AcompRelease.RELEASE_525MS, + "1000ms": AcompRelease.RELEASE_1000MS, +} + +AcompPreset = si4713_ns.enum("AcompPreset", True) +ACOMP_PRESET = { + "Minimal": AcompPreset.ACOMP_MINIMAL, + "Aggressive": AcompPreset.ACOMP_AGGRESSIVE, + "Custom": AcompPreset.ACOMP_CUSTOM, +} 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_OP_MODE, default="Analog"): cv.enum(OP_MODE), 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, + cv.Optional(CONF_PRE_EMPHASIS, default="75us"): cv.enum(PRE_EMPHASIS), + cv.Optional(CONF_SECTION_TUNER): cv.Schema( + { + cv.Optional(CONF_FREQUENCY, default=87.50): cv.float_range(76, 108), # MHz + cv.Optional(CONF_DEVIATION, default=68.25): cv.float_range(0, 90), # kHz + cv.Optional(CONF_POWER, default=115): cv.int_range(88, 115), + cv.Optional(CONF_ANTCAP, default=0): cv.int_range(0, 191), + } + ), + cv.Optional(CONF_SECTION_ANALOG): cv.Schema( + { + cv.Optional(CONF_LEVEL, default=636): cv.int_range(0, 1023), + cv.Optional(CONF_ATTENUATION, default=636): cv.enum(LINE_ATTENUATION), + } + ), + cv.Optional(CONF_SECTION_DIGITAL): cv.Schema( + { + cv.Optional(CONF_SAMPLE_RATE, default=44100): cv.int_range(32000, 48000), # Hz + cv.Optional(CONF_SAMPLE_BITS, default="16"): cv.enum(SAMPLE_BITS), + cv.Optional(CONF_CHANNELS, default="Stereo"): cv.enum(SAMPLE_CHANNELS), + cv.Optional(CONF_MODE, default="Default"): cv.enum(DIGITAL_MODE), + cv.Optional(CONF_CLOCK_EDGE, default="Rising"): cv.enum(DIGITAL_CLOCK_EDGE), + } + ), + cv.Optional(CONF_SECTION_PILOT): cv.Schema( + { + cv.Optional(CONF_ENABLE, default="True"): cv.boolean, + cv.Optional(CONF_FREQUENCY, default=19): cv.float_range(0, 19), # kHz + cv.Optional(CONF_DEVIATION, default=6.75): cv.float_range(0, 90), # kHz + } + ), + cv.Optional(CONF_SECTION_REFCLK): cv.Schema( + { + cv.Optional(CONF_FREQUENCY, default=32768): cv.int_range(31130, 34406), # Hz + cv.Optional(CONF_SOURCE, default="RCLK"): cv.enum(REFCLK_SOURCE), + cv.Optional(CONF_PRESCALER, default=1): cv.int_range(0, 4095), + + } + ), + cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema( + { + cv.Optional(CONF_ENABLE, default="False"): cv.boolean, + cv.Optional(CONF_THRESHOLD, default=-40): cv.int_range(-40, 0), + cv.Optional(CONF_ATTACK, default='0.5'): cv.enum(ACOMP_ATTACK), + cv.Optional(CONF_RELEASE, default="1000"): cv.enum(ACOMP_RELEASE), + cv.Optional(CONF_GAIN, default=15): cv.int_range(0, 20), + cv.Optional(CONF_PRESET, default="Custom"): cv.enum(ACOMP_PRESET), + } + ), + cv.Optional(CONF_SECTION_LIMITER): cv.Schema( + { + cv.Optional(CONF_ENABLE, default="True"): cv.boolean, + cv.Optional(CONF_RELEASE_TIME, default=5): cv.float_range(0.25, 102.4), + } + ), + cv.Optional(CONF_SECTION_ASQ): cv.Schema( + { + cv.Optional(CONF_IALL, default="False"): cv.boolean, + cv.Optional(CONF_IALH, default="False"): cv.boolean, + cv.Optional(CONF_OVERMOD, default="False"): cv.boolean, + cv.Optional(CONF_LEVEL_LOW, default=-50): cv.float_range(-70, 0), + cv.Optional(CONF_DURATION_LOW, default=10000): cv.int_range(0, 65535), + cv.Optional(CONF_LEVEL_HIGH, default=-20): cv.float_range(-70, 0), + cv.Optional(CONF_DURATION_HIGH, default=5000): cv.int_range(0, 65535), + } + ), + cv.Optional(CONF_SECTION_RDS): cv.Schema( + { + cv.Optional(CONF_ENABLE, default=False): cv.boolean, + cv.Optional(CONF_DEVIATION, default=2.0): cv.float_range(0, 7.5), # kHz + cv.Optional(CONF_STATION): cv.string, + cv.Optional(CONF_TEXT): cv.string, + } + ), + cv.Optional(CONF_SECTION_SENSOR): cv.Schema( + { + cv.Optional(CONF_CHIP_ID): text_sensor.text_sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_CHIP, + ), + cv.Optional(CONF_READ_FREQUENCY): sensor.sensor_schema( + unit_of_measurement=UNIT_MEGA_HERTZ, + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + state_class=STATE_CLASS_MEASUREMENT, + accuracy_decimals=2, + # icon=ICON_, + ), + cv.Optional(CONF_READ_POWER): sensor.sensor_schema( + unit_of_measurement=UNIT_DECIBEL_MICRO_VOLT, + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + state_class=STATE_CLASS_MEASUREMENT, + # icon=ICON_, + ), + cv.Optional(CONF_READ_ANTCAP): sensor.sensor_schema( + unit_of_measurement=UNIT_PICO_FARAD, + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + state_class=STATE_CLASS_MEASUREMENT, + # icon=ICON_, + ), + cv.Optional(CONF_READ_NOISE_LEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_DECIBEL_MICRO_VOLT, + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + # state_class=STATE_CLASS_MEASUREMENT, + # icon=ICON_, + ), + cv.Optional(CONF_IALL): binary_sensor.binary_sensor_schema( + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + # icon=ICON_, + ), + cv.Optional(CONF_IALH): binary_sensor.binary_sensor_schema( + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + # icon=ICON_, + ), + cv.Optional(CONF_OVERMOD): binary_sensor.binary_sensor_schema( + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + # icon=ICON_, + ), + cv.Optional(CONF_INLEVEL): sensor.sensor_schema( + unit_of_measurement=UNIT_DECIBEL_FS, + # entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + state_class=STATE_CLASS_MEASUREMENT, + # icon=ICON_, + ), + } ), } ) @@ -98,18 +352,43 @@ CONFIG_SCHEMA = ( ) +FREQUENCY_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(Si4713Component), + cv.Required(CONF_FREQUENCY): cv.templatable(cv.float_range(min = 76, max = 108)), + } +) + + +@automation.register_action("si4713.set_frequency", SetFrequencyAction, FREQUENCY_SCHEMA) +@automation.register_action("si4713.measure_frequency", MeasureFrequencyAction, FREQUENCY_SCHEMA) +async def tune_frequency_action_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + if frequency := config.get(CONF_FREQUENCY): + template_ = await cg.templatable(frequency, args, cg.float_) + cg.add(var.set_frequency(template_)) + return var + + async def set_var(config, id, setter): if c := config.get(id): cg.add(setter(c)) -async def set_sensor(config, id, setter): +async def new_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): +async def new_binary_sensor(config, id, setter): + if c := config.get(id): + s = await binary_sensor.new_binary_sensor(c) + cg.add(setter(s)) + + +async def new_text_sensor(config, id, setter): if c := config.get(id): s = await text_sensor.new_text_sensor(c) cg.add(setter(s)) @@ -121,11 +400,62 @@ async def to_code(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_OP_MODE, var.set_op_mode) 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) + await set_var(config, CONF_PRE_EMPHASIS, var.set_pre_emphasis) + if tuner_config := config.get(CONF_SECTION_TUNER): + await set_var(tuner_config, CONF_FREQUENCY, var.set_frequency) + await set_var(tuner_config, CONF_DEVIATION, var.set_audio_deviation) + await set_var(tuner_config, CONF_POWER, var.set_power) + await set_var(tuner_config, CONF_ANTCAP, var.set_antcap) + if analog_config := config.get(CONF_SECTION_ANALOG): + await set_var(analog_config, CONF_LEVEL, var.set_analog_level) + await set_var(analog_config, CONF_ATTENUATION, var.set_analog_attenuation) + if digital_config := config.get(CONF_SECTION_DIGITAL): + await set_var(digital_config, CONF_SAMPLE_RATE, var.set_digital_sample_rate) + await set_var(digital_config, CONF_SAMPLE_BITS, var.set_digital_sample_bits) + await set_var(digital_config, CONF_CHANNELS, var.set_digital_channels) + await set_var(digital_config, CONF_MODE, var.set_digital_mode) + await set_var(digital_config, CONF_CLOCK_EDGE, var.set_digital_clock_edge) + if pilot_config := config.get(CONF_SECTION_PILOT): + await set_var(pilot_config, CONF_ENABLE, var.set_pilot_enable) + await set_var(pilot_config, CONF_FREQUENCY, var.set_pilot_frequency) + await set_var(pilot_config, CONF_DEVIATION, var.set_pilot_deviation) + if refclk_config := config.get(CONF_SECTION_REFCLK): + await set_var(refclk_config, CONF_FREQUENCY, var.set_refclk_frequency) + await set_var(refclk_config, CONF_SOURCE, var.set_refclk_source) + await set_var(refclk_config, CONF_PRESCALER, var.set_refclk_prescaler) + if compressor_config := config.get(CONF_SECTION_COMPRESSOR): + await set_var(compressor_config, CONF_ENABLE, var.set_acomp_enable) + await set_var(compressor_config, CONF_THRESHOLD, var.set_acomp_threshold) + await set_var(compressor_config, CONF_ATTACK, var.set_acomp_attack) + await set_var(compressor_config, CONF_RELEASE, var.set_acomp_release) + await set_var(compressor_config, CONF_GAIN, var.set_acomp_gain) + await set_var(compressor_config, CONF_PRESET, var.set_acomp_preset) + if limiter_config := config.get(CONF_SECTION_LIMITER): + await set_var(limiter_config, CONF_ENABLE, var.set_limiter_enable) + await set_var(limiter_config, CONF_RELEASE_TIME, var.set_limiter_release_time) + if asq_config := config.get(CONF_SECTION_ASQ): + await set_var(asq_config, CONF_IALL, var.set_asq_iall_enable) + await set_var(asq_config, CONF_IALH, var.set_asq_ialh_enable) + await set_var(asq_config, CONF_OVERMOD, var.set_asq_overmod_enable) + await set_var(asq_config, CONF_LEVEL_LOW, var.set_asq_level_low) + await set_var(asq_config, CONF_DURATION_LOW, var.set_asq_duration_low) + await set_var(asq_config, CONF_LEVEL_HIGH, var.set_asq_level_high) + await set_var(asq_config, CONF_DURATION_HIGH, var.set_asq_duration_high) + if rds_config := config.get(CONF_SECTION_RDS): + await set_var(rds_config, CONF_ENABLE, var.set_rds_enable) + await set_var(rds_config, CONF_DEVIATION, var.set_rds_deviation) + await set_var(rds_config, CONF_STATION, var.set_rds_station) + await set_var(rds_config, CONF_TEXT, var.set_rds_text) + if sensor_config := config.get(CONF_SECTION_SENSOR): + await new_text_sensor(sensor_config, CONF_CHIP_ID, var.set_chip_id_text_sensor) + await new_sensor(sensor_config, CONF_READ_FREQUENCY, var.set_read_frequency_sensor) + await new_sensor(sensor_config, CONF_READ_POWER, var.set_read_power_sensor) + await new_sensor(sensor_config, CONF_READ_ANTCAP, var.set_read_antcap_sensor) + await new_sensor(sensor_config, CONF_READ_NOISE_LEVEL, var.set_read_noise_level_sensor) + await new_binary_sensor(sensor_config, CONF_IALL, var.set_iall_binary_sensor) + await new_binary_sensor(sensor_config, CONF_IALH, var.set_ialh_binary_sensor) + await new_binary_sensor(sensor_config, CONF_OVERMOD, var.set_overmod_binary_sensor) + await new_sensor(sensor_config, CONF_INLEVEL, var.set_inlevel_sensor) diff --git a/esphome/components/si4713_i2c/number/__init__.py b/esphome/components/si4713_i2c/number/__init__.py index 41b6dea463..087b4ed9b6 100644 --- a/esphome/components/si4713_i2c/number/__init__.py +++ b/esphome/components/si4713_i2c/number/__init__.py @@ -3,11 +3,15 @@ from esphome.components import number import esphome.config_validation as cv from esphome.const import ( CONF_FREQUENCY, - UNIT_PERCENT, + CONF_MODE, + UNIT_HERTZ, + UNIT_MILLISECOND, UNIT_DECIBEL, + UNIT_EMPTY, DEVICE_CLASS_FREQUENCY, - DEVICE_CLASS_CURRENT, + DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_SIGNAL_STRENGTH, + DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, ENTITY_CATEGORY_CONFIG, ) @@ -15,37 +19,245 @@ from .. import ( CONF_SI4713_ID, Si4713Component, si4713_ns, -# CONF_, + CONF_SECTION_TUNER, + CONF_SECTION_ANALOG, + CONF_SECTION_DIGITAL, + CONF_SECTION_PILOT, + CONF_SECTION_REFCLK, + CONF_SECTION_COMPRESSOR, + CONF_SECTION_LIMITER, + CONF_SECTION_ASQ, + CONF_SECTION_RDS, + CONF_FREQUENCY, + CONF_DEVIATION, + CONF_POWER, + CONF_ANTCAP, + CONF_LEVEL, + CONF_SAMPLE_RATE, + CONF_PRESCALER, + CONF_THRESHOLD, + CONF_GAIN, + CONF_RELEASE_TIME, + CONF_LEVEL_LOW, + CONF_DURATION_LOW, + CONF_LEVEL_HIGH, + CONF_DURATION_HIGH, UNIT_MEGA_HERTZ, UNIT_KILO_HERTZ, - UNIT_MICRO_AMPERE, + UNIT_MILLI_VOLT, UNIT_DECIBEL_MICRO_VOLT, + UNIT_PICO_FARAD, ) FrequencyNumber = si4713_ns.class_("FrequencyNumber", number.Number) +AudioDeviationNumber = si4713_ns.class_("AudioDeviationNumber", number.Number) +PowerNumber = si4713_ns.class_("PowerNumber", number.Number) +AntcapNumber = si4713_ns.class_("AntcapNumber", number.Number) +AnalogLevelNumber = si4713_ns.class_("AnalogLevelNumber", number.Number) +DigitalSampleRateNumber = si4713_ns.class_("DigitalSampleRateNumber", number.Number) +PilotFrequencyNumber = si4713_ns.class_("PilotFrequencyNumber", number.Number) +PilotDeviationNumber = si4713_ns.class_("PilotDeviationNumber", number.Number) +RefClkFrequencyNumber = si4713_ns.class_("RefClkFrequencyNumber", number.Number) +RefClkPrescalerNumber = si4713_ns.class_("RefClkPrescalerNumber", number.Number) +AcompThresholdNumber = si4713_ns.class_("AcompThresholdNumber", number.Number) +AcompGainNumber = si4713_ns.class_("AcompGainNumber", number.Number) +LimiterReleaseTimeNumber = si4713_ns.class_("LimiterReleaseTimeNumber", number.Number) +AsqLevelLowNumber = si4713_ns.class_("AsqLevelLowNumber", number.Number) +AsqDurationLowNumber = si4713_ns.class_("AsqDurationLowNumber", number.Number) +AsqLevelHighNumber = si4713_ns.class_("AsqLevelHighNumber", number.Number) +AsqDurationHighNumber = si4713_ns.class_("AsqDurationHighNumber", number.Number) +RdsDeviationNumber = si4713_ns.class_("RdsDeviationNumber", 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, + cv.Optional(CONF_SECTION_TUNER): cv.Schema( + { + cv.Optional(CONF_FREQUENCY): number.number_schema( + FrequencyNumber, + unit_of_measurement=UNIT_MEGA_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_DEVIATION): number.number_schema( + AudioDeviationNumber, + unit_of_measurement=UNIT_KILO_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_POWER): number.number_schema( + PowerNumber, + unit_of_measurement=UNIT_DECIBEL_MICRO_VOLT, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_ANTCAP): number.number_schema( + AntcapNumber, + unit_of_measurement=UNIT_PICO_FARAD, + device_class=DEVICE_CLASS_EMPTY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + } ), + cv.Optional(CONF_SECTION_ANALOG): cv.Schema( + { + cv.Optional(CONF_LEVEL): number.number_schema( + AnalogLevelNumber, + unit_of_measurement=UNIT_MILLI_VOLT, + device_class=DEVICE_CLASS_VOLTAGE, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_DIGITAL): cv.Schema( + { + cv.Optional(CONF_SAMPLE_RATE): number.number_schema( + DigitalSampleRateNumber, + unit_of_measurement=UNIT_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_PILOT): cv.Schema( + { + cv.Optional(CONF_FREQUENCY): number.number_schema( + PilotFrequencyNumber, + unit_of_measurement=UNIT_KILO_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_DEVIATION): number.number_schema( + PilotDeviationNumber, + unit_of_measurement=UNIT_KILO_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_REFCLK): cv.Schema( + { + cv.Optional(CONF_FREQUENCY): number.number_schema( + RefClkFrequencyNumber, + unit_of_measurement=UNIT_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_PRESCALER): number.number_schema( + RefClkPrescalerNumber, + unit_of_measurement=UNIT_EMPTY, + device_class=DEVICE_CLASS_EMPTY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema( + { + cv.Optional(CONF_THRESHOLD): number.number_schema( + AcompThresholdNumber, + unit_of_measurement=UNIT_DECIBEL, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_GAIN): number.number_schema( + AcompGainNumber, + unit_of_measurement=UNIT_DECIBEL, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_LIMITER): cv.Schema( + { + cv.Optional(CONF_RELEASE_TIME): number.number_schema( + LimiterReleaseTimeNumber, + unit_of_measurement=UNIT_MILLISECOND, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), + cv.Optional(CONF_SECTION_ASQ): cv.Schema( + { + cv.Optional(CONF_LEVEL_LOW): number.number_schema( + AsqLevelLowNumber, + unit_of_measurement=UNIT_DECIBEL, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_DURATION_LOW): number.number_schema( + AsqDurationLowNumber, + unit_of_measurement=UNIT_MILLISECOND, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_LEVEL_HIGH): number.number_schema( + AsqLevelHighNumber, + unit_of_measurement=UNIT_DECIBEL, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + cv.Optional(CONF_DURATION_HIGH): number.number_schema( + AsqDurationHighNumber, + unit_of_measurement=UNIT_MILLISECOND, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + } + ), + cv.Optional(CONF_SECTION_RDS): cv.Schema( + { + cv.Optional(CONF_DEVIATION): number.number_schema( + RdsDeviationNumber, + unit_of_measurement=UNIT_KILO_HERTZ, + device_class=DEVICE_CLASS_FREQUENCY, + entity_category=ENTITY_CATEGORY_CONFIG, + ), + }, + ), } ) -async def new_number(config, id, setter, min_value, max_value, step, *args): +async def new_number(parent, config, id, setter, min_value, max_value, step, *args, **kwargs): if c := config.get(id): + if CONF_MODE in kwargs: + if CONF_MODE not in c or c[CONF_MODE] == number.NumberMode.NUMBER_MODE_AUTO: + c[CONF_MODE] = kwargs.get(CONF_MODE) 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]) + await cg.register_parented(n, parent) cg.add(setter(n)) + return 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) + parent = await cg.get_variable(config[CONF_SI4713_ID]) + if tuner_config := config.get(CONF_SECTION_TUNER): + await new_number(parent, tuner_config, CONF_FREQUENCY, parent.set_frequency_number, 76, 108, 0.05) + await new_number(parent, tuner_config, CONF_DEVIATION, parent.set_audio_deviation_number, 0, 90, 0.01) + await new_number(parent, tuner_config, CONF_POWER, parent.set_power_number, 88, 120, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER) + await new_number(parent, tuner_config, CONF_ANTCAP, parent.set_antcap_number, 0, 191, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER) + if analog_config := config.get(CONF_SECTION_ANALOG): + await new_number(parent, analog_config, CONF_LEVEL, parent.set_analog_level_number, 0, 1023, 1, mode = number.NumberMode.NUMBER_MODE_SLIDER) + if digital_config := config.get(CONF_SECTION_DIGITAL): + await new_number(parent, digital_config, CONF_SAMPLE_RATE, parent.set_digital_sample_rate_number, 32000, 48000, 1) + if pilot_config := config.get(CONF_SECTION_PILOT): + await new_number(parent, pilot_config, CONF_FREQUENCY, parent.set_pilot_frequency_number, 0, 19, 0.001) + await new_number(parent, pilot_config, CONF_DEVIATION, parent.set_pilot_deviation_number, 0, 90, 0.001) + if refclk_config := config.get(CONF_SECTION_REFCLK): + await new_number(parent, refclk_config, CONF_FREQUENCY, parent.set_refclk_frequency_number, 31130, 34406, 1) + await new_number(parent, refclk_config, CONF_PRESCALER, parent.set_refclk_prescaler_number, 0, 4095, 1) + if compressor_config := config.get(CONF_SECTION_COMPRESSOR): + await new_number(parent, compressor_config, CONF_THRESHOLD, parent.set_acomp_threshold_number, -40, 0, 1) + await new_number(parent, compressor_config, CONF_GAIN, parent.set_acomp_gain_number, 0, 20, 1) + if limiter_config := config.get(CONF_SECTION_LIMITER): + await new_number(parent, limiter_config, CONF_RELEASE_TIME, parent.set_limiter_release_time_number, 0.25, 102.4, 0.01, mode = number.NumberMode.NUMBER_MODE_SLIDER) + if asq_config := config.get(CONF_SECTION_ASQ): + await new_number(parent, asq_config, CONF_LEVEL_LOW, parent.set_asq_level_low_number, -70, 0, 1) + await new_number(parent, asq_config, CONF_DURATION_LOW, parent.set_asq_duration_low_number, 0, 65535, 1) + await new_number(parent, asq_config, CONF_LEVEL_HIGH, parent.set_asq_level_high_number, -70, 0, 1) + await new_number(parent, asq_config, CONF_DURATION_HIGH, parent.set_asq_duration_high_number, 0, 65535, 1) + if rds_config := config.get(CONF_SECTION_RDS): + await new_number(parent, rds_config, CONF_DEVIATION, parent.set_rds_deviation_number, 0, 7.5, 0.01) diff --git a/esphome/components/si4713_i2c/number/acomp_gain_number.cpp b/esphome/components/si4713_i2c/number/acomp_gain_number.cpp new file mode 100644 index 0000000000..fa3baf4e82 --- /dev/null +++ b/esphome/components/si4713_i2c/number/acomp_gain_number.cpp @@ -0,0 +1,12 @@ +#include "acomp_gain_number.h" + +namespace esphome { +namespace si4713 { + +void AcompGainNumber::control(float value) { + this->publish_state(value); + this->parent_->set_acomp_gain(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/acomp_gain_number.h b/esphome/components/si4713_i2c/number/acomp_gain_number.h new file mode 100644 index 0000000000..4aa639ce0b --- /dev/null +++ b/esphome/components/si4713_i2c/number/acomp_gain_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompGainNumber : public number::Number, public Parented { + public: + AcompGainNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/acomp_threshold_number.cpp b/esphome/components/si4713_i2c/number/acomp_threshold_number.cpp new file mode 100644 index 0000000000..6c8603ed79 --- /dev/null +++ b/esphome/components/si4713_i2c/number/acomp_threshold_number.cpp @@ -0,0 +1,12 @@ +#include "acomp_threshold_number.h" + +namespace esphome { +namespace si4713 { + +void AcompThresholdNumber::control(float value) { + this->publish_state(value); + this->parent_->set_acomp_threshold(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/acomp_threshold_number.h b/esphome/components/si4713_i2c/number/acomp_threshold_number.h new file mode 100644 index 0000000000..0c76e86bc5 --- /dev/null +++ b/esphome/components/si4713_i2c/number/acomp_threshold_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompThresholdNumber : public number::Number, public Parented { + public: + AcompThresholdNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/analog_level_number.cpp b/esphome/components/si4713_i2c/number/analog_level_number.cpp new file mode 100644 index 0000000000..b7ec0d1071 --- /dev/null +++ b/esphome/components/si4713_i2c/number/analog_level_number.cpp @@ -0,0 +1,12 @@ +#include "analog_level_number.h" + +namespace esphome { +namespace si4713 { + +void AnalogLevelNumber::control(float value) { + this->publish_state(value); + this->parent_->set_analog_level(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/analog_level_number.h b/esphome/components/si4713_i2c/number/analog_level_number.h new file mode 100644 index 0000000000..12376f99e3 --- /dev/null +++ b/esphome/components/si4713_i2c/number/analog_level_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AnalogLevelNumber : public number::Number, public Parented { + public: + AnalogLevelNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/antcap_number.cpp b/esphome/components/si4713_i2c/number/antcap_number.cpp new file mode 100644 index 0000000000..fa59dc4fdb --- /dev/null +++ b/esphome/components/si4713_i2c/number/antcap_number.cpp @@ -0,0 +1,12 @@ +#include "antcap_number.h" + +namespace esphome { +namespace si4713 { + +void AntcapNumber::control(float value) { + this->publish_state(value); + this->parent_->set_antcap(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/antcap_number.h b/esphome/components/si4713_i2c/number/antcap_number.h new file mode 100644 index 0000000000..53901b156c --- /dev/null +++ b/esphome/components/si4713_i2c/number/antcap_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AntcapNumber : public number::Number, public Parented { + public: + AntcapNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_duration_high_number.cpp b/esphome/components/si4713_i2c/number/asq_duration_high_number.cpp new file mode 100644 index 0000000000..0d8832ba46 --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_duration_high_number.cpp @@ -0,0 +1,12 @@ +#include "asq_duration_high_number.h" + +namespace esphome { +namespace si4713 { + +void AsqDurationHighNumber::control(float value) { + this->publish_state(value); + this->parent_->set_asq_duration_high(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_duration_high_number.h b/esphome/components/si4713_i2c/number/asq_duration_high_number.h new file mode 100644 index 0000000000..6219a5021d --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_duration_high_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqDurationHighNumber : public number::Number, public Parented { + public: + AsqDurationHighNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_duration_low_number.cpp b/esphome/components/si4713_i2c/number/asq_duration_low_number.cpp new file mode 100644 index 0000000000..a8b352f92c --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_duration_low_number.cpp @@ -0,0 +1,12 @@ +#include "asq_duration_low_number.h" + +namespace esphome { +namespace si4713 { + +void AsqDurationLowNumber::control(float value) { + this->publish_state(value); + this->parent_->set_asq_duration_low(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_duration_low_number.h b/esphome/components/si4713_i2c/number/asq_duration_low_number.h new file mode 100644 index 0000000000..cea1d527b6 --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_duration_low_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqDurationLowNumber : public number::Number, public Parented { + public: + AsqDurationLowNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_level_high_number.cpp b/esphome/components/si4713_i2c/number/asq_level_high_number.cpp new file mode 100644 index 0000000000..ddc01cda99 --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_level_high_number.cpp @@ -0,0 +1,12 @@ +#include "asq_level_high_number.h" + +namespace esphome { +namespace si4713 { + +void AsqLevelHighNumber::control(float value) { + this->publish_state(value); + this->parent_->set_asq_level_high(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_level_high_number.h b/esphome/components/si4713_i2c/number/asq_level_high_number.h new file mode 100644 index 0000000000..8db5dcb160 --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_level_high_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqLevelHighNumber : public number::Number, public Parented { + public: + AsqLevelHighNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_level_low_number.cpp b/esphome/components/si4713_i2c/number/asq_level_low_number.cpp new file mode 100644 index 0000000000..de73a1036e --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_level_low_number.cpp @@ -0,0 +1,12 @@ +#include "asq_level_low_number.h" + +namespace esphome { +namespace si4713 { + +void AsqLevelLowNumber::control(float value) { + this->publish_state(value); + this->parent_->set_asq_level_low(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/asq_level_low_number.h b/esphome/components/si4713_i2c/number/asq_level_low_number.h new file mode 100644 index 0000000000..ffdf97b114 --- /dev/null +++ b/esphome/components/si4713_i2c/number/asq_level_low_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqLevelLowNumber : public number::Number, public Parented { + public: + AsqLevelLowNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/audio_deviation_number.cpp b/esphome/components/si4713_i2c/number/audio_deviation_number.cpp new file mode 100644 index 0000000000..afcd163511 --- /dev/null +++ b/esphome/components/si4713_i2c/number/audio_deviation_number.cpp @@ -0,0 +1,12 @@ +#include "audio_deviation_number.h" + +namespace esphome { +namespace si4713 { + +void AudioDeviationNumber::control(float value) { + this->publish_state(value); + this->parent_->set_audio_deviation(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/audio_deviation_number.h b/esphome/components/si4713_i2c/number/audio_deviation_number.h new file mode 100644 index 0000000000..a1061b3e0f --- /dev/null +++ b/esphome/components/si4713_i2c/number/audio_deviation_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AudioDeviationNumber : public number::Number, public Parented { + public: + AudioDeviationNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/digital_sample_rate_number.cpp b/esphome/components/si4713_i2c/number/digital_sample_rate_number.cpp new file mode 100644 index 0000000000..484772a2a7 --- /dev/null +++ b/esphome/components/si4713_i2c/number/digital_sample_rate_number.cpp @@ -0,0 +1,12 @@ +#include "digital_sample_rate_number.h" + +namespace esphome { +namespace si4713 { + +void DigitalSampleRateNumber::control(float value) { + this->publish_state(value); + this->parent_->set_digital_sample_rate(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/digital_sample_rate_number.h b/esphome/components/si4713_i2c/number/digital_sample_rate_number.h new file mode 100644 index 0000000000..2bf72453a3 --- /dev/null +++ b/esphome/components/si4713_i2c/number/digital_sample_rate_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class DigitalSampleRateNumber : public number::Number, public Parented { + public: + DigitalSampleRateNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/limiter_release_time_number.cpp b/esphome/components/si4713_i2c/number/limiter_release_time_number.cpp new file mode 100644 index 0000000000..aa294c7454 --- /dev/null +++ b/esphome/components/si4713_i2c/number/limiter_release_time_number.cpp @@ -0,0 +1,12 @@ +#include "limiter_release_time_number.h" + +namespace esphome { +namespace si4713 { + +void LimiterReleaseTimeNumber::control(float value) { + this->publish_state(value); + this->parent_->set_limiter_release_time(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/limiter_release_time_number.h b/esphome/components/si4713_i2c/number/limiter_release_time_number.h new file mode 100644 index 0000000000..b56790635a --- /dev/null +++ b/esphome/components/si4713_i2c/number/limiter_release_time_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class LimiterReleaseTimeNumber : public number::Number, public Parented { + public: + LimiterReleaseTimeNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/pilot_deviation_number.cpp b/esphome/components/si4713_i2c/number/pilot_deviation_number.cpp new file mode 100644 index 0000000000..a4d4457860 --- /dev/null +++ b/esphome/components/si4713_i2c/number/pilot_deviation_number.cpp @@ -0,0 +1,12 @@ +#include "pilot_deviation_number.h" + +namespace esphome { +namespace si4713 { + +void PilotDeviationNumber::control(float value) { + this->publish_state(value); + this->parent_->set_pilot_deviation(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/pilot_deviation_number.h b/esphome/components/si4713_i2c/number/pilot_deviation_number.h new file mode 100644 index 0000000000..b7529c5bef --- /dev/null +++ b/esphome/components/si4713_i2c/number/pilot_deviation_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class PilotDeviationNumber : public number::Number, public Parented { + public: + PilotDeviationNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/pilot_frequency_number.cpp b/esphome/components/si4713_i2c/number/pilot_frequency_number.cpp new file mode 100644 index 0000000000..954902b060 --- /dev/null +++ b/esphome/components/si4713_i2c/number/pilot_frequency_number.cpp @@ -0,0 +1,12 @@ +#include "pilot_frequency_number.h" + +namespace esphome { +namespace si4713 { + +void PilotFrequencyNumber::control(float value) { + this->publish_state(value); + this->parent_->set_pilot_frequency(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/pilot_frequency_number.h b/esphome/components/si4713_i2c/number/pilot_frequency_number.h new file mode 100644 index 0000000000..413e6473de --- /dev/null +++ b/esphome/components/si4713_i2c/number/pilot_frequency_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class PilotFrequencyNumber : public number::Number, public Parented { + public: + PilotFrequencyNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/power_number.cpp b/esphome/components/si4713_i2c/number/power_number.cpp new file mode 100644 index 0000000000..49da073516 --- /dev/null +++ b/esphome/components/si4713_i2c/number/power_number.cpp @@ -0,0 +1,12 @@ +#include "power_number.h" + +namespace esphome { +namespace si4713 { + +void PowerNumber::control(float value) { + this->publish_state(value); + this->parent_->set_power(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/power_number.h b/esphome/components/si4713_i2c/number/power_number.h new file mode 100644 index 0000000000..ea48f79e12 --- /dev/null +++ b/esphome/components/si4713_i2c/number/power_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class PowerNumber : public number::Number, public Parented { + public: + PowerNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/rds_deviation_number.cpp b/esphome/components/si4713_i2c/number/rds_deviation_number.cpp new file mode 100644 index 0000000000..d5a96f06a9 --- /dev/null +++ b/esphome/components/si4713_i2c/number/rds_deviation_number.cpp @@ -0,0 +1,12 @@ +#include "rds_deviation_number.h" + +namespace esphome { +namespace si4713 { + +void RdsDeviationNumber::control(float value) { + this->publish_state(value); + this->parent_->set_rds_deviation(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/rds_deviation_number.h b/esphome/components/si4713_i2c/number/rds_deviation_number.h new file mode 100644 index 0000000000..cf916249af --- /dev/null +++ b/esphome/components/si4713_i2c/number/rds_deviation_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class RdsDeviationNumber : public number::Number, public Parented { + public: + RdsDeviationNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/refclk_frequency_number.cpp b/esphome/components/si4713_i2c/number/refclk_frequency_number.cpp new file mode 100644 index 0000000000..10c8b23a55 --- /dev/null +++ b/esphome/components/si4713_i2c/number/refclk_frequency_number.cpp @@ -0,0 +1,12 @@ +#include "refclk_frequency_number.h" + +namespace esphome { +namespace si4713 { + +void RefClkFrequencyNumber::control(float value) { + this->publish_state(value); + this->parent_->set_refclk_frequency(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/refclk_frequency_number.h b/esphome/components/si4713_i2c/number/refclk_frequency_number.h new file mode 100644 index 0000000000..f6fa8c1753 --- /dev/null +++ b/esphome/components/si4713_i2c/number/refclk_frequency_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class RefClkFrequencyNumber : public number::Number, public Parented { + public: + RefClkFrequencyNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/refclk_prescaler_number.cpp b/esphome/components/si4713_i2c/number/refclk_prescaler_number.cpp new file mode 100644 index 0000000000..244889add9 --- /dev/null +++ b/esphome/components/si4713_i2c/number/refclk_prescaler_number.cpp @@ -0,0 +1,12 @@ +#include "refclk_prescaler_number.h" + +namespace esphome { +namespace si4713 { + +void RefClkPrescalerNumber::control(float value) { + this->publish_state(value); + this->parent_->set_refclk_prescaler(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/number/refclk_prescaler_number.h b/esphome/components/si4713_i2c/number/refclk_prescaler_number.h new file mode 100644 index 0000000000..ec449563b5 --- /dev/null +++ b/esphome/components/si4713_i2c/number/refclk_prescaler_number.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/number/number.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class RefClkPrescalerNumber : public number::Number, public Parented { + public: + RefClkPrescalerNumber() = default; + + protected: + void control(float value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/output/binary_output.cpp b/esphome/components/si4713_i2c/output/binary_output.cpp index 0ac2c4d976..faebfc30e2 100644 --- a/esphome/components/si4713_i2c/output/binary_output.cpp +++ b/esphome/components/si4713_i2c/output/binary_output.cpp @@ -12,7 +12,7 @@ void BinaryOutput::dump_config() { ESP_LOGCONFIG(TAG, " Pin: %d", this->pin_); } -void Si4713BinaryOutput::write_state(bool state) { +void BinaryOutput::write_state(bool state) { this->parent_->set_gpio(this->pin_, state); } diff --git a/esphome/components/si4713_i2c/select/__init__.py b/esphome/components/si4713_i2c/select/__init__.py index e34e0d5797..5a526fe193 100644 --- a/esphome/components/si4713_i2c/select/__init__.py +++ b/esphome/components/si4713_i2c/select/__init__.py @@ -9,34 +9,140 @@ from .. import ( CONF_SI4713_ID, Si4713Component, si4713_ns, - CONF_, - ICON_SLEEP, + CONF_SECTION_ANALOG, + CONF_SECTION_DIGITAL, + CONF_SECTION_REFCLK, + CONF_SECTION_COMPRESSOR, + CONF_PRE_EMPHASIS, + CONF_ATTENUATION, + CONF_SAMPLE_BITS, + CONF_CHANNELS, + CONF_MODE, + CONF_CLOCK_EDGE, + CONF_SOURCE, + CONF_ATTACK, + CONF_RELEASE, + CONF_PRESET, ICON_SINE_WAVE, ICON_RESISTOR, -# T1M_SEL, + ICON_EAR_HEARING, + PRE_EMPHASIS, + LINE_ATTENUATION, + SAMPLE_BITS, + SAMPLE_CHANNELS, + DIGITAL_MODE, + DIGITAL_CLOCK_EDGE, + REFCLK_SOURCE, + ACOMP_ATTACK, + ACOMP_RELEASE, + ACOMP_PRESET, ) -#T1mSelSelect = si4713_ns.class_("T1mSelSelect", select.Select) +PreEmphasisSelect = si4713_ns.class_("PreEmphasisSelect", select.Select) +AnalogAttenuationSelect = si4713_ns.class_("AnalogAttenuationSelect", select.Select) +DigitalSampleBitsSelect = si4713_ns.class_("DigitalSampleBitsSelect", select.Select) +DigitalChannelsSelect = si4713_ns.class_("DigitalChannelsSelect", select.Select) +DigitalModeSelect = si4713_ns.class_("DigitalModeSelect", select.Select) +DigitalClockEdgeSelect = si4713_ns.class_("DigitalClockEdgeSelect", select.Select) +RefClkSourceSelect = si4713_ns.class_("RefClkSourceSelect", select.Select) +AcompAttackSelect = si4713_ns.class_("AcompAttackSelect", select.Select) +AcompReleaseSelect = si4713_ns.class_("AcompReleaseSelect", select.Select) +AcompPresetSelect = si4713_ns.class_("AcompPresetSelect", 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, -# ), + cv.Optional(CONF_PRE_EMPHASIS): select.select_schema( + PreEmphasisSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + cv.Optional(CONF_SECTION_ANALOG): cv.Schema( + { + cv.Optional(CONF_ATTENUATION): select.select_schema( + AnalogAttenuationSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_RESISTOR, + ), + } + ), + cv.Optional(CONF_SECTION_DIGITAL): cv.Schema( + { + cv.Optional(CONF_SAMPLE_BITS): select.select_schema( + DigitalSampleBitsSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=ICON_, + ), + cv.Optional(CONF_CHANNELS): select.select_schema( + DigitalChannelsSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_EAR_HEARING, + ), + cv.Optional(CONF_MODE): select.select_schema( + DigitalModeSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=ICON_, + ), + cv.Optional(CONF_CLOCK_EDGE): select.select_schema( + DigitalClockEdgeSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_PULSE, + ), + } + ), + cv.Optional(CONF_SECTION_REFCLK): cv.Schema( + { + cv.Optional(CONF_SOURCE): select.select_schema( + RefClkSourceSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_PULSE, + ), + } + ), + cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema( + { + cv.Optional(CONF_ATTACK): select.select_schema( + AcompAttackSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + cv.Optional(CONF_RELEASE): select.select_schema( + AcompReleaseSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + cv.Optional(CONF_PRESET): select.select_schema( + AcompPresetSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + } + ), } ) -async def new_select(config, id, setter, options): +async def new_select(parent, 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]) + await cg.register_parented(s, parent) cg.add(setter(s)) + return 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) + parent = await cg.get_variable(config[CONF_SI4713_ID]) + await new_select(parent, config, CONF_PRE_EMPHASIS, parent.set_pre_emphasis_select, PRE_EMPHASIS) + if analog_config := config.get(CONF_SECTION_ANALOG): + await new_select(parent, analog_config, CONF_ATTENUATION, parent.set_analog_attenuation_select, LINE_ATTENUATION) + if digital_config := config.get(CONF_SECTION_DIGITAL): + await new_select(parent, digital_config, CONF_SAMPLE_BITS, parent.set_digital_sample_bits_select, SAMPLE_BITS) + await new_select(parent, digital_config, CONF_CHANNELS, parent.set_digital_channels_select, SAMPLE_CHANNELS) + await new_select(parent, digital_config, CONF_MODE, parent.set_digital_mode_select, DIGITAL_MODE) + await new_select(parent, digital_config, CONF_CLOCK_EDGE, parent.set_digital_clock_edge_select, DIGITAL_CLOCK_EDGE) + if refclk_config := config.get(CONF_SECTION_REFCLK): + await new_select(parent, refclk_config, CONF_SOURCE, parent.set_refclk_source_select, REFCLK_SOURCE) + if compressor_config := config.get(CONF_SECTION_COMPRESSOR): + await new_select(parent, compressor_config, CONF_ATTACK, parent.set_acomp_attack_select, ACOMP_ATTACK) + await new_select(parent, compressor_config, CONF_RELEASE, parent.set_acomp_release_select, ACOMP_RELEASE) + await new_select(parent, compressor_config, CONF_PRESET, parent.set_acomp_preset_select, ACOMP_PRESET) diff --git a/esphome/components/si4713_i2c/select/acomp_attack_select.cpp b/esphome/components/si4713_i2c/select/acomp_attack_select.cpp new file mode 100644 index 0000000000..97ede8c835 --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_attack_select.cpp @@ -0,0 +1,14 @@ +#include "acomp_attack_select.h" + +namespace esphome { +namespace si4713 { + +void AcompAttackSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_acomp_attack((AcompAttack) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/acomp_attack_select.h b/esphome/components/si4713_i2c/select/acomp_attack_select.h new file mode 100644 index 0000000000..77c74eac08 --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_attack_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompAttackSelect : public select::Select, public Parented { + public: + AcompAttackSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/acomp_preset_select.cpp b/esphome/components/si4713_i2c/select/acomp_preset_select.cpp new file mode 100644 index 0000000000..fa13abfbbb --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_preset_select.cpp @@ -0,0 +1,14 @@ +#include "acomp_preset_select.h" + +namespace esphome { +namespace si4713 { + +void AcompPresetSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_acomp_preset((AcompPreset) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/acomp_preset_select.h b/esphome/components/si4713_i2c/select/acomp_preset_select.h new file mode 100644 index 0000000000..5991c49c88 --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_preset_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompPresetSelect : public select::Select, public Parented { + public: + AcompPresetSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/acomp_release_select.cpp b/esphome/components/si4713_i2c/select/acomp_release_select.cpp new file mode 100644 index 0000000000..789286c7e6 --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_release_select.cpp @@ -0,0 +1,14 @@ +#include "acomp_release_select.h" + +namespace esphome { +namespace si4713 { + +void AcompReleaseSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_acomp_release((AcompRelease) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/acomp_release_select.h b/esphome/components/si4713_i2c/select/acomp_release_select.h new file mode 100644 index 0000000000..8c98d233a7 --- /dev/null +++ b/esphome/components/si4713_i2c/select/acomp_release_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompReleaseSelect : public select::Select, public Parented { + public: + AcompReleaseSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/analog_attenuation_select.cpp b/esphome/components/si4713_i2c/select/analog_attenuation_select.cpp new file mode 100644 index 0000000000..9fd406e09a --- /dev/null +++ b/esphome/components/si4713_i2c/select/analog_attenuation_select.cpp @@ -0,0 +1,14 @@ +#include "analog_attenuation_select.h" + +namespace esphome { +namespace si4713 { + +void AnalogAttenuationSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_analog_attenuation((LineAttenuation) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/analog_attenuation_select.h b/esphome/components/si4713_i2c/select/analog_attenuation_select.h new file mode 100644 index 0000000000..77b8f14e7f --- /dev/null +++ b/esphome/components/si4713_i2c/select/analog_attenuation_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AnalogAttenuationSelect : public select::Select, public Parented { + public: + AnalogAttenuationSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_channels_select.cpp b/esphome/components/si4713_i2c/select/digital_channels_select.cpp new file mode 100644 index 0000000000..180399c81e --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_channels_select.cpp @@ -0,0 +1,14 @@ +#include "digital_channels_select.h" + +namespace esphome { +namespace si4713 { + +void DigitalChannelsSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_digital_channels((SampleChannels) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_channels_select.h b/esphome/components/si4713_i2c/select/digital_channels_select.h new file mode 100644 index 0000000000..a7570f473f --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_channels_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class DigitalChannelsSelect : public select::Select, public Parented { + public: + DigitalChannelsSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_clock_edge_select.cpp b/esphome/components/si4713_i2c/select/digital_clock_edge_select.cpp new file mode 100644 index 0000000000..d9f01966b8 --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_clock_edge_select.cpp @@ -0,0 +1,14 @@ +#include "digital_clock_edge_select.h" + +namespace esphome { +namespace si4713 { + +void DigitalClockEdgeSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_digital_clock_edge((DigitalClockEdge) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_clock_edge_select.h b/esphome/components/si4713_i2c/select/digital_clock_edge_select.h new file mode 100644 index 0000000000..e6b013985b --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_clock_edge_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class DigitalClockEdgeSelect : public select::Select, public Parented { + public: + DigitalClockEdgeSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_mode_select.cpp b/esphome/components/si4713_i2c/select/digital_mode_select.cpp new file mode 100644 index 0000000000..89ba5efe2b --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_mode_select.cpp @@ -0,0 +1,14 @@ +#include "digital_mode_select.h" + +namespace esphome { +namespace si4713 { + +void DigitalModeSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_digital_mode((DigitalMode) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_mode_select.h b/esphome/components/si4713_i2c/select/digital_mode_select.h new file mode 100644 index 0000000000..c4ad7258fd --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_mode_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class DigitalModeSelect : public select::Select, public Parented { + public: + DigitalModeSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_sample_bits_select.cpp b/esphome/components/si4713_i2c/select/digital_sample_bits_select.cpp new file mode 100644 index 0000000000..58a0491a74 --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_sample_bits_select.cpp @@ -0,0 +1,14 @@ +#include "digital_sample_bits_select.h" + +namespace esphome { +namespace si4713 { + +void DigitalSampleBitsSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_digital_sample_bits((SampleBits) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/digital_sample_bits_select.h b/esphome/components/si4713_i2c/select/digital_sample_bits_select.h new file mode 100644 index 0000000000..133d7b4e35 --- /dev/null +++ b/esphome/components/si4713_i2c/select/digital_sample_bits_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class DigitalSampleBitsSelect : public select::Select, public Parented { + public: + DigitalSampleBitsSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/pre_emphasis_select.cpp b/esphome/components/si4713_i2c/select/pre_emphasis_select.cpp new file mode 100644 index 0000000000..6f9f58164d --- /dev/null +++ b/esphome/components/si4713_i2c/select/pre_emphasis_select.cpp @@ -0,0 +1,14 @@ +#include "pre_emphasis_select.h" + +namespace esphome { +namespace si4713 { + +void PreEmphasisSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_pre_emphasis((PreEmphasis) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/pre_emphasis_select.h b/esphome/components/si4713_i2c/select/pre_emphasis_select.h new file mode 100644 index 0000000000..19ea13b656 --- /dev/null +++ b/esphome/components/si4713_i2c/select/pre_emphasis_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class PreEmphasisSelect : public select::Select, public Parented { + public: + PreEmphasisSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/refclk_source_select.cpp b/esphome/components/si4713_i2c/select/refclk_source_select.cpp new file mode 100644 index 0000000000..ba317290ed --- /dev/null +++ b/esphome/components/si4713_i2c/select/refclk_source_select.cpp @@ -0,0 +1,14 @@ +#include "refclk_source_select.h" + +namespace esphome { +namespace si4713 { + +void RefClkSourceSelect::control(const std::string &value) { + this->publish_state(value); + if (auto index = this->active_index()) { + this->parent_->set_refclk_source((RefClkSource) *index); + } +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/select/refclk_source_select.h b/esphome/components/si4713_i2c/select/refclk_source_select.h new file mode 100644 index 0000000000..2f8d48d133 --- /dev/null +++ b/esphome/components/si4713_i2c/select/refclk_source_select.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/select/select.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class RefClkSourceSelect : public select::Select, public Parented { + public: + RefClkSourceSelect() = default; + + protected: + void control(const std::string &value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/si4713.cpp b/esphome/components/si4713_i2c/si4713.cpp index 4d26640532..3b8772dea6 100644 --- a/esphome/components/si4713_i2c/si4713.cpp +++ b/esphome/components/si4713_i2c/si4713.cpp @@ -15,13 +15,12 @@ static const char *const TAG = "si4713"; Si4713Component::Si4713Component() { this->reset_pin_ = nullptr; this->reset_ = false; + this->op_mode_ = OpMode::OPMODE_ANALOG; + this->frequency_ = 8750; + this->power_ = 115; + this->antcap_ = 0; + this->tx_acomp_preset_ = AcompPreset::ACOMP_CUSTOM; memset(this->gpio_, 0, sizeof(gpio_)); - // 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 } bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size_t res_size) { @@ -34,6 +33,10 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size return false; } + if ((CmdType) buff[0] != CmdType::GET_INT_STATUS && (CmdType) buff[0] != CmdType::TX_ASQ_STATUS) { + ESP_LOGV(TAG, "send_cmd(0x%02X, %d)", buff[0], cmd_size); + } + 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); @@ -66,171 +69,6 @@ bool Si4713Component::send_cmd(const void *cmd, size_t cmd_size, void *res, size void Si4713Component::rds_update_() {} -// overrides - -void Si4713Component::setup() { - // CHIP STATE: POWER DOWN - - if (!this->power_up()) { - this->mark_failed(); - return; - } - - if (!this->detect_chip_id()) { - this->mark_failed(); - return; - } - - // CHIP STATE: POWER UP - - uint16_t pilot = 1; - uint16_t stereo = 1; - uint16_t rds = 0; - uint16_t fmpe = 1; - uint16_t acen = 0; - uint16_t limiter = 1; - uint16_t digital = 0; - - // Use GPO? - - // Set RCLK settings - this->set_prop(PropRefClkFreq(32768)); - this->set_prop(PropRefClkPreScale(1, 0)); // div1, RCLK source - - // Mono/Stereo? - this->set_prop(PropTxPilotFrequency(19000)); - this->set_prop(PropTxPilotDeviation(675)); - this->set_prop(PropTxComponentEnable(pilot, stereo, rds)); - - // Set Audio Deviation - this->set_prop(PropTxAudioDeviation(6825)); - - // Transmit RDS? - // this->set_prop(PropTxRdsDeviation(200)); - // if(rds) PropTxRds* - // if(rds) CmdTxRdsPs - // if(rds) CmdTxRdsBuff - - // Preemphasis? - this->set_prop(PropTxPreEmphasis(fmpe)); - this->set_prop(PropTxAcompEnable(acen, limiter)); - - // Compressor? - if (acen) { - // minimal compression - this->set_prop(PropTxAcompThreshold(-40)); // -40dBFS - this->set_prop(PropTxAcompAttackTime(0)); // 5ms - this->set_prop(PropTxAcompReleaseTime(0)); // 100ms - this->set_prop(PropTxAcompGain(15)); // 15dB - // aggressive compression - // this->set_prop(PropTxAcompThreshold(-15)); // -15dBFS - // this->set_prop(PropTxAcompAttackTime(9)); // 0.5ms - // this->set_prop(PropTxAcompReleaseTime(4)); // 1000ms - // this->set_prop(PropTxAcompGain(5)); // 5dB - } - - // Limiter? - if (limiter) { - this->set_prop(PropTxLimiterReleaseTime(102)); // 5.01 ms - } - - this->tune_freq(8750); - this->tune_power(115); - - // CHIP STATE: TRANSMITTING - - if (digital) { - // Digital Audio Input? - this->set_prop(PropDigitalInputFormat(0, 0, 1, 0)); // 16-bit, stereo, I2S mode, rising edge - this->set_prop(PropDigitalInputSampleRate(44100)); - } else { - // Analog Audio Input? - this->set_prop(PropTxLineInputLevel(636, 3)); // 636 mvPK, 60 kOhm - } - - // Mute? - this->set_prop(PropTxLineInputMute(0, 0)); // left no mute, right no mute - // Optional: Mute or Unmute Audio based on ASQ status - - // Enable GPIO1, GPIO2 - // TOOD: - // output: - // - platform: si4713 - // pin: 1/2 - // ... - this->send_cmd(CmdGpioCtl(1, 1)); - /* - this->set_interval(3000, [this]() { - static uint8_t gpio1 = 0, gpio2 = 0; - this->send_cmd(CmdGpioSet(gpio1++ & 1, gpio2++ & 1)); - }); - */ - this->set_interval(3000, [this]() { - ResTxTuneStatus res; - if (this->send_cmd(CmdTxTuneStatus(), res)) { - ESP_LOGD(TAG, "ResTxTuneStatus FREQ %d RFdBuV %d ANTCAP %d NL %d", (res.READFREQH << 8) | res.READFREQL, - res.READRFdBuV, res.READANTCAP, res.RNL); - } - }); - - // Monitor Audio Signal Quality (ASQ)? - // TODO: PropTxAsqInterruptSource - // TODO: PropTxAsqLevelLow - // TODO: PropTxAsqDurationLow - // TODO: PropTxAsqLevelHigh - // TODO: PropTxAsqDurationHigh - - this->set_interval(3000, [this]() { - ResTxAsqStatus res; - if (this->send_cmd(CmdTxAsqStatus(), res)) { - ESP_LOGD(TAG, "ResTxAsqStatus OVERMOD %d IALH %d IALL %d INLEVEL %d", res.OVERMOD, res.IALH, res.IALL, - res.INLEVEL); - } - }); - - // TODO - - this->publish_frequency(); - this->publish_mute(); - this->publish_mono(); - this->publish_rds_enable(); - this->publish_rds_station(); - this->publish_rds_text(); - this->publish_gpio(0); - this->publish_gpio(1); - this->publish_gpio(2); - - 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() {} - -// - bool Si4713Component::reset() { if (this->reset_pin_ == nullptr) { ESP_LOGE(TAG, "cannot reset device, reset pin is not set"); @@ -253,15 +91,16 @@ bool Si4713Component::reset() { } bool Si4713Component::power_up() { - // Note: In FMTX component 1.0 and 2.0, a reset is required when the system + // 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(); CmdPowerUp cmd; - cmd.FUNC = 2; - cmd.XOSCEN = 1; // TODO: external oscillator - cmd.OPMODE = 0x50; // TODO: digital - cmd.GPO2OEN = 0; // TODO: GPIO2 enable + cmd.OPMODE = (uint8_t) this->op_mode_; + cmd.FUNC = 2; // transmit + cmd.XOSCEN = this->op_mode_ == OpMode::OPMODE_ANALOG ? 1 : 0; // auto-enable(?) xtal for analog mode + cmd.GPO2OEN = 0; // we do this later + cmd.CTSIEN = 0; // no interrupts return this->send_cmd(cmd); } @@ -277,7 +116,7 @@ bool Si4713Component::detect_chip_id() { 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 + // TODO: support all transmitters 10/11/12/13/20/21, mask unsupported features if (res.PN != 10 && res.PN != 11 && res.PN != 12 && res.PN != 13) { ESP_LOGE(TAG, "Si47%02d is not supported", res.PN); @@ -287,175 +126,676 @@ bool Si4713Component::detect_chip_id() { return true; } -bool Si4713Component::tune_freq(uint16_t freq) { - if (!this->send_cmd(CmdTxTuneFreq(freq))) { - return false; - } - return this->tune_wait(); -} +bool Si4713Component::tune_freq(uint16_t freq) { return this->send_cmd(CmdTxTuneFreq(freq)) && this->stc_wait(); } bool Si4713Component::tune_power(uint8_t power, uint8_t antcap) { - if (!this->send_cmd(CmdTxTunePower(power, antcap))) { - return false; - } - return this->tune_wait(); + return this->send_cmd(CmdTxTunePower(power, antcap)) && this->stc_wait(); } -bool Si4713Component::tune_wait() { +bool Si4713Component::stc_wait() { ResGetIntStatus res; - while (res.CTS != 1 || res.STCINT != 1) { + while (res.STCINT != 1) { // risky loop of the day, it will be fine if (!this->send_cmd(CmdGetIntStatus(), res)) { return false; } } - ResTxTuneStatus res2; // TODO: maybe store this as the last tune result and report it through sensors - if (!this->send_cmd(CmdTxTuneStatus(), res2)) { - return false; + return this->send_cmd(CmdTxTuneStatus(0), this->tune_status_); +} + +// overrides + +void Si4713Component::setup() { + // CHIP STATE: POWER DOWN + + if (!this->power_up()) { + this->mark_failed(); + return; } - return true; + if (!this->detect_chip_id()) { + this->mark_failed(); + return; + } + + // CHIP STATE: POWER UP + + // Set RCLK settings + this->set_prop(this->refclk_freq_); + this->set_prop(this->refclk_prescale_); + // Mono/Stereo? + this->set_prop(this->tx_pilot_frequency_); + this->set_prop(this->tx_pilot_deviation_); + this->set_prop(this->tx_component_enable_); + // Set Audio Deviation + this->set_prop(this->tx_audio_deviation_); + // Transmit RDS? + this->set_prop(this->tx_rds_deviation_); + // Preemphasis? + this->set_prop(this->tx_pre_emphasis_); + this->set_prop(this->tx_acomp_enable_); + // Compressor? + // if (tx_acomp_enable_.ACEN) { + this->set_prop(this->tx_acomp_threshold_); + this->set_prop(this->tx_acomp_attack_time_); + this->set_prop(this->tx_acomp_release_time_); + this->set_prop(this->tx_acomp_gain_); + //} + // Limiter? + // if (tx_acomp_enable_.LIMITEN) { + this->set_prop(tx_limiter_releasee_time_); + //} + // Tune + this->tune_freq(this->frequency_); + this->tune_power(this->power_, this->antcap_); + + // CHIP STATE: TRANSMITTING + + // if (this->op_mode_ == OpMode::OPMODE_DIGITAL) { + // Digital Audio Input? + this->set_prop(digital_input_format_); + this->set_prop(digital_input_sample_rate_); + //} else if (this->op_mode_ == OpMode::OPMODE_ANALOG) { + // Analog Audio Input? + this->set_prop(tx_line_input_level_); + //} + // Mute? Optional: Mute or Unmute Audio based on ASQ status + this->set_prop(this->tx_line_input_mute_); + // GPIO + this->send_cmd(CmdGpioCtl(1, 1, 0)); // enable gpio1 and gpio2, clock is on gpio3 + this->send_cmd(CmdGpioSet(0, 0, 0)); // init gpio to low (TODO: config) + // AQS + this->set_prop(this->tx_asq_interrupt_source_); + this->set_prop(this->tx_asq_level_low_); + this->set_prop(this->tx_asq_duration_low_); + this->set_prop(this->tx_asq_level_high_); + this->set_prop(this->tx_asq_duration_high_); + // RDS + // TODO: PropTxRds*, CmdTxRdsPs, CmdTxRdsBuff + + // publish + + this->publish_mute(); + this->publish_mono(); + this->publish_pre_emphasis(); + this->publish_frequency(); + this->publish_audio_deviation(); + this->publish_power(); + this->publish_antcap(); + this->publish_analog_level(); + this->publish_analog_attenuation(); + this->publish_digital_sample_rate(); + this->publish_digital_sample_bits(); + this->publish_digital_channels(); + this->publish_digital_mode(); + this->publish_digital_clock_edge(); + this->publish_pilot_enable(); + this->publish_pilot_frequency(); + this->publish_pilot_deviation(); + this->publish_refclk_frequency(); + this->publish_refclk_source(); + this->publish_refclk_prescaler(); + this->publish_acomp_enable(); + this->publish_acomp_threshold(); + this->publish_acomp_attack(); + this->publish_acomp_release(); + this->publish_acomp_gain(); + this->publish_acomp_preset(); + this->publish_limiter_enable(); + this->publish_limiter_release_time(); + this->publish_asq_iall_enable(); + this->publish_asq_ialh_enable(); + this->publish_asq_overmod_enable(); + this->publish_asq_level_low(); + this->publish_asq_duration_low(); + this->publish_asq_level_high(); + this->publish_asq_duration_high(); + this->publish_rds_enable(); + this->publish_rds_deviation(); + this->publish_rds_station(); + this->publish_rds_text(); + this->publish_gpio1(); + this->publish_gpio2(); + this->publish_gpio3(); + this->publish_chip_id(); + this->publish_read_frequency(); + this->publish_read_power(); + this->publish_read_antcap(); + this->publish_read_noise_level(); + this->publish_iall(); + this->publish_ialh(); + this->publish_overmod(); + this->publish_inlevel(); + + 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() { + // these might be changing too fast for loop() + this->publish_read_noise_level(); + this->publish_inlevel(); +} + +void Si4713Component::loop() { + ResGetIntStatus res; + if (this->send_cmd(CmdGetIntStatus(), res)) { + if (res.STCINT == 1) { + ESP_LOGV(TAG, "STCINT"); + if (this->send_cmd(CmdTxTuneStatus(1), this->tune_status_)) { + float f = (float) ((this->tune_status_.READFREQH << 8) | this->tune_status_.READFREQL) / 100; + ESP_LOGD(TAG, "ResTxTuneStatus FREQ %.2f RFdBuV %d ANTCAP %d NL %d", f, this->tune_status_.READRFdBuV, + this->tune_status_.READANTCAP, this->tune_status_.RNL); + this->publish_read_frequency(); + this->publish_read_power(); + this->publish_read_antcap(); + // this->publish_read_noise_level(); + } + } + if (res.ASQINT == 1) { + if (this->send_cmd(CmdTxAsqStatus(1), this->asq_status_)) { + // ESP_LOGD(TAG, "ResTxAsqStatus IALL %d IALH %d OVERMOD %d INLEVEL %d", + // this->asq_status_.IALL, this->asq_status_.IALH, this->asq_status_.OVERMOD, + // this->asq_status_.INLEVEL); + this->publish_iall(); + this->publish_ialh(); + this->publish_overmod(); + // this->publish_inlevel(); + } + } + // TODO: if (res.RDSINT == 1) {} + } } // 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; +#define CHECK_ENUM(value) \ + if (value >= GET_ENUM_LAST(value)) { \ + ESP_LOGE(TAG, "%s(%d) invalid", __func__, (int) value); \ + 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); +#define CHECK_FLOAT_RANGE(value, min_value, max_value) \ + if (!(min_value <= value && value <= max_value)) { \ + ESP_LOGE(TAG, "%s(%.2f) invalid (%.2f - %.2f)", __func__, value, min_value, max_value); \ + return; \ + } - this->publish_frequency(); -} +#define CHECK_INT_RANGE(value, min_value, max_value) \ + if (!(min_value <= value && value <= max_value)) { \ + ESP_LOGE(TAG, "%s(%d) invalid (%d - %d)", __func__, value, min_value, max_value); \ + return; \ + } -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; -} +#define CHECK_TEXT_RANGE(value, max_size) \ + if (value.size() > max_size) { \ + ESP_LOGW(TAG, "%s(%s) trimmed (max %d characters)", __func__, value.c_str(), max_size); \ + value.resize(max_size); \ + } + +void Si4713Component::set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; } + +void Si4713Component::set_op_mode(OpMode value) { this->op_mode_ = (OpMode) value; } void Si4713Component::set_mute(bool value) { - // this->state_.MUTE = value ? 1 : 0; - // this->write_reg_(REG_SYSTEM_ADDR); - + this->tx_line_input_mute_.LIMUTE = value ? 1 : 0; + this->tx_line_input_mute_.RIMUTE = value ? 1 : 0; + this->set_prop(this->tx_line_input_mute_); this->publish_mute(); } bool Si4713Component::get_mute() { - // return this->state_.MUTE == 1; - return false; + return this->tx_line_input_mute_.LIMUTE != 0 && this->tx_line_input_mute_.RIMUTE != 0; } void Si4713Component::set_mono(bool value) { - // this->state_.MONO = value ? 1 : 0; - // this->write_reg_(REG_SYSTEM_ADDR); - + // NOTE: analog/digital mono linked, easier to control this way + this->tx_component_enable_.LMR = value ? 0 : 1; + this->set_prop(this->tx_component_enable_); this->publish_mono(); + this->digital_input_format_.IMONO = value ? 1 : 0; + this->set_prop(this->digital_input_format_); + this->publish_digital_channels(); } -bool Si4713Component::get_mono() { - // return this->state_.MONO == 1; - return false; +bool Si4713Component::get_mono() { return this->tx_component_enable_.LMR == 0; } + +void Si4713Component::set_pre_emphasis(PreEmphasis value) { + CHECK_ENUM(value) + this->tx_pre_emphasis_.FMPE = (uint16_t) value; + this->set_prop(this->tx_pre_emphasis_); + this->publish_pre_emphasis(); } +PreEmphasis Si4713Component::get_pre_emphasis() { return (PreEmphasis) tx_pre_emphasis_.FMPE; } + +void Si4713Component::set_frequency(float value) { + CHECK_FLOAT_RANGE(value, FREQ_MIN, FREQ_MAX) + this->frequency_ = (uint16_t) clamp((int) std::lround(value * 20) * 5, FREQ_RAW_MIN, FREQ_RAW_MAX); + this->tune_freq(this->frequency_); + this->publish_frequency(); +} + +float Si4713Component::get_frequency() { return (float) this->frequency_ / 100; } + +void Si4713Component::set_audio_deviation(float value) { + CHECK_FLOAT_RANGE(value, TXADEV_MIN, TXADEV_MAX) + this->tx_audio_deviation_.TXADEV = (uint16_t) clamp((int) std::lround(value * 100), TXADEV_RAW_MIN, TXADEV_RAW_MAX); + this->set_prop(this->tx_audio_deviation_); + this->publish_audio_deviation(); +} + +float Si4713Component::get_audio_deviation() { return (float) this->tx_audio_deviation_.TXADEV / 100; } + +void Si4713Component::set_power(int value) { + CHECK_INT_RANGE(value, POWER_MIN, POWER_MAX) + this->power_ = (uint8_t) value; + this->tune_power(this->power_, this->antcap_); + this->publish_power(); +} + +int Si4713Component::get_power() { return (int) this->power_; } + +void Si4713Component::set_antcap(int value) { + CHECK_INT_RANGE(value, ANTCAP_MIN, ANTCAP_MAX) + this->antcap_ = (uint8_t) value; + this->tune_power(this->power_, this->antcap_); + this->publish_antcap(); +} + +int Si4713Component::get_antcap() { return (int) this->antcap_; } + +void Si4713Component::set_analog_level(int value) { + CHECK_INT_RANGE(value, LILEVEL_MIN, LILEVEL_MAX) + this->tx_line_input_level_.LILEVEL = (uint16_t) value; + this->set_prop(this->tx_line_input_level_); + this->publish_analog_level(); +} + +int Si4713Component::get_analog_level() { return (int) this->tx_line_input_level_.LILEVEL; } + +void Si4713Component::set_analog_attenuation(LineAttenuation value) { + CHECK_ENUM(value) + this->tx_line_input_level_.LIATTEN = (uint16_t) value; + this->set_prop(this->tx_line_input_level_); + this->publish_analog_attenuation(); +} + +LineAttenuation Si4713Component::get_analog_attenuation() { + return (LineAttenuation) this->tx_line_input_level_.LIATTEN; +} + +void Si4713Component::set_digital_sample_rate(int value) { + CHECK_INT_RANGE(value, DISR_MIN, DISR_MAX) + this->digital_input_sample_rate_.DISR = (uint16_t) value; + this->set_prop(this->digital_input_sample_rate_); + this->publish_digital_sample_rate(); +} + +int Si4713Component::get_digital_sample_rate() { return (int) this->digital_input_sample_rate_.DISR; } + +void Si4713Component::set_digital_sample_bits(SampleBits value) { + CHECK_ENUM(value) + this->digital_input_format_.ISIZE = (uint16_t) value; + this->set_prop(this->digital_input_format_); + this->publish_digital_sample_bits(); +} + +SampleBits Si4713Component::get_digital_sample_bits() { return (SampleBits) this->digital_input_format_.ISIZE; } + +void Si4713Component::set_digital_channels(SampleChannels value) { + CHECK_ENUM(value) + this->digital_input_format_.IMONO = (uint16_t) value; + this->set_prop(this->digital_input_format_); + this->publish_digital_channels(); +} + +SampleChannels Si4713Component::get_digital_channels() { return (SampleChannels) this->digital_input_format_.IMONO; } + +void Si4713Component::set_digital_mode(DigitalMode value) { + CHECK_ENUM(value) + this->digital_input_format_.IMODE = (uint16_t) value; + this->set_prop(this->digital_input_format_); + this->publish_digital_mode(); +} + +DigitalMode Si4713Component::get_digital_mode() { return (DigitalMode) this->digital_input_format_.IMODE; } + +void Si4713Component::set_digital_clock_edge(DigitalClockEdge value) { + CHECK_ENUM(value) + this->digital_input_format_.IFALL = (uint16_t) value; + this->set_prop(this->digital_input_format_); + this->publish_digital_clock_edge(); +} + +DigitalClockEdge Si4713Component::get_digital_clock_edge() { return (DigitalClockEdge) digital_input_format_.IFALL; } + +void Si4713Component::set_pilot_enable(bool value) { + this->tx_component_enable_.PILOT = value ? 1 : 0; + this->set_prop(this->tx_component_enable_); + this->publish_pilot_enable(); +} + +bool Si4713Component::get_pilot_enable() { return this->tx_component_enable_.PILOT != 0; } + +void Si4713Component::set_pilot_frequency(float value) { + CHECK_FLOAT_RANGE(value, PILOT_FREQ_MIN, PILOT_FREQ_MAX) + this->tx_pilot_frequency_.FREQ = + (uint16_t) clamp((int) std::lround(value * 1000), PILOT_FREQ_RAW_MIN, PILOT_FREQ_RAW_MAX); + this->set_prop(this->tx_pilot_frequency_); + this->publish_pilot_frequency(); +} + +float Si4713Component::get_pilot_frequency() { return (float) this->tx_pilot_frequency_.FREQ / 1000; } + +void Si4713Component::set_pilot_deviation(float value) { + CHECK_FLOAT_RANGE(value, TXPDEV_MIN, TXPDEV_MAX) + this->tx_pilot_deviation_.TXPDEV = (uint16_t) clamp((int) std::lround(value * 100), TXPDEV_RAW_MIN, TXPDEV_RAW_MAX); + this->set_prop(this->tx_pilot_deviation_); + this->publish_pilot_deviation(); +} + +float Si4713Component::get_pilot_deviation() { return (float) this->tx_pilot_deviation_.TXPDEV / 100; } + +void Si4713Component::set_refclk_frequency(int value) { + CHECK_INT_RANGE(value, REFCLKF_MIN, REFCLKF_MAX) + this->refclk_freq_.REFCLKF = (uint16_t) value; + this->set_prop(this->refclk_freq_); + this->publish_refclk_frequency(); +} + +int Si4713Component::get_refclk_frequency() { return this->refclk_freq_.REFCLKF; } + +void Si4713Component::set_refclk_source(RefClkSource value) { + CHECK_ENUM(value) + this->refclk_prescale_.RCLKSEL = (uint16_t) value; + this->set_prop(this->refclk_prescale_); + this->publish_refclk_source(); +} + +RefClkSource Si4713Component::get_refclk_source() { return (RefClkSource) this->refclk_prescale_.RCLKSEL; } + +void Si4713Component::set_refclk_prescaler(int value) { + CHECK_INT_RANGE(value, RCLKP_MIN, RCLKP_MAX) + this->refclk_prescale_.RCLKP = (uint16_t) value; + this->set_prop(this->refclk_freq_); + this->publish_refclk_prescaler(); +} + +int Si4713Component::get_refclk_prescaler() { return (int) this->refclk_prescale_.RCLKP; } + +void Si4713Component::set_acomp_enable(bool value) { + this->tx_acomp_enable_.ACEN = value ? 1 : 0; + this->set_prop(this->tx_acomp_enable_); + this->publish_acomp_enable(); +} + +bool Si4713Component::get_acomp_enable() { return this->tx_acomp_enable_.ACEN != 0; } + +void Si4713Component::set_acomp_threshold(int value) { + CHECK_INT_RANGE(value, ACOMP_THRESHOLD_MIN, ACOMP_THRESHOLD_MAX) + this->tx_acomp_threshold_.THRESHOLD = (int16_t) value; + this->set_prop(this->tx_acomp_threshold_); + this->publish_acomp_threshold(); +} + +int Si4713Component::get_acomp_threshold() { return (int) this->tx_acomp_threshold_.THRESHOLD; } + +void Si4713Component::set_acomp_attack(AcompAttack value) { + CHECK_ENUM(value) + this->tx_acomp_attack_time_.ATTACK = (uint16_t) value; + this->set_prop(this->tx_acomp_attack_time_); + this->publish_acomp_attack(); +} + +AcompAttack Si4713Component::get_acomp_attack() { return (AcompAttack) tx_acomp_attack_time_.ATTACK; } + +void Si4713Component::set_acomp_release(AcompRelease value) { + CHECK_ENUM(value) + this->tx_acomp_release_time_.RELEASE = (uint16_t) value; + this->set_prop(this->tx_acomp_release_time_); + this->publish_acomp_release(); +} + +AcompRelease Si4713Component::get_acomp_release() { return (AcompRelease) this->tx_acomp_release_time_.RELEASE; } + +void Si4713Component::set_acomp_gain(int value) { + CHECK_INT_RANGE(value, ACOMP_GAIN_MIN, ACOMP_GAIN_MAX) + this->tx_acomp_gain_.GAIN = (int16_t) value; + this->set_prop(this->tx_acomp_gain_); + this->publish_acomp_gain(); +} + +int Si4713Component::get_acomp_gain() { return (int) this->tx_acomp_gain_.GAIN; } + +void Si4713Component::set_acomp_preset(AcompPreset value) { + CHECK_ENUM(value) + this->tx_acomp_preset_ = value; + switch (value) { + case AcompPreset::ACOMP_MINIMAL: + this->set_acomp_threshold(-40); + this->set_acomp_attack(AcompAttack::ATTACK_50MS); + this->set_acomp_release(AcompRelease::RELEASE_100MS); + this->set_acomp_gain(15); + break; + case AcompPreset::ACOMP_AGGRESSIVE: + this->set_acomp_threshold(-15); + this->set_acomp_attack(AcompAttack::ATTACK_05MS); + this->set_acomp_release(AcompRelease::RELEASE_1000MS); + this->set_acomp_gain(5); + break; + } + this->publish_acomp_preset(); +} + +AcompPreset Si4713Component::get_acomp_preset() { return this->tx_acomp_preset_; } + +void Si4713Component::set_limiter_enable(bool value) { + this->tx_acomp_enable_.LIMITEN = value ? 1 : 0; + this->set_prop(this->tx_acomp_enable_); + this->publish_limiter_enable(); +} + +bool Si4713Component::get_limiter_enable() { return this->tx_acomp_enable_.LIMITEN != 0; } + +void Si4713Component::set_limiter_release_time(float value) { + CHECK_FLOAT_RANGE(value, LMITERTC_MIN, LMITERTC_MAX) + this->tx_limiter_releasee_time_.LMITERTC = + (uint16_t) clamp((int) std::lround(512.0f / value), LMITERTC_RAW_MIN, LMITERTC_RAW_MAX); + this->set_prop(this->tx_limiter_releasee_time_); + this->publish_limiter_release_time(); +} + +float Si4713Component::get_limiter_release_time() { return (float) 512.0f / this->tx_limiter_releasee_time_.LMITERTC; } + +void Si4713Component::set_asq_iall_enable(bool value) { + this->tx_asq_interrupt_source_.IALLIEN = value ? 1 : 0; + this->set_prop(this->tx_asq_interrupt_source_); + this->publish_asq_iall_enable(); +} + +bool Si4713Component::get_asq_iall_enable() { return this->tx_asq_interrupt_source_.IALLIEN != 0; } + +void Si4713Component::set_asq_ialh_enable(bool value) { + this->tx_asq_interrupt_source_.IALHIEN = value ? 1 : 0; + this->set_prop(this->tx_asq_interrupt_source_); + this->publish_asq_ialh_enable(); +} + +bool Si4713Component::get_asq_ialh_enable() { return this->tx_asq_interrupt_source_.IALHIEN != 0; } + +void Si4713Component::set_asq_overmod_enable(bool value) { + this->tx_asq_interrupt_source_.OVERMODIEN = value ? 1 : 0; + this->set_prop(this->tx_asq_interrupt_source_); + this->publish_asq_overmod_enable(); +} + +bool Si4713Component::get_asq_overmod_enable() { return this->tx_asq_interrupt_source_.OVERMODIEN != 0; } + +void Si4713Component::set_asq_level_low(int value) { + CHECK_INT_RANGE(value, IALTH_MIN, IALTH_MAX) + this->tx_asq_level_low_.IALLTH = (int8_t) value; + this->set_prop(this->tx_asq_level_low_); + this->publish_asq_level_low(); +} + +int Si4713Component::get_asq_level_low() { return (int) this->tx_asq_level_low_.IALLTH; } + +void Si4713Component::set_asq_duration_low(int value) { + CHECK_INT_RANGE(value, IALDUR_MIN, IALDUR_MAX) + this->tx_asq_duration_low_.IALLDUR = (uint16_t) value; + this->set_prop(this->tx_asq_duration_low_); + this->publish_asq_duration_low(); +} + +int Si4713Component::get_asq_duration_low() { return (int) this->tx_asq_duration_low_.IALLDUR; } + +void Si4713Component::set_asq_level_high(int value) { + CHECK_INT_RANGE(value, IALTH_MIN, IALTH_MAX) + this->tx_asq_level_high_.IALHTH = (int8_t) value; + this->set_prop(this->tx_asq_level_high_); + this->publish_asq_level_high(); +} + +int Si4713Component::get_asq_level_high() { return (int) this->tx_asq_level_high_.IALHTH; } + +void Si4713Component::set_asq_duration_high(int value) { + CHECK_INT_RANGE(value, IALDUR_MIN, IALDUR_MAX) + this->tx_asq_duration_high_.IALHDUR = (uint16_t) value; + this->set_prop(this->tx_asq_duration_high_); + this->publish_asq_duration_high(); +} + +int Si4713Component::get_asq_duration_high() { return (int) this->tx_asq_duration_high_.IALHDUR; } + void Si4713Component::set_rds_enable(bool value) { - // TODO - + this->tx_component_enable_.RDS = value ? 0 : 1; + this->set_prop(this->tx_component_enable_); this->publish_rds_enable(); } -bool Si4713Component::get_rds_enable() { - // return this->state_.RDSEN == 1; - return false; +bool Si4713Component::get_rds_enable() { return this->tx_component_enable_.RDS != 0; } + +void Si4713Component::set_rds_deviation(float value) { + CHECK_FLOAT_RANGE(value, TXRDEV_MIN, TXRDEV_MAX) + this->tx_rds_deviation_.TXRDEV = (uint16_t) clamp((int) std::lround(value * 100), TXRDEV_RAW_MIN, TXRDEV_RAW_MAX); + this->set_prop(this->tx_rds_deviation_); + this->publish_rds_deviation(); } +float Si4713Component::get_rds_deviation() { return (float) this->tx_rds_deviation_.TXRDEV / 100; } + 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->rds_station_pos_ = 0; + CHECK_TEXT_RANGE(this->rds_station_, RDS_STATION_MAX) this->publish_rds_station(); } +std::string Si4713Component::get_rds_station() { return this->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); - } - + CHECK_TEXT_RANGE(this->rds_text_, RDS_TEXT_MAX) this->publish_rds_text(); } +std::string Si4713Component::get_rds_text() { return this->rds_text_; } + void Si4713Component::set_gpio(uint8_t pin, bool value) { if (pin > 2) { - ESP_LOGE(TAG, "set_gpio(%d, %d) invalid pin number, 0 to 2", pin, value ? 1 : 0); + ESP_LOGE(TAG, "%s(%d, %d) invalid pin number (0 to 2)", __func__, pin, value); return; } - ESP_LOGD(TAG, "set_gpio(%d, %d)", pin, value ? 1 : 0); this->gpio_[pin] = value ? 1 : 0; - this->send_cmd(CmdGpioCtl(this->gpio_[0], this->gpio_[1], this->gpio_[2])); - + this->send_cmd(CmdGpioSet(this->gpio_[0], this->gpio_[1], this->gpio_[2])); this->publish_gpio(pin); } bool Si4713Component::get_gpio(uint8_t pin) { if (pin > 2) { - ESP_LOGE(TAG, "get_gpio(%d) invalid pin number, 0 to 2", pin); + ESP_LOGE(TAG, "%s(%d) invalid pin number (0 to 2)", __func__, pin); return false; } - return this->gpio_[pin]; + return this->gpio_[pin] != 0; } +void Si4713Component::set_gpio1(bool value) { + this->gpio_[0] = value ? 1 : 0; + this->send_cmd(CmdGpioSet(this->gpio_[0], this->gpio_[1], this->gpio_[2])); + this->publish_gpio1(); +} + +bool Si4713Component::get_gpio1() { return this->gpio_[0] != 0; } + +void Si4713Component::set_gpio2(bool value) { + this->gpio_[1] = value ? 1 : 0; + this->send_cmd(CmdGpioSet(this->gpio_[0], this->gpio_[1], this->gpio_[2])); + this->publish_gpio2(); +} + +bool Si4713Component::get_gpio2() { return this->gpio_[1] != 0; } + +void Si4713Component::set_gpio3(bool value) { + this->gpio_[2] = value ? 1 : 0; + this->send_cmd(CmdGpioSet(this->gpio_[0], this->gpio_[1], this->gpio_[2])); + this->publish_gpio2(); +} + +bool Si4713Component::get_gpio3() { return this->gpio_[2] != 0; } + +std::string Si4713Component::get_chip_id() { return this->chip_id_; } + +float Si4713Component::get_read_frequency() { + return (float) ((this->tune_status_.READFREQH << 8) | this->tune_status_.READFREQL) / 100; +} + +float Si4713Component::get_read_power() { return (float) this->tune_status_.READRFdBuV; } + +float Si4713Component::get_read_antcap() { return (float) this->tune_status_.READANTCAP; } + +float Si4713Component::get_read_noise_level() { return (float) this->tune_status_.RNL; } + +bool Si4713Component::get_iall() { return this->asq_status_.IALL != 0; } + +bool Si4713Component::get_ialh() { return this->asq_status_.IALH != 0; } + +bool Si4713Component::get_overmod() { return this->asq_status_.OVERMOD != 0; } + +float Si4713Component::get_inlevel() { return (float) this->asq_status_.INLEVEL; } + // 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_gpio(uint8_t pin) { switch (pin) { case 0: - this->publish(this->gpio1_switch_, this->gpio_[pin]); + this->publish_switch(this->gpio1_switch_, this->gpio_[pin] != 0); break; case 1: - this->publish(this->gpio2_switch_, this->gpio_[pin]); + this->publish_switch(this->gpio2_switch_, this->gpio_[pin] != 0); break; case 2: - this->publish(this->gpio3_switch_, this->gpio_[pin]); + this->publish_switch(this->gpio3_switch_, this->gpio_[pin] != 0); break; default: return; } } -void Si4713Component::publish(text_sensor::TextSensor *s, const std::string &state) { +template void Si4713Component::publish(S *s, T state) { if (s != nullptr) { if (!s->has_state() || s->state != state) { s->publish_state(state); @@ -463,23 +803,7 @@ void Si4713Component::publish(text_sensor::TextSensor *s, const std::string &sta } } -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) { +void Si4713Component::publish_switch(switch_::Switch *s, bool state) { if (s != nullptr) { if (s->state != state) { // ? s->publish_state(state); @@ -487,7 +811,7 @@ void Si4713Component::publish(switch_::Switch *s, bool state) { } } -void Si4713Component::publish(select::Select *s, size_t index) { +void Si4713Component::publish_select(select::Select *s, size_t index) { if (s != nullptr) { if (auto state = s->at(index)) { if (!s->has_state() || s->state != *state) { @@ -497,12 +821,13 @@ void Si4713Component::publish(select::Select *s, size_t index) { } } -void Si4713Component::publish(text::Text *t, const std::string &state) { - if (t != nullptr) { - if (!t->has_state() || t->state != state) { - t->publish_state(state); - } +void Si4713Component::measure_freq(float value) { + uint16_t f = (uint16_t) clamp((int) std::lround(value * 20) * 5, FREQ_RAW_MIN, FREQ_RAW_MAX); + if (!this->send_cmd(CmdTxTuneMeasure(f))) { + return; } + + // this->stc_wait(); // does not work, locks up, hmm } } // namespace si4713 diff --git a/esphome/components/si4713_i2c/si4713.h b/esphome/components/si4713_i2c/si4713.h index 33558c2e9a..02a8bbb9e1 100644 --- a/esphome/components/si4713_i2c/si4713.h +++ b/esphome/components/si4713_i2c/si4713.h @@ -5,6 +5,7 @@ #include "esphome/core/gpio.h" #include "esphome/components/i2c/i2c.h" #include "esphome/components/sensor/sensor.h" +#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/number/number.h" #include "esphome/components/switch/switch.h" @@ -25,20 +26,75 @@ namespace si4713 { void set_##name##_text(text::Text *text) { this->name##_text_ = text; } #endif +#define SUB_NUMBER_EX(name) \ + SUB_NUMBER(name) \ + void publish_##name() { this->publish(this->name##_number_, (float) this->get_##name()); } + +#define SUB_SWITCH_EX(name) \ + SUB_SWITCH(name) \ + void publish_##name() { this->publish_switch(this->name##_switch_, this->get_##name()); } + +#define SUB_SELECT_EX(name) \ + SUB_SELECT(name) \ + void publish_##name() { this->publish_select(this->name##_select_, (size_t) this->get_##name()); } + +#define SUB_TEXT_EX(name) \ + SUB_TEXT(name) \ + void publish_##name() { this->publish(this->name##_text_, this->get_##name()); } + +#define SUB_SENSOR_EX(name) \ + SUB_SENSOR(name) \ + void publish_##name() { this->publish(this->name##_sensor_, (float) this->get_##name()); } + +#define SUB_BINARY_SENSOR_EX(name) \ + SUB_BINARY_SENSOR(name) \ + void publish_##name() { this->publish(this->name##_binary_sensor_, this->get_##name()); } + +#define SUB_TEXT_SENSOR_EX(name) \ + SUB_TEXT_SENSOR(name) \ + void publish_##name() { this->publish(this->name##_text_sensor_, this->get_##name()); } + class Si4713Component : public PollingComponent, public i2c::I2CDevice { std::string chip_id_; InternalGPIOPin *reset_pin_; bool reset_; - bool gpio_[3]; - /* - union { - struct Si4713State state_; - uint8_t regs_[sizeof(struct Si4713State)]; - }; + ResTxTuneStatus tune_status_; + ResTxAsqStatus asq_status_; + + // config state + + OpMode op_mode_; + uint16_t frequency_; + uint8_t power_; + uint8_t antcap_; + PropTxComponentEnable tx_component_enable_; + PropTxAudioDeviation tx_audio_deviation_; + PropTxPreEmphasis tx_pre_emphasis_; + PropTxPilotFrequency tx_pilot_frequency_; + PropTxPilotDeviation tx_pilot_deviation_; + PropTxLineInputLevel tx_line_input_level_; + PropTxLineInputMute tx_line_input_mute_; + PropDigitalInputFormat digital_input_format_; + PropDigitalInputSampleRate digital_input_sample_rate_; + PropRefClkFreq refclk_freq_; + PropRefClkPreScale refclk_prescale_; + PropTxAcompEnable tx_acomp_enable_; + PropTxAcompThreshold tx_acomp_threshold_; + PropTxAcompAttackTime tx_acomp_attack_time_; + PropTxAcompReleaseTime tx_acomp_release_time_; + AcompPreset tx_acomp_preset_; + PropTxAcompGain tx_acomp_gain_; + PropTxLimiterReleaseTime tx_limiter_releasee_time_; + PropTxAsqInterruptSource tx_asq_interrupt_source_; + PropTxAsqLevelLow tx_asq_level_low_; + PropTxAsqDurationLow tx_asq_duration_low_; + PropTxAsqLevelHigh tx_asq_level_high_; + PropTxAsqDurationHigh tx_asq_duration_high_; + PropTxRdsDeviation tx_rds_deviation_; + std::string rds_station_; + std::string rds_text_; + uint8_t gpio_[3]; - 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 bool send_cmd(const CMD &cmd) { @@ -64,42 +120,86 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { return false; } - 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_(); // TODO - void rds_update_(); + bool reset(); + bool power_up(); + bool power_down(); + bool detect_chip_id(); + bool tune_freq(uint16_t freq); + bool tune_power(uint8_t power, uint8_t antcap = 0); + bool stc_wait(); - 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) - SUB_SWITCH(gpio1) - SUB_SWITCH(gpio2) - SUB_SWITCH(gpio3) + template void publish(S *s, T state); + // template specialization here is not supported by the compiler yet + void publish_switch(switch_::Switch *s, bool state); + void publish_select(select::Select *s, size_t index); - 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_gpio(uint8_t pin); - 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); + // general config + SUB_SWITCH_EX(mute) + SUB_SWITCH_EX(mono) + SUB_SELECT_EX(pre_emphasis) + // tuner + SUB_NUMBER_EX(frequency) + SUB_NUMBER_EX(audio_deviation) + SUB_NUMBER_EX(power) + SUB_NUMBER_EX(antcap) + // analog + SUB_NUMBER_EX(analog_level) + SUB_SELECT_EX(analog_attenuation) + // digital + SUB_NUMBER_EX(digital_sample_rate) + SUB_SELECT_EX(digital_sample_bits) + SUB_SELECT_EX(digital_channels) + SUB_SELECT_EX(digital_mode) + SUB_SELECT_EX(digital_clock_edge) + // pilot + SUB_SWITCH_EX(pilot_enable) + SUB_NUMBER_EX(pilot_frequency) + SUB_NUMBER_EX(pilot_deviation) + // refclk + SUB_NUMBER_EX(refclk_frequency) + SUB_SELECT_EX(refclk_source) + SUB_NUMBER_EX(refclk_prescaler) + // compressor + SUB_SWITCH_EX(acomp_enable) + SUB_NUMBER_EX(acomp_threshold) + SUB_SELECT_EX(acomp_attack) + SUB_SELECT_EX(acomp_release) + SUB_NUMBER_EX(acomp_gain) + SUB_SELECT_EX(acomp_preset) + // limiter + SUB_SWITCH_EX(limiter_enable) + SUB_NUMBER_EX(limiter_release_time) + // asq + SUB_SWITCH_EX(asq_iall_enable) + SUB_SWITCH_EX(asq_ialh_enable) + SUB_SWITCH_EX(asq_overmod_enable) + SUB_NUMBER_EX(asq_level_low) + SUB_NUMBER_EX(asq_duration_low) + SUB_NUMBER_EX(asq_level_high) + SUB_NUMBER_EX(asq_duration_high) + // rds + SUB_SWITCH_EX(rds_enable) + SUB_NUMBER_EX(rds_deviation) + SUB_TEXT_EX(rds_station) + SUB_TEXT_EX(rds_text) + // output + SUB_SWITCH_EX(gpio1) + SUB_SWITCH_EX(gpio2) + SUB_SWITCH_EX(gpio3) + // sensors + SUB_TEXT_SENSOR_EX(chip_id) + SUB_SENSOR_EX(read_frequency) + SUB_SENSOR_EX(read_power) + SUB_SENSOR_EX(read_antcap) + SUB_SENSOR_EX(read_noise_level) + SUB_BINARY_SENSOR_EX(iall) + SUB_BINARY_SENSOR_EX(ialh) + SUB_BINARY_SENSOR_EX(overmod) + SUB_SENSOR_EX(inlevel) + + void publish_gpio(uint8_t pin); // helper public: Si4713Component(); @@ -110,27 +210,121 @@ class Si4713Component : public PollingComponent, public i2c::I2CDevice { void update() override; void loop() override; - bool reset(); - bool power_up(); - bool power_down(); - bool detect_chip_id(); - bool tune_freq(uint16_t freq); - bool tune_power(uint8_t power = 0, uint8_t antcap = 0); - bool tune_wait(); - + // non-mutable config (opmode could be) void set_reset_pin(InternalGPIOPin *pin); - void set_frequency(float value); - float get_frequency(); + void set_op_mode(OpMode value); + + // config void set_mute(bool value); bool get_mute(); void set_mono(bool value); bool get_mono(); + void set_pre_emphasis(PreEmphasis value); + PreEmphasis get_pre_emphasis(); + void set_frequency(float value); + float get_frequency(); + void set_audio_deviation(float value); + float get_audio_deviation(); + void set_power(int value); + int get_power(); + void set_antcap(int value); + int get_antcap(); + void set_analog_level(int value); + int get_analog_level(); + void set_analog_attenuation(LineAttenuation value); + LineAttenuation get_analog_attenuation(); + void set_digital_sample_rate(int value); + int get_digital_sample_rate(); + void set_digital_sample_bits(SampleBits value); + SampleBits get_digital_sample_bits(); + void set_digital_channels(SampleChannels value); + SampleChannels get_digital_channels(); + void set_digital_mode(DigitalMode value); + DigitalMode get_digital_mode(); + void set_digital_clock_edge(DigitalClockEdge value); + DigitalClockEdge get_digital_clock_edge(); + void set_pilot_enable(bool value); + bool get_pilot_enable(); + void set_pilot_frequency(float value); + float get_pilot_frequency(); + void set_pilot_deviation(float value); + float get_pilot_deviation(); + void set_refclk_frequency(int value); + int get_refclk_frequency(); + void set_refclk_source(RefClkSource value); + RefClkSource get_refclk_source(); + void set_refclk_prescaler(int value); + int get_refclk_prescaler(); + void set_acomp_enable(bool value); + bool get_acomp_enable(); + void set_acomp_threshold(int value); + int get_acomp_threshold(); + void set_acomp_attack(AcompAttack value); + AcompAttack get_acomp_attack(); + void set_acomp_release(AcompRelease value); + AcompRelease get_acomp_release(); + void set_acomp_gain(int value); + int get_acomp_gain(); + void set_acomp_preset(AcompPreset value); + AcompPreset get_acomp_preset(); + void set_limiter_enable(bool value); + bool get_limiter_enable(); + void set_limiter_release_time(float value); + float get_limiter_release_time(); + void set_asq_iall_enable(bool value); + bool get_asq_iall_enable(); + void set_asq_ialh_enable(bool value); + bool get_asq_ialh_enable(); + void set_asq_overmod_enable(bool value); + bool get_asq_overmod_enable(); + void set_asq_level_low(int value); + int get_asq_level_low(); + void set_asq_duration_low(int value); + int get_asq_duration_low(); + void set_asq_level_high(int value); + int get_asq_level_high(); + void set_asq_duration_high(int value); + int get_asq_duration_high(); void set_rds_enable(bool value); bool get_rds_enable(); + void set_rds_deviation(float value); + float get_rds_deviation(); void set_rds_station(const std::string &value); + std::string get_rds_station(); void set_rds_text(const std::string &value); - void set_gpio(uint8_t pin, bool value); - bool get_gpio(uint8_t pin); + std::string get_rds_text(); + void set_gpio(uint8_t pin, bool value); // helper + bool get_gpio(uint8_t pin); // helper + void set_gpio1(bool value); + bool get_gpio1(); + void set_gpio2(bool value); + bool get_gpio2(); + void set_gpio3(bool value); + bool get_gpio3(); + + // used by sensors + std::string get_chip_id(); + float get_read_frequency(); + float get_read_power(); + float get_read_antcap(); + float get_read_noise_level(); + bool get_iall(); + bool get_ialh(); + bool get_overmod(); + float get_inlevel(); + + // used by automation + void measure_freq(float value); +}; + +template class SetFrequencyAction : public Action, public Parented { + TEMPLATABLE_VALUE(float, frequency) + void play(Ts... x) override { this->parent_->set_frequency(this->frequency_.value(x...)); } +}; + +template class MeasureFrequencyAction : public Action, public Parented { + TEMPLATABLE_VALUE(float, frequency) + void play(Ts... x) override { this->parent_->measure_freq(this->frequency_.value(x...)); } }; } // namespace si4713 diff --git a/esphome/components/si4713_i2c/si4713defs.h b/esphome/components/si4713_i2c/si4713defs.h index 1c6c948a62..7425d01493 100644 --- a/esphome/components/si4713_i2c/si4713defs.h +++ b/esphome/components/si4713_i2c/si4713defs.h @@ -5,11 +5,140 @@ namespace si4713 { static const uint8_t SI4710_STATUS_CTS = 0x80; -static const float CH_FREQ_MIN = 76; -static const float CH_FREQ_MAX = 108; +static const float FREQ_MIN = 76; +static const float FREQ_MAX = 108; +static const int FREQ_RAW_MIN = 7600; +static const int FREQ_RAW_MAX = 10800; +static const int POWER_MIN = 88; +static const int POWER_MAX = 120; +static const int ANTCAP_MIN = 0; +static const int ANTCAP_MAX = 191; +static const int LILEVEL_MIN = 0; +static const int LILEVEL_MAX = 1023; // no max in the datasheet, only that it is 10 bits +static const int DISR_MIN = 32000; +static const int DISR_MAX = 48000; +static const float PILOT_FREQ_MIN = 0; +static const float PILOT_FREQ_MAX = 19; +static const int PILOT_FREQ_RAW_MIN = 0; +static const int PILOT_FREQ_RAW_MAX = 19000; +static const float TXADEV_MIN = 0; +static const float TXADEV_MAX = 90; +static const int TXADEV_RAW_MIN = 0; +static const int TXADEV_RAW_MAX = 9000; +static const float TXPDEV_MIN = 0; +static const float TXPDEV_MAX = 90; +static const int TXPDEV_RAW_MIN = 0; +static const int TXPDEV_RAW_MAX = 9000; +static const float TXRDEV_MIN = 0; +static const float TXRDEV_MAX = 7.5f; +static const int TXRDEV_RAW_MIN = 0; +static const int TXRDEV_RAW_MAX = 750; +static const int REFCLKF_MIN = 31130; +static const int REFCLKF_MAX = 34406; +static const int RCLKP_MIN = 1; +static const int RCLKP_MAX = 4095; +static const int ACOMP_THRESHOLD_MIN = -40; +static const int ACOMP_THRESHOLD_MAX = 0; +static const int ACOMP_GAIN_MIN = 0; +static const int ACOMP_GAIN_MAX = 20; +static const float ACOMP_ATTACK_MIN = 0.5f; +static const float ACOMP_ATTACK_MAX = 5.0f; +static const int ACOMP_ATTACK_RAW_MIN = 0; +static const int ACOMP_ATTACK_RAW_MAX = 9; +static const float LMITERTC_MIN = 0.25f; +static const float LMITERTC_MAX = 102.4f; +static const int LMITERTC_RAW_MIN = 5; +static const int LMITERTC_RAW_MAX = 2000; +static const int IALTH_MIN = -70; +static const int IALTH_MAX = 0; +static const int IALDUR_MIN = 0; +static const int IALDUR_MAX = 65535; -static const uint8_t RDS_STATION_MAX = 8; -static const uint8_t RDS_TEXT_MAX = 64; +static const uint8_t RDS_STATION_MAX = 8; // TODO +static const uint8_t RDS_TEXT_MAX = 64; // TODO + +template T GET_ENUM_LAST(T value) { return T::LAST; } + +enum class OpMode { + OPMODE_ANALOG = 0b01010000, // 0x50 + OPMODE_DIGITAL = 0b00001111, // 0x0F + LAST, +}; + +enum class PreEmphasis { + FMPE_75US, // USA + FMPE_50US, // EU + FMPE_DISABLED, + LAST, +}; + +enum class LineAttenuation { + LIATTEN_396KOHM, + LIATTEN_100KOHM, + LIATTEN_74KOHM, + LIATTEN_60KOHM, + LAST, +}; + +enum class SampleBits { + ISIZE_16BITS, + ISIZE_20BITS, + ISIZE_24BITS, + ISIZE_8BITS, + LAST, +}; + +enum class SampleChannels { + IMONO_STEREO, + IMONO_MONO, + LAST, +}; + +enum class DigitalMode { + IMODE_DEFAULT, + IMODE_I2S, + IMODE_LEFT_JUSTIFIED, + IMODE_MSB_AT_1ST, + IMODE_MSB_AT_2ND, + LAST, +}; + +enum class DigitalClockEdge { + IFALL_DCLK_RISING_EDGE, + IFALL_DCLK_FALLIBG_EDGE, + LAST, +}; + +enum class RefClkSource { + RCLKSEL_RCLK, + RCLKSEL_DCLK, + LAST, +}; + +enum class AcompAttack { + ATTACK_05MS, + ATTACK_10MS, + ATTACK_15MS, + ATTACK_20MS, + ATTACK_25MS, + ATTACK_30MS, + ATTACK_35MS, + ATTACK_40MS, + ATTACK_45MS, + ATTACK_50MS, + LAST, +}; + +enum class AcompRelease { + RELEASE_100MS, + RELEASE_200MS, + RELEASE_350MS, + RELEASE_525MS, + RELEASE_1000MS, + LAST, +}; + +enum class AcompPreset { ACOMP_MINIMAL, ACOMP_AGGRESSIVE, ACOMP_CUSTOM, LAST }; enum class CmdType : uint8_t { POWER_UP = 0x01, // Power up device and mode selection. @@ -407,20 +536,17 @@ struct ResTxTuneMeasure : ResBase {}; struct CmdTxTuneStatus : CmdBase { union { - uint8_t ARG[2]; + uint8_t ARG[1]; struct { // ARG1 - uint8_t : 8; // zero - // ARG2 uint8_t INTACK : 1; // Seek/Tune Interrupt Clear. uint8_t : 7; }; }; - CmdTxTuneStatus(uint8_t intack = 1) { + CmdTxTuneStatus(uint8_t intack) { this->CMD = CmdType::TX_TUNE_STATUS; this->ARG[0] = 0; - this->ARG[1] = 0; this->INTACK = intack; } }; @@ -449,20 +575,17 @@ struct ResTxTuneStatus : ResBase { struct CmdTxAsqStatus : CmdBase { union { - uint8_t ARG[2]; + uint8_t ARG[1]; struct { // ARG1 - uint8_t : 8; // zero - // ARG2 uint8_t INTACK : 1; // Interrupt Acknowledge. Clears ASQINT, OVERMOD, IALDH, and IALDL uint8_t : 7; }; }; - CmdTxAsqStatus(uint8_t intack = 1) { + CmdTxAsqStatus(uint8_t intack) { this->CMD = CmdType::TX_ASQ_STATUS; this->ARG[0] = 0; - this->ARG[1] = 0; this->INTACK = intack; } }; @@ -472,9 +595,9 @@ struct ResTxAsqStatus : ResBase { uint8_t RESP[4]; struct { // RESP1 - uint8_t OVERMOD : 1; // Overmodulation Detection + uint8_t IALL : 1; // Overmodulation Detection uint8_t IALH : 1; // Input Audio Level Threshold Detect High - uint8_t IALL : 1; // Input Audio Level Threshold Detect Low + uint8_t OVERMOD : 1; // Input Audio Level Threshold Detect Low uint8_t : 5; // RESP2 uint8_t : 8; @@ -673,13 +796,16 @@ struct PropDigitalInputFormat : PropBase { }; }; - PropDigitalInputFormat(uint16_t isize = 0, uint16_t imono = 0, uint16_t imode = 0, uint16_t ifall = 0) { + PropDigitalInputFormat(SampleBits isize = SampleBits::ISIZE_16BITS, + SampleChannels imono = SampleChannels::IMONO_STEREO, + DigitalMode imode = DigitalMode::IMODE_DEFAULT, + DigitalClockEdge ifall = DigitalClockEdge::IFALL_DCLK_RISING_EDGE) { this->PROP = PropType::DIGITAL_INPUT_FORMAT; this->PROPD = 0x0000; - this->ISIZE = isize; - this->IMONO = imono; - this->IMODE = imode; - this->IFALL = ifall; + this->ISIZE = (uint16_t) isize; + this->IMONO = (uint16_t) imono; + this->IMODE = (uint16_t) imode; + this->IFALL = (uint16_t) ifall; } }; @@ -724,11 +850,11 @@ struct PropRefClkPreScale : PropBase { }; }; - PropRefClkPreScale(uint16_t rclkp = 1, uint16_t rclksel = 0) { + PropRefClkPreScale(uint16_t rclkp = 1, RefClkSource rclksel = RefClkSource::RCLKSEL_RCLK) { this->PROP = PropType::REFCLK_PRESCALE; this->PROPD = 0x0001; this->RCLKP = rclkp; - this->RCLKSEL = rclksel; + this->RCLKSEL = (uint16_t) rclksel; } }; @@ -805,11 +931,11 @@ struct PropTxLineInputLevel : PropBase { }; }; - PropTxLineInputLevel(uint16_t lilevel = 636, uint16_t liatten = 3) { + PropTxLineInputLevel(uint16_t lilevel = 636, LineAttenuation liatten = LineAttenuation::LIATTEN_60KOHM) { this->PROP = PropType::TX_LINE_INPUT_LEVEL; this->PROPD = 0x327C; this->LILEVEL = lilevel; - this->LIATTEN = liatten; + this->LIATTEN = (uint16_t) liatten; } }; @@ -840,10 +966,10 @@ struct PropTxPreEmphasis : PropBase { }; }; - PropTxPreEmphasis(uint16_t fmpe = 0) { + PropTxPreEmphasis(PreEmphasis fmpe = PreEmphasis::FMPE_75US) { this->PROP = PropType::TX_PREEMPHASIS; this->PROPD = 0x0000; - this->FMPE = fmpe; + this->FMPE = (uint16_t) fmpe; } }; @@ -920,10 +1046,10 @@ struct PropTxAcompReleaseTime : PropBase { }; }; - PropTxAcompReleaseTime(uint16_t release = 4) { + PropTxAcompReleaseTime(AcompRelease release = AcompRelease::RELEASE_1000MS) { this->PROP = PropType::TX_ACOMP_RELEASE_TIME; this->PROPD = 0x0004; - this->RELEASE = release; + this->RELEASE = (uint16_t) release; } }; @@ -978,8 +1104,8 @@ struct PropTxAsqLevelLow : PropBase { union { uint16_t PROPD; struct { - uint16_t IALLTH : 8; // Input Audio Level Low Threshold (-70 to 0 dB) - uint16_t : 8; + int8_t IALLTH : 8; // Input Audio Level Low Threshold (-70 to 0 dB) + uint8_t : 8; }; }; @@ -1007,8 +1133,8 @@ struct PropTxAsqLevelHigh : PropBase { union { uint16_t PROPD; struct { - uint16_t IALHTH : 8; // Input Audio Level High Threshold (-70 to 0 dB) - uint16_t : 8; + int8_t IALHTH : 8; // Input Audio Level High Threshold (-70 to 0 dB) + uint8_t : 8; }; }; diff --git a/esphome/components/si4713_i2c/switch/__init__.py b/esphome/components/si4713_i2c/switch/__init__.py index 27f6714ba9..e1bd1484f5 100644 --- a/esphome/components/si4713_i2c/switch/__init__.py +++ b/esphome/components/si4713_i2c/switch/__init__.py @@ -10,20 +10,36 @@ from .. import ( CONF_SI4713_ID, Si4713Component, si4713_ns, + CONF_SECTION_PILOT, + CONF_SECTION_COMPRESSOR, + CONF_SECTION_LIMITER, + CONF_SECTION_ASQ, + CONF_SECTION_RDS, + CONF_SECTION_OUTPUT, CONF_MUTE, CONF_MONO, - CONF_RDS_ENABLE, + CONF_ENABLE, + CONF_OVERMOD, + CONF_IALL, + CONF_IALH, + CONF_GPIO1, + CONF_GPIO2, + CONF_GPIO3, + ICON_SINE_WAVE, ICON_VOLUME_MUTE, ICON_EAR_HEARING, ICON_FORMAT_TEXT, ) -CONF_GPIO1="gpio1" -CONF_GPIO2="gpio2" -CONF_GPIO3="gpio3" - MuteSwitch = si4713_ns.class_("MuteSwitch", switch.Switch) MonoSwitch = si4713_ns.class_("MonoSwitch", switch.Switch) +PilotEnableSwitch = si4713_ns.class_("PilotEnableSwitch", switch.Switch) +AcompEnableSwitch = si4713_ns.class_("AcompEnableSwitch", switch.Switch) +LimiterEnableSwitch = si4713_ns.class_("LimiterEnableSwitch", switch.Switch) +AsqOvermodEnableSwitch = si4713_ns.class_("AsqOvermodEnableSwitch", switch.Switch) +AsqIallEnableSwitch = si4713_ns.class_("AsqIallEnableSwitch", switch.Switch) +AsqIalhEnableSwitch = si4713_ns.class_("AsqIalhEnableSwitch", switch.Switch) +RdsEnable = si4713_ns.class_("RdsEnable", switch.Switch) RDSEnableSwitch = si4713_ns.class_("RDSEnableSwitch", switch.Switch) GPIOSwitch = si4713_ns.class_("GPIOSwitch", switch.Switch) @@ -42,50 +58,122 @@ CONFIG_SCHEMA = cv.Schema( 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, + cv.Optional(CONF_SECTION_PILOT): cv.Schema( + { + cv.Optional(CONF_ENABLE): switch.switch_schema( + PilotEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + } ), - cv.Optional(CONF_GPIO1): switch.switch_schema( - GPIOSwitch, - device_class=DEVICE_CLASS_SWITCH, - entity_category=ENTITY_CATEGORY_CONFIG, - # icon=, + cv.Optional(CONF_SECTION_COMPRESSOR): cv.Schema( + { + cv.Optional(CONF_ENABLE): switch.switch_schema( + AcompEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + } ), - cv.Optional(CONF_GPIO2): switch.switch_schema( - GPIOSwitch, - device_class=DEVICE_CLASS_SWITCH, - entity_category=ENTITY_CATEGORY_CONFIG, - # icon=, + cv.Optional(CONF_SECTION_LIMITER): cv.Schema( + { + cv.Optional(CONF_ENABLE): switch.switch_schema( + LimiterEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_SINE_WAVE, + ), + } ), - cv.Optional(CONF_GPIO3): switch.switch_schema( - GPIOSwitch, - device_class=DEVICE_CLASS_SWITCH, - entity_category=ENTITY_CATEGORY_CONFIG, - # icon=, + cv.Optional(CONF_SECTION_ASQ): cv.Schema( + { + cv.Optional(CONF_OVERMOD): switch.switch_schema( + AsqOvermodEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=ICON_, + ), + cv.Optional(CONF_IALL): switch.switch_schema( + AsqIallEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=ICON_, + ), + cv.Optional(CONF_IALH): switch.switch_schema( + AsqIalhEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=ICON_, + ), + } ), + cv.Optional(CONF_SECTION_RDS): cv.Schema( + { + cv.Optional(CONF_ENABLE): switch.switch_schema( + RDSEnableSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_FORMAT_TEXT, + ), + } + ), + cv.Optional(CONF_SECTION_OUTPUT): cv.Schema( + { + cv.Optional(CONF_GPIO1): switch.switch_schema( + GPIOSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=, + ), + cv.Optional(CONF_GPIO2): switch.switch_schema( + GPIOSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=, + ), + cv.Optional(CONF_GPIO3): switch.switch_schema( + GPIOSwitch, + device_class=DEVICE_CLASS_SWITCH, + entity_category=ENTITY_CATEGORY_CONFIG, + # icon=, + ), + } + ) } ) -async def new_switch(config, id, setter): +async def new_switch(parent, config, id, setter): if c := config.get(id): s = await switch.new_switch(c) - await cg.register_parented(s, config[CONF_SI4713_ID]) + await cg.register_parented(s, parent) cg.add(setter(s)) return 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) - s = await new_switch(config, CONF_GPIO1, c.set_gpio1_switch) - s.set_pin(1) - s = await new_switch(config, CONF_GPIO2, c.set_gpio2_switch) - s.set_pin(2) - s = await new_switch(config, CONF_GPIO3, c.set_gpio3_switch) - s.set_pin(3) + parent = await cg.get_variable(config[CONF_SI4713_ID]) + await new_switch(parent, config, CONF_MUTE, parent.set_mute_switch) + await new_switch(parent, config, CONF_MONO, parent.set_mono_switch) + if pilot_config := config.get(CONF_SECTION_PILOT): + await new_switch(parent, pilot_config, CONF_ENABLE, parent.set_pilot_enable_switch) + if compressor_config := config.get(CONF_SECTION_COMPRESSOR): + await new_switch(parent, compressor_config, CONF_ENABLE, parent.set_acomp_enable_switch) + if limiter_config := config.get(CONF_SECTION_LIMITER): + await new_switch(parent, limiter_config, CONF_ENABLE, parent.set_limiter_enable_switch) + if asq_config := config.get(CONF_SECTION_ASQ): + await new_switch(parent, asq_config, CONF_IALL, parent.set_asq_iall_enable_switch) + await new_switch(parent, asq_config, CONF_IALH, parent.set_asq_ialh_enable_switch) + await new_switch(parent, asq_config, CONF_OVERMOD, parent.set_asq_overmod_enable_switch) + if rds_config := config.get(CONF_SECTION_RDS): + await new_switch(parent, rds_config, CONF_ENABLE, parent.set_rds_enable_switch) + if output_config := config.get(CONF_SECTION_OUTPUT): + gpio1 = await new_switch(parent, output_config, CONF_GPIO1, parent.set_gpio1_switch) + gpio2 = await new_switch(parent, output_config, CONF_GPIO2, parent.set_gpio2_switch) + gpio3 = await new_switch(parent, output_config, CONF_GPIO3, parent.set_gpio3_switch) + cg.add(gpio1.set_pin(1)) + cg.add(gpio2.set_pin(2)) + cg.add(gpio3.set_pin(3)) diff --git a/esphome/components/si4713_i2c/switch/acomp_enable_switch.cpp b/esphome/components/si4713_i2c/switch/acomp_enable_switch.cpp new file mode 100644 index 0000000000..132be0ad0a --- /dev/null +++ b/esphome/components/si4713_i2c/switch/acomp_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "acomp_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void AcompEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_acomp_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/acomp_enable_switch.h b/esphome/components/si4713_i2c/switch/acomp_enable_switch.h new file mode 100644 index 0000000000..f91ebe5f1c --- /dev/null +++ b/esphome/components/si4713_i2c/switch/acomp_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AcompEnableSwitch : public switch_::Switch, public Parented { + public: + AcompEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.cpp b/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.cpp new file mode 100644 index 0000000000..bb94940634 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "asq_ialh_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void AsqIalhEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_asq_ialh_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.h b/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.h new file mode 100644 index 0000000000..a3010a4472 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_ialh_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqIalhEnableSwitch : public switch_::Switch, public Parented { + public: + AsqIalhEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.cpp b/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.cpp new file mode 100644 index 0000000000..b8f6b93d36 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "asq_iall_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void AsqIallEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_asq_iall_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.h b/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.h new file mode 100644 index 0000000000..b1d1622c04 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_iall_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqIallEnableSwitch : public switch_::Switch, public Parented { + public: + AsqIallEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.cpp b/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.cpp new file mode 100644 index 0000000000..21d1d6ef61 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "asq_overmod_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void AsqOvermodEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_asq_overmod_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.h b/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.h new file mode 100644 index 0000000000..069232440f --- /dev/null +++ b/esphome/components/si4713_i2c/switch/asq_overmod_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class AsqOvermodEnableSwitch : public switch_::Switch, public Parented { + public: + AsqOvermodEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/limiter_enable_switch.cpp b/esphome/components/si4713_i2c/switch/limiter_enable_switch.cpp new file mode 100644 index 0000000000..f1530fb2c3 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/limiter_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "limiter_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void LimiterEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_limiter_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/limiter_enable_switch.h b/esphome/components/si4713_i2c/switch/limiter_enable_switch.h new file mode 100644 index 0000000000..6a445a4197 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/limiter_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class LimiterEnableSwitch : public switch_::Switch, public Parented { + public: + LimiterEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/pilot_enable_switch.cpp b/esphome/components/si4713_i2c/switch/pilot_enable_switch.cpp new file mode 100644 index 0000000000..ea6c26ce09 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/pilot_enable_switch.cpp @@ -0,0 +1,12 @@ +#include "pilot_enable_switch.h" + +namespace esphome { +namespace si4713 { + +void PilotEnableSwitch::write_state(bool value) { + this->publish_state(value); + this->parent_->set_pilot_enable(value); +} + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/switch/pilot_enable_switch.h b/esphome/components/si4713_i2c/switch/pilot_enable_switch.h new file mode 100644 index 0000000000..271bbbfab9 --- /dev/null +++ b/esphome/components/si4713_i2c/switch/pilot_enable_switch.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../si4713.h" + +namespace esphome { +namespace si4713 { + +class PilotEnableSwitch : public switch_::Switch, public Parented { + public: + PilotEnableSwitch() = default; + + protected: + void write_state(bool value) override; +}; + +} // namespace si4713 +} // namespace esphome \ No newline at end of file diff --git a/esphome/components/si4713_i2c/text/__init__.py b/esphome/components/si4713_i2c/text/__init__.py index 169818b458..f68dde55c9 100644 --- a/esphome/components/si4713_i2c/text/__init__.py +++ b/esphome/components/si4713_i2c/text/__init__.py @@ -18,8 +18,9 @@ from .. import ( CONF_SI4713_ID, Si4713Component, si4713_ns, - CONF_RDS_STATION, - CONF_RDS_TEXT, + CONF_SECTION_RDS, + CONF_STATION, + CONF_TEXT, ICON_FORMAT_TEXT, ) @@ -123,32 +124,38 @@ async def new_text( 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, + cv.Optional(CONF_SECTION_RDS): cv.Schema( + { + cv.Optional(CONF_STATION): text_schema( + RDSStationText, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_FORMAT_TEXT, + ), + cv.Optional(CONF_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): +async def new_text_simple(parent, 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]) + await cg.register_parented(t, parent) cg.add(setter(t)) + return 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 - ) + parent = await cg.get_variable(config[CONF_SI4713_ID]) + if rds_config := config.get(CONF_SECTION_RDS): + await new_text_simple( + parent, rds_config, CONF_STATION, parent.set_rds_station_text, 0, si4713_ns.RDS_STATION_MAX + ) + await new_text_simple( + parent, rds_config, CONF_TEXT, parent.set_rds_text_text, 0, si4713_ns.RDS_TEXT_MAX + )