Performance issue with PollingComponent

Hi,
i’m trying tu use a MKS DLC32 board to control peristaltic pumps (wich use stepper motor) and i have performance issue with the PollingComponent in esphome.
There is an esp32 wich is connected to an 75hc595 shift register, and the output of this shift register manage the stepper motor drivers (i use a4988).

I use a custom component with the PollingComponent class to control the drivers :

#include "esphome.h"

class DLC32HC595 : public PoollingComponent {
 public:

  // constructor
  MyCustomSensor() : PollingComponent(1) {}


  // HC595 input
  // int latchPin = 17;      // RCLK/Latch pin of 74HC595 is connected to Digital pin GPIO17
  // int clockPin = 16;      // SRCLK/Clock pin of 74HC595 is connected to Digital pin GPIO16
  // int dataPin = 21;       // SER/Data pin of 74HC595 is connected to Digital pin GPIO21

  // HC595 output
  int xyzenregidx = 0;        // my_register index to control Enable for X,Y and Z
  int xstepregidx = 1;        // my_register index to control Step for X
  int xdirregidx = 2;        // my_register index to control direction for X
  int zstepregidx = 3;        // my_register index to control Step for Z
  int zdirregidx = 4;        // my_register index to control direction for Z
  int ystepregidx = 5;       // my_register index to control Step for Y
  int ydirregidx = 6;        // my_register index to control direction for Y
  // idx 7 not used

  byte my_register = B01010101;         // Variable to hold the pattern of which Pins are currently turned on or off


  void setup() override {
  }

  void update() override {
      StepMotor();
  }

  void updateShiftRegister() {
     id(spidev).enable();
     id(spidev).write_byte(my_register);
     id(spidev).disable();
  }

  void StepMotor() {
    if ( Xrun->value() == true or Yrun->value() == true or Zrun->value() == true ) {
      if ( bitRead(my_register, xyzenregidx) == 1 ) {
        bitClear(my_register, xyzenregidx);
        // ESP_LOGD("custom", "XYZ Enable register value is 0 (steppers are active with 0)");
      }
    }
    else {
      if ( bitRead(my_register, xyzenregidx) == 0 ) {
        bitSet(my_register, xyzenregidx);
        // ESP_LOGD("custom", "XYZ Enable register value is 1 (steppers are active with 0)");
      }
    }
    if ( Xrun->value() ) {
      bitToggle(my_register, xstepregidx);
    }
    if ( Yrun->value() ) {
      bitToggle(my_register, ystepregidx);
    }
    if ( Zrun->value() ) {
      bitToggle(my_register, zstepregidx);
    }
    updateShiftRegister();
  }
};

And this is the Yaml :

esphome:
  name: poolchemicaldispenser
  friendly_name: PoolChemicalDispenser
  includes: 
    - dlc32hc595spi.h

esp32:
  board: esp32dev
  framework:
    type: arduino


# Enable logging
#logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  domain: .home

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Poolchemicaldispenser"
    password: "xxxxxxxxxxxxxxxx"

captive_portal:

   
# Web Server: https://esphome.io/components/web_server.html
#web_server:
#  local: true
#  port: 80    

# Global variables
globals:
  - id: Xrun
    type: bool
    restore_value: no
    initial_value: "false"
  - id: Yrun
    type: bool
    restore_value: no
    initial_value: "false"
  - id: Zrun
    type: bool
    restore_value: no
    initial_value: "false"

# Example configuration entry
switch:
  - platform: template
    name: "X motor"
    id: X_switch
    optimistic: true
    turn_on_action:
            - logger.log: "Setting X motor to run state"
            - lambda: |-
                id(Xrun) = true;
    turn_off_action:
            - logger.log: "Setting X motor to stop state"
            - lambda: |-
                id(Xrun) = false;
  - platform: template
    name: "Y motor"
    id: Y_switch
    optimistic: true
    turn_on_action:
            - logger.log: "Setting Y motor to run state"
            - lambda: |-
                id(Yrun) = true;
    turn_off_action:
            - logger.log: "Setting Y motor to stop state"
            - lambda: |-
                id(Yrun) = false;
  - platform: template
    name: "Z motor"
    id: Z_switch
    optimistic: true
    turn_on_action:
            - logger.log: "Setting Z motor to run state"
            - lambda: |-
                id(Zrun) = true;
    turn_off_action:
            - logger.log: "Setting Z motor to stop state"
            - lambda: |-
                id(Zrun) = false;


custom_component:
- lambda: |-
    auto dlc32_board = new DLC32HC595();
    return {dlc32_board};
  components:
  - id: dlc32_board_id

spi:
    clk_pin: GPIO16
    mosi_pin: GPIO21
    interface: hardware

spi_device:
    id: spidev
    cs_pin: GPIO17
    data_rate: 1MHz
    mode: 3
    bit_order: msb_first

With my logic analyser, i can see that the output of my shift register can’t be update less than 5ms despite the value i set in PollingComponent(1). When logger and web server is enable it’s worst.

did someone have any tips to run it quicker ?
i did a test without polling component, and with loop() instead of update() function, but it is worst (about 30ms).

thanks

Esphome is not designed to be real-time, if it’s what you are trying to achieve.
There is an implicit loop where housekeeping is happening.

If you want real-time, you’ll probably have to run a different thread in your custom component, with its own loop.

Thank you for your answer :slight_smile:

Have you any information or documentation about how to do that with esphome ?

Multithreading will be in your custom component.
You create the thread in setup() and then you’re basically independent of esphome.

Thank you very much !

after learning about xTaskCreate, i try and it work fine :slight_smile: