ESPHome vs Arduino IDE & MQTT

I have yet to use ESPHome but I have a number of sensors set up that tie into Home Assistant via MQTT.

Is anyone able to tell me the benefits of using ESPHome over creating the code in Arduino IDE and talking to Home Assistant via the Mosquito plugin? Is ESPHome more lightweight? does it provide better capability on Wemos D1?

I have created a number of custom devices (one that is servo controlled by an attached temp probe (on the same Wemos). I have the temp outputted via MQTT to Home Assistant for Monitoring. The Wemos itself handles the servo controller when the temp exceeds a threshold. Can ESPHome be used to do the same thing? I was wondering how custom code runs on the devices, or is it just a simple way of adding basic sensors?

It is just so quick and easy to use. It also has a native api which is an alternative to mqtt connection to HA. See here for pros and cons of api vs mqtt. https://esphome.io/components/api.html#advantages-over-mqtt

You can do automations on the esp or on HA or both. So effectively, yes you could activate a servo on a temp being reached without involving HA.

Thanks. I have created the code already in Arduino IDE so are you able to reuse code or do you have to create it all from scratch? I may give it a go this weekend. I am having MQTT issues with my wifi and was looking for alternatives.

Esphome code is written in yaml, which esphome interprets and passes to platformio to compile. You can add c++ code but for your example that shouldn’t be needed.

I have a simple motion sensor working as that is just linking a motion sensor to a pin. I have pasted my code currently uploaded to the servo actuator but I cant really see how this can be tied to a YAML file.

I have a transistor added to open and close the circuit to the battery pack tied to the servo as it was draining the batteries too quick. Its going to take me a while to workout how to build the yaml configs but any pointers would be much appreciated. The transistor is on D4 and the temp probe is on D2.

void setup() {
  // Start the Serial Monitor
  Serial.begin(9600);
  servo.attach(D1);
  delay(2000);
  pinMode (transistor, OUTPUT);
  servo.write(30);
  servo.write(0);
  
}

void loop() {
  delay(3000);
  char message[58];
  sensors.requestTemperatures(); 
  float temperatureC = sensors.getTempCByIndex(0);
  float temperatureF = sensors.getTempFByIndex(0);
  Serial.print(temperatureC);
  Serial.println("ºC");
  //client.publish("pccabinet/temp/status", String(temperatureC).c_str());
  Serial.print(temperatureF);
  Serial.println("ºF");
  delay(2000);
  if (temperatureC > 33 && isDoorOpen == false){
    digitalWrite (transistor, HIGH);
    delay(1000);
    servo.write(95);
    digitalWrite (transistor, LOW);
    isDoorOpen = true;
  }
  if (temperatureC < 26 && isDoorOpen == true) {
    digitalWrite (transistor, HIGH);
    delay(1000);
    servo.write(0);
    digitalWrite (transistor, LOW);
    isDoorOpen = false;
  }
}

I don’t really like tutorial by video, but I hear that this is a good starter. https://www.youtube.com/watch?v=soKuma8DJWQ

Ok thanks I will give it a watch and see if I can decode what is needed here.

Ok that was surprisingly a lot easier than I was expecting. Once I got my head around the logic and defining sensors it is more straight forward than the Arduino IDE. Decided to try all three ways to call the pins. Below is the code:

dallas:
  - pin: GPIO4
    update_interval: 10s
  
switch:
  - platform: gpio
    pin: 14
    name: "Servo Transistor"
    id: servotrans

servo:
  - id: cabinet_servo
    output: pwm_output

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D1
    frequency: 50 Hz
  
sensor:
  - platform: dallas
    address: 0x1A030597946B5528
    name: "Cabinet Temperature"
    on_value_range:
        - above: 28.0
          then:
            - switch.turn_on: servotrans
            - delay: 1s
            - servo.write:
                id: cabinet_servo
                level: -50.0%
            - delay: 1s
            - switch.turn_off: servotrans
        - below: 26.0
          then:
            - switch.turn_on: servotrans
            - delay: 1s
            - servo.write:
                id: cabinet_servo
                level: +50.0%
            - delay: 1s
            - switch.turn_off: servotrans

In terms of scalability and management there is nothing comparable available imho. I update my ~35 esphome nodes with one click (one for all nodes!) to the latest version. Most people not running esphome will most like run older code on the esp which is affected to one or more security issues - just because it’s to hard to upgrade seamlessly.

In anyway you will save a lot’s of time. While some one’s tinkering with arduino code or trying to reproduce a device behaviour on a browser based setup system (like tasmota for example) with esphome you will have your third device already successfully deployed.

I like to finish my projects and not burn time with the software part - that’s why only use esphome.

Beside that I also ditched mqtt completely (20 years is enough) and only use the esphome api

1 Like

I am enjoying ESPHome so far. I have now converted all my standard sensors over.

I am currently in the middle of creating a roller blind controller, using a DC motor with built in rotary encoder. I have the code almost working in Arduino IDE, but I am using interrupts to break the motor movement when the encoder value hits a certain limit. Interrupts are used when the encoder detects changes in state.

How does ESPHome deal with interrupts as I would love to be able to move this controller into ESPHome but currently I am a bit lost on how to recreate it.

The code currently under development is listed below:

void ICACHE_RAM_ATTR doEncoderA();
void ICACHE_RAM_ATTR doEncoderB();
char receivedChar;
boolean newData = false;

volatile long encoderValue = 0;

void setup() {
  Serial.begin(9600);
  delay(10);

  pinMode(D1, INPUT); //encoderA input
  pinMode(D2, INPUT); //encoderB input
  pinMode(D3, OUTPUT); //motordriver outputA
  pinMode(D4, OUTPUT); //motordriver outputB

  digitalWrite(D1, HIGH); //turn pullup resistor on
  digitalWrite(D2, HIGH); //turn pullup resistor on  

  attachInterrupt(digitalPinToInterrupt(D1), doEncoderA, CHANGE); //add interrupt on pin on state change
  attachInterrupt(digitalPinToInterrupt(D2), doEncoderB, CHANGE);
}

void loop() {
  recvOneChar(); //listen on serial port for input
  movemotor(); //move motor depending on serial input
}

void recvOneChar() { //read in serial input to variable
    if (Serial.available() > 0) {
        receivedChar = Serial.read();
        newData = true;
    }
}

void movemotor() { //move motor based on serial character
    if (newData == true) {
      if (receivedChar == 'u') {
        digitalWrite(D3, LOW);
        digitalWrite(D4, HIGH);
        newData = false;
      }
      if (receivedChar == 'd') {
        digitalWrite(D3, HIGH);
        digitalWrite(D4, LOW);
        newData = false;
      }
      else
        newData = false;
    }
}

void doEncoderA() {
  if(digitalRead(D2) != digitalRead(D1)) {
    encoderValue++; //increase encoder movement on rotation
    if(encoderValue > 30000) { //set max limit of encoder
      digitalWrite(D3, LOW); //stop moving motor when hits limit
    digitalWrite(D4, LOW);
    }
  }
  else {
    encoderValue--;
    if(encoderValue < 0) {
      digitalWrite(D3, LOW);
      digitalWrite(D4, LOW);
      } 
}
}

void doEncoderB() {
  if(digitalRead(D2) == digitalRead(D1)) {
    encoderValue++;
    if(encoderValue > 30000) {
      digitalWrite(D3, LOW);
    digitalWrite(D4, LOW);
  }
  }
  else {
    encoderValue--;
    if(encoderValue < 0) {
      digitalWrite(D3, LOW);
      digitalWrite(D4, LOW);
    }
  } 
}