Adding a new library to esphome

Hi Guys

I have a problem and it seems i can’t really find an answer to solve it.

How can i add a custom library to esphome through the directory?

Thank you for your help!

Through what directory?

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


Where is this?

Ah I see.

/config/esphome/custom_components/your_project_name

Do libraries added to an esphome configuration need to come from platformio, or can a libarary be stored in the configuration directory of esphome (along with the .yaml configs for individual devices) and be ‘installed’/included in as a global libarary in the config for the device you are building?

For instance, I am building a 4x4 keypad that uses a PCF8574 I2C expansion IO board that connects to esphome via a Wemos D1 Mini. In fact, I have had this operating for months now, but in a recent esphome update, it appears that the I2C keypad library that I have stored in the config directory (because it is not on platformio) is no longer being loaded correctly during compilation, and therefore the compilation is failing when it comes to my custom component.

I’m using this library: arduino_keypads/Keypad_I2C at master · joeyoung/arduino_keypads · GitHub

This is the device configuration I’m trying to get working.
esp-d1m-07.yaml (located here: /config/esp-d1m-07.yaml)

substitutions:
   device_name: esp-d1m-07
   device_name_upper: ESP Wemos 07
   device_icon: mdi:chip
   device_ip: 10.40.70.149


esphome:
  name: ${device_name}
  platform: ESP8266
  board: d1_mini
  libraries:                #built-in libraries
    - "Keypad"
    - "Wire"
#    - Keypad_I2C/Keypad_I2C  #there is a copy of the full library folder located at: /config/Keypad_I2
  includes:
    - Keypad_I2C.h          #file located here: /config/Keypad_I2C.h
    - keypad_sensor_i2c.h   #file located here: /config/keypad_sensor_i2c.h


####NOTE: this is the output for the below keypad (see keypad_sensor_i2c.h)
#        // Set the Key at Use (4x4)
#        char keys[ROWS][COLS] = {
#          {'1', '4', '7', '/'},
#          {'2', '5', '8', '0'},
#          {'3', '6', '9', '.'},
#          {'A', 'B', 'C', 'D'}
#        };

####NOTE: this is the functioning order of pins (see keypad_sensor_i2c.h)
#        byte rowPins[ROWS] = {2, 4, 5, 6}; // Connect to Keyboard Row Pin
#        byte colPins[COLS] = {7, 0, 1, 3}; // Connect to Pin column of keypad.


wifi:
  networks:
  - ssid: !secret ssid_wifi_dvshem
    password: !secret pwd_wifi_dvshem
    manual_ip:
      static_ip: ${device_ip}
      gateway: 10.40.70.1
      subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${device_name_upper} Fallback Hotspot
    password: !secret pwd_wifi_backupap

captive_portal:

# Enable logging
logger:

# Enable Web Server (optional)
web_server:
  port: 80

# Enable Home Assistant API
api:
  password: !secret pwd_esp_api_ota

ota:
  password: !secret pwd_esp_api_ota

########################################

# The following can be omitted 
#  - platform: restart
#    name: ${devicename} restart 

binary_sensor:
  - platform: status
    name: ${device_name} status


sensor:
  - platform: wifi_signal
    name: ${device_name} wifi signal
    update_interval: 600s
 
  - platform: uptime
    name: ${device_name} uptime

#####################
## Custom Keypad Sensor
  - platform: custom
    lambda: |-
      auto my_sensor = new KeypadSensor();
      App.register_component(my_sensor);
      return {my_sensor};
    
    sensors:
      name: ${device_name} Keypad Sensor

###########################################

And this is the code for my custom component.
keypad_sensor_i2c.h (located here: /config/keypad_sensor_i2c.h)

#include "esphome.h"
#include <Keypad.h>
#include <Wire.h>
#include "Keypad_I2C.h"

#define I2CADDR 0x20 // Set the Address of the PCF8574

class KeypadSensor : public Component, public Sensor {

    public:

        static const byte ROWS = 4; // Set the number of Rows
        static const byte COLS = 4; // Set the number of Columns

        // Set the Key at Use (4x4)
        char keys[ROWS][COLS] = {
          {'1', '4', '7', '/'},
          {'2', '5', '8', '0'},
          {'3', '6', '9', '.'},
          {'A', 'B', 'C', 'D'}
        };
    
        bool keyPublished = false;

        static const unsigned int resetTime = 500;
        unsigned int lastPublish = 0;
    
        // define active Pin (4x4)
        byte rowPins[ROWS] = {2, 4, 5, 6}; // Connect to Keyboard Row Pin
        byte colPins[COLS] = {7, 0, 1, 3}; // Connect to Pin column of keypad.

        // makeKeymap (keys): Define Keymap
        // rowPins:Set Pin to Keyboard Row
        // colPins: Set Pin Column of Keypad
        // ROWS: Set Number of Rows.
        // COLS: Set the number of Columns
        // I2CADDR: Set the Address for i2C
        // PCF8574: Set the number IC
        Keypad_I2C myKeypad = Keypad_I2C ( makeKeymap (keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574);

        void setup() override {
        // This will be called by App.setup()
            Wire.begin();
            myKeypad.begin();
        }
        void loop() override {
        // This will be called by App.loop()
            char myKey = myKeypad.getKey();
            if (myKey != NO_KEY) {
                ESP_LOGD("custom","A key has been pressed!");
                int key = myKey - 48;
                publish_state(key);
                keyPublished = true;
                lastPublish = millis();
            }
            else {
                if (keyPublished && (millis() - lastPublish) >= resetTime) {
                    publish_state(NAN);
                    keyPublished = false;
                }
            }
        }
};

As I mentioned, I’ve had this working for quite a while now, but a recent update to esphome seems to have changed something in how it looks for libraries or include files.
If you might have any thoughts, that would be greatly appreciated.

Ah, clearly I wasn’t reading properly. Just testing it now, but it looks like it is in the ‘includes’ section after all.

This was driving me crazy for a few days but I finally found the answer. You can add a library to your ESPHome project from a local folder like this:

esphome:
  name: $device_name
  libraries:
    - file:///config/custom_src/library    # file://<absolute_path>
    - ./custom_src/library    # This doesn't work!

This is documented in the core configuration. Specifically, it says…

ESPHome accepts the same syntax as the pio lib install command.

In my case, I missed the pio lib link which explains to use the “file://” prefex, which led to me
getting “VCSBaseException: VCS: Unknown repository type…” errors.

Thx - super info - I’ve been looking for this for so long