├── yaml ├── kickstart-base-libretiny.yaml ├── import-esp32.yaml ├── import-esp8266.yaml ├── import-ln882hki.yaml ├── import-bk7231n.yaml ├── import-bk7231t.yaml ├── import-rtl8710bn.yaml ├── kickstart-esp8266.yaml ├── kickstart-esp32.yaml ├── kickstart-bk7231n.yaml ├── kickstart-bk7231t.yaml ├── kickstart-rtl8710bn.yaml ├── kickstart-ln882hki.yaml ├── kickstart-esp32-c2.yaml └── kickstart-base.yaml ├── components ├── pinscan │ ├── automation.cpp │ ├── automation.h │ ├── pinscan.h │ ├── __init__.py │ └── pinscan.cpp └── hub_api │ ├── __init__.py │ ├── hub_api.h │ └── hub_api.cpp ├── .github └── workflows │ ├── build.yml │ └── build-inner.yml ├── .gitignore └── .clang-format /yaml/kickstart-base-libretiny.yaml: -------------------------------------------------------------------------------- 1 | hub_api: 2 | 3 | text_sensor: 4 | - platform: libretiny 5 | version: 6 | name: LibreTiny Version 7 | -------------------------------------------------------------------------------- /components/pinscan/automation.cpp: -------------------------------------------------------------------------------- 1 | #include "automation.h" 2 | #include "esphome/core/log.h" 3 | 4 | namespace esphome { 5 | namespace pinscan { 6 | 7 | static const char *const TAG = "pinscan.automation"; 8 | 9 | } // namespace pinscan 10 | } // namespace esphome 11 | -------------------------------------------------------------------------------- /yaml/import-esp32.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-esp32 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/import-esp8266.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-esp8266 3 | 4 | esp8266: 5 | board: esp01_1m 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/import-ln882hki.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-ln882hki 3 | 4 | ln882x: 5 | board: generic-ln882hki 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/import-bk7231n.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-bk7231n 3 | 4 | bk72xx: 5 | board: generic-bk7231n-qfn32-tuya 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/import-bk7231t.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-bk7231t 3 | 4 | bk72xx: 5 | board: generic-bk7231t-qfn32-tuya 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/import-rtl8710bn.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: kickstart-rtl8710bn-2mb-788k 3 | 4 | rtl87xx: 5 | board: generic-rtl8710bn-2mb-788k 6 | 7 | logger: 8 | web_server: 9 | captive_portal: 10 | mdns: 11 | api: 12 | ota: 13 | - platform: esphome 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_password 18 | ap: 19 | -------------------------------------------------------------------------------- /yaml/kickstart-esp8266.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-esp8266 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-esp8266.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | 8 | esp8266: 9 | board: esp01_1m 10 | 11 | select: 12 | - platform: template 13 | id: !extend pin 14 | options: 15 | - Select PIN 16 | - GPIO0 17 | - GPIO1 18 | - GPIO2 / SDA 19 | - GPIO3 20 | - GPIO4 21 | - GPIO5 / SCL 22 | - GPIO12 / MISO 23 | - GPIO13 / MOSI 24 | - GPIO14 / SCK 25 | - GPIO15 / SS 26 | - GPIO16 27 | -------------------------------------------------------------------------------- /yaml/kickstart-esp32.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-esp32 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-esp32.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | 8 | esp32: 9 | board: esp32dev 10 | 11 | select: 12 | - platform: template 13 | id: !extend pin 14 | options: 15 | - Select PIN 16 | - GPIO0 17 | - GPIO1 18 | - GPIO2 19 | - GPIO3 20 | - GPIO4 21 | - GPIO5 / SS 22 | - GPIO12 23 | - GPIO13 24 | - GPIO14 25 | - GPIO15 26 | - GPIO16 27 | - GPIO17 28 | - GPIO18 / SCK 29 | - GPIO19 / MISO 30 | - GPIO21 / SDA 31 | - GPIO22 / SCL 32 | - GPIO23 / MOSI 33 | - GPIO25 / DAC1 34 | - GPIO26 / DAC2 35 | - GPIO27 36 | - GPIO32 37 | - GPIO33 38 | - GPIO34 39 | - GPIO35 40 | - GPIO36 41 | - GPIO39 42 | -------------------------------------------------------------------------------- /components/pinscan/automation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/automation.h" 4 | #include "esphome/core/component.h" 5 | #include "pinscan.h" 6 | 7 | namespace esphome { 8 | namespace pinscan { 9 | 10 | template class SetPinAction : public Action { 11 | public: 12 | explicit SetPinAction(Pinscan *a_pinscan) : pinscan_(a_pinscan) {} 13 | TEMPLATABLE_VALUE(int, pin); 14 | void play(const Ts &...x) override { this->pinscan_->set_pin(this->pin_.value(x...)); } 15 | 16 | protected: 17 | Pinscan *pinscan_; 18 | }; 19 | 20 | template class SetModeAction : public Action { 21 | public: 22 | explicit SetModeAction(Pinscan *a_pinscan) : pinscan_(a_pinscan) {} 23 | TEMPLATABLE_VALUE(int, mode); 24 | void play(const Ts &...x) override { this->pinscan_->set_mode(this->mode_.value(x...)); } 25 | 26 | protected: 27 | Pinscan *pinscan_; 28 | }; 29 | 30 | } // namespace pinscan 31 | } // namespace esphome 32 | -------------------------------------------------------------------------------- /components/pinscan/pinscan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/components/text_sensor/text_sensor.h" 4 | #include "esphome/core/component.h" 5 | #include "esphome/core/hal.h" 6 | #include "esphome/core/log.h" 7 | 8 | namespace esphome { 9 | namespace pinscan { 10 | 11 | class Pinscan : public PollingComponent { 12 | public: 13 | Pinscan() : PollingComponent(50) {} 14 | void setup() override; 15 | void dump_config() override; 16 | void update() override; 17 | float get_setup_priority() const override { return setup_priority::HARDWARE; } 18 | void set_pin(int pin); 19 | void set_mode(int mode); 20 | void set_pin_state_sensor(text_sensor::TextSensor *pin_state_sensor) { pin_state_sensor_ = pin_state_sensor; } 21 | 22 | protected: 23 | int current_pin_{-1}; 24 | int current_mode_{-1}; 25 | int current_state_{-1}; 26 | text_sensor::TextSensor *pin_state_sensor_{nullptr}; 27 | }; 28 | 29 | } // namespace pinscan 30 | } // namespace esphome 31 | -------------------------------------------------------------------------------- /components/hub_api/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.config_validation as cv 2 | import esphome.codegen as cg 3 | from esphome.const import CONF_ID 4 | from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID 5 | from esphome.components import web_server_base 6 | 7 | DEPENDENCIES = ["libretiny"] 8 | AUTO_LOAD = ["web_server_base"] 9 | 10 | hub_api_ns = cg.esphome_ns.namespace("hub_api") 11 | HubAPIHandler = hub_api_ns.class_("HubAPI", cg.Component) 12 | 13 | CONFIG_SCHEMA = cv.Schema( 14 | { 15 | cv.GenerateID(): cv.declare_id(HubAPIHandler), 16 | cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id( 17 | web_server_base.WebServerBase 18 | ), 19 | }, 20 | cv.only_with_arduino, 21 | ).extend(cv.COMPONENT_SCHEMA) 22 | 23 | 24 | async def to_code(config): 25 | paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) 26 | 27 | var = cg.new_Pvariable(config[CONF_ID], paren) 28 | await cg.register_component(var, config) 29 | -------------------------------------------------------------------------------- /yaml/kickstart-bk7231n.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-bk7231n 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-bk7231n.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | libretiny: !include kickstart-base-libretiny.yaml 8 | 9 | bk72xx: 10 | board: generic-bk7231n-qfn32-tuya 11 | framework: 12 | version: latest 13 | loglevel: debug 14 | 15 | select: 16 | - platform: template 17 | id: !extend pin 18 | options: 19 | - Select PIN 20 | - P0 / UART2_TX / I2C2_SCL 21 | - P1 / UART2_RX / I2C2_SDA 22 | - P6 / PWM0 23 | - P7 / PWM1 24 | - P8 / PWM2 25 | - P9 / PWM3 26 | - P10 / UART1_RX 27 | - P11 / UART1_TX 28 | - P14 / SCK 29 | - P15 / CS 30 | - P16 / MOSI 31 | - P17 / MISO 32 | - P20 / I2C1_SCL / TCK 33 | - P21 / I2C1_SDA / TMS 34 | - P22 / TDI 35 | - P23 / TDO / ADC3 36 | - P24 / PWM4 37 | - P26 / PWM5 38 | - P28 39 | -------------------------------------------------------------------------------- /yaml/kickstart-bk7231t.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-bk7231t 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-bk7231t.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | libretiny: !include kickstart-base-libretiny.yaml 8 | 9 | bk72xx: 10 | board: generic-bk7231t-qfn32-tuya 11 | framework: 12 | version: latest 13 | loglevel: debug 14 | 15 | select: 16 | - platform: template 17 | id: !extend pin 18 | options: 19 | - Select PIN 20 | - P0 / UART2_TX / I2C2_SCL 21 | - P1 / UART2_RX / I2C2_SDA 22 | - P6 / PWM0 23 | - P7 / PWM1 24 | - P8 / PWM2 25 | - P9 / PWM3 26 | - P10 / UART1_RX 27 | - P11 / UART1_TX 28 | - P14 / SCK 29 | - P15 / CS 30 | - P16 / MOSI 31 | - P17 / MISO 32 | - P20 / I2C1_SCL / TCK 33 | - P21 / I2C1_SDA / TMS 34 | - P22 / TDI 35 | - P23 / TDO / ADC3 36 | - P24 / PWM4 37 | - P26 / PWM5 38 | - P28 39 | -------------------------------------------------------------------------------- /yaml/kickstart-rtl8710bn.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-rtl8710bn 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-rtl8710bn.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | libretiny: !include kickstart-base-libretiny.yaml 8 | 9 | rtl87xx: 10 | board: generic-rtl8710bn-2mb-788k 11 | framework: 12 | version: latest 13 | loglevel: debug 14 | 15 | select: 16 | - platform: template 17 | id: !extend pin 18 | options: 19 | - Select PIN 20 | - PA00 / PWM2 21 | - PA05 / PWM4 22 | - PA06 / FCS 23 | - PA07 / FD1 24 | - PA08 / FD2 25 | - PA09 / FD0 26 | - PA10 / FSCK 27 | - PA11 / FD3 28 | - PA12 / PWM3 29 | - PA14 / PWM0 / SWCLK 30 | - PA15 / PWM1 / SWDIO 31 | - PA18 / UART0_RX / I2C1_SCL / SPI0_SCK / SPI1_SCK 32 | - PA19 / UART0_CTS / I2C0_SDA / SPI0_CS / SPI1_CS 33 | - PA22 / UART0_RTS / I2C0_SCL / SPI0_MISO / SPI1_MISO / PWM5 34 | - PA23 / UART0_TX / I2C1_SDA / SPI0_MISO / SPI1_MISO / PWM0 35 | - PA29 / UART2_RX / I2C0_SCL / PWM4 36 | - PA30 / UART2_TX / I2C0_SDA / PWM4 37 | -------------------------------------------------------------------------------- /components/hub_api/hub_api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef USE_ARDUINO 4 | 5 | #include 6 | #include 7 | 8 | #include "esphome/components/web_server_base/web_server_base.h" 9 | #include "esphome/core/controller.h" 10 | #include "esphome/core/component.h" 11 | 12 | namespace esphome { 13 | namespace hub_api { 14 | 15 | class HubAPI : public AsyncWebHandler, public Component { 16 | public: 17 | HubAPI(web_server_base::WebServerBase *base) : base_(base) {} 18 | 19 | bool canHandle(AsyncWebServerRequest *request) const override { 20 | if (request->method() == HTTP_GET) { 21 | if (request->url().startsWith("/hub")) 22 | return true; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | void handleRequest(AsyncWebServerRequest *req) override; 29 | 30 | void setup() override { 31 | this->base_->init(); 32 | this->base_->add_handler(this); 33 | } 34 | float get_setup_priority() const override { 35 | // After WiFi 36 | return setup_priority::WIFI - 1.0f; 37 | } 38 | 39 | protected: 40 | web_server_base::WebServerBase *base_; 41 | }; 42 | 43 | } // namespace hub_api 44 | } // namespace esphome 45 | 46 | #endif // USE_ARDUINO 47 | -------------------------------------------------------------------------------- /yaml/kickstart-ln882hki.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-ln882hki 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-ln882hki.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | libretiny: !include kickstart-base-libretiny.yaml 8 | 9 | ln882x: 10 | board: generic-ln882hki 11 | framework: 12 | version: dev 13 | loglevel: debug 14 | 15 | select: 16 | - platform: template 17 | id: !extend pin 18 | options: 19 | - Select PIN 20 | - PA00 / ADC2 / I2C0_SCL / I2C0_SDA 21 | - PA01 / ADC3 / SWDIO / I2C0_SCL / I2C0_SDA 22 | - PA02 / UART0_TX / I2C0_SCL / I2C0_SDA 23 | - PA03 / UART0_RX / I2C0_SCL / I2C0_SDA 24 | - PA04 / ADC4 / SWCLK / I2C0_SCL / I2C0_SDA 25 | - PA05 / I2C0_SCL / I2C0_SDA 26 | - PA06 / SD_D2 / I2C0_SCL / I2C0_SDA 27 | - PA07 / SD_D3 / I2S0_RX / I2C0_SCL / I2C0_SDA 28 | - PA08 / BOOT0 / SD_CMD / I2S0_WS / I2C0_SCL / I2C0_SDA 29 | - PA09 / BOOT1 / SD_CLK / I2S0_SCLK / I2C0_SCL / I2C0_SDA 30 | - PA10 / SD_D0 / I2S0_TX / I2C0_SCL / I2C0_SDA 31 | - PA11 / SD_D1 / I2C0_SCL / I2C0_SDA 32 | - PA12 / I2C0_SCL / I2C0_SDA 33 | - PB03 / ADC5 / I2C0_SCL / I2C0_SDA 34 | - PB04 / ADC6 / I2C0_SCL / I2C0_SDA 35 | - PB05 / ADC7 / I2C0_SCL / I2C0_SDA 36 | - PB06 / I2C0_SCL / I2C0_SDA 37 | - PB07 / I2C0_SCL / I2C0_SDA 38 | - PB08 / UART1_RX / I2C0_SCL / I2C0_SDA 39 | - PB09 / UART1_TX / I2C0_SCL / I2C0_SDA 40 | -------------------------------------------------------------------------------- /components/hub_api/hub_api.cpp: -------------------------------------------------------------------------------- 1 | #ifdef USE_ARDUINO 2 | 3 | #include "hub_api.h" 4 | #include "esphome/core/application.h" 5 | 6 | #include 7 | 8 | #undef min 9 | 10 | namespace esphome { 11 | namespace hub_api { 12 | 13 | static const char *const TAG = "hub_api"; 14 | 15 | void HubAPI::handleRequest(AsyncWebServerRequest *req) { 16 | if (req->url().substring(4) == "/flash_read") { 17 | uint32_t offset, length; 18 | 19 | if (req->hasParam("offset")) { 20 | offset = req->getParam("offset")->value().toInt(); 21 | } else { 22 | offset = 0; 23 | } 24 | 25 | if (req->hasParam("length")) { 26 | length = req->getParam("length")->value().toInt(); 27 | } else { 28 | length = FLASH_LENGTH; 29 | } 30 | 31 | auto callback = [offset, length](uint8_t *buffer, size_t maxLen, size_t position) -> size_t { 32 | size_t blockStart = offset + position; 33 | size_t blockSize = std::min(static_cast(maxLen), static_cast(length - position)); 34 | blockSize = std::min(blockSize, static_cast(4096)); 35 | 36 | if (blockSize) { 37 | ESP_LOGD(TAG, "Reading flash: offset=%06x, length=%u", blockStart, blockSize); 38 | Flash.readBlock(blockStart, buffer, blockSize); 39 | } 40 | 41 | return blockSize; 42 | }; 43 | 44 | req->send("application/octet-stream", length, callback); 45 | return; 46 | } 47 | 48 | EMPTY: 49 | #ifdef LT_BANNER_STR 50 | req->send(200, "text/plain", LT_BANNER_STR); 51 | #else 52 | req->send(200, "text/plain", "LibreTuya " LT_VERSION_STR); 53 | #endif 54 | } 55 | 56 | } // namespace hub_api 57 | } // namespace esphome 58 | 59 | #endif // USE_ARDUINO 60 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "Build ESPHome" 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | bk7231t: 7 | type: boolean 8 | description: BK7231T 9 | bk7231n: 10 | type: boolean 11 | description: BK7231N 12 | ln882hki: 13 | type: boolean 14 | description: LN882HKI 15 | rtl8710bn: 16 | type: boolean 17 | description: RTL8710BN 18 | esp8266: 19 | type: boolean 20 | description: ESP8266 21 | esp32: 22 | type: boolean 23 | description: ESP32 24 | esp32-c2: 25 | type: boolean 26 | description: ESP32-C2 27 | 28 | permissions: 29 | contents: write 30 | 31 | jobs: 32 | build: 33 | name: Build ESPHome 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | include: 38 | - enabled: ${{ inputs.bk7231t }} 39 | config: bk7231t 40 | - enabled: ${{ inputs.bk7231n }} 41 | config: bk7231n 42 | - enabled: ${{ inputs.rtl8710bn }} 43 | config: rtl8710bn 44 | - enabled: ${{ inputs.ln882hki }} 45 | config: ln882hki 46 | - enabled: ${{ inputs.esp8266 }} 47 | config: esp8266 48 | - enabled: ${{ inputs.esp32 }} 49 | config: esp32 50 | - enabled: ${{ inputs.esp32-c2 }} 51 | config: esp32-c2 52 | esphome-repo: libretiny-eu/libretiny-esphome 53 | esphome-ref: feature/esp32-c2 54 | uses: libretiny-eu/esphome-kickstart/.github/workflows/build-inner.yml@master 55 | with: 56 | enabled: ${{ fromJSON(matrix.enabled) }} 57 | config: ${{ matrix.config }} 58 | esphome-repo: ${{ matrix.esphome-repo }} 59 | esphome-ref: ${{ matrix.esphome-ref }} 60 | -------------------------------------------------------------------------------- /yaml/kickstart-esp32-c2.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: kickstart-esp32-c2 3 | import_url: github://libretiny-eu/esphome-kickstart/yaml/import-esp32-c2.yaml@master 4 | 5 | packages: 6 | base: !include kickstart-base.yaml 7 | 8 | esp32: 9 | board: esp32-c2-devkitm-1 10 | framework: 11 | type: arduino 12 | # force arduino-esp32 v3.2.0, otherwise ESPHome will use PIO registry v2.0.5 13 | source: https://github.com/espressif/arduino-esp32/releases/download/3.2.0/esp32-3.2.0.zip 14 | # version spec required with custom source 15 | version: 3.2.0 16 | # switch to pioarduino - IDF v5.4/arduino v3.2.0 17 | platform_version: https://github.com/pioarduino/platform-espressif32.git#f0bb1b844ed63e525c9a54750427b7b5ac92dccf 18 | 19 | esphome: 20 | platformio_options: 21 | platform_packages: 22 | # use C2 skeleton with lwIP v2.2.0 23 | - framework-arduino-c2-skeleton-lib @ https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/c2_arduino_compile_skeleton.zip 24 | # use IDF compatible with this skeleton (libnet80211.a and other closed blobs) 25 | - framework-espidf @ https://github.com/pioarduino/esp-idf/releases/download/v5.4.1.250411/esp-idf-v5.4.1.zip 26 | custom_component_remove: 27 | # remove network_provisioning and other features unsupported on ESP32-C2 28 | - espressif/esp-dsp 29 | - espressif/network_provisioning 30 | - espressif/esp-zboss-lib 31 | - espressif/esp-zigbee-lib 32 | - espressif/esp_rainmaker 33 | - espressif/esp-sr 34 | - espressif/esp-modbus 35 | - espressif/esp32-camera 36 | 37 | select: 38 | - platform: template 39 | id: !extend pin 40 | options: 41 | - Select PIN 42 | - GPIO0 43 | - GPIO1 44 | - GPIO2 45 | - GPIO3 46 | - GPIO4 47 | - GPIO5 / SS 48 | - GPIO12 49 | - GPIO13 50 | - GPIO14 51 | - GPIO15 52 | - GPIO16 53 | - GPIO17 54 | - GPIO18 / SCK 55 | - GPIO19 / MISO 56 | - GPIO21 / SDA 57 | - GPIO22 / SCL 58 | - GPIO23 / MOSI 59 | - GPIO25 / DAC1 60 | - GPIO26 / DAC2 61 | - GPIO27 62 | - GPIO32 63 | - GPIO33 64 | - GPIO34 65 | - GPIO35 66 | - GPIO36 67 | - GPIO39 68 | -------------------------------------------------------------------------------- /yaml/kickstart-base.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: REPLACEME 3 | import_url: REPLACEME 4 | 5 | esphome: 6 | name: $name 7 | project: 8 | name: lt.kickstart 9 | version: "1.0" 10 | 11 | dashboard_import: 12 | package_import_url: $import_url 13 | import_full_config: true 14 | 15 | external_components: 16 | source: ../components 17 | components: 18 | - pinscan 19 | - hub_api 20 | refresh: 10 min 21 | 22 | logger: 23 | baud_rate: 115200 24 | logs: 25 | select: ERROR 26 | sensor: ERROR 27 | text_sensor: ERROR 28 | 29 | ota: 30 | - platform: esphome 31 | 32 | wifi: 33 | ap: 34 | ssid: $name 35 | 36 | captive_portal: 37 | 38 | mdns: 39 | 40 | api: 41 | reboot_timeout: 0s 42 | 43 | web_server: 44 | local: true 45 | 46 | pinscan: 47 | id: scanner 48 | pin_state_sensor: 49 | name: -> Pin State 50 | 51 | select: 52 | - platform: template 53 | id: mode 54 | name: -> Pin Mode 55 | options: 56 | - INPUT 57 | - INPUT_PULLUP 58 | - OUTPUT_HIGH 59 | - OUTPUT_LOW 60 | optimistic: true 61 | on_value: 62 | - pinscan.set_mode: 63 | id: scanner 64 | mode: !lambda "return id(mode).active_index().value();" 65 | 66 | - platform: template 67 | id: pin 68 | name: -> Pin 69 | optimistic: true 70 | on_value: 71 | - pinscan.set_pin: 72 | id: scanner 73 | pin: !lambda "return id(pin).active_index().value() - 1;" 74 | - pinscan.set_mode: 75 | id: scanner 76 | mode: !lambda "return id(mode).active_index().value();" 77 | 78 | text_sensor: 79 | - platform: wifi_info 80 | ip_address: 81 | id: ip_address 82 | name: IP Address 83 | - platform: debug 84 | device: 85 | name: Device Info 86 | reset_reason: 87 | name: Reset Reason 88 | 89 | button: 90 | - platform: factory_reset 91 | name: Reset to Factory Settings 92 | - platform: restart 93 | name: Restart 94 | 95 | debug: 96 | update_interval: 5s 97 | 98 | sensor: 99 | - platform: debug 100 | free: 101 | name: Heap Free 102 | loop_time: 103 | name: Loop Time 104 | - platform: uptime 105 | name: Uptime 106 | -------------------------------------------------------------------------------- /components/pinscan/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome import automation 4 | from esphome.components import text_sensor 5 | from esphome.const import CONF_ID, CONF_MODE, CONF_PIN 6 | 7 | AUTO_LOAD = ["text_sensor"] 8 | 9 | pinscan_ns = cg.esphome_ns.namespace("pinscan") 10 | 11 | PinscanComponent = pinscan_ns.class_("Pinscan", cg.Component, cg.PollingComponent) 12 | SetPinAction = pinscan_ns.class_("SetPinAction", automation.Action) 13 | SetModeAction = pinscan_ns.class_("SetModeAction", automation.Action) 14 | 15 | CONF_PIN_STATE_SENSOR = "pin_state_sensor" 16 | 17 | CONFIG_SCHEMA = cv.Schema( 18 | { 19 | cv.GenerateID(): cv.declare_id(PinscanComponent), 20 | cv.Optional(CONF_PIN_STATE_SENSOR): text_sensor.text_sensor_schema(), 21 | } 22 | ).extend(cv.COMPONENT_SCHEMA) 23 | 24 | 25 | async def to_code(config): 26 | var = cg.new_Pvariable(config[CONF_ID]) 27 | await cg.register_component(var, config) 28 | if CONF_PIN_STATE_SENSOR in config: 29 | sens = await text_sensor.new_text_sensor(config[CONF_PIN_STATE_SENSOR]) 30 | cg.add(var.set_pin_state_sensor(sens)) 31 | 32 | 33 | @automation.register_action( 34 | "pinscan.set_pin", 35 | SetPinAction, 36 | automation.maybe_simple_id( 37 | cv.Schema( 38 | { 39 | cv.Required(CONF_ID): cv.use_id(PinscanComponent), 40 | cv.Required(CONF_PIN): cv.templatable(cv.int_), 41 | } 42 | ) 43 | ), 44 | ) 45 | async def pinscan_set_pin_to_code(config, action_id, template_arg, args): 46 | paren = await cg.get_variable(config[CONF_ID]) 47 | var = cg.new_Pvariable(action_id, template_arg, paren) 48 | template_ = await cg.templatable(config[CONF_PIN], args, cg.int_) 49 | cg.add(var.set_pin(template_)) 50 | return var 51 | 52 | 53 | @automation.register_action( 54 | "pinscan.set_mode", 55 | SetModeAction, 56 | automation.maybe_simple_id( 57 | cv.Schema( 58 | { 59 | cv.Required(CONF_ID): cv.use_id(PinscanComponent), 60 | cv.Required(CONF_MODE): cv.templatable(cv.int_), 61 | } 62 | ) 63 | ), 64 | ) 65 | async def pinscan_set_mode_to_code(config, action_id, template_arg, args): 66 | paren = await cg.get_variable(config[CONF_ID]) 67 | var = cg.new_Pvariable(action_id, template_arg, paren) 68 | template_ = await cg.templatable(config[CONF_MODE], args, cg.int_) 69 | cg.add(var.set_mode(template_)) 70 | return var 71 | -------------------------------------------------------------------------------- /.github/workflows/build-inner.yml: -------------------------------------------------------------------------------- 1 | name: "Build ESPHome (single)" 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | enabled: 7 | required: false 8 | type: boolean 9 | default: true 10 | config: 11 | required: true 12 | type: string 13 | esphome-repo: 14 | required: false 15 | type: string 16 | esphome-ref: 17 | required: false 18 | type: string 19 | 20 | jobs: 21 | esphome: 22 | name: Build ESPHome (${{ inputs.config }}) 23 | runs-on: ubuntu-latest 24 | if: ${{ inputs.enabled }} 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v3 28 | - name: Checkout ESPHome 29 | uses: actions/checkout@v3 30 | with: 31 | repository: ${{ inputs.esphome-repo || 'esphome/esphome' }} 32 | ref: ${{ inputs.esphome-ref || 'release' }} 33 | path: esphome 34 | - name: Set up Python 35 | uses: actions/setup-python@v3 36 | with: 37 | python-version: '3.12' 38 | 39 | - name: Cache PlatformIO 40 | uses: actions/cache@v4 41 | with: 42 | path: ~/.platformio 43 | key: ${{ runner.os }}-${{ inputs.esphome-repo || 'esphome/esphome' }} 44 | 45 | - name: Install PlatformIO Core 46 | run: | 47 | pip install --upgrade platformio 48 | - name: Install ESPHome 49 | run: | 50 | cd esphome/ 51 | pip install -e . 52 | 53 | - name: Get current date 54 | id: date 55 | run: | 56 | echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT 57 | echo "datever=$(date +'%y.%m.%d')" >> $GITHUB_OUTPUT 58 | 59 | - name: Build firmware binaries 60 | run: | 61 | mkdir -p build/ 62 | cd yaml/ 63 | esphome compile kickstart-${{ inputs.config }}.yaml 64 | 65 | - name: Copy firmware binaries 66 | run: | 67 | cd yaml/ 68 | 69 | config=${{ inputs.config }} 70 | date=${{ steps.date.outputs.date }} 71 | outdir=.esphome/build/kickstart-${config}/.pioenvs/kickstart-${config} 72 | 73 | # copy UF2 if available, otherwise BIN 74 | if [ -f ${outdir}/firmware.uf2 ]; then 75 | cp ${outdir}/firmware.uf2 ../build/kickstart-${config}-${date}.uf2 76 | else 77 | cp ${outdir}/firmware.bin ../build/kickstart-${config}-${date}.bin 78 | fi 79 | 80 | if [ -f ${outdir}/firmware.factory.bin ]; then 81 | cp ${outdir}/firmware.factory.bin ../build/kickstart-${config}-${date}.factory.bin 82 | fi 83 | 84 | if [ $config = 'bk7231t' ]; then 85 | cp ${outdir}/*.ota.rbl ${outdir}/*.ota.ug.bin ../build/ 86 | cp ${outdir}/*.ota.rbl ../build/OpenBK7231T_OTA_upgrade_to_esphome_${date}.rbl 87 | fi 88 | if [ $config = 'bk7231n' ]; then 89 | cp ${outdir}/*.ota.rbl ${outdir}/*.ota.ug.bin ../build/ 90 | cp ${outdir}/*.ota.rbl ../build/OpenBK7231N_OTA_upgrade_to_esphome_${date}.rbl 91 | fi 92 | 93 | - name: Add GitHub release assets 94 | uses: softprops/action-gh-release@v1 95 | with: 96 | files: | 97 | build/*.* 98 | tag_name: v${{ steps.date.outputs.datever }} 99 | fail_on_unmatched_files: true 100 | env: 101 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 102 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/c,platformio,c++,visualstudiocode,intellij+all 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=c,platformio,c++,visualstudiocode,intellij+all 3 | 4 | ### C ### 5 | # Prerequisites 6 | *.d 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Linker output 15 | *.ilk 16 | *.map 17 | *.exp 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | 29 | # Shared objects (inc. Windows DLLs) 30 | *.dll 31 | *.so 32 | *.so.* 33 | *.dylib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | *.i*86 40 | *.x86_64 41 | *.hex 42 | 43 | # Debug files 44 | *.dSYM/ 45 | *.su 46 | *.idb 47 | *.pdb 48 | 49 | # Kernel Module Compile Results 50 | *.mod* 51 | *.cmd 52 | .tmp_versions/ 53 | modules.order 54 | Module.symvers 55 | Mkfile.old 56 | dkms.conf 57 | 58 | ### C++ ### 59 | # Prerequisites 60 | 61 | # Compiled Object files 62 | *.slo 63 | 64 | # Precompiled Headers 65 | 66 | # Compiled Dynamic libraries 67 | 68 | # Fortran module files 69 | *.mod 70 | *.smod 71 | 72 | # Compiled Static libraries 73 | *.lai 74 | 75 | # Executables 76 | 77 | ### Intellij+all ### 78 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 79 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 80 | 81 | # User-specific stuff 82 | .idea/**/workspace.xml 83 | .idea/**/tasks.xml 84 | .idea/**/usage.statistics.xml 85 | .idea/**/dictionaries 86 | .idea/**/shelf 87 | 88 | # AWS User-specific 89 | .idea/**/aws.xml 90 | 91 | # Generated files 92 | .idea/**/contentModel.xml 93 | 94 | # Sensitive or high-churn files 95 | .idea/**/dataSources/ 96 | .idea/**/dataSources.ids 97 | .idea/**/dataSources.local.xml 98 | .idea/**/sqlDataSources.xml 99 | .idea/**/dynamic.xml 100 | .idea/**/uiDesigner.xml 101 | .idea/**/dbnavigator.xml 102 | 103 | # Gradle 104 | .idea/**/gradle.xml 105 | .idea/**/libraries 106 | 107 | # Gradle and Maven with auto-import 108 | # When using Gradle or Maven with auto-import, you should exclude module files, 109 | # since they will be recreated, and may cause churn. Uncomment if using 110 | # auto-import. 111 | # .idea/artifacts 112 | # .idea/compiler.xml 113 | # .idea/jarRepositories.xml 114 | # .idea/modules.xml 115 | # .idea/*.iml 116 | # .idea/modules 117 | # *.iml 118 | # *.ipr 119 | 120 | # CMake 121 | cmake-build-*/ 122 | 123 | # Mongo Explorer plugin 124 | .idea/**/mongoSettings.xml 125 | 126 | # File-based project format 127 | *.iws 128 | 129 | # IntelliJ 130 | out/ 131 | 132 | # mpeltonen/sbt-idea plugin 133 | .idea_modules/ 134 | 135 | # JIRA plugin 136 | atlassian-ide-plugin.xml 137 | 138 | # Cursive Clojure plugin 139 | .idea/replstate.xml 140 | 141 | # SonarLint plugin 142 | .idea/sonarlint/ 143 | 144 | # Crashlytics plugin (for Android Studio and IntelliJ) 145 | com_crashlytics_export_strings.xml 146 | crashlytics.properties 147 | crashlytics-build.properties 148 | fabric.properties 149 | 150 | # Editor-based Rest Client 151 | .idea/httpRequests 152 | 153 | # Android studio 3.1+ serialized cache file 154 | .idea/caches/build_file_checksums.ser 155 | 156 | ### Intellij+all Patch ### 157 | # Ignore everything but code style settings and run configurations 158 | # that are supposed to be shared within teams. 159 | 160 | .idea/* 161 | 162 | !.idea/codeStyles 163 | !.idea/runConfigurations 164 | 165 | ### PlatformIO ### 166 | .pioenvs 167 | .piolibdeps 168 | .clang_complete 169 | .gcc-flags.json 170 | .pio 171 | 172 | ### VisualStudioCode ### 173 | .vscode/* 174 | !.vscode/settings.json 175 | !.vscode/tasks.json 176 | !.vscode/launch.json 177 | !.vscode/extensions.json 178 | !.vscode/*.code-snippets 179 | 180 | # Local History for Visual Studio Code 181 | .history/ 182 | 183 | # Built Visual Studio Code Extensions 184 | *.vsix 185 | 186 | ### VisualStudioCode Patch ### 187 | # Ignore all local history of files 188 | .history 189 | .ionide 190 | 191 | # End of https://www.toptal.com/developers/gitignore/api/c,platformio,c++,visualstudiocode,intellij+all 192 | 193 | .esphome/ 194 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | AccessModifierOffset: -1 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignEscapedNewlines: DontAlign 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: false 17 | AlwaysBreakTemplateDeclarations: MultiLine 18 | BinPackArguments: true 19 | BinPackParameters: true 20 | BraceWrapping: 21 | AfterClass: false 22 | AfterControlStatement: false 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterObjCDeclaration: false 27 | AfterStruct: false 28 | AfterUnion: false 29 | AfterExternBlock: false 30 | BeforeCatch: false 31 | BeforeElse: false 32 | IndentBraces: false 33 | SplitEmptyFunction: true 34 | SplitEmptyRecord: true 35 | SplitEmptyNamespace: true 36 | BreakBeforeBinaryOperators: None 37 | BreakBeforeBraces: Attach 38 | BreakBeforeInheritanceComma: false 39 | BreakInheritanceList: BeforeColon 40 | BreakBeforeTernaryOperators: true 41 | BreakConstructorInitializersBeforeComma: false 42 | BreakConstructorInitializers: BeforeColon 43 | BreakAfterJavaFieldAnnotations: false 44 | BreakStringLiterals: true 45 | ColumnLimit: 120 46 | CommentPragmas: '^ IWYU pragma:' 47 | CompactNamespaces: false 48 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 49 | ConstructorInitializerIndentWidth: 4 50 | ContinuationIndentWidth: 4 51 | Cpp11BracedListStyle: true 52 | DerivePointerAlignment: false 53 | DisableFormat: false 54 | ExperimentalAutoDetectBinPacking: false 55 | FixNamespaceComments: true 56 | ForEachMacros: 57 | - foreach 58 | - Q_FOREACH 59 | - BOOST_FOREACH 60 | IncludeBlocks: Preserve 61 | IncludeCategories: 62 | - Regex: '^' 63 | Priority: 2 64 | - Regex: '^<.*\.h>' 65 | Priority: 1 66 | - Regex: '^<.*' 67 | Priority: 2 68 | - Regex: '.*' 69 | Priority: 3 70 | IncludeIsMainRegex: '([-_](test|unittest))?$' 71 | IndentCaseLabels: true 72 | IndentPPDirectives: None 73 | IndentWidth: 2 74 | IndentWrappedFunctionNames: false 75 | KeepEmptyLinesAtTheStartOfBlocks: false 76 | MacroBlockBegin: '' 77 | MacroBlockEnd: '' 78 | MaxEmptyLinesToKeep: 1 79 | NamespaceIndentation: None 80 | PenaltyBreakAssignment: 2 81 | PenaltyBreakBeforeFirstCallParameter: 1 82 | PenaltyBreakComment: 300 83 | PenaltyBreakFirstLessLess: 120 84 | PenaltyBreakString: 1000 85 | PenaltyBreakTemplateDeclaration: 10 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyReturnTypeOnItsOwnLine: 2000 88 | PointerAlignment: Right 89 | RawStringFormats: 90 | - Language: Cpp 91 | Delimiters: 92 | - cc 93 | - CC 94 | - cpp 95 | - Cpp 96 | - CPP 97 | - 'c++' 98 | - 'C++' 99 | CanonicalDelimiter: '' 100 | BasedOnStyle: google 101 | - Language: TextProto 102 | Delimiters: 103 | - pb 104 | - PB 105 | - proto 106 | - PROTO 107 | EnclosingFunctions: 108 | - EqualsProto 109 | - EquivToProto 110 | - PARSE_PARTIAL_TEXT_PROTO 111 | - PARSE_TEST_PROTO 112 | - PARSE_TEXT_PROTO 113 | - ParseTextOrDie 114 | - ParseTextProtoOrDie 115 | CanonicalDelimiter: '' 116 | BasedOnStyle: google 117 | ReflowComments: true 118 | SortIncludes: false 119 | SortUsingDeclarations: false 120 | SpaceAfterCStyleCast: true 121 | SpaceAfterTemplateKeyword: false 122 | SpaceBeforeAssignmentOperators: true 123 | SpaceBeforeCpp11BracedList: false 124 | SpaceBeforeCtorInitializerColon: true 125 | SpaceBeforeInheritanceColon: true 126 | SpaceBeforeParens: ControlStatements 127 | SpaceBeforeRangeBasedForLoopColon: true 128 | SpaceInEmptyParentheses: false 129 | SpacesBeforeTrailingComments: 2 130 | SpacesInAngles: false 131 | SpacesInContainerLiterals: false 132 | SpacesInCStyleCastParentheses: false 133 | SpacesInParentheses: false 134 | SpacesInSquareBrackets: false 135 | Standard: Auto 136 | TabWidth: 2 137 | UseTab: Never 138 | -------------------------------------------------------------------------------- /components/pinscan/pinscan.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "pinscan.h" 3 | #include "Arduino.h" 4 | 5 | namespace esphome { 6 | namespace pinscan { 7 | 8 | static const char *const TAG = "pinscan"; 9 | 10 | #if defined(LT_BK7231N) || defined(LT_BK7231T) 11 | static const int PIN_MAP[] = { 12 | PIN_P0, // P0 / UART2_TX / I2C2_SCL 13 | PIN_P1, // P1 / UART2_RX / I2C2_SDA 14 | PIN_P6, // P6 / PWM0 15 | PIN_P7, // P7 / PWM1 16 | PIN_P8, // P8 / PWM2 17 | PIN_P9, // P9 / PWM3 18 | PIN_P10, // P10 / UART1_RX 19 | PIN_P11, // P11 / UART1_TX 20 | PIN_P14, // P14 / SCK 21 | PIN_P15, // P15 / CS 22 | PIN_P16, // P16 / MOSI 23 | PIN_P17, // P17 / MISO 24 | PIN_P20, // P20 / I2C1_SCL / TCK 25 | PIN_P21, // P21 / I2C1_SDA / TMS 26 | PIN_P22, // P22 / TDI 27 | PIN_P23, // P23 / TDO / ADC3 28 | PIN_P24, // P24 / PWM4 29 | PIN_P26, // P26 / PWM5 30 | PIN_P28, // P28 31 | }; 32 | #elif defined(LT_RTL8710B) 33 | static const int PIN_MAP[] = { 34 | PIN_PA00, // PA00 / PWM2 35 | PIN_PA05, // PA05 / PWM4 36 | PIN_PA06, // PA06 / FCS 37 | PIN_PA07, // PA07 / FD1 38 | PIN_PA08, // PA08 / FD2 39 | PIN_PA09, // PA09 / FD0 40 | PIN_PA10, // PA10 / FSCK 41 | PIN_PA11, // PA11 / FD3 42 | PIN_PA12, // PA12 / PWM3 43 | PIN_PA14, // PA14 / PWM0 / SWCLK 44 | PIN_PA15, // PA15 / PWM1 / SWDIO 45 | PIN_PA18, // PA18 / UART0_RX / I2C1_SCL / SPI0_SCK / SPI1_SCK 46 | PIN_PA19, // PA19 / UART0_CTS / I2C0_SDA / SPI0_CS / SPI1_CS 47 | PIN_PA22, // PA22 / UART0_RTS / I2C0_SCL / SPI0_MISO / SPI1_MISO / PWM5 48 | PIN_PA23, // PA23 / UART0_TX / I2C1_SDA / SPI0_MISO / SPI1_MISO / PWM0 49 | PIN_PA29, // PA29 / UART2_RX / I2C0_SCL / PWM4 50 | PIN_PA30, // PA30 / UART2_TX / I2C0_SDA / PWM4 51 | 52 | }; 53 | #elif defined(LT_LN882H) 54 | static const int PIN_MAP[] = { 55 | PIN_PA00, // PA00 / ADC2 / I2C0_SCL / I2C0_SDA 56 | PIN_PA01, // PA01 / ADC3 / SWDIO / I2C0_SCL / I2C0_SDA 57 | PIN_PA02, // PA02 / UART0_TX / I2C0_SCL / I2C0_SDA 58 | PIN_PA03, // PA03 / UART0_RX / I2C0_SCL / I2C0_SDA 59 | PIN_PA04, // PA04 / ADC4 / SWCLK / I2C0_SCL / I2C0_SDA 60 | PIN_PA05, // PA05 / I2C0_SCL / I2C0_SDA 61 | PIN_PA06, // PA06 / SD_D2 / I2C0_SCL / I2C0_SDA 62 | PIN_PA07, // PA07 / SD_D3 / I2S0_RX / I2C0_SCL / I2C0_SDA 63 | PIN_PA08, // PA08 / BOOT0 / SD_CMD / I2S0_WS / I2C0_SCL / I2C0_SDA 64 | PIN_PA09, // PA09 / BOOT1 / SD_CLK / I2S0_SCLK / I2C0_SCL / I2C0_SDA 65 | PIN_PA10, // PA10 / SD_D0 / I2S0_TX / I2C0_SCL / I2C0_SDA 66 | PIN_PA11, // PA11 / SD_D1 / I2C0_SCL / I2C0_SDA 67 | PIN_PA12, // PA12 / I2C0_SCL / I2C0_SDA 68 | PIN_PB03, // PB03 / ADC5 / I2C0_SCL / I2C0_SDA 69 | PIN_PB04, // PB04 / ADC6 / I2C0_SCL / I2C0_SDA 70 | PIN_PB05, // PB05 / ADC7 / I2C0_SCL / I2C0_SDA 71 | PIN_PB06, // PB06 / I2C0_SCL / I2C0_SDA 72 | PIN_PB07, // PB07 / I2C0_SCL / I2C0_SDA 73 | PIN_PB08, // PB08 / UART1_RX / I2C0_SCL / I2C0_SDA 74 | PIN_PB09, // PB09 / UART1_TX / I2C0_SCL / I2C0_SDA 75 | }; 76 | #elif defined(USE_ESP8266) 77 | static const int PIN_MAP[] = { 78 | 0, // GPIO0 79 | 1, // GPIO1 80 | 2, // GPIO2 / SDA 81 | 3, // GPIO3 82 | 4, // GPIO4 83 | 5, // GPIO5 / SCL 84 | 12, // GPIO12 / MISO 85 | 13, // GPIO13 / MOSI 86 | 14, // GPIO14 / SCK 87 | 15, // GPIO15 / SS 88 | 16, // GPIO16 89 | }; 90 | #elif defined(USE_ESP32) 91 | static const int PIN_MAP[] = { 92 | 0, // GPIO0 93 | 1, // GPIO1 94 | 2, // GPIO2 95 | 3, // GPIO3 96 | 4, // GPIO4 97 | 5, // GPIO5 98 | 12, // GPIO12 99 | 13, // GPIO13 100 | 14, // GPIO14 101 | 15, // GPIO15 102 | 16, // GPIO16 103 | 17, // GPIO17 104 | 18, // GPIO18 105 | 19, // GPIO19 / MISO 106 | 21, // GPIO21 / SDA 107 | 22, // GPIO22 / SCL 108 | 23, // GPIO23 / MOSI 109 | 25, // GPIO25 / DAC1 110 | 26, // GPIO26 / DAC2 111 | 27, // GPIO27 112 | 32, // GPIO32 113 | 33, // GPIO33 114 | 34, // GPIO34 115 | 35, // GPIO35 116 | 36, // GPIO36 117 | 39, // GPIO39 118 | }; 119 | #else 120 | #error "Unsupported chip type" 121 | #endif 122 | 123 | void Pinscan::setup() { ESP_LOGCONFIG(TAG, "Setting up Pinscan..."); } 124 | 125 | void Pinscan::dump_config() { ESP_LOGCONFIG(TAG, "Pinscan:"); } 126 | 127 | void Pinscan::set_pin(int pin) { 128 | if (pin != -1) { 129 | pin = PIN_MAP[pin]; 130 | } 131 | if (this->current_pin_ != pin && this->current_pin_ != -1) { 132 | pinMode(this->current_pin_, INPUT); 133 | } 134 | this->current_pin_ = pin; 135 | } 136 | 137 | void Pinscan::set_mode(int mode) { 138 | if (this->current_pin_ != -1) { 139 | std::string modeStr = ""; 140 | switch (mode) { 141 | case 0: 142 | pinMode(this->current_pin_, INPUT); 143 | this->current_state_ = -1; 144 | this->current_mode_ = 1; 145 | modeStr = "INPUT"; 146 | break; 147 | case 1: 148 | pinMode(this->current_pin_, INPUT_PULLUP); 149 | this->current_state_ = -1; 150 | this->current_mode_ = 1; 151 | modeStr = "INPUT_PULLUP"; 152 | break; 153 | case 2: 154 | pinMode(this->current_pin_, OUTPUT); 155 | digitalWrite(this->current_pin_, HIGH); 156 | this->current_state_ = -1; 157 | this->current_mode_ = 0; 158 | modeStr = "OUTPUT_HIGH"; 159 | break; 160 | case 3: 161 | pinMode(this->current_pin_, OUTPUT); 162 | digitalWrite(this->current_pin_, LOW); 163 | this->current_state_ = -1; 164 | this->current_mode_ = 0; 165 | modeStr = "OUTPUT_LOW"; 166 | break; 167 | default: 168 | pinMode(this->current_pin_, INPUT); 169 | modeStr = "OUTPUT_HIGH"; 170 | break; 171 | } 172 | ESP_LOGD(TAG, "Changed pin to %d, mode: %s", this->current_pin_, modeStr.c_str()); 173 | } 174 | } 175 | 176 | void Pinscan::update() { 177 | if (this->current_mode_ == 1 && this->current_pin_ != -1) { 178 | int newState = digitalRead(this->current_pin_); 179 | if (newState != this->current_state_) { 180 | this->current_state_ = newState; 181 | ESP_LOGD(TAG, "Pin changed to %s", (this->current_state_) ? "HIGH" : "LOW"); 182 | if (this->pin_state_sensor_ != nullptr) { 183 | this->pin_state_sensor_->publish_state((this->current_state_) ? "HIGH" : "LOW"); 184 | } 185 | } 186 | } 187 | } 188 | 189 | } // namespace pinscan 190 | } // namespace esphome 191 | --------------------------------------------------------------------------------