I have spent a better half of yesterday trying to find how all the components come together and did not do a stellar job.
After looking at SI4703 driver (.h, .cpp, .ino) it turns out that communication with the device is done through i2c on the address 0x10, with the addition of two pins declared as pinMode OUTPUT for reset signal and busy (STC for seek/tune complete).
I was initially misled that its an UART component, but it turns out that there was just a serial control interface for the convenience of a user connecting the module to Arduino and Arduino to a computer.
I have tried to piece together various components, but have not an example that does something similar. My biggest problem is the cpp part. I have made it this far:
#include "esphome.h"
#include "SparkFunSi4703.h"
int resetPin = 16;
int SCT = 14;
Si4703_Breakout radio(resetPin, SDIO, SCLK, SCT);
int ch;
int vol;
char rdsBuffer[10];
// initialization of SDIO and SCLK is also missing
class FM_Radio : public Component, public Sensor {
public:
void setup() override {
// Initialize the device here. Usually, Wire.begin() will be called in here,
// though that call is unnecessary if you have an 'i2c:' entry in your config
Wire.begin();
radio.powerOn();
radio.setVolume(0);
}
void loop() override {
Wire.beginTransmission(0x10);
// here is something missing
Wire.endTransmission();
}
};
For the yaml part, some of the parts I have gathered, and some other I cannot understand. I would assume that SCT and reset signals are binary outputs (because they are declared as outputs in cpp file). And that the returning Infos are the text sensors, so that should be something like that:
i2c:
id: bus_a
esphome:
includes:
- radio.h
custom_component:
- id: fm
lambda: |-
auto my_radio = new radio(bus_a, 0x10);
return {my_radio};
output:
- platform: custom
type: binary
internal: true
lambda: |-
return {reset(fm, 16)};
- platform: custom
type: binary
internal: true
lambda: |-
return {sct(fm, 14)};
text_sensor:
- platform: custom
id: RDS_message
lambda: |-
return {RDS_message(fm, radio.readRDS(rdsBuffer, 15000)};
- platform: custom
id: fm_volume
lambda: |-
return {volume(fm, vol)};
- platform: custom
id: fm_channel
lambda: |-
return {channel(fm, ch)};
On this journey, most helpful were @glmnet’s GitHub repository and a Hackday article about a custom component. But, still, my knowledge of all this is very limited.
The question that I have been thinking about is what would be the most appropriate way to send commands to the module. There are seven commands, vol+, vol-, ch+, ch-, seek+, seek- and read rds and there are three return data fields, channel, volume and rds message. The question now is just how all of this comes together.
I have not yet tried to write any of this in hassio, because so much is missing so there may be errors that I do not know about.