ESP Home and FM Tuner

After I solve the other problem, I have to integrate an FM tuner into an ESP8266 or ESP32 node. I have two FM tuner boards, one si Si4703 which I have successfully run from an Arduino and TEA5767 which I haven’t yet played with.

As I could not find an integration for an FM tuner in ESPHome module lists, what would be the best way to control these devices with ESP?

I do not know how it is with TEA5767, but Si4703 can receive command through UART. So, I imagine that I could run the code for the FM module on an Arduino Nano and control it in some way trough UART from the ESP board, from inside ESPHome. Is there a way and what would be the approach to solve this problem if I would control the FM module directly from the ESP board with ESP Home?

And, please, when you are answering keep in mind that I am very new to this whole ecosystem (HA, ESPHome, ESP boards)

2 Likes

sound cool

dum question

will it be able to transmit a FM

just thinking out side the RADIO box

1 Like

@myle no, it’s just an FM 88-108MHz receiver, like this one. On the other end, it will get a PAM 8403 3W Stereo amp and some small speakers like those in small BT speakers.

Si has some preamp on-board, so a fixed amplification amplifier board can be used with it while the volume control stays with Si module. I just need to figure out the simplest method to control it.

LOL I gave up FM for the same stations streaming years ago. Much easier to set up in a whole house system.

If there is not a esphome component, then you could perhaps control by UART sending the appropriate signals, or you could use an esphome custom component.

But if you have an arduino doing the job already, it might be easier to integrate that.

Is there a way to use Arduino code and libraries in ESP home?

Someone somewhere wrote that ESP home generates Arduino code based on yaml files, but did not elaborate how and where. Would it be possible for me to add Arduino code to existing source created based on yaml file.

For example that ESP module has control of SK6812 strip, Bosch temperature, humidity and pressure sensor and an OLED display to show date time and data from Bosch sensor. Those elements including HA time and elevation triggers for LED strip are all neatly scripted in yaml. If there is an Arduino code for that yaml I would like to add a reference to FM tuner library and insert appropriate code to interact with the tuner and create a final version to be OTA updated to the ESP.

I searched the documentation, but did not find anything in that direction. If you could point me to some article where I can read about it it would be of great help.

1 Like

More correctly esphome writes, compiles and loads c++ code from directions given in a yaml file.

If thrre isn’t a component built in to esphome, you can use custom components based on existing arduino code. Those are documented on the esphome docs.

I’ll look into it. Thanks

https://esphome.io/custom/custom_component.html

Great I have 1 FM tuner for Arduino

If it is supported I can make many interest things.

I want to start C Language, when I see like this.

Some one can share arduino custom codes to make it ?

I wish it can be supported.

Google. 10 char minimum.

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.

1 Like

I have come a little bit further. On this site, I have found this C++ example for ESP32

#include <SparkFunSi4703.h>
#include <Wire.h>
 
int resetPin = 0;
int SDIO = 20;
int SCLK = 19;
int SCT = 2;
 
Si4703_Breakout radio(resetPin, SDIO, SCLK, SCT);
int channel;
int volume;
char rdsBuffer[10];
 
void setup()
{
  Serial.begin(9600);
  Serial.println("\n\nSi4703_Breakout Test Sketch");
  Serial.println("===========================");  
  Serial.println("a b     Favourite stations");
  Serial.println("+ -     Volume (max 15)");
  Serial.println("u d     Seek up / down");
  Serial.println("r       Listen for RDS Data (15 sec timeout)");
  Serial.println("Send me a command letter.");
 
 
  radio.powerOn();
  radio.setVolume(0);
}
 
void loop()
{
  if (Serial.available())
  {
    char ch = Serial.read();
    if (ch == 'u') 
    {
      channel = radio.seekUp();
      displayInfo();
    } 
    else if (ch == 'd') 
    {
      channel = radio.seekDown();
      displayInfo();
    } 
    else if (ch == '+') 
    {
      volume ++;
      if (volume == 16) volume = 15;
      radio.setVolume(volume);
      displayInfo();
    } 
    else if (ch == '-') 
    {
      volume --;
      if (volume < 0) volume = 0;
      radio.setVolume(volume);
      displayInfo();
    } 
    else if (ch == 'a')
    {
      channel = 1020; // Rock FM
      radio.setChannel(channel);
      displayInfo();
    }
    else if (ch == 'b')
    {
      channel = 1028; // BBC R4
      radio.setChannel(channel);
      displayInfo();
    }
    else if (ch == 'r')
    {
      Serial.println("RDS listening");
      radio.readRDS(rdsBuffer, 15000);
      Serial.print("RDS heard:");
      Serial.println(rdsBuffer);      
    }
  }
}
 
void displayInfo()
{
   Serial.print("Channel:"); Serial.print(channel); 
   Serial.print(" Volume:"); Serial.println(volume); 
}

Now the question is how to interact with the code from ESPHome without serial connection. Is there an object that can be used to send the commands? Can it be done through a few custom switches and text sensors or is there a more appropriate component for this scenario?

1 Like

Start here I think https://esphome.io/custom/i2c.html

1 Like

Were you able to get the TES5767 to work with ESPHome? I need to create a silence detector that will:

  1. Set the FM receiver to a frequency (e.g. 91.5MHz)
  2. Monitor the audio or carrier for silence and/or loss of carrier and raise an alert.

If I can do it through ESPHome that would be great.

1 Like

No, I have abandoned that solution. Could not find out how to write the custom component. So, I chose to connect the radio to an Arduino and control the Arduino among other components on that node with ESP32 running ESPhome.

It should be fairly easy for someone with a bit of experience developing in Cpp but was not able to accomplish the goal mainly because my only contact with C-like language was the Arduino environment.

Generally, (conveying what I have been told) anything that can be done in the Arduino environment can also be put in a custom component and it should work. So, if you are familiar with C and have a working sketch for Arduino you should be able to convert it.

1 Like

You don’t need to write esp code using esphome. It can be written in platformio or the arduino, and use the library for this component. No different to using it with arduino.

There is a library available on github, so I suggest that you post a feature request in the esphome github.

I was helped out by a wonderful community member in getting the ESPHome component for the TEA5767 and you can check it out here:

Example ESPHome YAML configuration:

esphome:
  name: example-fm-radio
  friendly_name: example-fm-radio

esp8266:
  board: esp01_1m

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

captive_portal:
logger:
api:
ota:
  - platform: esphome
sensor:
web_server:
external_components:
  - source: github://catalin2402/esphome-components
    refresh: 1s
    components:
      - tea5767
i2c:
  sda: GPIO4
  scl: GPIO5
tea5767:
  id: radio
  in_japan: false
  frequency: 88.1 Mhz
  level_sensor:
    name: "Station signal"
  mono_sensor:
    name: "Station is mono"
  frequency_sensor:
    name: "Current frequency"
button:
  - platform: template
    name: "set mono"
    id: set_mono
    on_press:
      tea5767.set_mono:
        id: radio
        mono: false
  - platform: template
    name: "set mute"
    id: set_mute
    on_press:
      tea5767.set_mute:
        id: radio
        mute: false
  - platform: template
    name: "88.1"
    id: set_freq_preset1
    on_press:
      tea5767.set_frequency:
        id: radio
        frequency: 88.1 Mhz
  - platform: template
    name: "92.5"
    id: set_freq_preset2
    on_press:
      tea5767.set_frequency:
        id: radio
        frequency: 92.5 Mhz
  - platform: template
    name: "96.3"
    id: set_freq_preset3
    on_press:
      tea5767.set_frequency:
        id: radio
        frequency: 96.3 Mhz
  - platform: template
    name: "97.1"
    id: set_freq_preset4
    on_press:
      tea5767.set_frequency:
        id: radio
        frequency: 97.1 Mhz
  - platform: template
    name: "99.5"
    id: set_freq_preset5
    on_press:
      tea5767.set_frequency:
        id: radio
        frequency: 99.5 Mhz
1 Like