mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 00:18:11 +01:00
Add host target platform (#4783)
Co-authored-by: Otto winter <otto@otto-winter.com>
This commit is contained in:
parent
8c32941428
commit
c835b67bac
24 changed files with 448 additions and 9 deletions
|
@ -109,6 +109,7 @@ esphome/components/heatpumpir/* @rob-deutsch
|
||||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||||
esphome/components/homeassistant/* @OttoWinter
|
esphome/components/homeassistant/* @OttoWinter
|
||||||
esphome/components/honeywellabp/* @RubyBailey
|
esphome/components/honeywellabp/* @RubyBailey
|
||||||
|
esphome/components/host/* @esphome/core
|
||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
||||||
esphome/components/hte501/* @Stock-M
|
esphome/components/hte501/* @Stock-M
|
||||||
esphome/components/hydreon_rgxx/* @functionpointer
|
esphome/components/hydreon_rgxx/* @functionpointer
|
||||||
|
|
|
@ -978,6 +978,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||||
resp.manufacturer = "Espressif";
|
resp.manufacturer = "Espressif";
|
||||||
#elif defined(USE_RP2040)
|
#elif defined(USE_RP2040)
|
||||||
resp.manufacturer = "Raspberry Pi";
|
resp.manufacturer = "Raspberry Pi";
|
||||||
|
#elif defined(USE_HOST)
|
||||||
|
resp.manufacturer = "Host";
|
||||||
#endif
|
#endif
|
||||||
resp.model = ESPHOME_BOARD;
|
resp.model = ESPHOME_BOARD;
|
||||||
#ifdef USE_DEEP_SLEEP
|
#ifdef USE_DEEP_SLEEP
|
||||||
|
|
38
esphome/components/host/__init__.py
Normal file
38
esphome/components/host/__init__.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from esphome.const import (
|
||||||
|
KEY_CORE,
|
||||||
|
KEY_FRAMEWORK_VERSION,
|
||||||
|
KEY_TARGET_FRAMEWORK,
|
||||||
|
KEY_TARGET_PLATFORM,
|
||||||
|
)
|
||||||
|
from esphome.core import CORE
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
from .const import KEY_HOST
|
||||||
|
|
||||||
|
# force import gpio to register pin schema
|
||||||
|
from .gpio import host_pin_to_code # noqa
|
||||||
|
|
||||||
|
|
||||||
|
CODEOWNERS = ["@esphome/core"]
|
||||||
|
AUTO_LOAD = ["network"]
|
||||||
|
|
||||||
|
|
||||||
|
def set_core_data(config):
|
||||||
|
CORE.data[KEY_HOST] = {}
|
||||||
|
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = "host"
|
||||||
|
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "host"
|
||||||
|
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version(1, 0, 0)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
cv.Schema({}),
|
||||||
|
set_core_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
cg.add_build_flag("-DUSE_HOST")
|
||||||
|
cg.add_define("ESPHOME_BOARD", "host")
|
||||||
|
cg.add_platformio_option("platform", "platformio/native")
|
5
esphome/components/host/const.py
Normal file
5
esphome/components/host/const.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
KEY_HOST = "host"
|
||||||
|
|
||||||
|
host_ns = cg.esphome_ns.namespace("host")
|
77
esphome/components/host/core.cpp
Normal file
77
esphome/components/host/core.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "preferences.h"
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
|
||||||
|
void IRAM_ATTR HOT yield() { ::sched_yield(); }
|
||||||
|
uint32_t IRAM_ATTR HOT millis() {
|
||||||
|
struct timespec spec;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||||
|
time_t seconds = spec.tv_sec;
|
||||||
|
uint32_t ms = round(spec.tv_nsec / 1e6);
|
||||||
|
return ((uint32_t) seconds) * 1000U + ms;
|
||||||
|
}
|
||||||
|
void IRAM_ATTR HOT delay(uint32_t ms) {
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = ms / 1000;
|
||||||
|
ts.tv_nsec = (ms % 1000) * 1000000;
|
||||||
|
int res;
|
||||||
|
do {
|
||||||
|
res = nanosleep(&ts, &ts);
|
||||||
|
} while (res != 0 && errno == EINTR);
|
||||||
|
}
|
||||||
|
uint32_t IRAM_ATTR HOT micros() {
|
||||||
|
struct timespec spec;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||||
|
time_t seconds = spec.tv_sec;
|
||||||
|
uint32_t us = round(spec.tv_nsec / 1e3);
|
||||||
|
return ((uint32_t) seconds) * 1000000U + us;
|
||||||
|
}
|
||||||
|
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) {
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = us / 1000000U;
|
||||||
|
ts.tv_nsec = (us % 1000000U) * 1000U;
|
||||||
|
int res;
|
||||||
|
do {
|
||||||
|
res = nanosleep(&ts, &ts);
|
||||||
|
} while (res != 0 && errno == EINTR);
|
||||||
|
}
|
||||||
|
void arch_restart() { exit(0); }
|
||||||
|
void arch_init() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
void IRAM_ATTR HOT arch_feed_wdt() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
|
||||||
|
uint32_t arch_get_cpu_cycle_count() {
|
||||||
|
struct timespec spec;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||||
|
time_t seconds = spec.tv_sec;
|
||||||
|
uint32_t us = spec.tv_nsec;
|
||||||
|
return ((uint32_t) seconds) * 1000000000U + us;
|
||||||
|
}
|
||||||
|
uint32_t arch_get_cpu_freq_hz() { return 1000000000U; }
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void loop();
|
||||||
|
int main() {
|
||||||
|
esphome::host::setup_preferences();
|
||||||
|
setup();
|
||||||
|
while (true) {
|
||||||
|
loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_HOST
|
59
esphome/components/host/gpio.cpp
Normal file
59
esphome/components/host/gpio.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace host {
|
||||||
|
|
||||||
|
static const char *const TAG = "host";
|
||||||
|
|
||||||
|
struct ISRPinArg {
|
||||||
|
uint8_t pin;
|
||||||
|
bool inverted;
|
||||||
|
};
|
||||||
|
|
||||||
|
ISRInternalGPIOPin HostGPIOPin::to_isr() const {
|
||||||
|
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
arg->pin = pin_;
|
||||||
|
arg->inverted = inverted_;
|
||||||
|
return ISRInternalGPIOPin((void *) arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
|
||||||
|
ESP_LOGD(TAG, "Attaching interrupt %p to pin %d and mode %d", func, pin_, (uint32_t) type);
|
||||||
|
}
|
||||||
|
void HostGPIOPin::pin_mode(gpio::Flags flags) { ESP_LOGD(TAG, "Setting pin %d mode to %02X", pin_, (uint32_t) flags); }
|
||||||
|
|
||||||
|
std::string HostGPIOPin::dump_summary() const {
|
||||||
|
char buffer[32];
|
||||||
|
snprintf(buffer, sizeof(buffer), "GPIO%u", pin_);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostGPIOPin::digital_read() { return inverted_; }
|
||||||
|
void HostGPIOPin::digital_write(bool value) {
|
||||||
|
// pass
|
||||||
|
ESP_LOGD(TAG, "Setting pin %d to %s", pin_, value != inverted_ ? "HIGH" : "LOW");
|
||||||
|
}
|
||||||
|
void HostGPIOPin::detach_interrupt() const {}
|
||||||
|
|
||||||
|
} // namespace host
|
||||||
|
|
||||||
|
using namespace host;
|
||||||
|
|
||||||
|
bool IRAM_ATTR ISRInternalGPIOPin::digital_read() {
|
||||||
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
|
return arg->inverted;
|
||||||
|
}
|
||||||
|
void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
||||||
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
|
ESP_LOGD(TAG, "Clearing interrupt for pin %d", arg->pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_HOST
|
37
esphome/components/host/gpio.h
Normal file
37
esphome/components/host/gpio.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace host {
|
||||||
|
|
||||||
|
class HostGPIOPin : public InternalGPIOPin {
|
||||||
|
public:
|
||||||
|
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||||
|
void set_inverted(bool inverted) { inverted_ = inverted; }
|
||||||
|
void set_flags(gpio::Flags flags) { flags_ = flags; }
|
||||||
|
|
||||||
|
void setup() override { pin_mode(flags_); }
|
||||||
|
void pin_mode(gpio::Flags flags) override;
|
||||||
|
bool digital_read() override;
|
||||||
|
void digital_write(bool value) override;
|
||||||
|
std::string dump_summary() const override;
|
||||||
|
void detach_interrupt() const override;
|
||||||
|
ISRInternalGPIOPin to_isr() const override;
|
||||||
|
uint8_t get_pin() const override { return pin_; }
|
||||||
|
bool is_inverted() const override { return inverted_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
|
||||||
|
|
||||||
|
uint8_t pin_;
|
||||||
|
bool inverted_;
|
||||||
|
gpio::Flags flags_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace host
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_HOST
|
73
esphome/components/host/gpio.py
Normal file
73
esphome/components/host/gpio.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_INPUT,
|
||||||
|
CONF_INVERTED,
|
||||||
|
CONF_MODE,
|
||||||
|
CONF_NUMBER,
|
||||||
|
CONF_OPEN_DRAIN,
|
||||||
|
CONF_OUTPUT,
|
||||||
|
CONF_PULLDOWN,
|
||||||
|
CONF_PULLUP,
|
||||||
|
)
|
||||||
|
from esphome import pins
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
from .const import host_ns
|
||||||
|
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
HostGPIOPin = host_ns.class_("HostGPIOPin", cg.InternalGPIOPin)
|
||||||
|
|
||||||
|
|
||||||
|
def _translate_pin(value):
|
||||||
|
if isinstance(value, dict) or value is None:
|
||||||
|
raise cv.Invalid(
|
||||||
|
"This variable only supports pin numbers, not full pin schemas "
|
||||||
|
"(with inverted and mode)."
|
||||||
|
)
|
||||||
|
if isinstance(value, int):
|
||||||
|
return value
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if value.startswith("GPIO"):
|
||||||
|
return cv.int_(value[len("GPIO") :].strip())
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_gpio_pin(value):
|
||||||
|
return _translate_pin(value)
|
||||||
|
|
||||||
|
|
||||||
|
HOST_PIN_SCHEMA = cv.All(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(HostGPIOPin),
|
||||||
|
cv.Required(CONF_NUMBER): validate_gpio_pin,
|
||||||
|
cv.Optional(CONF_MODE, default={}): cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_INPUT, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_OUTPUT, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_OPEN_DRAIN, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_PULLUP, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_PULLDOWN, default=False): cv.boolean,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pins.PIN_SCHEMA_REGISTRY.register("host", HOST_PIN_SCHEMA)
|
||||||
|
async def host_pin_to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
num = config[CONF_NUMBER]
|
||||||
|
cg.add(var.set_pin(num))
|
||||||
|
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||||
|
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||||
|
return var
|
36
esphome/components/host/preferences.cpp
Normal file
36
esphome/components/host/preferences.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "preferences.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include "esphome/core/preferences.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace host {
|
||||||
|
|
||||||
|
static const char *const TAG = "host.preferences";
|
||||||
|
|
||||||
|
class HostPreferences : public ESPPreferences {
|
||||||
|
public:
|
||||||
|
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { return {}; }
|
||||||
|
|
||||||
|
ESPPreferenceObject make_preference(size_t length, uint32_t type) override { return {}; }
|
||||||
|
|
||||||
|
bool sync() override { return true; }
|
||||||
|
bool reset() override { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup_preferences() {
|
||||||
|
auto *pref = new HostPreferences(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
global_preferences = pref;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace host
|
||||||
|
|
||||||
|
ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_HOST
|
13
esphome/components/host/preferences.h
Normal file
13
esphome/components/host/preferences.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace host {
|
||||||
|
|
||||||
|
void setup_preferences();
|
||||||
|
|
||||||
|
} // namespace host
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // USE_HOST
|
|
@ -17,6 +17,9 @@ from esphome.const import (
|
||||||
CONF_TAG,
|
CONF_TAG,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_TX_BUFFER_SIZE,
|
CONF_TX_BUFFER_SIZE,
|
||||||
|
PLATFORM_ESP32,
|
||||||
|
PLATFORM_ESP8266,
|
||||||
|
PLATFORM_RP2040,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority
|
from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority
|
||||||
from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant
|
from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant
|
||||||
|
@ -141,7 +144,10 @@ CONFIG_SCHEMA = cv.All(
|
||||||
esp8266=UART0,
|
esp8266=UART0,
|
||||||
esp32=UART0,
|
esp32=UART0,
|
||||||
rp2040=USB_CDC,
|
rp2040=USB_CDC,
|
||||||
): uart_selection,
|
): cv.All(
|
||||||
|
cv.only_on([PLATFORM_ESP8266, PLATFORM_ESP32, PLATFORM_RP2040]),
|
||||||
|
uart_selection,
|
||||||
|
),
|
||||||
cv.Optional(CONF_LEVEL, default="DEBUG"): is_log_level,
|
cv.Optional(CONF_LEVEL, default="DEBUG"): is_log_level,
|
||||||
cv.Optional(CONF_LOGS, default={}): cv.Schema(
|
cv.Optional(CONF_LOGS, default={}): cv.Schema(
|
||||||
{
|
{
|
||||||
|
|
|
@ -145,6 +145,9 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) {
|
||||||
if (xPortGetFreeHeapSize() < 2048)
|
if (xPortGetFreeHeapSize() < 2048)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_HOST
|
||||||
|
puts(msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
this->log_callback_.call(level, tag, msg);
|
this->log_callback_.call(level, tag, msg);
|
||||||
}
|
}
|
||||||
|
@ -262,7 +265,11 @@ void Logger::set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }
|
||||||
void Logger::set_log_level(const std::string &tag, int log_level) {
|
void Logger::set_log_level(const std::string &tag, int log_level) {
|
||||||
this->log_levels_.push_back(LogLevelOverride{tag, log_level});
|
this->log_levels_.push_back(LogLevelOverride{tag, log_level});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||||
UARTSelection Logger::get_uart() const { return this->uart_; }
|
UARTSelection Logger::get_uart() const { return this->uart_; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void Logger::add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback) {
|
void Logger::add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback) {
|
||||||
this->log_callback_.add(std::move(callback));
|
this->log_callback_.add(std::move(callback));
|
||||||
}
|
}
|
||||||
|
@ -294,7 +301,10 @@ void Logger::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "Logger:");
|
ESP_LOGCONFIG(TAG, "Logger:");
|
||||||
ESP_LOGCONFIG(TAG, " Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]);
|
ESP_LOGCONFIG(TAG, " Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]);
|
||||||
ESP_LOGCONFIG(TAG, " Log Baud Rate: %" PRIu32, this->baud_rate_);
|
ESP_LOGCONFIG(TAG, " Log Baud Rate: %" PRIu32, this->baud_rate_);
|
||||||
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||||
ESP_LOGCONFIG(TAG, " Hardware UART: %s", UART_SELECTIONS[this->uart_]);
|
ESP_LOGCONFIG(TAG, " Hardware UART: %s", UART_SELECTIONS[this->uart_]);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (auto &it : this->log_levels_) {
|
for (auto &it : this->log_levels_) {
|
||||||
ESP_LOGCONFIG(TAG, " Level for '%s': %s", it.tag.c_str(), LOG_LEVELS[it.level]);
|
ESP_LOGCONFIG(TAG, " Level for '%s': %s", it.tag.c_str(), LOG_LEVELS[it.level]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace esphome {
|
||||||
|
|
||||||
namespace logger {
|
namespace logger {
|
||||||
|
|
||||||
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||||
/** Enum for logging UART selection
|
/** Enum for logging UART selection
|
||||||
*
|
*
|
||||||
* Advanced configuration (pin selection, etc) is not supported.
|
* Advanced configuration (pin selection, etc) is not supported.
|
||||||
|
@ -52,6 +53,7 @@ enum UARTSelection {
|
||||||
UART_SELECTION_USB_CDC,
|
UART_SELECTION_USB_CDC,
|
||||||
#endif // USE_RP2040
|
#endif // USE_RP2040
|
||||||
};
|
};
|
||||||
|
#endif // USE_ESP32 || USE_ESP8266
|
||||||
|
|
||||||
class Logger : public Component {
|
class Logger : public Component {
|
||||||
public:
|
public:
|
||||||
|
@ -66,10 +68,11 @@ class Logger : public Component {
|
||||||
#ifdef USE_ESP_IDF
|
#ifdef USE_ESP_IDF
|
||||||
uart_port_t get_uart_num() const { return uart_num_; }
|
uart_port_t get_uart_num() const { return uart_num_; }
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||||
void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
|
void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
|
||||||
/// Get the UART used by the logger.
|
/// Get the UART used by the logger.
|
||||||
UARTSelection get_uart() const;
|
UARTSelection get_uart() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Set the log level of the specified tag.
|
/// Set the log level of the specified tag.
|
||||||
void set_log_level(const std::string &tag, int log_level);
|
void set_log_level(const std::string &tag, int log_level);
|
||||||
|
@ -139,7 +142,9 @@ class Logger : public Component {
|
||||||
char *tx_buffer_{nullptr};
|
char *tx_buffer_{nullptr};
|
||||||
int tx_buffer_at_{0};
|
int tx_buffer_at_{0};
|
||||||
int tx_buffer_size_{0};
|
int tx_buffer_size_{0};
|
||||||
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||||
UARTSelection uart_{UART_SELECTION_UART0};
|
UARTSelection uart_{UART_SELECTION_UART0};
|
||||||
|
#endif
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
Stream *hw_serial_{nullptr};
|
Stream *hw_serial_{nullptr};
|
||||||
#endif
|
#endif
|
||||||
|
|
18
esphome/components/mdns/mdns_host.cpp
Normal file
18
esphome/components/mdns/mdns_host.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifdef USE_HOST
|
||||||
|
|
||||||
|
#include "esphome/components/network/ip_address.h"
|
||||||
|
#include "esphome/components/network/util.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "mdns_component.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mdns {
|
||||||
|
|
||||||
|
void MDNSComponent::setup() { this->compile_records_(); }
|
||||||
|
|
||||||
|
void MDNSComponent::on_shutdown() {}
|
||||||
|
|
||||||
|
} // namespace mdns
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,6 +23,9 @@ bool is_connected() {
|
||||||
return wifi::global_wifi_component->is_connected();
|
return wifi::global_wifi_component->is_connected();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_HOST
|
||||||
|
return true; // Assume its connected
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
esp8266=IMPLEMENTATION_LWIP_TCP,
|
esp8266=IMPLEMENTATION_LWIP_TCP,
|
||||||
esp32=IMPLEMENTATION_BSD_SOCKETS,
|
esp32=IMPLEMENTATION_BSD_SOCKETS,
|
||||||
rp2040=IMPLEMENTATION_LWIP_TCP,
|
rp2040=IMPLEMENTATION_LWIP_TCP,
|
||||||
|
host=IMPLEMENTATION_BSD_SOCKETS,
|
||||||
): cv.one_of(
|
): cv.one_of(
|
||||||
IMPLEMENTATION_LWIP_TCP, IMPLEMENTATION_BSD_SOCKETS, lower=True, space="_"
|
IMPLEMENTATION_LWIP_TCP, IMPLEMENTATION_BSD_SOCKETS, lower=True, space="_"
|
||||||
),
|
),
|
||||||
|
|
|
@ -130,6 +130,13 @@ struct iovec {
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef USE_HOST
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#endif // USE_HOST
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
// arduino-esp32 declares a global var called INADDR_NONE which is replaced
|
// arduino-esp32 declares a global var called INADDR_NONE which is replaced
|
||||||
// by the define
|
// by the define
|
||||||
|
|
|
@ -1455,6 +1455,7 @@ class SplitDefault(Optional):
|
||||||
esp32_arduino=vol.UNDEFINED,
|
esp32_arduino=vol.UNDEFINED,
|
||||||
esp32_idf=vol.UNDEFINED,
|
esp32_idf=vol.UNDEFINED,
|
||||||
rp2040=vol.UNDEFINED,
|
rp2040=vol.UNDEFINED,
|
||||||
|
host=vol.UNDEFINED,
|
||||||
):
|
):
|
||||||
super().__init__(key)
|
super().__init__(key)
|
||||||
self._esp8266_default = vol.default_factory(esp8266)
|
self._esp8266_default = vol.default_factory(esp8266)
|
||||||
|
@ -1465,6 +1466,7 @@ class SplitDefault(Optional):
|
||||||
esp32_idf if esp32 is vol.UNDEFINED else esp32
|
esp32_idf if esp32 is vol.UNDEFINED else esp32
|
||||||
)
|
)
|
||||||
self._rp2040_default = vol.default_factory(rp2040)
|
self._rp2040_default = vol.default_factory(rp2040)
|
||||||
|
self._host_default = vol.default_factory(host)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default(self):
|
def default(self):
|
||||||
|
@ -1476,6 +1478,8 @@ class SplitDefault(Optional):
|
||||||
return self._esp32_idf_default
|
return self._esp32_idf_default
|
||||||
if CORE.is_rp2040:
|
if CORE.is_rp2040:
|
||||||
return self._rp2040_default
|
return self._rp2040_default
|
||||||
|
if CORE.is_host:
|
||||||
|
return self._host_default
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@default.setter
|
@default.setter
|
||||||
|
|
|
@ -7,8 +7,9 @@ ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
PLATFORM_ESP32 = "esp32"
|
PLATFORM_ESP32 = "esp32"
|
||||||
PLATFORM_ESP8266 = "esp8266"
|
PLATFORM_ESP8266 = "esp8266"
|
||||||
PLATFORM_RP2040 = "rp2040"
|
PLATFORM_RP2040 = "rp2040"
|
||||||
|
PLATFORM_HOST = "host"
|
||||||
|
|
||||||
TARGET_PLATFORMS = [PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]
|
TARGET_PLATFORMS = [PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_HOST]
|
||||||
|
|
||||||
SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"}
|
SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"}
|
||||||
HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"}
|
HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"}
|
||||||
|
|
|
@ -602,6 +602,10 @@ class EsphomeCore:
|
||||||
def is_rp2040(self):
|
def is_rp2040(self):
|
||||||
return self.target_platform == "rp2040"
|
return self.target_platform == "rp2040"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_host(self):
|
||||||
|
return self.target_platform == "host"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_framework(self):
|
def target_framework(self):
|
||||||
return self.data[KEY_CORE][KEY_TARGET_FRAMEWORK]
|
return self.data[KEY_CORE][KEY_TARGET_FRAMEWORK]
|
||||||
|
|
|
@ -102,6 +102,10 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_HOST
|
||||||
|
#define USE_SOCKET_IMPL_BSD_SOCKETS
|
||||||
|
#endif
|
||||||
|
|
||||||
// Disabled feature flags
|
// Disabled feature flags
|
||||||
//#define USE_BSEC // Requires a library with proprietary license.
|
//#define USE_BSEC // Requires a library with proprietary license.
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#if defined(USE_ESP8266)
|
#if defined(USE_ESP8266)
|
||||||
#include <osapi.h>
|
#include <osapi.h>
|
||||||
|
@ -18,17 +19,20 @@
|
||||||
#elif defined(USE_ESP32_FRAMEWORK_ARDUINO)
|
#elif defined(USE_ESP32_FRAMEWORK_ARDUINO)
|
||||||
#include <Esp.h>
|
#include <Esp.h>
|
||||||
#elif defined(USE_ESP_IDF)
|
#elif defined(USE_ESP_IDF)
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/portmacro.h>
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
#include "esp_random.h"
|
#include "esp_random.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/portmacro.h>
|
|
||||||
#elif defined(USE_RP2040)
|
#elif defined(USE_RP2040)
|
||||||
#if defined(USE_WIFI)
|
#if defined(USE_WIFI)
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#endif
|
#endif
|
||||||
#include <hardware/structs/rosc.h>
|
#include <hardware/structs/rosc.h>
|
||||||
#include <hardware/sync.h>
|
#include <hardware/sync.h>
|
||||||
|
#elif defined(USE_HOST)
|
||||||
|
#include <limits>
|
||||||
|
#include <random>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC
|
#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC
|
||||||
|
@ -38,6 +42,8 @@
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
|
static const char *const TAG = "helpers";
|
||||||
|
|
||||||
// STL backports
|
// STL backports
|
||||||
|
|
||||||
#if _GLIBCXX_RELEASE < 7
|
#if _GLIBCXX_RELEASE < 7
|
||||||
|
@ -106,6 +112,11 @@ uint32_t random_uint32() {
|
||||||
result |= rosc_hw->randombit;
|
result |= rosc_hw->randombit;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
#elif defined(USE_HOST)
|
||||||
|
std::random_device dev;
|
||||||
|
std::mt19937 rng(dev());
|
||||||
|
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
|
||||||
|
return dist(rng);
|
||||||
#else
|
#else
|
||||||
#error "No random source available for this configuration."
|
#error "No random source available for this configuration."
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,6 +138,19 @@ bool random_bytes(uint8_t *data, size_t len) {
|
||||||
*data++ = result;
|
*data++ = result;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(USE_HOST)
|
||||||
|
FILE *fp = fopen("/dev/urandom", "r");
|
||||||
|
if (fp == nullptr) {
|
||||||
|
ESP_LOGW(TAG, "Could not open /dev/urandom, errno=%d", errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
size_t read = fread(data, 1, len, fp);
|
||||||
|
if (read != len) {
|
||||||
|
ESP_LOGW(TAG, "Not enough data from /dev/urandom");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
#error "No random source available for this configuration."
|
#error "No random source available for this configuration."
|
||||||
#endif
|
#endif
|
||||||
|
@ -145,7 +169,7 @@ std::string str_truncate(const std::string &str, size_t length) {
|
||||||
return str.length() > length ? str.substr(0, length) : str;
|
return str.length() > length ? str.substr(0, length) : str;
|
||||||
}
|
}
|
||||||
std::string str_until(const char *str, char ch) {
|
std::string str_until(const char *str, char ch) {
|
||||||
char *pos = strchr(str, ch);
|
const char *pos = strchr(str, ch);
|
||||||
return pos == nullptr ? std::string(str) : std::string(str, pos - str);
|
return pos == nullptr ? std::string(str) : std::string(str, pos - str);
|
||||||
}
|
}
|
||||||
std::string str_until(const std::string &str, char ch) { return str.substr(0, str.find(ch)); }
|
std::string str_until(const std::string &str, char ch) { return str.substr(0, str.find(ch)); }
|
||||||
|
@ -395,7 +419,7 @@ void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green
|
||||||
}
|
}
|
||||||
|
|
||||||
// System APIs
|
// System APIs
|
||||||
#if defined(USE_ESP8266) || defined(USE_RP2040)
|
#if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_HOST)
|
||||||
// ESP8266 doesn't have mutexes, but that shouldn't be an issue as it's single-core and non-preemptive OS.
|
// ESP8266 doesn't have mutexes, but that shouldn't be an issue as it's single-core and non-preemptive OS.
|
||||||
Mutex::Mutex() {}
|
Mutex::Mutex() {}
|
||||||
void Mutex::lock() {}
|
void Mutex::lock() {}
|
||||||
|
@ -469,6 +493,7 @@ void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); }
|
||||||
|
|
||||||
void delay_microseconds_safe(uint32_t us) { // avoids CPU locks that could trigger WDT or affect WiFi/BT stability
|
void delay_microseconds_safe(uint32_t us) { // avoids CPU locks that could trigger WDT or affect WiFi/BT stability
|
||||||
uint32_t start = micros();
|
uint32_t start = micros();
|
||||||
|
|
||||||
const uint32_t lag = 5000; // microseconds, specifies the maximum time for a CPU busy-loop.
|
const uint32_t lag = 5000; // microseconds, specifies the maximum time for a CPU busy-loop.
|
||||||
// it must be larger than the worst-case duration of a delay(1) call (hardware tasks)
|
// it must be larger than the worst-case duration of a delay(1) call (hardware tasks)
|
||||||
// 5ms is conservative, it could be reduced when exact BT/WiFi stack delays are known
|
// 5ms is conservative, it could be reduced when exact BT/WiFi stack delays are known
|
||||||
|
|
|
@ -251,3 +251,12 @@ board = rpipico
|
||||||
build_flags =
|
build_flags =
|
||||||
${common:rp2040-arduino.build_flags}
|
${common:rp2040-arduino.build_flags}
|
||||||
${flags:runtime.build_flags}
|
${flags:runtime.build_flags}
|
||||||
|
|
||||||
|
[env:host]
|
||||||
|
extends = common
|
||||||
|
platform = platformio/native
|
||||||
|
lib_deps =
|
||||||
|
esphome/noise-c@0.1.1 ; used by api
|
||||||
|
build_flags =
|
||||||
|
${common.build_flags}
|
||||||
|
-DUSE_HOST
|
||||||
|
|
|
@ -535,6 +535,7 @@ def lint_relative_py_import(fname):
|
||||||
"esphome/components/esp32/core.cpp",
|
"esphome/components/esp32/core.cpp",
|
||||||
"esphome/components/esp8266/core.cpp",
|
"esphome/components/esp8266/core.cpp",
|
||||||
"esphome/components/rp2040/core.cpp",
|
"esphome/components/rp2040/core.cpp",
|
||||||
|
"esphome/components/host/core.cpp",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def lint_namespace(fname, content):
|
def lint_namespace(fname, content):
|
||||||
|
|
Loading…
Reference in a new issue