mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	| @@ -246,6 +246,7 @@ esphome/components/radon_eye_rd200/* @jeffeb3 | ||||
| esphome/components/rc522/* @glmnet | ||||
| esphome/components/rc522_i2c/* @glmnet | ||||
| esphome/components/rc522_spi/* @glmnet | ||||
| esphome/components/resistance_sampler/* @jesserockz | ||||
| esphome/components/restart/* @esphome/core | ||||
| esphome/components/rf_bridge/* @jesserockz | ||||
| esphome/components/rgbct/* @jesserockz | ||||
|   | ||||
| @@ -1,71 +1,65 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
| from datetime import datetime | ||||
| from typing import Optional | ||||
| from typing import Any | ||||
|  | ||||
| from aioesphomeapi import APIClient, ReconnectLogic, APIConnectionError, LogLevel | ||||
| import zeroconf | ||||
| from aioesphomeapi import APIClient | ||||
| from aioesphomeapi.api_pb2 import SubscribeLogsResponse | ||||
| from aioesphomeapi.log_runner import async_run | ||||
| from zeroconf.asyncio import AsyncZeroconf | ||||
|  | ||||
| from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__ | ||||
| from esphome.core import CORE | ||||
|  | ||||
| from esphome.const import CONF_KEY, CONF_PORT, CONF_PASSWORD, __version__ | ||||
| from esphome.util import safe_print | ||||
| from . import CONF_ENCRYPTION | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| async def async_run_logs(config, address): | ||||
|     """Run the logs command in the event loop.""" | ||||
|     conf = config["api"] | ||||
|     port: int = int(conf[CONF_PORT]) | ||||
|     password: str = conf[CONF_PASSWORD] | ||||
|     noise_psk: Optional[str] = None | ||||
|     noise_psk: str | None = None | ||||
|     if CONF_ENCRYPTION in conf: | ||||
|         noise_psk = conf[CONF_ENCRYPTION][CONF_KEY] | ||||
|     _LOGGER.info("Starting log output from %s using esphome API", address) | ||||
|     aiozc = AsyncZeroconf() | ||||
|  | ||||
|     cli = APIClient( | ||||
|         address, | ||||
|         port, | ||||
|         password, | ||||
|         client_info=f"ESPHome Logs {__version__}", | ||||
|         noise_psk=noise_psk, | ||||
|         zeroconf_instance=aiozc.zeroconf, | ||||
|     ) | ||||
|     first_connect = True | ||||
|     dashboard = CORE.dashboard | ||||
|  | ||||
|     def on_log(msg): | ||||
|         time_ = datetime.now().time().strftime("[%H:%M:%S]") | ||||
|         text = msg.message.decode("utf8", "backslashreplace") | ||||
|         safe_print(time_ + text) | ||||
|  | ||||
|     async def on_connect(): | ||||
|         nonlocal first_connect | ||||
|         try: | ||||
|             await cli.subscribe_logs( | ||||
|                 on_log, | ||||
|                 log_level=LogLevel.LOG_LEVEL_VERY_VERBOSE, | ||||
|                 dump_config=first_connect, | ||||
|             ) | ||||
|             first_connect = False | ||||
|         except APIConnectionError: | ||||
|             cli.disconnect() | ||||
|  | ||||
|     async def on_disconnect(expected_disconnect: bool) -> None: | ||||
|         _LOGGER.warning("Disconnected from API") | ||||
|  | ||||
|     zc = zeroconf.Zeroconf() | ||||
|     reconnect = ReconnectLogic( | ||||
|         client=cli, | ||||
|         on_connect=on_connect, | ||||
|         on_disconnect=on_disconnect, | ||||
|         zeroconf_instance=zc, | ||||
|     ) | ||||
|     await reconnect.start() | ||||
|     def on_log(msg: SubscribeLogsResponse) -> None: | ||||
|         """Handle a new log message.""" | ||||
|         time_ = datetime.now() | ||||
|         message: bytes = msg.message | ||||
|         text = message.decode("utf8", "backslashreplace") | ||||
|         if dashboard: | ||||
|             text = text.replace("\033", "\\033") | ||||
|         print(f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]{text}") | ||||
|  | ||||
|     stop = await async_run(cli, on_log, aio_zeroconf_instance=aiozc) | ||||
|     try: | ||||
|         while True: | ||||
|             await asyncio.sleep(60) | ||||
|     finally: | ||||
|         await aiozc.async_close() | ||||
|         await stop() | ||||
|  | ||||
|  | ||||
| def run_logs(config: dict[str, Any], address: str) -> None: | ||||
|     """Run the logs command.""" | ||||
|     try: | ||||
|         asyncio.run(async_run_logs(config, address)) | ||||
|     except KeyboardInterrupt: | ||||
|         await reconnect.stop() | ||||
|         zc.close() | ||||
|  | ||||
|  | ||||
| def run_logs(config, address): | ||||
|     asyncio.run(async_run_logs(config, address)) | ||||
|         pass | ||||
|   | ||||
| @@ -68,6 +68,7 @@ void LD2420Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "LD2420:"); | ||||
|   ESP_LOGCONFIG(TAG, "  Firmware Version : %7s", this->ld2420_firmware_ver_); | ||||
|   ESP_LOGCONFIG(TAG, "LD2420 Number:"); | ||||
| #ifdef USE_NUMBER | ||||
|   LOG_NUMBER(TAG, "  Gate Timeout:", this->gate_timeout_number_); | ||||
|   LOG_NUMBER(TAG, "  Gate Max Distance:", this->max_gate_distance_number_); | ||||
|   LOG_NUMBER(TAG, "  Gate Min Distance:", this->min_gate_distance_number_); | ||||
| @@ -76,10 +77,13 @@ void LD2420Component::dump_config() { | ||||
|     LOG_NUMBER(TAG, "  Gate Move Threshold:", this->gate_move_threshold_numbers_[gate]); | ||||
|     LOG_NUMBER(TAG, "  Gate Still Threshold::", this->gate_still_threshold_numbers_[gate]); | ||||
|   } | ||||
| #endif | ||||
| #ifdef USE_BUTTON | ||||
|   LOG_BUTTON(TAG, "  Apply Config:", this->apply_config_button_); | ||||
|   LOG_BUTTON(TAG, "  Revert Edits:", this->revert_config_button_); | ||||
|   LOG_BUTTON(TAG, "  Factory Reset:", this->factory_reset_button_); | ||||
|   LOG_BUTTON(TAG, "  Restart Module:", this->restart_module_button_); | ||||
| #endif | ||||
|   ESP_LOGCONFIG(TAG, "LD2420 Select:"); | ||||
|   LOG_SELECT(TAG, "  Operating Mode", this->operating_selector_); | ||||
|   if (this->get_firmware_int_(ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) { | ||||
| @@ -183,9 +187,11 @@ void LD2420Component::factory_reset_action() { | ||||
|     return; | ||||
|   } | ||||
|   this->set_min_max_distances_timeout(FACTORY_MAX_GATE, FACTORY_MIN_GATE, FACTORY_TIMEOUT); | ||||
| #ifdef USE_NUMBER | ||||
|   this->gate_timeout_number_->state = FACTORY_TIMEOUT; | ||||
|   this->min_gate_distance_number_->state = FACTORY_MIN_GATE; | ||||
|   this->max_gate_distance_number_->state = FACTORY_MAX_GATE; | ||||
| #endif | ||||
|   for (uint8_t gate = 0; gate < LD2420_TOTAL_GATES; gate++) { | ||||
|     this->new_config.move_thresh[gate] = FACTORY_MOVE_THRESH[gate]; | ||||
|     this->new_config.still_thresh[gate] = FACTORY_STILL_THRESH[gate]; | ||||
|   | ||||
| @@ -2,7 +2,7 @@ from math import log | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import sensor | ||||
| from esphome.components import sensor, resistance_sampler | ||||
| from esphome.const import ( | ||||
|     CONF_CALIBRATION, | ||||
|     CONF_REFERENCE_RESISTANCE, | ||||
| @@ -15,6 +15,8 @@ from esphome.const import ( | ||||
|     UNIT_CELSIUS, | ||||
| ) | ||||
|  | ||||
| AUTO_LOAD = ["resistance_sampler"] | ||||
|  | ||||
| ntc_ns = cg.esphome_ns.namespace("ntc") | ||||
| NTC = ntc_ns.class_("NTC", cg.Component, sensor.Sensor) | ||||
|  | ||||
| @@ -124,7 +126,7 @@ CONFIG_SCHEMA = ( | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|             cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor), | ||||
|             cv.Required(CONF_SENSOR): cv.use_id(resistance_sampler.ResistanceSampler), | ||||
|             cv.Required(CONF_CALIBRATION): process_calibration, | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/resistance_sampler/resistance_sampler.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/core/component.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace resistance { | ||||
| @@ -11,7 +12,7 @@ enum ResistanceConfiguration { | ||||
|   DOWNSTREAM, | ||||
| }; | ||||
|  | ||||
| class ResistanceSensor : public Component, public sensor::Sensor { | ||||
| class ResistanceSensor : public Component, public sensor::Sensor, resistance_sampler::ResistanceSampler { | ||||
|  public: | ||||
|   void set_sensor(Sensor *sensor) { sensor_ = sensor; } | ||||
|   void set_configuration(ResistanceConfiguration configuration) { configuration_ = configuration; } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor | ||||
| from esphome.components import sensor, resistance_sampler | ||||
| from esphome.const import ( | ||||
|     CONF_SENSOR, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
| @@ -8,8 +8,15 @@ from esphome.const import ( | ||||
|     ICON_FLASH, | ||||
| ) | ||||
|  | ||||
| AUTO_LOAD = ["resistance_sampler"] | ||||
|  | ||||
| resistance_ns = cg.esphome_ns.namespace("resistance") | ||||
| ResistanceSensor = resistance_ns.class_("ResistanceSensor", cg.Component, sensor.Sensor) | ||||
| ResistanceSensor = resistance_ns.class_( | ||||
|     "ResistanceSensor", | ||||
|     cg.Component, | ||||
|     sensor.Sensor, | ||||
|     resistance_sampler.ResistanceSampler, | ||||
| ) | ||||
|  | ||||
| CONF_REFERENCE_VOLTAGE = "reference_voltage" | ||||
| CONF_CONFIGURATION = "configuration" | ||||
|   | ||||
							
								
								
									
										6
									
								
								esphome/components/resistance_sampler/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								esphome/components/resistance_sampler/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
|  | ||||
| resistance_sampler_ns = cg.esphome_ns.namespace("resistance_sampler") | ||||
| ResistanceSampler = resistance_sampler_ns.class_("ResistanceSampler") | ||||
|  | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
							
								
								
									
										10
									
								
								esphome/components/resistance_sampler/resistance_sampler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								esphome/components/resistance_sampler/resistance_sampler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| namespace esphome { | ||||
| namespace resistance_sampler { | ||||
|  | ||||
| /// Abstract interface to mark components that provide resistance values. | ||||
| class ResistanceSampler {}; | ||||
|  | ||||
| }  // namespace resistance_sampler | ||||
| }  // namespace esphome | ||||
| @@ -1,6 +1,6 @@ | ||||
| """Constants used by esphome.""" | ||||
|  | ||||
| __version__ = "2023.11.0b3" | ||||
| __version__ = "2023.11.0b4" | ||||
|  | ||||
| ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" | ||||
| VALID_SUBSTITUTIONS_CHARACTERS = ( | ||||
|   | ||||
| @@ -147,12 +147,13 @@ class DashboardImportDiscovery: | ||||
|  | ||||
|  | ||||
| class EsphomeZeroconf(Zeroconf): | ||||
|     def resolve_host(self, host: str, timeout=3.0): | ||||
|     def resolve_host(self, host: str, timeout: float = 3.0) -> str | None: | ||||
|         """Resolve a host name to an IP address.""" | ||||
|         name = host.partition(".")[0] | ||||
|         info = HostResolver(f"{name}.{ESPHOME_SERVICE_TYPE}", ESPHOME_SERVICE_TYPE) | ||||
|         if (info.load_from_cache(self) or info.request(self, timeout * 1000)) and ( | ||||
|             addresses := info.ip_addresses_by_version(IPVersion.V4Only) | ||||
|         ): | ||||
|         info = HostResolver(ESPHOME_SERVICE_TYPE, f"{name}.{ESPHOME_SERVICE_TYPE}") | ||||
|         if ( | ||||
|             info.load_from_cache(self) | ||||
|             or (timeout and info.request(self, timeout * 1000)) | ||||
|         ) and (addresses := info.ip_addresses_by_version(IPVersion.V4Only)): | ||||
|             return str(addresses[0]) | ||||
|         return None | ||||
|   | ||||
| @@ -10,8 +10,8 @@ platformio==6.1.11  # When updating platformio, also update Dockerfile | ||||
| esptool==4.6.2 | ||||
| click==8.1.7 | ||||
| esphome-dashboard==20231107.0 | ||||
| aioesphomeapi==18.2.7 | ||||
| zeroconf==0.122.3 | ||||
| aioesphomeapi==18.4.0 | ||||
| zeroconf==0.123.0 | ||||
|  | ||||
| # esp-idf requires this, but doesn't bundle it by default | ||||
| # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user