mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'dev' into bump-1.21.0b1
This commit is contained in:
		| @@ -11,6 +11,7 @@ from esphome.config import iter_components, read_config, strip_default_ids | ||||
| from esphome.const import ( | ||||
|     CONF_BAUD_RATE, | ||||
|     CONF_BROKER, | ||||
|     CONF_DEASSERT_RTS_DTR, | ||||
|     CONF_LOGGER, | ||||
|     CONF_OTA, | ||||
|     CONF_PASSWORD, | ||||
| @@ -99,10 +100,21 @@ def run_miniterm(config, port): | ||||
|     baud_rate = config["logger"][CONF_BAUD_RATE] | ||||
|     if baud_rate == 0: | ||||
|         _LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.") | ||||
|         return | ||||
|     _LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate) | ||||
|  | ||||
|     backtrace_state = False | ||||
|     with serial.Serial(port, baudrate=baud_rate) as ser: | ||||
|     ser = serial.Serial() | ||||
|     ser.baudrate = baud_rate | ||||
|     ser.port = port | ||||
|  | ||||
|     # We can't set to False by default since it leads to toggling and hence | ||||
|     # ESP32 resets on some platforms. | ||||
|     if config["logger"][CONF_DEASSERT_RTS_DTR]: | ||||
|         ser.dtr = False | ||||
|         ser.rts = False | ||||
|  | ||||
|     with ser: | ||||
|         while True: | ||||
|             try: | ||||
|                 raw = ser.readline() | ||||
| @@ -284,7 +296,6 @@ def command_vscode(args): | ||||
|  | ||||
|     logging.disable(logging.INFO) | ||||
|     logging.disable(logging.WARNING) | ||||
|     CORE.config_path = args.configuration | ||||
|     vscode.read_config(args) | ||||
|  | ||||
|  | ||||
| @@ -394,7 +405,7 @@ def command_update_all(args): | ||||
|     import click | ||||
|  | ||||
|     success = {} | ||||
|     files = list_yaml_files(args.configuration[0]) | ||||
|     files = list_yaml_files(args.configuration) | ||||
|     twidth = 60 | ||||
|  | ||||
|     def print_bar(middle_text): | ||||
| @@ -408,7 +419,7 @@ def command_update_all(args): | ||||
|         print("-" * twidth) | ||||
|         print() | ||||
|         rc = run_external_process( | ||||
|             "esphome", "--dashboard", "run", "--no-logs", "--device", "OTA", f | ||||
|             "esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA" | ||||
|         ) | ||||
|         if rc == 0: | ||||
|             print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f)) | ||||
| @@ -505,6 +516,7 @@ def parse_args(argv): | ||||
|             "clean", | ||||
|             "dashboard", | ||||
|             "vscode", | ||||
|             "update-all", | ||||
|         ], | ||||
|     ) | ||||
|  | ||||
| @@ -681,14 +693,12 @@ def parse_args(argv): | ||||
|     ) | ||||
|  | ||||
|     parser_vscode = subparsers.add_parser("vscode") | ||||
|     parser_vscode.add_argument( | ||||
|         "configuration", help="Your YAML configuration file.", nargs=1 | ||||
|     ) | ||||
|     parser_vscode.add_argument("configuration", help="Your YAML configuration file.") | ||||
|     parser_vscode.add_argument("--ace", action="store_true") | ||||
|  | ||||
|     parser_update = subparsers.add_parser("update-all") | ||||
|     parser_update.add_argument( | ||||
|         "configuration", help="Your YAML configuration file directory.", nargs=1 | ||||
|         "configuration", help="Your YAML configuration file directories.", nargs="+" | ||||
|     ) | ||||
|  | ||||
|     return parser.parse_args(argv[1:]) | ||||
|   | ||||
							
								
								
									
										875
									
								
								esphome/boards.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										875
									
								
								esphome/boards.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,875 @@ | ||||
| ESP8266_BASE_PINS = { | ||||
|     "A0": 17, | ||||
|     "SS": 15, | ||||
|     "MOSI": 13, | ||||
|     "MISO": 12, | ||||
|     "SCK": 14, | ||||
|     "SDA": 4, | ||||
|     "SCL": 5, | ||||
|     "RX": 3, | ||||
|     "TX": 1, | ||||
| } | ||||
|  | ||||
| ESP8266_BOARD_PINS = { | ||||
|     "d1": { | ||||
|         "D0": 3, | ||||
|         "D1": 1, | ||||
|         "D2": 16, | ||||
|         "D3": 5, | ||||
|         "D4": 4, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 0, | ||||
|         "D9": 2, | ||||
|         "D10": 15, | ||||
|         "D11": 13, | ||||
|         "D12": 14, | ||||
|         "D13": 14, | ||||
|         "D14": 4, | ||||
|         "D15": 5, | ||||
|         "LED": 2, | ||||
|     }, | ||||
|     "d1_mini": { | ||||
|         "D0": 16, | ||||
|         "D1": 5, | ||||
|         "D2": 4, | ||||
|         "D3": 0, | ||||
|         "D4": 2, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 15, | ||||
|         "LED": 2, | ||||
|     }, | ||||
|     "d1_mini_lite": "d1_mini", | ||||
|     "d1_mini_pro": "d1_mini", | ||||
|     "esp01": {}, | ||||
|     "esp01_1m": {}, | ||||
|     "esp07": {}, | ||||
|     "esp12e": {}, | ||||
|     "esp210": {}, | ||||
|     "esp8285": {}, | ||||
|     "esp_wroom_02": {}, | ||||
|     "espduino": {"LED": 16}, | ||||
|     "espectro": {"LED": 15, "BUTTON": 2}, | ||||
|     "espino": {"LED": 2, "LED_RED": 2, "LED_GREEN": 4, "LED_BLUE": 5, "BUTTON": 0}, | ||||
|     "espinotee": {"LED": 16}, | ||||
|     "espresso_lite_v1": {"LED": 16}, | ||||
|     "espresso_lite_v2": {"LED": 2}, | ||||
|     "gen4iod": {}, | ||||
|     "heltec_wifi_kit_8": "d1_mini", | ||||
|     "huzzah": { | ||||
|         "LED": 0, | ||||
|         "LED_RED": 0, | ||||
|         "LED_BLUE": 2, | ||||
|         "D4": 4, | ||||
|         "D5": 5, | ||||
|         "D12": 12, | ||||
|         "D13": 13, | ||||
|         "D14": 14, | ||||
|         "D15": 15, | ||||
|         "D16": 16, | ||||
|     }, | ||||
|     "inventone": {}, | ||||
|     "modwifi": {}, | ||||
|     "nodemcu": { | ||||
|         "D0": 16, | ||||
|         "D1": 5, | ||||
|         "D2": 4, | ||||
|         "D3": 0, | ||||
|         "D4": 2, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 15, | ||||
|         "D9": 3, | ||||
|         "D10": 1, | ||||
|         "LED": 16, | ||||
|     }, | ||||
|     "nodemcuv2": "nodemcu", | ||||
|     "oak": { | ||||
|         "P0": 2, | ||||
|         "P1": 5, | ||||
|         "P2": 0, | ||||
|         "P3": 3, | ||||
|         "P4": 1, | ||||
|         "P5": 4, | ||||
|         "P6": 15, | ||||
|         "P7": 13, | ||||
|         "P8": 12, | ||||
|         "P9": 14, | ||||
|         "P10": 16, | ||||
|         "P11": 17, | ||||
|         "LED": 5, | ||||
|     }, | ||||
|     "phoenix_v1": {"LED": 16}, | ||||
|     "phoenix_v2": {"LED": 2}, | ||||
|     "sparkfunBlynk": "thing", | ||||
|     "thing": {"LED": 5, "SDA": 2, "SCL": 14}, | ||||
|     "thingdev": "thing", | ||||
|     "wifi_slot": {"LED": 2}, | ||||
|     "wifiduino": { | ||||
|         "D0": 3, | ||||
|         "D1": 1, | ||||
|         "D2": 2, | ||||
|         "D3": 0, | ||||
|         "D4": 4, | ||||
|         "D5": 5, | ||||
|         "D6": 16, | ||||
|         "D7": 14, | ||||
|         "D8": 12, | ||||
|         "D9": 13, | ||||
|         "D10": 15, | ||||
|         "D11": 13, | ||||
|         "D12": 12, | ||||
|         "D13": 14, | ||||
|     }, | ||||
|     "wifinfo": { | ||||
|         "LED": 12, | ||||
|         "D0": 16, | ||||
|         "D1": 5, | ||||
|         "D2": 4, | ||||
|         "D3": 0, | ||||
|         "D4": 2, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 15, | ||||
|         "D9": 3, | ||||
|         "D10": 1, | ||||
|     }, | ||||
|     "wio_link": {"LED": 2, "GROVE": 15, "D0": 14, "D1": 12, "D2": 13, "BUTTON": 0}, | ||||
|     "wio_node": {"LED": 2, "GROVE": 15, "D0": 3, "D1": 5, "BUTTON": 0}, | ||||
|     "xinabox_cw01": {"SDA": 2, "SCL": 14, "LED": 5, "LED_RED": 12, "LED_GREEN": 13}, | ||||
| } | ||||
|  | ||||
| FLASH_SIZE_1_MB = 2 ** 20 | ||||
| FLASH_SIZE_512_KB = FLASH_SIZE_1_MB // 2 | ||||
| FLASH_SIZE_2_MB = 2 * FLASH_SIZE_1_MB | ||||
| FLASH_SIZE_4_MB = 4 * FLASH_SIZE_1_MB | ||||
| FLASH_SIZE_16_MB = 16 * FLASH_SIZE_1_MB | ||||
|  | ||||
| ESP8266_FLASH_SIZES = { | ||||
|     "d1": FLASH_SIZE_4_MB, | ||||
|     "d1_mini": FLASH_SIZE_4_MB, | ||||
|     "d1_mini_lite": FLASH_SIZE_1_MB, | ||||
|     "d1_mini_pro": FLASH_SIZE_16_MB, | ||||
|     "esp01": FLASH_SIZE_512_KB, | ||||
|     "esp01_1m": FLASH_SIZE_1_MB, | ||||
|     "esp07": FLASH_SIZE_4_MB, | ||||
|     "esp12e": FLASH_SIZE_4_MB, | ||||
|     "esp210": FLASH_SIZE_4_MB, | ||||
|     "esp8285": FLASH_SIZE_1_MB, | ||||
|     "esp_wroom_02": FLASH_SIZE_2_MB, | ||||
|     "espduino": FLASH_SIZE_4_MB, | ||||
|     "espectro": FLASH_SIZE_4_MB, | ||||
|     "espino": FLASH_SIZE_4_MB, | ||||
|     "espinotee": FLASH_SIZE_4_MB, | ||||
|     "espresso_lite_v1": FLASH_SIZE_4_MB, | ||||
|     "espresso_lite_v2": FLASH_SIZE_4_MB, | ||||
|     "gen4iod": FLASH_SIZE_512_KB, | ||||
|     "heltec_wifi_kit_8": FLASH_SIZE_4_MB, | ||||
|     "huzzah": FLASH_SIZE_4_MB, | ||||
|     "inventone": FLASH_SIZE_4_MB, | ||||
|     "modwifi": FLASH_SIZE_2_MB, | ||||
|     "nodemcu": FLASH_SIZE_4_MB, | ||||
|     "nodemcuv2": FLASH_SIZE_4_MB, | ||||
|     "oak": FLASH_SIZE_4_MB, | ||||
|     "phoenix_v1": FLASH_SIZE_4_MB, | ||||
|     "phoenix_v2": FLASH_SIZE_4_MB, | ||||
|     "sparkfunBlynk": FLASH_SIZE_4_MB, | ||||
|     "thing": FLASH_SIZE_512_KB, | ||||
|     "thingdev": FLASH_SIZE_512_KB, | ||||
|     "wifi_slot": FLASH_SIZE_1_MB, | ||||
|     "wifiduino": FLASH_SIZE_4_MB, | ||||
|     "wifinfo": FLASH_SIZE_1_MB, | ||||
|     "wio_link": FLASH_SIZE_4_MB, | ||||
|     "wio_node": FLASH_SIZE_4_MB, | ||||
|     "xinabox_cw01": FLASH_SIZE_4_MB, | ||||
| } | ||||
|  | ||||
| ESP8266_LD_SCRIPTS = { | ||||
|     FLASH_SIZE_512_KB: ("eagle.flash.512k0.ld", "eagle.flash.512k.ld"), | ||||
|     FLASH_SIZE_1_MB: ("eagle.flash.1m0.ld", "eagle.flash.1m.ld"), | ||||
|     FLASH_SIZE_2_MB: ("eagle.flash.2m.ld", "eagle.flash.2m.ld"), | ||||
|     FLASH_SIZE_4_MB: ("eagle.flash.4m.ld", "eagle.flash.4m.ld"), | ||||
|     FLASH_SIZE_16_MB: ("eagle.flash.16m.ld", "eagle.flash.16m14m.ld"), | ||||
| } | ||||
|  | ||||
| ESP32_BASE_PINS = { | ||||
|     "TX": 1, | ||||
|     "RX": 3, | ||||
|     "SDA": 21, | ||||
|     "SCL": 22, | ||||
|     "SS": 5, | ||||
|     "MOSI": 23, | ||||
|     "MISO": 19, | ||||
|     "SCK": 18, | ||||
|     "A0": 36, | ||||
|     "A3": 39, | ||||
|     "A4": 32, | ||||
|     "A5": 33, | ||||
|     "A6": 34, | ||||
|     "A7": 35, | ||||
|     "A10": 4, | ||||
|     "A11": 0, | ||||
|     "A12": 2, | ||||
|     "A13": 15, | ||||
|     "A14": 13, | ||||
|     "A15": 12, | ||||
|     "A16": 14, | ||||
|     "A17": 27, | ||||
|     "A18": 25, | ||||
|     "A19": 26, | ||||
|     "T0": 4, | ||||
|     "T1": 0, | ||||
|     "T2": 2, | ||||
|     "T3": 15, | ||||
|     "T4": 13, | ||||
|     "T5": 12, | ||||
|     "T6": 14, | ||||
|     "T7": 27, | ||||
|     "T8": 33, | ||||
|     "T9": 32, | ||||
|     "DAC1": 25, | ||||
|     "DAC2": 26, | ||||
|     "SVP": 36, | ||||
|     "SVN": 39, | ||||
| } | ||||
|  | ||||
| ESP32_BOARD_PINS = { | ||||
|     "alksesp32": { | ||||
|         "A0": 32, | ||||
|         "A1": 33, | ||||
|         "A2": 25, | ||||
|         "A3": 26, | ||||
|         "A4": 27, | ||||
|         "A5": 14, | ||||
|         "A6": 12, | ||||
|         "A7": 15, | ||||
|         "D0": 40, | ||||
|         "D1": 41, | ||||
|         "D10": 19, | ||||
|         "D11": 21, | ||||
|         "D12": 22, | ||||
|         "D13": 23, | ||||
|         "D2": 15, | ||||
|         "D3": 2, | ||||
|         "D4": 0, | ||||
|         "D5": 4, | ||||
|         "D6": 16, | ||||
|         "D7": 17, | ||||
|         "D8": 5, | ||||
|         "D9": 18, | ||||
|         "DHT_PIN": 26, | ||||
|         "LED": 23, | ||||
|         "L_B": 5, | ||||
|         "L_G": 17, | ||||
|         "L_R": 22, | ||||
|         "L_RGB_B": 16, | ||||
|         "L_RGB_G": 21, | ||||
|         "L_RGB_R": 4, | ||||
|         "L_Y": 23, | ||||
|         "MISO": 22, | ||||
|         "MOSI": 21, | ||||
|         "PHOTO": 25, | ||||
|         "PIEZO1": 19, | ||||
|         "PIEZO2": 18, | ||||
|         "POT1": 32, | ||||
|         "POT2": 33, | ||||
|         "S1": 4, | ||||
|         "S2": 16, | ||||
|         "S3": 18, | ||||
|         "S4": 19, | ||||
|         "S5": 21, | ||||
|         "SCK": 23, | ||||
|         "SCL": 14, | ||||
|         "SDA": 27, | ||||
|         "SS": 19, | ||||
|         "SW1": 15, | ||||
|         "SW2": 2, | ||||
|         "SW3": 0, | ||||
|     }, | ||||
|     "bpi-bit": { | ||||
|         "BUTTON_A": 35, | ||||
|         "BUTTON_B": 27, | ||||
|         "BUZZER": 25, | ||||
|         "LIGHT_SENSOR1": 36, | ||||
|         "LIGHT_SENSOR2": 39, | ||||
|         "MPU9250_INT": 0, | ||||
|         "P0": 25, | ||||
|         "P1": 32, | ||||
|         "P10": 26, | ||||
|         "P11": 27, | ||||
|         "P12": 2, | ||||
|         "P13": 18, | ||||
|         "P14": 19, | ||||
|         "P15": 23, | ||||
|         "P16": 5, | ||||
|         "P19": 22, | ||||
|         "P2": 33, | ||||
|         "P20": 21, | ||||
|         "P3": 13, | ||||
|         "P4": 15, | ||||
|         "P5": 35, | ||||
|         "P6": 12, | ||||
|         "P7": 14, | ||||
|         "P8": 16, | ||||
|         "P9": 17, | ||||
|         "RGB_LED": 4, | ||||
|         "TEMPERATURE_SENSOR": 34, | ||||
|     }, | ||||
|     "d-duino-32": { | ||||
|         "D1": 5, | ||||
|         "D10": 1, | ||||
|         "D2": 4, | ||||
|         "D3": 0, | ||||
|         "D4": 2, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 15, | ||||
|         "D9": 3, | ||||
|         "MISO": 12, | ||||
|         "MOSI": 13, | ||||
|         "SCK": 14, | ||||
|         "SCL": 4, | ||||
|         "SDA": 5, | ||||
|         "SS": 15, | ||||
|     }, | ||||
|     "esp-wrover-kit": {}, | ||||
|     "esp32-devkitlipo": {}, | ||||
|     "esp32-evb": { | ||||
|         "BUTTON": 34, | ||||
|         "MISO": 15, | ||||
|         "MOSI": 2, | ||||
|         "SCK": 14, | ||||
|         "SCL": 16, | ||||
|         "SDA": 13, | ||||
|         "SS": 17, | ||||
|     }, | ||||
|     "esp32-gateway": {"BUTTON": 34, "LED": 33, "SCL": 16, "SDA": 32}, | ||||
|     "esp32-poe-iso": { | ||||
|         "BUTTON": 34, | ||||
|         "MISO": 15, | ||||
|         "MOSI": 2, | ||||
|         "SCK": 14, | ||||
|         "SCL": 16, | ||||
|         "SDA": 13, | ||||
|     }, | ||||
|     "esp32-poe": {"BUTTON": 34, "MISO": 15, "MOSI": 2, "SCK": 14, "SCL": 16, "SDA": 13}, | ||||
|     "esp32-pro": { | ||||
|         "BUTTON": 34, | ||||
|         "MISO": 15, | ||||
|         "MOSI": 2, | ||||
|         "SCK": 14, | ||||
|         "SCL": 16, | ||||
|         "SDA": 13, | ||||
|         "SS": 17, | ||||
|     }, | ||||
|     "esp320": { | ||||
|         "LED": 5, | ||||
|         "MISO": 12, | ||||
|         "MOSI": 13, | ||||
|         "SCK": 14, | ||||
|         "SCL": 14, | ||||
|         "SDA": 2, | ||||
|         "SS": 15, | ||||
|     }, | ||||
|     "esp32cam": {}, | ||||
|     "esp32dev": {}, | ||||
|     "esp32doit-devkit-v1": {"LED": 2}, | ||||
|     "esp32thing": {"BUTTON": 0, "LED": 5, "SS": 2}, | ||||
|     "esp32vn-iot-uno": {}, | ||||
|     "espea32": {"BUTTON": 0, "LED": 5}, | ||||
|     "espectro32": {"LED": 15, "SD_SS": 33}, | ||||
|     "espino32": {"BUTTON": 0, "LED": 16}, | ||||
|     "featheresp32": { | ||||
|         "A0": 26, | ||||
|         "A1": 25, | ||||
|         "A10": 27, | ||||
|         "A11": 12, | ||||
|         "A12": 13, | ||||
|         "A13": 35, | ||||
|         "A2": 34, | ||||
|         "A4": 36, | ||||
|         "A5": 4, | ||||
|         "A6": 14, | ||||
|         "A7": 32, | ||||
|         "A8": 15, | ||||
|         "A9": 33, | ||||
|         "Ax": 2, | ||||
|         "LED": 13, | ||||
|         "MOSI": 18, | ||||
|         "RX": 16, | ||||
|         "SCK": 5, | ||||
|         "SDA": 23, | ||||
|         "SS": 33, | ||||
|         "TX": 17, | ||||
|     }, | ||||
|     "firebeetle32": {"LED": 2}, | ||||
|     "fm-devkit": { | ||||
|         "D0": 34, | ||||
|         "D1": 35, | ||||
|         "D10": 0, | ||||
|         "D2": 32, | ||||
|         "D3": 33, | ||||
|         "D4": 27, | ||||
|         "D5": 14, | ||||
|         "D6": 12, | ||||
|         "D7": 13, | ||||
|         "D8": 15, | ||||
|         "D9": 23, | ||||
|         "I2S_DOUT": 22, | ||||
|         "I2S_LRCLK": 25, | ||||
|         "I2S_MCLK": 2, | ||||
|         "I2S_SCLK": 26, | ||||
|         "LED": 5, | ||||
|         "SCL": 17, | ||||
|         "SDA": 16, | ||||
|         "SW1": 4, | ||||
|         "SW2": 18, | ||||
|         "SW3": 19, | ||||
|         "SW4": 21, | ||||
|     }, | ||||
|     "frogboard": {}, | ||||
|     "heltec_wifi_kit_32": { | ||||
|         "A1": 37, | ||||
|         "A2": 38, | ||||
|         "BUTTON": 0, | ||||
|         "LED": 25, | ||||
|         "RST_OLED": 16, | ||||
|         "SCL_OLED": 15, | ||||
|         "SDA_OLED": 4, | ||||
|         "Vext": 21, | ||||
|     }, | ||||
|     "heltec_wifi_lora_32": { | ||||
|         "BUTTON": 0, | ||||
|         "DIO0": 26, | ||||
|         "DIO1": 33, | ||||
|         "DIO2": 32, | ||||
|         "LED": 25, | ||||
|         "MOSI": 27, | ||||
|         "RST_LoRa": 14, | ||||
|         "RST_OLED": 16, | ||||
|         "SCK": 5, | ||||
|         "SCL_OLED": 15, | ||||
|         "SDA_OLED": 4, | ||||
|         "SS": 18, | ||||
|         "Vext": 21, | ||||
|     }, | ||||
|     "heltec_wifi_lora_32_V2": { | ||||
|         "BUTTON": 0, | ||||
|         "DIO0": 26, | ||||
|         "DIO1": 35, | ||||
|         "DIO2": 34, | ||||
|         "LED": 25, | ||||
|         "MOSI": 27, | ||||
|         "RST_LoRa": 14, | ||||
|         "RST_OLED": 16, | ||||
|         "SCK": 5, | ||||
|         "SCL_OLED": 15, | ||||
|         "SDA_OLED": 4, | ||||
|         "SS": 18, | ||||
|         "Vext": 21, | ||||
|     }, | ||||
|     "heltec_wireless_stick": { | ||||
|         "BUTTON": 0, | ||||
|         "DIO0": 26, | ||||
|         "DIO1": 35, | ||||
|         "DIO2": 34, | ||||
|         "LED": 25, | ||||
|         "MOSI": 27, | ||||
|         "RST_LoRa": 14, | ||||
|         "RST_OLED": 16, | ||||
|         "SCK": 5, | ||||
|         "SCL_OLED": 15, | ||||
|         "SDA_OLED": 4, | ||||
|         "SS": 18, | ||||
|         "Vext": 21, | ||||
|     }, | ||||
|     "hornbill32dev": {"BUTTON": 0, "LED": 13}, | ||||
|     "hornbill32minima": {"SS": 2}, | ||||
|     "intorobot": { | ||||
|         "A1": 39, | ||||
|         "A2": 35, | ||||
|         "A3": 25, | ||||
|         "A4": 26, | ||||
|         "A5": 14, | ||||
|         "A6": 12, | ||||
|         "A7": 15, | ||||
|         "A8": 13, | ||||
|         "A9": 2, | ||||
|         "BUTTON": 0, | ||||
|         "D0": 19, | ||||
|         "D1": 23, | ||||
|         "D2": 18, | ||||
|         "D3": 17, | ||||
|         "D4": 16, | ||||
|         "D5": 5, | ||||
|         "D6": 4, | ||||
|         "LED": 4, | ||||
|         "MISO": 17, | ||||
|         "MOSI": 16, | ||||
|         "RGB_B_BUILTIN": 22, | ||||
|         "RGB_G_BUILTIN": 21, | ||||
|         "RGB_R_BUILTIN": 27, | ||||
|         "SCL": 19, | ||||
|         "SDA": 23, | ||||
|         "T0": 19, | ||||
|         "T1": 23, | ||||
|         "T2": 18, | ||||
|         "T3": 17, | ||||
|         "T4": 16, | ||||
|         "T5": 5, | ||||
|         "T6": 4, | ||||
|     }, | ||||
|     "iotaap_magnolia": {}, | ||||
|     "iotbusio": {}, | ||||
|     "iotbusproteus": {}, | ||||
|     "lolin32": {"LED": 5}, | ||||
|     "lolin32_lite": {"LED": 22}, | ||||
|     "lolin_d32": {"LED": 5, "_VBAT": 35}, | ||||
|     "lolin_d32_pro": {"LED": 5, "_VBAT": 35}, | ||||
|     "lopy": { | ||||
|         "A1": 37, | ||||
|         "A2": 38, | ||||
|         "LED": 0, | ||||
|         "MISO": 37, | ||||
|         "MOSI": 22, | ||||
|         "SCK": 13, | ||||
|         "SCL": 13, | ||||
|         "SDA": 12, | ||||
|         "SS": 17, | ||||
|     }, | ||||
|     "lopy4": { | ||||
|         "A1": 37, | ||||
|         "A2": 38, | ||||
|         "LED": 0, | ||||
|         "MISO": 37, | ||||
|         "MOSI": 22, | ||||
|         "SCK": 13, | ||||
|         "SCL": 13, | ||||
|         "SDA": 12, | ||||
|         "SS": 18, | ||||
|     }, | ||||
|     "m5stack-core-esp32": { | ||||
|         "ADC1": 35, | ||||
|         "ADC2": 36, | ||||
|         "G0": 0, | ||||
|         "G1": 1, | ||||
|         "G12": 12, | ||||
|         "G13": 13, | ||||
|         "G15": 15, | ||||
|         "G16": 16, | ||||
|         "G17": 17, | ||||
|         "G18": 18, | ||||
|         "G19": 19, | ||||
|         "G2": 2, | ||||
|         "G21": 21, | ||||
|         "G22": 22, | ||||
|         "G23": 23, | ||||
|         "G25": 25, | ||||
|         "G26": 26, | ||||
|         "G3": 3, | ||||
|         "G34": 34, | ||||
|         "G35": 35, | ||||
|         "G36": 36, | ||||
|         "G5": 5, | ||||
|         "RXD2": 16, | ||||
|         "TXD2": 17, | ||||
|     }, | ||||
|     "m5stack-fire": { | ||||
|         "ADC1": 35, | ||||
|         "ADC2": 36, | ||||
|         "G0": 0, | ||||
|         "G1": 1, | ||||
|         "G12": 12, | ||||
|         "G13": 13, | ||||
|         "G15": 15, | ||||
|         "G16": 16, | ||||
|         "G17": 17, | ||||
|         "G18": 18, | ||||
|         "G19": 19, | ||||
|         "G2": 2, | ||||
|         "G21": 21, | ||||
|         "G22": 22, | ||||
|         "G23": 23, | ||||
|         "G25": 25, | ||||
|         "G26": 26, | ||||
|         "G3": 3, | ||||
|         "G34": 34, | ||||
|         "G35": 35, | ||||
|         "G36": 36, | ||||
|         "G5": 5, | ||||
|     }, | ||||
|     "m5stack-grey": { | ||||
|         "ADC1": 35, | ||||
|         "ADC2": 36, | ||||
|         "G0": 0, | ||||
|         "G1": 1, | ||||
|         "G12": 12, | ||||
|         "G13": 13, | ||||
|         "G15": 15, | ||||
|         "G16": 16, | ||||
|         "G17": 17, | ||||
|         "G18": 18, | ||||
|         "G19": 19, | ||||
|         "G2": 2, | ||||
|         "G21": 21, | ||||
|         "G22": 22, | ||||
|         "G23": 23, | ||||
|         "G25": 25, | ||||
|         "G26": 26, | ||||
|         "G3": 3, | ||||
|         "G34": 34, | ||||
|         "G35": 35, | ||||
|         "G36": 36, | ||||
|         "G5": 5, | ||||
|         "RXD2": 16, | ||||
|         "TXD2": 17, | ||||
|     }, | ||||
|     "m5stick-c": { | ||||
|         "ADC1": 35, | ||||
|         "ADC2": 36, | ||||
|         "G0": 0, | ||||
|         "G10": 10, | ||||
|         "G26": 26, | ||||
|         "G32": 32, | ||||
|         "G33": 33, | ||||
|         "G36": 36, | ||||
|         "G37": 37, | ||||
|         "G39": 39, | ||||
|         "G9": 9, | ||||
|         "MISO": 36, | ||||
|         "MOSI": 15, | ||||
|         "SCK": 13, | ||||
|         "SCL": 33, | ||||
|         "SDA": 32, | ||||
|     }, | ||||
|     "magicbit": { | ||||
|         "BLUE_LED": 17, | ||||
|         "BUZZER": 25, | ||||
|         "GREEN_LED": 16, | ||||
|         "LDR": 36, | ||||
|         "LED": 16, | ||||
|         "LEFT_BUTTON": 35, | ||||
|         "MOTOR1A": 27, | ||||
|         "MOTOR1B": 18, | ||||
|         "MOTOR2A": 16, | ||||
|         "MOTOR2B": 17, | ||||
|         "POT": 39, | ||||
|         "RED_LED": 27, | ||||
|         "RIGHT_PUTTON": 34, | ||||
|         "YELLOW_LED": 18, | ||||
|     }, | ||||
|     "mhetesp32devkit": {"LED": 2}, | ||||
|     "mhetesp32minikit": {"LED": 2}, | ||||
|     "microduino-core-esp32": { | ||||
|         "A0": 12, | ||||
|         "A1": 13, | ||||
|         "A10": 25, | ||||
|         "A11": 26, | ||||
|         "A12": 27, | ||||
|         "A13": 14, | ||||
|         "A2": 15, | ||||
|         "A3": 4, | ||||
|         "A6": 38, | ||||
|         "A7": 37, | ||||
|         "A8": 32, | ||||
|         "A9": 33, | ||||
|         "D0": 3, | ||||
|         "D1": 1, | ||||
|         "D10": 5, | ||||
|         "D11": 23, | ||||
|         "D12": 19, | ||||
|         "D13": 18, | ||||
|         "D14": 12, | ||||
|         "D15": 13, | ||||
|         "D16": 15, | ||||
|         "D17": 4, | ||||
|         "D18": 22, | ||||
|         "D19": 21, | ||||
|         "D2": 16, | ||||
|         "D20": 38, | ||||
|         "D21": 37, | ||||
|         "D3": 17, | ||||
|         "D4": 32, | ||||
|         "D5": 33, | ||||
|         "D6": 25, | ||||
|         "D7": 26, | ||||
|         "D8": 27, | ||||
|         "D9": 14, | ||||
|         "SCL": 21, | ||||
|         "SCL1": 13, | ||||
|         "SDA": 22, | ||||
|         "SDA1": 12, | ||||
|     }, | ||||
|     "nano32": {"BUTTON": 0, "LED": 16}, | ||||
|     "nina_w10": { | ||||
|         "D0": 3, | ||||
|         "D1": 1, | ||||
|         "D10": 5, | ||||
|         "D11": 19, | ||||
|         "D12": 23, | ||||
|         "D13": 18, | ||||
|         "D14": 13, | ||||
|         "D15": 12, | ||||
|         "D16": 32, | ||||
|         "D17": 33, | ||||
|         "D18": 21, | ||||
|         "D19": 34, | ||||
|         "D2": 26, | ||||
|         "D20": 36, | ||||
|         "D21": 39, | ||||
|         "D3": 25, | ||||
|         "D4": 35, | ||||
|         "D5": 27, | ||||
|         "D6": 22, | ||||
|         "D7": 0, | ||||
|         "D8": 15, | ||||
|         "D9": 14, | ||||
|         "LED_BLUE": 21, | ||||
|         "LED_GREEN": 33, | ||||
|         "LED_RED": 23, | ||||
|         "SCL": 13, | ||||
|         "SDA": 12, | ||||
|         "SW1": 33, | ||||
|         "SW2": 27, | ||||
|     }, | ||||
|     "node32s": {}, | ||||
|     "nodemcu-32s": {"BUTTON": 0, "LED": 2}, | ||||
|     "odroid_esp32": {"ADC1": 35, "ADC2": 36, "LED": 2, "SCL": 4, "SDA": 15, "SS": 22}, | ||||
|     "onehorse32dev": {"A1": 37, "A2": 38, "BUTTON": 0, "LED": 5}, | ||||
|     "oroca_edubot": { | ||||
|         "A0": 34, | ||||
|         "A1": 39, | ||||
|         "A2": 36, | ||||
|         "A3": 33, | ||||
|         "D0": 4, | ||||
|         "D1": 16, | ||||
|         "D2": 17, | ||||
|         "D3": 22, | ||||
|         "D4": 23, | ||||
|         "D5": 5, | ||||
|         "D6": 18, | ||||
|         "D7": 19, | ||||
|         "D8": 33, | ||||
|         "LED": 13, | ||||
|         "MOSI": 18, | ||||
|         "RX": 16, | ||||
|         "SCK": 5, | ||||
|         "SDA": 23, | ||||
|         "SS": 2, | ||||
|         "TX": 17, | ||||
|         "VBAT": 35, | ||||
|     }, | ||||
|     "pico32": {}, | ||||
|     "pocket_32": {"LED": 16}, | ||||
|     "pycom_gpy": { | ||||
|         "A1": 37, | ||||
|         "A2": 38, | ||||
|         "LED": 0, | ||||
|         "MISO": 37, | ||||
|         "MOSI": 22, | ||||
|         "SCK": 13, | ||||
|         "SCL": 13, | ||||
|         "SDA": 12, | ||||
|         "SS": 17, | ||||
|     }, | ||||
|     "quantum": {}, | ||||
|     "sparkfun_lora_gateway_1-channel": {"MISO": 12, "MOSI": 13, "SCK": 14, "SS": 16}, | ||||
|     "tinypico": {}, | ||||
|     "ttgo-lora32-v1": { | ||||
|         "A1": 37, | ||||
|         "A2": 38, | ||||
|         "BUTTON": 0, | ||||
|         "LED": 2, | ||||
|         "MOSI": 27, | ||||
|         "SCK": 5, | ||||
|         "SS": 18, | ||||
|     }, | ||||
|     "ttgo-t-beam": {"BUTTON": 39, "LED": 14, "MOSI": 27, "SCK": 5, "SS": 18}, | ||||
|     "ttgo-t-watch": {"BUTTON": 36, "MISO": 2, "MOSI": 15, "SCK": 14, "SS": 13}, | ||||
|     "ttgo-t1": {"LED": 22, "MISO": 2, "MOSI": 15, "SCK": 14, "SCL": 23, "SS": 13}, | ||||
|     "ttgo-t7-v13-mini32": {"LED": 22}, | ||||
|     "ttgo-t7-v14-mini32": {"LED": 19}, | ||||
|     "turta_iot_node": {}, | ||||
|     "vintlabs-devkit-v1": { | ||||
|         "LED": 2, | ||||
|         "PWM0": 12, | ||||
|         "PWM1": 13, | ||||
|         "PWM2": 14, | ||||
|         "PWM3": 15, | ||||
|         "PWM4": 16, | ||||
|         "PWM5": 17, | ||||
|         "PWM6": 18, | ||||
|         "PWM7": 19, | ||||
|     }, | ||||
|     "wemos_d1_mini32": { | ||||
|         "D0": 26, | ||||
|         "D1": 22, | ||||
|         "D2": 21, | ||||
|         "D3": 17, | ||||
|         "D4": 16, | ||||
|         "D5": 18, | ||||
|         "D6": 19, | ||||
|         "D7": 23, | ||||
|         "D8": 5, | ||||
|         "LED": 2, | ||||
|         "RXD": 3, | ||||
|         "TXD": 1, | ||||
|         "_VBAT": 35, | ||||
|     }, | ||||
|     "wemosbat": {"LED": 16}, | ||||
|     "wesp32": {"MISO": 32, "SCL": 4, "SDA": 15}, | ||||
|     "widora-air": { | ||||
|         "A1": 39, | ||||
|         "A2": 35, | ||||
|         "A3": 25, | ||||
|         "A4": 26, | ||||
|         "A5": 14, | ||||
|         "A6": 12, | ||||
|         "A7": 15, | ||||
|         "A8": 13, | ||||
|         "A9": 2, | ||||
|         "BUTTON": 0, | ||||
|         "D0": 19, | ||||
|         "D1": 23, | ||||
|         "D2": 18, | ||||
|         "D3": 17, | ||||
|         "D4": 16, | ||||
|         "D5": 5, | ||||
|         "D6": 4, | ||||
|         "LED": 25, | ||||
|         "MISO": 17, | ||||
|         "MOSI": 16, | ||||
|         "SCL": 19, | ||||
|         "SDA": 23, | ||||
|         "T0": 19, | ||||
|         "T1": 23, | ||||
|         "T2": 18, | ||||
|         "T3": 17, | ||||
|         "T4": 16, | ||||
|         "T5": 5, | ||||
|         "T6": 4, | ||||
|     }, | ||||
|     "xinabox_cw02": {"LED": 27}, | ||||
| } | ||||
|  | ||||
| ESP32_C3_BASE_PINS = { | ||||
|     "TX": 21, | ||||
|     "RX": 20, | ||||
|     "ADC1_0": 0, | ||||
|     "ADC1_1": 1, | ||||
|     "ADC1_2": 2, | ||||
|     "ADC1_3": 3, | ||||
|     "ADC1_4": 4, | ||||
|     "ADC2_0": 5, | ||||
| } | ||||
|  | ||||
| ESP32_C3_BOARD_PINS = { | ||||
|     "esp32-c3-devkitm-1": {"LED": 8}, | ||||
|     "esp32-c3-devkitc-02": "esp32-c3-devkitm-1", | ||||
| } | ||||
| @@ -125,7 +125,7 @@ void ICACHE_RAM_ATTR HOT AcDimmerDataStore::gpio_intr() { | ||||
| } | ||||
|  | ||||
| void ICACHE_RAM_ATTR HOT AcDimmerDataStore::s_gpio_intr(AcDimmerDataStore *store) { | ||||
|   // Attaching pin interrupts on the same pin will override the previous interupt | ||||
|   // Attaching pin interrupts on the same pin will override the previous interrupt | ||||
|   // However, the user expects that multiple dimmers sharing the same ZC pin will work. | ||||
|   // We solve this in a bit of a hacky way: On each pin interrupt, we check all dimmers | ||||
|   // if any of them are using the same ZC pin, and also trigger the interrupt for *them*. | ||||
|   | ||||
| @@ -42,7 +42,7 @@ void AdalightLightEffect::reset_frame_(light::AddressableLight &it) { | ||||
|  | ||||
| void AdalightLightEffect::blank_all_leds_(light::AddressableLight &it) { | ||||
|   for (int led = it.size(); led-- > 0;) { | ||||
|     it[led].set(COLOR_BLACK); | ||||
|     it[led].set(Color::BLACK); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -14,6 +14,7 @@ static const char *const TAG = "adc"; | ||||
| void ADCSensor::set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; } | ||||
|  | ||||
| inline adc1_channel_t gpio_to_adc1(uint8_t pin) { | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|   switch (pin) { | ||||
|     case 36: | ||||
|       return ADC1_CHANNEL_0; | ||||
| @@ -34,6 +35,22 @@ inline adc1_channel_t gpio_to_adc1(uint8_t pin) { | ||||
|     default: | ||||
|       return ADC1_CHANNEL_MAX; | ||||
|   } | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 | ||||
|   switch (pin) { | ||||
|     case 0: | ||||
|       return ADC1_CHANNEL_0; | ||||
|     case 1: | ||||
|       return ADC1_CHANNEL_1; | ||||
|     case 2: | ||||
|       return ADC1_CHANNEL_2; | ||||
|     case 3: | ||||
|       return ADC1_CHANNEL_3; | ||||
|     case 4: | ||||
|       return ADC1_CHANNEL_4; | ||||
|     default: | ||||
|       return ADC1_CHANNEL_MAX; | ||||
|   } | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @@ -46,8 +63,10 @@ void ADCSensor::setup() { | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|   adc1_config_channel_atten(gpio_to_adc1(pin_), attenuation_); | ||||
|   adc1_config_width(ADC_WIDTH_BIT_12); | ||||
| #if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 | ||||
|   adc_gpio_init(ADC_UNIT_1, (adc_channel_t) gpio_to_adc1(pin_)); | ||||
| #endif | ||||
| #endif | ||||
| } | ||||
| void ADCSensor::dump_config() { | ||||
|   LOG_SENSOR("", "ADC Sensor", this); | ||||
| @@ -89,6 +108,7 @@ float ADCSensor::sample() { | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|   int raw = adc1_get_raw(gpio_to_adc1(pin_)); | ||||
|   float value_v = raw / 4095.0f; | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|   switch (this->attenuation_) { | ||||
|     case ADC_ATTEN_DB_0: | ||||
|       value_v *= 1.1; | ||||
| @@ -105,6 +125,24 @@ float ADCSensor::sample() { | ||||
|     default:  // This is to satisfy the unused ADC_ATTEN_MAX | ||||
|       break; | ||||
|   } | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 | ||||
|   switch (this->attenuation_) { | ||||
|     case ADC_ATTEN_DB_0: | ||||
|       value_v *= 0.84; | ||||
|       break; | ||||
|     case ADC_ATTEN_DB_2_5: | ||||
|       value_v *= 1.13; | ||||
|       break; | ||||
|     case ADC_ATTEN_DB_6: | ||||
|       value_v *= 1.56; | ||||
|       break; | ||||
|     case ADC_ATTEN_DB_11: | ||||
|       value_v *= 3.0; | ||||
|       break; | ||||
|     default:  // This is to satisfy the unused ADC_ATTEN_MAX | ||||
|       break; | ||||
|   } | ||||
| #endif | ||||
|   return value_v; | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,6 @@ from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_PIN, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_VOLT, | ||||
| ) | ||||
| @@ -37,7 +36,10 @@ ADCSensor = adc_ns.class_( | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_VOLT, | ||||
|         accuracy_decimals=2, | ||||
|         device_class=DEVICE_CLASS_VOLTAGE, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -8,7 +8,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     DEVICE_CLASS_POWER, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_VOLT, | ||||
|     UNIT_AMPERE, | ||||
| @@ -32,27 +31,34 @@ CONFIG_SCHEMA = ( | ||||
|             cv.GenerateID(): cv.declare_id(ADE7953), | ||||
|             cv.Optional(CONF_IRQ_PIN): pins.input_pin, | ||||
|             cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( | ||||
|                 UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_VOLT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_VOLTAGE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_CURRENT_A): sensor.sensor_schema( | ||||
|                 UNIT_AMPERE, | ||||
|                 ICON_EMPTY, | ||||
|                 2, | ||||
|                 DEVICE_CLASS_CURRENT, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_AMPERE, | ||||
|                 accuracy_decimals=2, | ||||
|                 device_class=DEVICE_CLASS_CURRENT, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_CURRENT_B): sensor.sensor_schema( | ||||
|                 UNIT_AMPERE, | ||||
|                 ICON_EMPTY, | ||||
|                 2, | ||||
|                 DEVICE_CLASS_CURRENT, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_AMPERE, | ||||
|                 accuracy_decimals=2, | ||||
|                 device_class=DEVICE_CLASS_CURRENT, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema( | ||||
|                 UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_WATT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_POWER, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema( | ||||
|                 UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_WATT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_POWER, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -5,7 +5,6 @@ from esphome.const import ( | ||||
|     CONF_GAIN, | ||||
|     CONF_MULTIPLEXER, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_VOLT, | ||||
|     CONF_ID, | ||||
| @@ -53,7 +52,10 @@ ADS1115Sensor = ads1115_ns.class_( | ||||
| CONF_ADS1115_ID = "ads1115_id" | ||||
| CONFIG_SCHEMA = ( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_VOLT, | ||||
|         accuracy_decimals=3, | ||||
|         device_class=DEVICE_CLASS_VOLTAGE, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
| // | ||||
| // According to the datasheet, the component is supposed to respond in more than 75ms. In fact, it can answer almost | ||||
| // immediately for temperature. But for humidity, it takes >90ms to get a valid data. From experience, we have best | ||||
| // results making successive requests; the current implementation make 3 attemps with a delay of 30ms each time. | ||||
| // results making successive requests; the current implementation makes 3 attempts with a delay of 30ms each time. | ||||
|  | ||||
| #include "aht10.h" | ||||
| #include "esphome/core/log.h" | ||||
| @@ -23,7 +23,7 @@ static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1}; | ||||
| static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00}; | ||||
| static const uint8_t AHT10_DEFAULT_DELAY = 5;    // ms, for calibration and temperature measurement | ||||
| static const uint8_t AHT10_HUMIDITY_DELAY = 30;  // ms | ||||
| static const uint8_t AHT10_ATTEMPS = 3;          // safety margin, normally 3 attemps are enough: 3*30=90ms | ||||
| static const uint8_t AHT10_ATTEMPTS = 3;         // safety margin, normally 3 attempts are enough: 3*30=90ms | ||||
|  | ||||
| void AHT10Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up AHT10..."); | ||||
| @@ -58,8 +58,8 @@ void AHT10Component::update() { | ||||
|   uint8_t delay = AHT10_DEFAULT_DELAY; | ||||
|   if (this->humidity_sensor_ != nullptr) | ||||
|     delay = AHT10_HUMIDITY_DELAY; | ||||
|   for (int i = 0; i < AHT10_ATTEMPS; ++i) { | ||||
|     ESP_LOGVV(TAG, "Attemps %u at %6ld", i, millis()); | ||||
|   for (int i = 0; i < AHT10_ATTEMPTS; ++i) { | ||||
|     ESP_LOGVV(TAG, "Attempt %u at %6ld", i, millis()); | ||||
|     delay_microseconds_accurate(4); | ||||
|     if (!this->read_bytes(0, data, 6, delay)) { | ||||
|       ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); | ||||
|   | ||||
| @@ -7,7 +7,6 @@ from esphome.const import ( | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PERCENT, | ||||
| @@ -23,18 +22,16 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(AHT10Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 2, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=2, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 2, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=2, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     ICON_EMPTY, | ||||
|     UNIT_PERCENT, | ||||
| ) | ||||
|  | ||||
| @@ -25,18 +24,16 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(AM2320Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
							
								
								
									
										0
									
								
								esphome/components/am43/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/am43/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										115
									
								
								esphome/components/am43/am43.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								esphome/components/am43/am43.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| #include "am43.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| static const char *TAG = "am43"; | ||||
|  | ||||
| void Am43::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "AM43"); | ||||
|   LOG_SENSOR(" ", "Battery", this->battery_); | ||||
|   LOG_SENSOR(" ", "Illuminance", this->illuminance_); | ||||
| } | ||||
|  | ||||
| void Am43::setup() { | ||||
|   this->encoder_ = new Am43Encoder(); | ||||
|   this->decoder_ = new Am43Decoder(); | ||||
|   this->logged_in_ = false; | ||||
|   this->last_battery_update_ = 0; | ||||
|   this->current_sensor_ = 0; | ||||
| } | ||||
|  | ||||
| void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { | ||||
|   switch (event) { | ||||
|     case ESP_GATTC_OPEN_EVT: { | ||||
|       this->logged_in_ = false; | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_DISCONNECT_EVT: { | ||||
|       this->logged_in_ = false; | ||||
|       this->node_state = espbt::ClientState::Idle; | ||||
|       if (this->battery_ != nullptr) | ||||
|         this->battery_->publish_state(NAN); | ||||
|       if (this->illuminance_ != nullptr) | ||||
|         this->illuminance_->publish_state(NAN); | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||
|       auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); | ||||
|       if (chr == nullptr) { | ||||
|         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { | ||||
|           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", | ||||
|                    this->parent_->address_str().c_str()); | ||||
|         } else { | ||||
|           ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", | ||||
|                    this->parent_->address_str().c_str()); | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|       this->char_handle_ = chr->handle; | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_REG_FOR_NOTIFY_EVT: { | ||||
|       this->node_state = espbt::ClientState::Established; | ||||
|       this->update(); | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_NOTIFY_EVT: { | ||||
|       if (param->notify.handle != this->char_handle_) | ||||
|         break; | ||||
|       this->decoder_->decode(param->notify.value, param->notify.value_len); | ||||
|  | ||||
|       if (this->battery_ != nullptr && this->decoder_->has_battery_level() && | ||||
|           millis() - this->last_battery_update_ > 10000) { | ||||
|         this->battery_->publish_state(this->decoder_->battery_level_); | ||||
|         this->last_battery_update_ = millis(); | ||||
|       } | ||||
|  | ||||
|       if (this->illuminance_ != nullptr && this->decoder_->has_light_level()) { | ||||
|         this->illuminance_->publish_state(this->decoder_->light_level_); | ||||
|       } | ||||
|  | ||||
|       if (this->current_sensor_ > 0) { | ||||
|         if (this->illuminance_ != nullptr) { | ||||
|           auto packet = this->encoder_->get_light_level_request(); | ||||
|           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||
|                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, | ||||
|                                                  ESP_GATT_AUTH_REQ_NONE); | ||||
|           if (status) | ||||
|             ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), | ||||
|                      status); | ||||
|         } | ||||
|         this->current_sensor_ = 0; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Am43::update() { | ||||
|   if (this->node_state != espbt::ClientState::Established) { | ||||
|     ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str().c_str()); | ||||
|     return; | ||||
|   } | ||||
|   if (this->current_sensor_ == 0) { | ||||
|     if (this->battery_ != nullptr) { | ||||
|       auto packet = this->encoder_->get_battery_level_request(); | ||||
|       auto status = | ||||
|           esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||
|                                    packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|       if (status) | ||||
|         ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); | ||||
|     } | ||||
|     this->current_sensor_++; | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										45
									
								
								esphome/components/am43/am43.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								esphome/components/am43/am43.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/ble_client/ble_client.h" | ||||
| #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/am43/am43_base.h" | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|  | ||||
| #include <esp_gattc_api.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| namespace espbt = esphome::esp32_ble_tracker; | ||||
|  | ||||
| class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||
|                            esp_ble_gattc_cb_param_t *param) override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override { return setup_priority::DATA; } | ||||
|   void set_battery(sensor::Sensor *battery) { battery_ = battery; } | ||||
|   void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; } | ||||
|  | ||||
|  protected: | ||||
|   uint16_t char_handle_; | ||||
|   Am43Encoder *encoder_; | ||||
|   Am43Decoder *decoder_; | ||||
|   bool logged_in_; | ||||
|   sensor::Sensor *battery_{nullptr}; | ||||
|   sensor::Sensor *illuminance_{nullptr}; | ||||
|   uint8_t current_sensor_; | ||||
|   // The AM43 often gets into a state where it spams loads of battery update | ||||
|   // notifications. Here we will limit to no more than every 10s. | ||||
|   uint8_t last_battery_update_; | ||||
| }; | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										142
									
								
								esphome/components/am43/am43_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								esphome/components/am43/am43_base.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| #include "am43_base.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a}; | ||||
|  | ||||
| std::string pkt_to_hex(const uint8_t *data, uint16_t len) { | ||||
|   char buf[64]; | ||||
|   memset(buf, 0, 64); | ||||
|   for (int i = 0; i < len; i++) | ||||
|     sprintf(&buf[i * 2], "%02x", data[i]); | ||||
|   std::string ret = buf; | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_battery_level_request() { | ||||
|   uint8_t data = 0x1; | ||||
|   return this->encode_(0xA2, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_light_level_request() { | ||||
|   uint8_t data = 0x1; | ||||
|   return this->encode_(0xAA, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_position_request() { | ||||
|   uint8_t data = 0x1; | ||||
|   return this->encode_(CMD_GET_POSITION, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_send_pin_request(uint16_t pin) { | ||||
|   uint8_t data[2]; | ||||
|   data[0] = (pin & 0xFF00) >> 8; | ||||
|   data[1] = pin & 0xFF; | ||||
|   return this->encode_(CMD_SEND_PIN, data, 2); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_open_request() { | ||||
|   uint8_t data = 0xDD; | ||||
|   return this->encode_(CMD_SET_STATE, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_close_request() { | ||||
|   uint8_t data = 0xEE; | ||||
|   return this->encode_(CMD_SET_STATE, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_stop_request() { | ||||
|   uint8_t data = 0xCC; | ||||
|   return this->encode_(CMD_SET_STATE, &data, 1); | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::get_set_position_request(uint8_t position) { | ||||
|   return this->encode_(CMD_SET_POSITION, &position, 1); | ||||
| } | ||||
|  | ||||
| void Am43Encoder::checksum_() { | ||||
|   uint8_t checksum = 0; | ||||
|   int i = 0; | ||||
|   for (i = 0; i < this->packet_.length; i++) | ||||
|     checksum = checksum ^ this->packet_.data[i]; | ||||
|   this->packet_.data[i] = checksum ^ 0xff; | ||||
|   this->packet_.length++; | ||||
| } | ||||
|  | ||||
| Am43Packet *Am43Encoder::encode_(uint8_t command, uint8_t *data, uint8_t length) { | ||||
|   memcpy(this->packet_.data, START_PACKET, 5); | ||||
|   this->packet_.data[5] = command; | ||||
|   this->packet_.data[6] = length; | ||||
|   memcpy(&this->packet_.data[7], data, length); | ||||
|   this->packet_.length = length + 7; | ||||
|   this->checksum_(); | ||||
|   ESP_LOGV("am43", "ENC(%d): 0x%s", packet_.length, pkt_to_hex(packet_.data, packet_.length).c_str()); | ||||
|   return &this->packet_; | ||||
| } | ||||
|  | ||||
| #define VERIFY_MIN_LENGTH(x) \ | ||||
|   if (length < (x)) \ | ||||
|     return; | ||||
|  | ||||
| void Am43Decoder::decode(const uint8_t *data, uint16_t length) { | ||||
|   this->has_battery_level_ = false; | ||||
|   this->has_light_level_ = false; | ||||
|   this->has_set_position_response_ = false; | ||||
|   this->has_set_state_response_ = false; | ||||
|   this->has_position_ = false; | ||||
|   this->has_pin_response_ = false; | ||||
|   ESP_LOGV("am43", "DEC(%d): 0x%s", length, pkt_to_hex(data, length).c_str()); | ||||
|  | ||||
|   if (length < 2 || data[0] != 0x9a) | ||||
|     return; | ||||
|   switch (data[1]) { | ||||
|     case CMD_GET_BATTERY_LEVEL: { | ||||
|       VERIFY_MIN_LENGTH(8); | ||||
|       this->battery_level_ = data[7]; | ||||
|       this->has_battery_level_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_GET_LIGHT_LEVEL: { | ||||
|       VERIFY_MIN_LENGTH(5); | ||||
|       this->light_level_ = 100 * ((float) data[4] / 9); | ||||
|       this->has_light_level_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_GET_POSITION: { | ||||
|       VERIFY_MIN_LENGTH(6); | ||||
|       this->position_ = data[5]; | ||||
|       this->has_position_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_NOTIFY_POSITION: { | ||||
|       VERIFY_MIN_LENGTH(5); | ||||
|       this->position_ = data[4]; | ||||
|       this->has_position_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_SEND_PIN: { | ||||
|       VERIFY_MIN_LENGTH(4); | ||||
|       this->pin_ok_ = data[3] == RESPONSE_ACK; | ||||
|       this->has_pin_response_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_SET_POSITION: { | ||||
|       VERIFY_MIN_LENGTH(4); | ||||
|       this->set_position_ok_ = data[3] == RESPONSE_ACK; | ||||
|       this->has_set_position_response_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_SET_STATE: { | ||||
|       VERIFY_MIN_LENGTH(4); | ||||
|       this->set_state_ok_ = data[3] == RESPONSE_ACK; | ||||
|       this->has_set_state_response_ = true; | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										78
									
								
								esphome/components/am43/am43_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								esphome/components/am43/am43_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| static const uint16_t AM43_SERVICE_UUID = 0xFE50; | ||||
| static const uint16_t AM43_CHARACTERISTIC_UUID = 0xFE51; | ||||
| // | ||||
| // Tuya identifiers, only to detect and warn users as they are incompatible. | ||||
| static const uint16_t AM43_TUYA_SERVICE_UUID = 0x1910; | ||||
| static const uint16_t AM43_TUYA_CHARACTERISTIC_UUID = 0x2b11; | ||||
|  | ||||
| struct Am43Packet { | ||||
|   uint8_t length; | ||||
|   uint8_t data[24]; | ||||
| }; | ||||
|  | ||||
| static const uint8_t CMD_GET_BATTERY_LEVEL = 0xA2; | ||||
| static const uint8_t CMD_GET_LIGHT_LEVEL = 0xAA; | ||||
| static const uint8_t CMD_GET_POSITION = 0xA7; | ||||
| static const uint8_t CMD_SEND_PIN = 0x17; | ||||
| static const uint8_t CMD_SET_STATE = 0x0A; | ||||
| static const uint8_t CMD_SET_POSITION = 0x0D; | ||||
| static const uint8_t CMD_NOTIFY_POSITION = 0xA1; | ||||
|  | ||||
| static const uint8_t RESPONSE_ACK = 0x5A; | ||||
| static const uint8_t RESPONSE_NACK = 0xA5; | ||||
|  | ||||
| class Am43Encoder { | ||||
|  public: | ||||
|   Am43Packet *get_battery_level_request(); | ||||
|   Am43Packet *get_light_level_request(); | ||||
|   Am43Packet *get_position_request(); | ||||
|   Am43Packet *get_send_pin_request(uint16_t pin); | ||||
|   Am43Packet *get_open_request(); | ||||
|   Am43Packet *get_close_request(); | ||||
|   Am43Packet *get_stop_request(); | ||||
|   Am43Packet *get_set_position_request(uint8_t position); | ||||
|  | ||||
|  protected: | ||||
|   void checksum_(); | ||||
|   Am43Packet *encode_(uint8_t command, uint8_t *data, uint8_t length); | ||||
|   Am43Packet packet_; | ||||
| }; | ||||
|  | ||||
| class Am43Decoder { | ||||
|  public: | ||||
|   void decode(const uint8_t *data, uint16_t length); | ||||
|   bool has_battery_level() { return this->has_battery_level_; } | ||||
|   bool has_light_level() { return this->has_light_level_; } | ||||
|   bool has_set_position_response() { return this->has_set_position_response_; } | ||||
|   bool has_set_state_response() { return this->has_set_state_response_; } | ||||
|   bool has_position() { return this->has_position_; } | ||||
|   bool has_pin_response() { return this->has_pin_response_; } | ||||
|  | ||||
|   union { | ||||
|     uint8_t position_; | ||||
|     uint8_t battery_level_; | ||||
|     float light_level_; | ||||
|     uint8_t set_position_ok_; | ||||
|     uint8_t set_state_ok_; | ||||
|     uint8_t pin_ok_; | ||||
|   }; | ||||
|  | ||||
|  protected: | ||||
|   bool has_battery_level_; | ||||
|   bool has_light_level_; | ||||
|   bool has_set_position_response_; | ||||
|   bool has_set_state_response_; | ||||
|   bool has_position_; | ||||
|   bool has_pin_response_; | ||||
| }; | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										36
									
								
								esphome/components/am43/cover/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								esphome/components/am43/cover/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import cover, ble_client | ||||
| from esphome.const import CONF_ID, CONF_PIN | ||||
|  | ||||
| CODEOWNERS = ["@buxtronix"] | ||||
| DEPENDENCIES = ["ble_client"] | ||||
| AUTO_LOAD = ["am43"] | ||||
|  | ||||
| CONF_INVERT_POSITION = "invert_position" | ||||
|  | ||||
| am43_ns = cg.esphome_ns.namespace("am43") | ||||
| Am43Component = am43_ns.class_( | ||||
|     "Am43Component", cover.Cover, ble_client.BLEClientNode, cg.Component | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cover.COVER_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Am43Component), | ||||
|             cv.Optional(CONF_PIN, default=8888): cv.int_range(min=0, max=0xFFFF), | ||||
|             cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean, | ||||
|         } | ||||
|     ) | ||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
| ) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_pin(config[CONF_PIN])) | ||||
|     cg.add(var.set_invert_position(config[CONF_INVERT_POSITION])) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield cover.register_cover(var, config) | ||||
|     yield ble_client.register_ble_node(var, config) | ||||
							
								
								
									
										149
									
								
								esphome/components/am43/cover/am43_cover.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								esphome/components/am43/cover/am43_cover.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| #include "am43_cover.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| static const char *TAG = "am43_cover"; | ||||
|  | ||||
| using namespace esphome::cover; | ||||
|  | ||||
| void Am43Component::dump_config() { | ||||
|   LOG_COVER("", "AM43 Cover", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Device Pin: %d", this->pin_); | ||||
|   ESP_LOGCONFIG(TAG, "  Invert Position: %d", (int) this->invert_position_); | ||||
| } | ||||
|  | ||||
| void Am43Component::setup() { | ||||
|   this->position = COVER_OPEN; | ||||
|   this->encoder_ = new Am43Encoder(); | ||||
|   this->decoder_ = new Am43Decoder(); | ||||
|   this->logged_in_ = false; | ||||
| } | ||||
|  | ||||
| void Am43Component::loop() { | ||||
|   if (this->node_state == espbt::ClientState::Established && !this->logged_in_) { | ||||
|     auto packet = this->encoder_->get_send_pin_request(this->pin_); | ||||
|     auto status = | ||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|     ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str()); | ||||
|     if (status) | ||||
|       ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status); | ||||
|     else | ||||
|       this->logged_in_ = true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| CoverTraits Am43Component::get_traits() { | ||||
|   auto traits = CoverTraits(); | ||||
|   traits.set_supports_position(true); | ||||
|   traits.set_supports_tilt(false); | ||||
|   traits.set_is_assumed_state(false); | ||||
|   return traits; | ||||
| } | ||||
|  | ||||
| void Am43Component::control(const CoverCall &call) { | ||||
|   if (this->node_state != espbt::ClientState::Established) { | ||||
|     ESP_LOGW(TAG, "[%s] Cannot send cover control, not connected", this->get_name().c_str()); | ||||
|     return; | ||||
|   } | ||||
|   if (call.get_stop()) { | ||||
|     auto packet = this->encoder_->get_stop_request(); | ||||
|     auto status = | ||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|     if (status) | ||||
|       ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status); | ||||
|   } | ||||
|   if (call.get_position().has_value()) { | ||||
|     auto pos = *call.get_position(); | ||||
|  | ||||
|     if (this->invert_position_) | ||||
|       pos = 1 - pos; | ||||
|     auto packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100)); | ||||
|     auto status = | ||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|     if (status) | ||||
|       ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||
|                                         esp_ble_gattc_cb_param_t *param) { | ||||
|   switch (event) { | ||||
|     case ESP_GATTC_DISCONNECT_EVT: { | ||||
|       this->logged_in_ = false; | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||
|       auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); | ||||
|       if (chr == nullptr) { | ||||
|         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { | ||||
|           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str()); | ||||
|         } else { | ||||
|           ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", this->get_name().c_str()); | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|       this->char_handle_ = chr->handle; | ||||
|  | ||||
|       auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle); | ||||
|       if (status) { | ||||
|         ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status); | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_REG_FOR_NOTIFY_EVT: { | ||||
|       this->node_state = espbt::ClientState::Established; | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_NOTIFY_EVT: { | ||||
|       if (param->notify.handle != this->char_handle_) | ||||
|         break; | ||||
|       this->decoder_->decode(param->notify.value, param->notify.value_len); | ||||
|  | ||||
|       if (this->decoder_->has_position()) { | ||||
|         this->position = ((float) this->decoder_->position_ / 100.0); | ||||
|         if (!this->invert_position_) | ||||
|           this->position = 1 - this->position; | ||||
|         if (this->position > 0.97) | ||||
|           this->position = 1.0; | ||||
|         if (this->position < 0.02) | ||||
|           this->position = 0.0; | ||||
|         this->publish_state(); | ||||
|       } | ||||
|  | ||||
|       if (this->decoder_->has_pin_response()) { | ||||
|         if (this->decoder_->pin_ok_) { | ||||
|           ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str()); | ||||
|           auto packet = this->encoder_->get_position_request(); | ||||
|           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||
|                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, | ||||
|                                                  ESP_GATT_AUTH_REQ_NONE); | ||||
|           if (status) | ||||
|             ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status); | ||||
|         } else { | ||||
|           ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str()); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) | ||||
|         ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str()); | ||||
|  | ||||
|       if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) | ||||
|         ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str()); | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										45
									
								
								esphome/components/am43/cover/am43_cover.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								esphome/components/am43/cover/am43_cover.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/ble_client/ble_client.h" | ||||
| #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" | ||||
| #include "esphome/components/cover/cover.h" | ||||
| #include "esphome/components/am43/am43_base.h" | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|  | ||||
| #include <esp_gattc_api.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace am43 { | ||||
|  | ||||
| namespace espbt = esphome::esp32_ble_tracker; | ||||
|  | ||||
| class Am43Component : public cover::Cover, public esphome::ble_client::BLEClientNode, public Component { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||
|                            esp_ble_gattc_cb_param_t *param) override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override { return setup_priority::DATA; } | ||||
|   cover::CoverTraits get_traits() override; | ||||
|   void set_pin(uint16_t pin) { this->pin_ = pin; } | ||||
|   void set_invert_position(bool invert_position) { this->invert_position_ = invert_position; } | ||||
|  | ||||
|  protected: | ||||
|   void control(const cover::CoverCall &call) override; | ||||
|   uint16_t char_handle_; | ||||
|   uint16_t pin_; | ||||
|   bool invert_position_; | ||||
|   Am43Encoder *encoder_; | ||||
|   Am43Decoder *decoder_; | ||||
|   bool logged_in_; | ||||
|  | ||||
|   float position_; | ||||
| }; | ||||
|  | ||||
| }  // namespace am43 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										46
									
								
								esphome/components/am43/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								esphome/components/am43/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor, ble_client | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_BATTERY_LEVEL, | ||||
|     ICON_BATTERY, | ||||
|     CONF_ILLUMINANCE, | ||||
|     ICON_BRIGHTNESS_5, | ||||
|     UNIT_PERCENT, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@buxtronix"] | ||||
|  | ||||
| am43_ns = cg.esphome_ns.namespace("am43") | ||||
| Am43 = am43_ns.class_("Am43", ble_client.BLEClientNode, cg.PollingComponent) | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Am43), | ||||
|             cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, ICON_BATTERY, 0 | ||||
|             ), | ||||
|             cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, ICON_BRIGHTNESS_5, 0 | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||
|     .extend(cv.polling_component_schema("120s")) | ||||
| ) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield ble_client.register_ble_node(var, config) | ||||
|  | ||||
|     if CONF_BATTERY_LEVEL in config: | ||||
|         sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) | ||||
|         cg.add(var.set_battery(sens)) | ||||
|  | ||||
|     if CONF_ILLUMINANCE in config: | ||||
|         sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE]) | ||||
|         cg.add(var.set_illuminance(sens)) | ||||
| @@ -90,19 +90,24 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | ||||
|       if (this->codec_->has_running()) { | ||||
|         this->mode = this->codec_->running_ ? climate::CLIMATE_MODE_HEAT : climate::CLIMATE_MODE_OFF; | ||||
|       } | ||||
|       if (this->codec_->has_unit()) { | ||||
|         this->fahrenheit_ = (this->codec_->unit_ == 'f'); | ||||
|         ESP_LOGD(TAG, "Anova units is %s", this->fahrenheit_ ? "fahrenheit" : "celcius"); | ||||
|         this->current_request_++; | ||||
|       } | ||||
|       this->publish_state(); | ||||
|  | ||||
|       if (this->current_request_ > 0) { | ||||
|       if (this->current_request_ > 1) { | ||||
|         AnovaPacket *pkt = nullptr; | ||||
|         switch (this->current_request_++) { | ||||
|           case 1: | ||||
|           case 2: | ||||
|             pkt = this->codec_->get_read_target_temp_request(); | ||||
|             break; | ||||
|           case 2: | ||||
|           case 3: | ||||
|             pkt = this->codec_->get_read_current_temp_request(); | ||||
|             break; | ||||
|           default: | ||||
|             this->current_request_ = 0; | ||||
|             this->current_request_ = 1; | ||||
|             break; | ||||
|         } | ||||
|         if (pkt != nullptr) { | ||||
| @@ -121,12 +126,16 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Anova::set_unit_of_measurement(const char *unit) { this->fahrenheit_ = !strncmp(unit, "f", 1); } | ||||
|  | ||||
| void Anova::update() { | ||||
|   if (this->node_state != espbt::ClientState::Established) | ||||
|     return; | ||||
|  | ||||
|   if (this->current_request_ == 0) { | ||||
|   if (this->current_request_ < 2) { | ||||
|     auto pkt = this->codec_->get_read_device_status_request(); | ||||
|     if (this->current_request_ == 0) | ||||
|       auto pkt = this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c'); | ||||
|     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||
|                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||
|     if (status) | ||||
|   | ||||
| @@ -36,12 +36,14 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode | ||||
|     traits.set_visual_temperature_step(0.1); | ||||
|     return traits; | ||||
|   } | ||||
|   void set_unit_of_measurement(const char *); | ||||
|  | ||||
|  protected: | ||||
|   AnovaCodec *codec_; | ||||
|   void control(const climate::ClimateCall &call) override; | ||||
|   uint16_t char_handle_; | ||||
|   uint8_t current_request_; | ||||
|   bool fahrenheit_; | ||||
| }; | ||||
|  | ||||
| }  // namespace anova | ||||
|   | ||||
| @@ -3,6 +3,10 @@ | ||||
| namespace esphome { | ||||
| namespace anova { | ||||
|  | ||||
| float ftoc(float f) { return (f - 32.0) * (5.0f / 9.0f); } | ||||
|  | ||||
| float ctof(float c) { return (c * 9.0f / 5.0f) + 32.0; } | ||||
|  | ||||
| AnovaPacket *AnovaCodec::clean_packet_() { | ||||
|   this->packet_.length = strlen((char *) this->packet_.data); | ||||
|   this->packet_.data[this->packet_.length] = '\0'; | ||||
| @@ -42,6 +46,8 @@ AnovaPacket *AnovaCodec::get_read_data_request() { | ||||
|  | ||||
| AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) { | ||||
|   this->current_query_ = SET_TARGET_TEMPERATURE; | ||||
|   if (this->fahrenheit_) | ||||
|     temperature = ctof(temperature); | ||||
|   sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature); | ||||
|   return this->clean_packet_(); | ||||
| } | ||||
| @@ -67,7 +73,6 @@ AnovaPacket *AnovaCodec::get_stop_request() { | ||||
| void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|   memset(this->buf_, 0, 32); | ||||
|   strncpy(this->buf_, (char *) data, length); | ||||
|   ESP_LOGV("anova", "Received: %s\n", this->buf_); | ||||
|   this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false; | ||||
|   switch (this->current_query_) { | ||||
|     case READ_DEVICE_STATUS: { | ||||
| @@ -97,19 +102,32 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|     } | ||||
|     case READ_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case SET_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case READ_CURRENT_TEMPERATURE: { | ||||
|       this->current_temp_ = strtof(this->buf_, nullptr); | ||||
|       if (this->fahrenheit_) | ||||
|         this->current_temp_ = ftoc(this->current_temp_); | ||||
|       this->has_current_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case SET_UNIT: | ||||
|     case READ_UNIT: { | ||||
|       this->unit_ = this->buf_[0]; | ||||
|       this->fahrenheit_ = this->buf_[0] == 'f'; | ||||
|       this->has_unit_ = true; | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
|   | ||||
| @@ -71,6 +71,7 @@ class AnovaCodec { | ||||
|   bool has_unit_; | ||||
|   bool has_running_; | ||||
|   char buf_[32]; | ||||
|   bool fahrenheit_; | ||||
|  | ||||
|   CurrentQuery current_query_; | ||||
| }; | ||||
|   | ||||
| @@ -1,7 +1,12 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import climate, ble_client | ||||
| from esphome.const import CONF_ID | ||||
| from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT | ||||
|  | ||||
| UNITS = { | ||||
|     "f": "f", | ||||
|     "c": "c", | ||||
| } | ||||
|  | ||||
| CODEOWNERS = ["@buxtronix"] | ||||
| DEPENDENCIES = ["ble_client"] | ||||
| @@ -12,14 +17,20 @@ Anova = anova_ns.class_( | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     climate.CLIMATE_SCHEMA.extend({cv.GenerateID(): cv.declare_id(Anova)}) | ||||
|     climate.CLIMATE_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Anova), | ||||
|             cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS), | ||||
|         } | ||||
|     ) | ||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
| ) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield climate.register_climate(var, config) | ||||
|     yield ble_client.register_ble_node(var, config) | ||||
|     await cg.register_component(var, config) | ||||
|     await climate.register_climate(var, config) | ||||
|     await ble_client.register_ble_node(var, config) | ||||
|     cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) | ||||
|   | ||||
| @@ -3,7 +3,6 @@ import esphome.config_validation as cv | ||||
| from esphome.components import sensor | ||||
| from esphome.const import ( | ||||
|     CONF_TYPE, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_PERCENT, | ||||
|     ICON_LIGHTBULB, | ||||
| @@ -21,7 +20,10 @@ TYPES = { | ||||
| } | ||||
|  | ||||
| CONFIG_SCHEMA = sensor.sensor_schema( | ||||
|     UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|     unit_of_measurement=UNIT_PERCENT, | ||||
|     icon=ICON_LIGHTBULB, | ||||
|     accuracy_decimals=1, | ||||
|     state_class=STATE_CLASS_MEASUREMENT, | ||||
| ).extend( | ||||
|     { | ||||
|         cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True), | ||||
|   | ||||
| @@ -39,6 +39,7 @@ service APIConnection { | ||||
|   rpc camera_image (CameraImageRequest) returns (void) {} | ||||
|   rpc climate_command (ClimateCommandRequest) returns (void) {} | ||||
|   rpc number_command (NumberCommandRequest) returns (void) {} | ||||
|   rpc select_command (SelectCommandRequest) returns (void) {} | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -213,6 +214,7 @@ message ListEntitiesBinarySensorResponse { | ||||
|  | ||||
|   string device_class = 5; | ||||
|   bool is_status_binary_sensor = 6; | ||||
|   bool disabled_by_default = 7; | ||||
| } | ||||
| message BinarySensorStateResponse { | ||||
|   option (id) = 21; | ||||
| @@ -242,6 +244,7 @@ message ListEntitiesCoverResponse { | ||||
|   bool supports_position = 6; | ||||
|   bool supports_tilt = 7; | ||||
|   string device_class = 8; | ||||
|   bool disabled_by_default = 9; | ||||
| } | ||||
|  | ||||
| enum LegacyCoverState { | ||||
| @@ -309,6 +312,7 @@ message ListEntitiesFanResponse { | ||||
|   bool supports_speed = 6; | ||||
|   bool supports_direction = 7; | ||||
|   int32 supported_speed_count = 8; | ||||
|   bool disabled_by_default = 9; | ||||
| } | ||||
| enum FanSpeed { | ||||
|   FAN_SPEED_LOW = 0; | ||||
| @@ -352,6 +356,18 @@ message FanCommandRequest { | ||||
| } | ||||
|  | ||||
| // ==================== LIGHT ==================== | ||||
| enum ColorMode { | ||||
|   COLOR_MODE_UNKNOWN = 0; | ||||
|   COLOR_MODE_ON_OFF = 1; | ||||
|   COLOR_MODE_BRIGHTNESS = 2; | ||||
|   COLOR_MODE_WHITE = 7; | ||||
|   COLOR_MODE_COLOR_TEMPERATURE = 11; | ||||
|   COLOR_MODE_COLD_WARM_WHITE = 19; | ||||
|   COLOR_MODE_RGB = 35; | ||||
|   COLOR_MODE_RGB_WHITE = 39; | ||||
|   COLOR_MODE_RGB_COLOR_TEMPERATURE = 47; | ||||
|   COLOR_MODE_RGB_COLD_WARM_WHITE = 51; | ||||
| } | ||||
| message ListEntitiesLightResponse { | ||||
|   option (id) = 15; | ||||
|   option (source) = SOURCE_SERVER; | ||||
| @@ -362,13 +378,16 @@ message ListEntitiesLightResponse { | ||||
|   string name = 3; | ||||
|   string unique_id = 4; | ||||
|  | ||||
|   bool supports_brightness = 5; | ||||
|   bool supports_rgb = 6; | ||||
|   bool supports_white_value = 7; | ||||
|   bool supports_color_temperature = 8; | ||||
|   repeated ColorMode supported_color_modes = 12; | ||||
|   // next four supports_* are for legacy clients, newer clients should use color modes | ||||
|   bool legacy_supports_brightness = 5 [deprecated=true]; | ||||
|   bool legacy_supports_rgb = 6 [deprecated=true]; | ||||
|   bool legacy_supports_white_value = 7 [deprecated=true]; | ||||
|   bool legacy_supports_color_temperature = 8 [deprecated=true]; | ||||
|   float min_mireds = 9; | ||||
|   float max_mireds = 10; | ||||
|   repeated string effects = 11; | ||||
|   bool disabled_by_default = 13; | ||||
| } | ||||
| message LightStateResponse { | ||||
|   option (id) = 24; | ||||
| @@ -379,12 +398,15 @@ message LightStateResponse { | ||||
|   fixed32 key = 1; | ||||
|   bool state = 2; | ||||
|   float brightness = 3; | ||||
|   ColorMode color_mode = 11; | ||||
|   float color_brightness = 10; | ||||
|   float red = 4; | ||||
|   float green = 5; | ||||
|   float blue = 6; | ||||
|   float white = 7; | ||||
|   float color_temperature = 8; | ||||
|   float cold_white = 12; | ||||
|   float warm_white = 13; | ||||
|   string effect = 9; | ||||
| } | ||||
| message LightCommandRequest { | ||||
| @@ -398,6 +420,8 @@ message LightCommandRequest { | ||||
|   bool state = 3; | ||||
|   bool has_brightness = 4; | ||||
|   float brightness = 5; | ||||
|   bool has_color_mode = 22; | ||||
|   ColorMode color_mode = 23; | ||||
|   bool has_color_brightness = 20; | ||||
|   float color_brightness = 21; | ||||
|   bool has_rgb = 6; | ||||
| @@ -408,6 +432,10 @@ message LightCommandRequest { | ||||
|   float white = 11; | ||||
|   bool has_color_temperature = 12; | ||||
|   float color_temperature = 13; | ||||
|   bool has_cold_white = 24; | ||||
|   float cold_white = 25; | ||||
|   bool has_warm_white = 26; | ||||
|   float warm_white = 27; | ||||
|   bool has_transition_length = 14; | ||||
|   uint32 transition_length = 15; | ||||
|   bool has_flash_length = 16; | ||||
| @@ -445,6 +473,7 @@ message ListEntitiesSensorResponse { | ||||
|   string device_class = 9; | ||||
|   SensorStateClass state_class = 10; | ||||
|   SensorLastResetType last_reset_type = 11; | ||||
|   bool disabled_by_default = 12; | ||||
| } | ||||
| message SensorStateResponse { | ||||
|   option (id) = 25; | ||||
| @@ -472,6 +501,7 @@ message ListEntitiesSwitchResponse { | ||||
|  | ||||
|   string icon = 5; | ||||
|   bool assumed_state = 6; | ||||
|   bool disabled_by_default = 7; | ||||
| } | ||||
| message SwitchStateResponse { | ||||
|   option (id) = 26; | ||||
| @@ -504,6 +534,7 @@ message ListEntitiesTextSensorResponse { | ||||
|   string unique_id = 4; | ||||
|  | ||||
|   string icon = 5; | ||||
|   bool disabled_by_default = 6; | ||||
| } | ||||
| message TextSensorStateResponse { | ||||
|   option (id) = 27; | ||||
| @@ -663,6 +694,7 @@ message ListEntitiesCameraResponse { | ||||
|   fixed32 key = 2; | ||||
|   string name = 3; | ||||
|   string unique_id = 4; | ||||
|   bool disabled_by_default = 5; | ||||
| } | ||||
|  | ||||
| message CameraImageResponse { | ||||
| @@ -755,6 +787,7 @@ message ListEntitiesClimateResponse { | ||||
|   repeated string supported_custom_fan_modes = 15; | ||||
|   repeated ClimatePreset supported_presets = 16; | ||||
|   repeated string supported_custom_presets = 17; | ||||
|   bool disabled_by_default = 18; | ||||
| } | ||||
| message ClimateStateResponse { | ||||
|   option (id) = 47; | ||||
| @@ -822,6 +855,7 @@ message ListEntitiesNumberResponse { | ||||
|   float min_value = 6; | ||||
|   float max_value = 7; | ||||
|   float step = 8; | ||||
|   bool disabled_by_default = 9; | ||||
| } | ||||
| message NumberStateResponse { | ||||
|   option (id) = 50; | ||||
| @@ -844,3 +878,40 @@ message NumberCommandRequest { | ||||
|   fixed32 key = 1; | ||||
|   float state = 2; | ||||
| } | ||||
|  | ||||
| // ==================== SELECT ==================== | ||||
| message ListEntitiesSelectResponse { | ||||
|   option (id) = 52; | ||||
|   option (source) = SOURCE_SERVER; | ||||
|   option (ifdef) = "USE_SELECT"; | ||||
|  | ||||
|   string object_id = 1; | ||||
|   fixed32 key = 2; | ||||
|   string name = 3; | ||||
|   string unique_id = 4; | ||||
|  | ||||
|   string icon = 5; | ||||
|   repeated string options = 6; | ||||
|   bool disabled_by_default = 7; | ||||
| } | ||||
| message SelectStateResponse { | ||||
|   option (id) = 53; | ||||
|   option (source) = SOURCE_SERVER; | ||||
|   option (ifdef) = "USE_SELECT"; | ||||
|   option (no_delay) = true; | ||||
|  | ||||
|   fixed32 key = 1; | ||||
|   string state = 2; | ||||
|   // If the select does not have a valid state yet. | ||||
|   // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller | ||||
|   bool missing_state = 3; | ||||
| } | ||||
| message SelectCommandRequest { | ||||
|   option (id) = 54; | ||||
|   option (source) = SOURCE_CLIENT; | ||||
|   option (ifdef) = "USE_SELECT"; | ||||
|   option (no_delay) = true; | ||||
|  | ||||
|   fixed32 key = 1; | ||||
|   string state = 2; | ||||
| } | ||||
|   | ||||
| @@ -176,6 +176,7 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_ | ||||
|   msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); | ||||
|   msg.device_class = binary_sensor->get_device_class(); | ||||
|   msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); | ||||
|   msg.disabled_by_default = binary_sensor->is_disabled_by_default(); | ||||
|   return this->send_list_entities_binary_sensor_response(msg); | ||||
| } | ||||
| #endif | ||||
| @@ -207,6 +208,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) { | ||||
|   msg.supports_position = traits.get_supports_position(); | ||||
|   msg.supports_tilt = traits.get_supports_tilt(); | ||||
|   msg.device_class = cover->get_device_class(); | ||||
|   msg.disabled_by_default = cover->is_disabled_by_default(); | ||||
|   return this->send_list_entities_cover_response(msg); | ||||
| } | ||||
| void APIConnection::cover_command(const CoverCommandRequest &msg) { | ||||
| @@ -268,6 +270,7 @@ bool APIConnection::send_fan_info(fan::FanState *fan) { | ||||
|   msg.supports_speed = traits.supports_speed(); | ||||
|   msg.supports_direction = traits.supports_direction(); | ||||
|   msg.supported_speed_count = traits.supported_speed_count(); | ||||
|   msg.disabled_by_default = fan->is_disabled_by_default(); | ||||
|   return this->send_list_entities_fan_response(msg); | ||||
| } | ||||
| void APIConnection::fan_command(const FanCommandRequest &msg) { | ||||
| @@ -301,22 +304,28 @@ bool APIConnection::send_light_state(light::LightState *light) { | ||||
|  | ||||
|   auto traits = light->get_traits(); | ||||
|   auto values = light->remote_values; | ||||
|   auto color_mode = values.get_color_mode(); | ||||
|   LightStateResponse resp{}; | ||||
|  | ||||
|   resp.key = light->get_object_id_hash(); | ||||
|   resp.state = values.is_on(); | ||||
|   if (traits.get_supports_brightness()) | ||||
|   resp.color_mode = static_cast<enums::ColorMode>(color_mode); | ||||
|   if (color_mode & light::ColorCapability::BRIGHTNESS) | ||||
|     resp.brightness = values.get_brightness(); | ||||
|   if (traits.get_supports_rgb()) { | ||||
|   if (color_mode & light::ColorCapability::RGB) { | ||||
|     resp.color_brightness = values.get_color_brightness(); | ||||
|     resp.red = values.get_red(); | ||||
|     resp.green = values.get_green(); | ||||
|     resp.blue = values.get_blue(); | ||||
|   } | ||||
|   if (traits.get_supports_rgb_white_value()) | ||||
|   if (color_mode & light::ColorCapability::WHITE) | ||||
|     resp.white = values.get_white(); | ||||
|   if (traits.get_supports_color_temperature()) | ||||
|   if (color_mode & light::ColorCapability::COLOR_TEMPERATURE) | ||||
|     resp.color_temperature = values.get_color_temperature(); | ||||
|   if (color_mode & light::ColorCapability::COLD_WARM_WHITE) { | ||||
|     resp.cold_white = values.get_cold_white(); | ||||
|     resp.warm_white = values.get_warm_white(); | ||||
|   } | ||||
|   if (light->supports_effects()) | ||||
|     resp.effect = light->get_effect_name(); | ||||
|   return this->send_light_state_response(resp); | ||||
| @@ -328,11 +337,21 @@ bool APIConnection::send_light_info(light::LightState *light) { | ||||
|   msg.object_id = light->get_object_id(); | ||||
|   msg.name = light->get_name(); | ||||
|   msg.unique_id = get_default_unique_id("light", light); | ||||
|   msg.supports_brightness = traits.get_supports_brightness(); | ||||
|   msg.supports_rgb = traits.get_supports_rgb(); | ||||
|   msg.supports_white_value = traits.get_supports_rgb_white_value(); | ||||
|   msg.supports_color_temperature = traits.get_supports_color_temperature(); | ||||
|   if (msg.supports_color_temperature) { | ||||
|  | ||||
|   msg.disabled_by_default = light->is_disabled_by_default(); | ||||
|  | ||||
|   for (auto mode : traits.get_supported_color_modes()) | ||||
|     msg.supported_color_modes.push_back(static_cast<enums::ColorMode>(mode)); | ||||
|  | ||||
|   msg.legacy_supports_brightness = traits.supports_color_capability(light::ColorCapability::BRIGHTNESS); | ||||
|   msg.legacy_supports_rgb = traits.supports_color_capability(light::ColorCapability::RGB); | ||||
|   msg.legacy_supports_white_value = | ||||
|       msg.legacy_supports_rgb && (traits.supports_color_capability(light::ColorCapability::WHITE) || | ||||
|                                   traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE)); | ||||
|   msg.legacy_supports_color_temperature = traits.supports_color_capability(light::ColorCapability::COLOR_TEMPERATURE) || | ||||
|                                           traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE); | ||||
|  | ||||
|   if (msg.legacy_supports_color_temperature) { | ||||
|     msg.min_mireds = traits.get_min_mireds(); | ||||
|     msg.max_mireds = traits.get_max_mireds(); | ||||
|   } | ||||
| @@ -353,6 +372,8 @@ void APIConnection::light_command(const LightCommandRequest &msg) { | ||||
|     call.set_state(msg.state); | ||||
|   if (msg.has_brightness) | ||||
|     call.set_brightness(msg.brightness); | ||||
|   if (msg.has_color_mode) | ||||
|     call.set_color_mode(static_cast<light::ColorMode>(msg.color_mode)); | ||||
|   if (msg.has_color_brightness) | ||||
|     call.set_color_brightness(msg.color_brightness); | ||||
|   if (msg.has_rgb) { | ||||
| @@ -364,6 +385,10 @@ void APIConnection::light_command(const LightCommandRequest &msg) { | ||||
|     call.set_white(msg.white); | ||||
|   if (msg.has_color_temperature) | ||||
|     call.set_color_temperature(msg.color_temperature); | ||||
|   if (msg.has_cold_white) | ||||
|     call.set_cold_white(msg.cold_white); | ||||
|   if (msg.has_warm_white) | ||||
|     call.set_warm_white(msg.warm_white); | ||||
|   if (msg.has_transition_length) | ||||
|     call.set_transition_length(msg.transition_length); | ||||
|   if (msg.has_flash_length) | ||||
| @@ -400,6 +425,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) { | ||||
|   msg.device_class = sensor->get_device_class(); | ||||
|   msg.state_class = static_cast<enums::SensorStateClass>(sensor->state_class); | ||||
|   msg.last_reset_type = static_cast<enums::SensorLastResetType>(sensor->last_reset_type); | ||||
|   msg.disabled_by_default = sensor->is_disabled_by_default(); | ||||
|  | ||||
|   return this->send_list_entities_sensor_response(msg); | ||||
| } | ||||
| @@ -423,6 +449,7 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) { | ||||
|   msg.unique_id = get_default_unique_id("switch", a_switch); | ||||
|   msg.icon = a_switch->get_icon(); | ||||
|   msg.assumed_state = a_switch->assumed_state(); | ||||
|   msg.disabled_by_default = a_switch->is_disabled_by_default(); | ||||
|   return this->send_list_entities_switch_response(msg); | ||||
| } | ||||
| void APIConnection::switch_command(const SwitchCommandRequest &msg) { | ||||
| @@ -457,6 +484,7 @@ bool APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) | ||||
|   if (msg.unique_id.empty()) | ||||
|     msg.unique_id = get_default_unique_id("text_sensor", text_sensor); | ||||
|   msg.icon = text_sensor->get_icon(); | ||||
|   msg.disabled_by_default = text_sensor->is_disabled_by_default(); | ||||
|   return this->send_list_entities_text_sensor_response(msg); | ||||
| } | ||||
| #endif | ||||
| @@ -500,6 +528,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) { | ||||
|   msg.object_id = climate->get_object_id(); | ||||
|   msg.name = climate->get_name(); | ||||
|   msg.unique_id = get_default_unique_id("climate", climate); | ||||
|  | ||||
|   msg.disabled_by_default = climate->is_disabled_by_default(); | ||||
|  | ||||
|   msg.supports_current_temperature = traits.get_supports_current_temperature(); | ||||
|   msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature(); | ||||
|  | ||||
| @@ -572,6 +603,7 @@ bool APIConnection::send_number_info(number::Number *number) { | ||||
|   msg.name = number->get_name(); | ||||
|   msg.unique_id = get_default_unique_id("number", number); | ||||
|   msg.icon = number->traits.get_icon(); | ||||
|   msg.disabled_by_default = number->is_disabled_by_default(); | ||||
|  | ||||
|   msg.min_value = number->traits.get_min_value(); | ||||
|   msg.max_value = number->traits.get_max_value(); | ||||
| @@ -590,6 +622,42 @@ void APIConnection::number_command(const NumberCommandRequest &msg) { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SELECT | ||||
| bool APIConnection::send_select_state(select::Select *select, std::string state) { | ||||
|   if (!this->state_subscription_) | ||||
|     return false; | ||||
|  | ||||
|   SelectStateResponse resp{}; | ||||
|   resp.key = select->get_object_id_hash(); | ||||
|   resp.state = std::move(state); | ||||
|   resp.missing_state = !select->has_state(); | ||||
|   return this->send_select_state_response(resp); | ||||
| } | ||||
| bool APIConnection::send_select_info(select::Select *select) { | ||||
|   ListEntitiesSelectResponse msg; | ||||
|   msg.key = select->get_object_id_hash(); | ||||
|   msg.object_id = select->get_object_id(); | ||||
|   msg.name = select->get_name(); | ||||
|   msg.unique_id = get_default_unique_id("select", select); | ||||
|   msg.icon = select->traits.get_icon(); | ||||
|   msg.disabled_by_default = select->is_disabled_by_default(); | ||||
|  | ||||
|   for (const auto &option : select->traits.get_options()) | ||||
|     msg.options.push_back(option); | ||||
|  | ||||
|   return this->send_list_entities_select_response(msg); | ||||
| } | ||||
| void APIConnection::select_command(const SelectCommandRequest &msg) { | ||||
|   select::Select *select = App.get_select_by_key(msg.key); | ||||
|   if (select == nullptr) | ||||
|     return; | ||||
|  | ||||
|   auto call = select->make_call(); | ||||
|   call.set_option(msg.state); | ||||
|   call.perform(); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_ESP32_CAMERA | ||||
| void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { | ||||
|   if (!this->state_subscription_) | ||||
| @@ -604,6 +672,7 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) { | ||||
|   msg.object_id = camera->get_object_id(); | ||||
|   msg.name = camera->get_name(); | ||||
|   msg.unique_id = get_default_unique_id("camera", camera); | ||||
|   msg.disabled_by_default = camera->is_disabled_by_default(); | ||||
|   return this->send_list_entities_camera_response(msg); | ||||
| } | ||||
| void APIConnection::camera_image(const CameraImageRequest &msg) { | ||||
| @@ -655,7 +724,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { | ||||
|  | ||||
|   HelloResponse resp; | ||||
|   resp.api_version_major = 1; | ||||
|   resp.api_version_minor = 5; | ||||
|   resp.api_version_minor = 6; | ||||
|   resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; | ||||
|   this->connection_state_ = ConnectionState::CONNECTED; | ||||
|   return resp; | ||||
|   | ||||
| @@ -67,6 +67,11 @@ class APIConnection : public APIServerConnection { | ||||
|   bool send_number_state(number::Number *number, float state); | ||||
|   bool send_number_info(number::Number *number); | ||||
|   void number_command(const NumberCommandRequest &msg) override; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   bool send_select_state(select::Select *select, std::string state); | ||||
|   bool send_select_info(select::Select *select); | ||||
|   void select_command(const SelectCommandRequest &msg) override; | ||||
| #endif | ||||
|   bool send_log_message(int level, const char *tag, const char *line); | ||||
|   void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -32,6 +32,18 @@ enum FanDirection : uint32_t { | ||||
|   FAN_DIRECTION_FORWARD = 0, | ||||
|   FAN_DIRECTION_REVERSE = 1, | ||||
| }; | ||||
| enum ColorMode : uint32_t { | ||||
|   COLOR_MODE_UNKNOWN = 0, | ||||
|   COLOR_MODE_ON_OFF = 1, | ||||
|   COLOR_MODE_BRIGHTNESS = 2, | ||||
|   COLOR_MODE_WHITE = 7, | ||||
|   COLOR_MODE_COLOR_TEMPERATURE = 11, | ||||
|   COLOR_MODE_COLD_WARM_WHITE = 19, | ||||
|   COLOR_MODE_RGB = 35, | ||||
|   COLOR_MODE_RGB_WHITE = 39, | ||||
|   COLOR_MODE_RGB_COLOR_TEMPERATURE = 47, | ||||
|   COLOR_MODE_RGB_COLD_WARM_WHITE = 51, | ||||
| }; | ||||
| enum SensorStateClass : uint32_t { | ||||
|   STATE_CLASS_NONE = 0, | ||||
|   STATE_CLASS_MEASUREMENT = 1, | ||||
| @@ -111,7 +123,9 @@ class HelloRequest : public ProtoMessage { | ||||
|  public: | ||||
|   std::string client_info{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -122,7 +136,9 @@ class HelloResponse : public ProtoMessage { | ||||
|   uint32_t api_version_minor{0}; | ||||
|   std::string server_info{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -132,7 +148,9 @@ class ConnectRequest : public ProtoMessage { | ||||
|  public: | ||||
|   std::string password{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -141,7 +159,9 @@ class ConnectResponse : public ProtoMessage { | ||||
|  public: | ||||
|   bool invalid_password{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| @@ -149,35 +169,45 @@ class ConnectResponse : public ProtoMessage { | ||||
| class DisconnectRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class DisconnectResponse : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class PingRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class PingResponse : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class DeviceInfoRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| @@ -193,7 +223,9 @@ class DeviceInfoResponse : public ProtoMessage { | ||||
|   std::string project_name{}; | ||||
|   std::string project_version{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -202,21 +234,27 @@ class DeviceInfoResponse : public ProtoMessage { | ||||
| class ListEntitiesRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class ListEntitiesDoneResponse : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| class SubscribeStatesRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| @@ -228,8 +266,11 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage { | ||||
|   std::string unique_id{}; | ||||
|   std::string device_class{}; | ||||
|   bool is_status_binary_sensor{false}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -242,7 +283,9 @@ class BinarySensorStateResponse : public ProtoMessage { | ||||
|   bool state{false}; | ||||
|   bool missing_state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -258,8 +301,11 @@ class ListEntitiesCoverResponse : public ProtoMessage { | ||||
|   bool supports_position{false}; | ||||
|   bool supports_tilt{false}; | ||||
|   std::string device_class{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -274,7 +320,9 @@ class CoverStateResponse : public ProtoMessage { | ||||
|   float tilt{0.0f}; | ||||
|   enums::CoverOperation current_operation{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -291,7 +339,9 @@ class CoverCommandRequest : public ProtoMessage { | ||||
|   float tilt{0.0f}; | ||||
|   bool stop{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -307,8 +357,11 @@ class ListEntitiesFanResponse : public ProtoMessage { | ||||
|   bool supports_speed{false}; | ||||
|   bool supports_direction{false}; | ||||
|   int32_t supported_speed_count{0}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -324,7 +377,9 @@ class FanStateResponse : public ProtoMessage { | ||||
|   enums::FanDirection direction{}; | ||||
|   int32_t speed_level{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -344,7 +399,9 @@ class FanCommandRequest : public ProtoMessage { | ||||
|   bool has_speed_level{false}; | ||||
|   int32_t speed_level{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -356,15 +413,19 @@ class ListEntitiesLightResponse : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   std::string name{}; | ||||
|   std::string unique_id{}; | ||||
|   bool supports_brightness{false}; | ||||
|   bool supports_rgb{false}; | ||||
|   bool supports_white_value{false}; | ||||
|   bool supports_color_temperature{false}; | ||||
|   std::vector<enums::ColorMode> supported_color_modes{}; | ||||
|   bool legacy_supports_brightness{false}; | ||||
|   bool legacy_supports_rgb{false}; | ||||
|   bool legacy_supports_white_value{false}; | ||||
|   bool legacy_supports_color_temperature{false}; | ||||
|   float min_mireds{0.0f}; | ||||
|   float max_mireds{0.0f}; | ||||
|   std::vector<std::string> effects{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -376,15 +437,20 @@ class LightStateResponse : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   bool state{false}; | ||||
|   float brightness{0.0f}; | ||||
|   enums::ColorMode color_mode{}; | ||||
|   float color_brightness{0.0f}; | ||||
|   float red{0.0f}; | ||||
|   float green{0.0f}; | ||||
|   float blue{0.0f}; | ||||
|   float white{0.0f}; | ||||
|   float color_temperature{0.0f}; | ||||
|   float cold_white{0.0f}; | ||||
|   float warm_white{0.0f}; | ||||
|   std::string effect{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -398,6 +464,8 @@ class LightCommandRequest : public ProtoMessage { | ||||
|   bool state{false}; | ||||
|   bool has_brightness{false}; | ||||
|   float brightness{0.0f}; | ||||
|   bool has_color_mode{false}; | ||||
|   enums::ColorMode color_mode{}; | ||||
|   bool has_color_brightness{false}; | ||||
|   float color_brightness{0.0f}; | ||||
|   bool has_rgb{false}; | ||||
| @@ -408,6 +476,10 @@ class LightCommandRequest : public ProtoMessage { | ||||
|   float white{0.0f}; | ||||
|   bool has_color_temperature{false}; | ||||
|   float color_temperature{0.0f}; | ||||
|   bool has_cold_white{false}; | ||||
|   float cold_white{0.0f}; | ||||
|   bool has_warm_white{false}; | ||||
|   float warm_white{0.0f}; | ||||
|   bool has_transition_length{false}; | ||||
|   uint32_t transition_length{0}; | ||||
|   bool has_flash_length{false}; | ||||
| @@ -415,7 +487,9 @@ class LightCommandRequest : public ProtoMessage { | ||||
|   bool has_effect{false}; | ||||
|   std::string effect{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -435,8 +509,11 @@ class ListEntitiesSensorResponse : public ProtoMessage { | ||||
|   std::string device_class{}; | ||||
|   enums::SensorStateClass state_class{}; | ||||
|   enums::SensorLastResetType last_reset_type{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -449,7 +526,9 @@ class SensorStateResponse : public ProtoMessage { | ||||
|   float state{0.0f}; | ||||
|   bool missing_state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -463,8 +542,11 @@ class ListEntitiesSwitchResponse : public ProtoMessage { | ||||
|   std::string unique_id{}; | ||||
|   std::string icon{}; | ||||
|   bool assumed_state{false}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -476,7 +558,9 @@ class SwitchStateResponse : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   bool state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -487,7 +571,9 @@ class SwitchCommandRequest : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   bool state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -500,12 +586,16 @@ class ListEntitiesTextSensorResponse : public ProtoMessage { | ||||
|   std::string name{}; | ||||
|   std::string unique_id{}; | ||||
|   std::string icon{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| }; | ||||
| class TextSensorStateResponse : public ProtoMessage { | ||||
|  public: | ||||
| @@ -513,7 +603,9 @@ class TextSensorStateResponse : public ProtoMessage { | ||||
|   std::string state{}; | ||||
|   bool missing_state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -525,7 +617,9 @@ class SubscribeLogsRequest : public ProtoMessage { | ||||
|   enums::LogLevel level{}; | ||||
|   bool dump_config{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| @@ -537,7 +631,9 @@ class SubscribeLogsResponse : public ProtoMessage { | ||||
|   std::string message{}; | ||||
|   bool send_failed{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -546,7 +642,9 @@ class SubscribeLogsResponse : public ProtoMessage { | ||||
| class SubscribeHomeassistantServicesRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| @@ -555,7 +653,9 @@ class HomeassistantServiceMap : public ProtoMessage { | ||||
|   std::string key{}; | ||||
|   std::string value{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -568,7 +668,9 @@ class HomeassistantServiceResponse : public ProtoMessage { | ||||
|   std::vector<HomeassistantServiceMap> variables{}; | ||||
|   bool is_event{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -577,7 +679,9 @@ class HomeassistantServiceResponse : public ProtoMessage { | ||||
| class SubscribeHomeAssistantStatesRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| @@ -586,7 +690,9 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { | ||||
|   std::string entity_id{}; | ||||
|   std::string attribute{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -597,7 +703,9 @@ class HomeAssistantStateResponse : public ProtoMessage { | ||||
|   std::string state{}; | ||||
|   std::string attribute{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -605,7 +713,9 @@ class HomeAssistantStateResponse : public ProtoMessage { | ||||
| class GetTimeRequest : public ProtoMessage { | ||||
|  public: | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| }; | ||||
| @@ -613,7 +723,9 @@ class GetTimeResponse : public ProtoMessage { | ||||
|  public: | ||||
|   uint32_t epoch_seconds{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -623,7 +735,9 @@ class ListEntitiesServicesArgument : public ProtoMessage { | ||||
|   std::string name{}; | ||||
|   enums::ServiceArgType type{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| @@ -635,7 +749,9 @@ class ListEntitiesServicesResponse : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   std::vector<ListEntitiesServicesArgument> args{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -653,7 +769,9 @@ class ExecuteServiceArgument : public ProtoMessage { | ||||
|   std::vector<float> float_array{}; | ||||
|   std::vector<std::string> string_array{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -665,7 +783,9 @@ class ExecuteServiceRequest : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   std::vector<ExecuteServiceArgument> args{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -677,12 +797,16 @@ class ListEntitiesCameraResponse : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   std::string name{}; | ||||
|   std::string unique_id{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| }; | ||||
| class CameraImageResponse : public ProtoMessage { | ||||
|  public: | ||||
| @@ -690,7 +814,9 @@ class CameraImageResponse : public ProtoMessage { | ||||
|   std::string data{}; | ||||
|   bool done{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -702,7 +828,9 @@ class CameraImageRequest : public ProtoMessage { | ||||
|   bool single{false}; | ||||
|   bool stream{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| @@ -726,8 +854,11 @@ class ListEntitiesClimateResponse : public ProtoMessage { | ||||
|   std::vector<std::string> supported_custom_fan_modes{}; | ||||
|   std::vector<enums::ClimatePreset> supported_presets{}; | ||||
|   std::vector<std::string> supported_custom_presets{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -750,7 +881,9 @@ class ClimateStateResponse : public ProtoMessage { | ||||
|   enums::ClimatePreset preset{}; | ||||
|   std::string custom_preset{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -781,7 +914,9 @@ class ClimateCommandRequest : public ProtoMessage { | ||||
|   bool has_custom_preset{false}; | ||||
|   std::string custom_preset{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -798,12 +933,16 @@ class ListEntitiesNumberResponse : public ProtoMessage { | ||||
|   float min_value{0.0f}; | ||||
|   float max_value{0.0f}; | ||||
|   float step{0.0f}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| }; | ||||
| class NumberStateResponse : public ProtoMessage { | ||||
|  public: | ||||
| @@ -811,7 +950,9 @@ class NumberStateResponse : public ProtoMessage { | ||||
|   float state{0.0f}; | ||||
|   bool missing_state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| @@ -822,11 +963,60 @@ class NumberCommandRequest : public ProtoMessage { | ||||
|   uint32_t key{0}; | ||||
|   float state{0.0f}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
| }; | ||||
| class ListEntitiesSelectResponse : public ProtoMessage { | ||||
|  public: | ||||
|   std::string object_id{}; | ||||
|   uint32_t key{0}; | ||||
|   std::string name{}; | ||||
|   std::string unique_id{}; | ||||
|   std::string icon{}; | ||||
|   std::vector<std::string> options{}; | ||||
|   bool disabled_by_default{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| }; | ||||
| class SelectStateResponse : public ProtoMessage { | ||||
|  public: | ||||
|   uint32_t key{0}; | ||||
|   std::string state{}; | ||||
|   bool missing_state{false}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||
| }; | ||||
| class SelectCommandRequest : public ProtoMessage { | ||||
|  public: | ||||
|   uint32_t key{0}; | ||||
|   std::string state{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace api | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -9,58 +9,82 @@ namespace api { | ||||
| static const char *const TAG = "api.service"; | ||||
|  | ||||
| bool APIServerConnectionBase::send_hello_response(const HelloResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_hello_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<HelloResponse>(msg, 2); | ||||
| } | ||||
| bool APIServerConnectionBase::send_connect_response(const ConnectResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_connect_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ConnectResponse>(msg, 4); | ||||
| } | ||||
| bool APIServerConnectionBase::send_disconnect_request(const DisconnectRequest &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_disconnect_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<DisconnectRequest>(msg, 5); | ||||
| } | ||||
| bool APIServerConnectionBase::send_disconnect_response(const DisconnectResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_disconnect_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<DisconnectResponse>(msg, 6); | ||||
| } | ||||
| bool APIServerConnectionBase::send_ping_request(const PingRequest &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_ping_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<PingRequest>(msg, 7); | ||||
| } | ||||
| bool APIServerConnectionBase::send_ping_response(const PingResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_ping_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<PingResponse>(msg, 8); | ||||
| } | ||||
| bool APIServerConnectionBase::send_device_info_response(const DeviceInfoResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_device_info_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<DeviceInfoResponse>(msg, 10); | ||||
| } | ||||
| bool APIServerConnectionBase::send_list_entities_done_response(const ListEntitiesDoneResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_done_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesDoneResponse>(msg, 19); | ||||
| } | ||||
| #ifdef USE_BINARY_SENSOR | ||||
| bool APIServerConnectionBase::send_list_entities_binary_sensor_response(const ListEntitiesBinarySensorResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_binary_sensor_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesBinarySensorResponse>(msg, 12); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_BINARY_SENSOR | ||||
| bool APIServerConnectionBase::send_binary_sensor_state_response(const BinarySensorStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_binary_sensor_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<BinarySensorStateResponse>(msg, 21); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_COVER | ||||
| bool APIServerConnectionBase::send_list_entities_cover_response(const ListEntitiesCoverResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_cover_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesCoverResponse>(msg, 13); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_COVER | ||||
| bool APIServerConnectionBase::send_cover_state_response(const CoverStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_cover_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<CoverStateResponse>(msg, 22); | ||||
| } | ||||
| #endif | ||||
| @@ -68,13 +92,17 @@ bool APIServerConnectionBase::send_cover_state_response(const CoverStateResponse | ||||
| #endif | ||||
| #ifdef USE_FAN | ||||
| bool APIServerConnectionBase::send_list_entities_fan_response(const ListEntitiesFanResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_fan_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesFanResponse>(msg, 14); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_FAN | ||||
| bool APIServerConnectionBase::send_fan_state_response(const FanStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_fan_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<FanStateResponse>(msg, 23); | ||||
| } | ||||
| #endif | ||||
| @@ -82,13 +110,17 @@ bool APIServerConnectionBase::send_fan_state_response(const FanStateResponse &ms | ||||
| #endif | ||||
| #ifdef USE_LIGHT | ||||
| bool APIServerConnectionBase::send_list_entities_light_response(const ListEntitiesLightResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_light_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesLightResponse>(msg, 15); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_LIGHT | ||||
| bool APIServerConnectionBase::send_light_state_response(const LightStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_light_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<LightStateResponse>(msg, 24); | ||||
| } | ||||
| #endif | ||||
| @@ -96,25 +128,33 @@ bool APIServerConnectionBase::send_light_state_response(const LightStateResponse | ||||
| #endif | ||||
| #ifdef USE_SENSOR | ||||
| bool APIServerConnectionBase::send_list_entities_sensor_response(const ListEntitiesSensorResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_sensor_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesSensorResponse>(msg, 16); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SENSOR | ||||
| bool APIServerConnectionBase::send_sensor_state_response(const SensorStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_sensor_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<SensorStateResponse>(msg, 25); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
| bool APIServerConnectionBase::send_list_entities_switch_response(const ListEntitiesSwitchResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_switch_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesSwitchResponse>(msg, 17); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
| bool APIServerConnectionBase::send_switch_state_response(const SwitchStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_switch_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<SwitchStateResponse>(msg, 26); | ||||
| } | ||||
| #endif | ||||
| @@ -122,13 +162,17 @@ bool APIServerConnectionBase::send_switch_state_response(const SwitchStateRespon | ||||
| #endif | ||||
| #ifdef USE_TEXT_SENSOR | ||||
| bool APIServerConnectionBase::send_list_entities_text_sensor_response(const ListEntitiesTextSensorResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_text_sensor_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesTextSensorResponse>(msg, 18); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_TEXT_SENSOR | ||||
| bool APIServerConnectionBase::send_text_sensor_state_response(const TextSensorStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_text_sensor_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<TextSensorStateResponse>(msg, 27); | ||||
| } | ||||
| #endif | ||||
| @@ -136,35 +180,49 @@ bool APIServerConnectionBase::send_subscribe_logs_response(const SubscribeLogsRe | ||||
|   return this->send_message_<SubscribeLogsResponse>(msg, 29); | ||||
| } | ||||
| bool APIServerConnectionBase::send_homeassistant_service_response(const HomeassistantServiceResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_homeassistant_service_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<HomeassistantServiceResponse>(msg, 35); | ||||
| } | ||||
| bool APIServerConnectionBase::send_subscribe_home_assistant_state_response( | ||||
|     const SubscribeHomeAssistantStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_subscribe_home_assistant_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<SubscribeHomeAssistantStateResponse>(msg, 39); | ||||
| } | ||||
| bool APIServerConnectionBase::send_get_time_request(const GetTimeRequest &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_get_time_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<GetTimeRequest>(msg, 36); | ||||
| } | ||||
| bool APIServerConnectionBase::send_get_time_response(const GetTimeResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_get_time_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<GetTimeResponse>(msg, 37); | ||||
| } | ||||
| bool APIServerConnectionBase::send_list_entities_services_response(const ListEntitiesServicesResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_services_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesServicesResponse>(msg, 41); | ||||
| } | ||||
| #ifdef USE_ESP32_CAMERA | ||||
| bool APIServerConnectionBase::send_list_entities_camera_response(const ListEntitiesCameraResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_camera_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesCameraResponse>(msg, 43); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_ESP32_CAMERA | ||||
| bool APIServerConnectionBase::send_camera_image_response(const CameraImageResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_camera_image_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<CameraImageResponse>(msg, 44); | ||||
| } | ||||
| #endif | ||||
| @@ -172,13 +230,17 @@ bool APIServerConnectionBase::send_camera_image_response(const CameraImageRespon | ||||
| #endif | ||||
| #ifdef USE_CLIMATE | ||||
| bool APIServerConnectionBase::send_list_entities_climate_response(const ListEntitiesClimateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_climate_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesClimateResponse>(msg, 46); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_CLIMATE | ||||
| bool APIServerConnectionBase::send_climate_state_response(const ClimateStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_climate_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ClimateStateResponse>(msg, 47); | ||||
| } | ||||
| #endif | ||||
| @@ -186,87 +248,129 @@ bool APIServerConnectionBase::send_climate_state_response(const ClimateStateResp | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
| bool APIServerConnectionBase::send_list_entities_number_response(const ListEntitiesNumberResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_number_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesNumberResponse>(msg, 49); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
| bool APIServerConnectionBase::send_number_state_response(const NumberStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_number_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<NumberStateResponse>(msg, 50); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| bool APIServerConnectionBase::send_list_entities_select_response(const ListEntitiesSelectResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_list_entities_select_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<ListEntitiesSelectResponse>(msg, 52); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| bool APIServerConnectionBase::send_select_state_response(const SelectStateResponse &msg) { | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   ESP_LOGVV(TAG, "send_select_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|   return this->send_message_<SelectStateResponse>(msg, 53); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| #endif | ||||
| bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { | ||||
|   switch (msg_type) { | ||||
|     case 1: { | ||||
|       HelloRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_hello_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_hello_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 3: { | ||||
|       ConnectRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_connect_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_connect_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 5: { | ||||
|       DisconnectRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_disconnect_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_disconnect_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 6: { | ||||
|       DisconnectResponse msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_disconnect_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_disconnect_response(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 7: { | ||||
|       PingRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_ping_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_ping_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 8: { | ||||
|       PingResponse msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_ping_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_ping_response(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 9: { | ||||
|       DeviceInfoRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_device_info_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_device_info_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 11: { | ||||
|       ListEntitiesRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_list_entities_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_list_entities_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 20: { | ||||
|       SubscribeStatesRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_subscribe_states_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_subscribe_states_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 28: { | ||||
|       SubscribeLogsRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_subscribe_logs_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_subscribe_logs_request(msg); | ||||
|       break; | ||||
|     } | ||||
| @@ -274,7 +378,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_COVER | ||||
|       CoverCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_cover_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_cover_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -283,7 +389,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_FAN | ||||
|       FanCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_fan_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_fan_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -292,7 +400,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_LIGHT | ||||
|       LightCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_light_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_light_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -301,7 +411,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_SWITCH | ||||
|       SwitchCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_switch_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_switch_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -309,42 +421,54 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
|     case 34: { | ||||
|       SubscribeHomeassistantServicesRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_subscribe_homeassistant_services_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_subscribe_homeassistant_services_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 36: { | ||||
|       GetTimeRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_get_time_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_get_time_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 37: { | ||||
|       GetTimeResponse msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_get_time_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_get_time_response(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 38: { | ||||
|       SubscribeHomeAssistantStatesRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_subscribe_home_assistant_states_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_subscribe_home_assistant_states_request(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 40: { | ||||
|       HomeAssistantStateResponse msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_home_assistant_state_response: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_home_assistant_state_response(msg); | ||||
|       break; | ||||
|     } | ||||
|     case 42: { | ||||
|       ExecuteServiceRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_execute_service_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_execute_service_request(msg); | ||||
|       break; | ||||
|     } | ||||
| @@ -352,7 +476,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_ESP32_CAMERA | ||||
|       CameraImageRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_camera_image_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_camera_image_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -361,7 +487,9 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_CLIMATE | ||||
|       ClimateCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_climate_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
| @@ -370,8 +498,21 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | ||||
| #ifdef USE_NUMBER | ||||
|       NumberCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_number_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
|     } | ||||
|     case 54: { | ||||
| #ifdef USE_SELECT | ||||
|       SelectCommandRequest msg; | ||||
|       msg.decode(msg_data, msg_size); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|       ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str()); | ||||
| #endif | ||||
|       this->on_select_command_request(msg); | ||||
| #endif | ||||
|       break; | ||||
|     } | ||||
| @@ -583,6 +724,19 @@ void APIServerConnection::on_number_command_request(const NumberCommandRequest & | ||||
|   this->number_command(msg); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| void APIServerConnection::on_select_command_request(const SelectCommandRequest &msg) { | ||||
|   if (!this->is_connection_setup()) { | ||||
|     this->on_no_setup_connection(); | ||||
|     return; | ||||
|   } | ||||
|   if (!this->is_authenticated()) { | ||||
|     this->on_unauthenticated_access(); | ||||
|     return; | ||||
|   } | ||||
|   this->select_command(msg); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| }  // namespace api | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -120,6 +120,15 @@ class APIServerConnectionBase : public ProtoService { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   virtual void on_number_command_request(const NumberCommandRequest &value){}; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   bool send_list_entities_select_response(const ListEntitiesSelectResponse &msg); | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   bool send_select_state_response(const SelectStateResponse &msg); | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   virtual void on_select_command_request(const SelectCommandRequest &value){}; | ||||
| #endif | ||||
|  protected: | ||||
|   bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; | ||||
| @@ -159,6 +168,9 @@ class APIServerConnection : public APIServerConnectionBase { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   virtual void number_command(const NumberCommandRequest &msg) = 0; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   virtual void select_command(const SelectCommandRequest &msg) = 0; | ||||
| #endif | ||||
|  protected: | ||||
|   void on_hello_request(const HelloRequest &msg) override; | ||||
| @@ -194,6 +206,9 @@ class APIServerConnection : public APIServerConnectionBase { | ||||
| #ifdef USE_NUMBER | ||||
|   void on_number_command_request(const NumberCommandRequest &msg) override; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   void on_select_command_request(const SelectCommandRequest &msg) override; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| }  // namespace api | ||||
|   | ||||
| @@ -206,6 +206,15 @@ void APIServer::on_number_update(number::Number *obj, float state) { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SELECT | ||||
| void APIServer::on_select_update(select::Select *obj, const std::string &state) { | ||||
|   if (obj->is_internal()) | ||||
|     return; | ||||
|   for (auto *c : this->clients_) | ||||
|     c->send_select_state(obj, state); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } | ||||
| void APIServer::set_port(uint16_t port) { this->port_ = port; } | ||||
| APIServer *global_api_server = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| #include "util.h" | ||||
| #include "list_entities.h" | ||||
| #include "subscribe_state.h" | ||||
| #include "homeassistant_service.h" | ||||
| #include "user_services.h" | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
| @@ -63,6 +62,9 @@ class APIServer : public Component, public Controller { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   void on_number_update(number::Number *obj, float state) override; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   void on_select_update(select::Select *obj, const std::string &state) override; | ||||
| #endif | ||||
|   void send_homeassistant_service_call(const HomeassistantServiceResponse &call); | ||||
|   void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } | ||||
|   | ||||
| @@ -55,5 +55,9 @@ bool ListEntitiesIterator::on_climate(climate::Climate *climate) { return this-> | ||||
| bool ListEntitiesIterator::on_number(number::Number *number) { return this->client_->send_number_info(number); } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SELECT | ||||
| bool ListEntitiesIterator::on_select(select::Select *select) { return this->client_->send_select_info(select); } | ||||
| #endif | ||||
|  | ||||
| }  // namespace api | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -42,6 +42,9 @@ class ListEntitiesIterator : public ComponentIterator { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   bool on_number(number::Number *number) override; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   bool on_select(select::Select *select) override; | ||||
| #endif | ||||
|   bool on_end() override; | ||||
|  | ||||
|   | ||||
| @@ -80,11 +80,13 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
| std::string ProtoMessage::dump() const { | ||||
|   std::string out; | ||||
|   this->dump_to(out); | ||||
|   return out; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| }  // namespace api | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -1,8 +1,13 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||
| #define HAS_PROTO_MESSAGE_DUMP | ||||
| #endif | ||||
|  | ||||
| namespace esphome { | ||||
| namespace api { | ||||
|  | ||||
| @@ -243,8 +248,10 @@ class ProtoMessage { | ||||
|  public: | ||||
|   virtual void encode(ProtoWriteBuffer buffer) const = 0; | ||||
|   void decode(const uint8_t *buffer, size_t length); | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   std::string dump() const; | ||||
|   virtual void dump_to(std::string &out) const = 0; | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   virtual bool decode_varint(uint32_t field_id, ProtoVarInt value) { return false; } | ||||
|   | ||||
| @@ -42,6 +42,11 @@ bool InitialStateIterator::on_number(number::Number *number) { | ||||
|   return this->client_->send_number_state(number, number->state); | ||||
| } | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| bool InitialStateIterator::on_select(select::Select *select) { | ||||
|   return this->client_->send_select_state(select, select->state); | ||||
| } | ||||
| #endif | ||||
| InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client) | ||||
|     : ComponentIterator(server), client_(client) {} | ||||
|  | ||||
|   | ||||
| @@ -39,6 +39,9 @@ class InitialStateIterator : public ComponentIterator { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   bool on_number(number::Number *number) override; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   bool on_select(select::Select *select) override; | ||||
| #endif | ||||
|  protected: | ||||
|   APIConnection *client_; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ template<> std::string get_execute_arg_value<std::string>(const ExecuteServiceAr | ||||
| template<> std::vector<bool> get_execute_arg_value<std::vector<bool>>(const ExecuteServiceArgument &arg) { | ||||
|   return arg.bool_array; | ||||
| } | ||||
| template<> std::vector<int> get_execute_arg_value<std::vector<int>>(const ExecuteServiceArgument &arg) { | ||||
| template<> std::vector<int32_t> get_execute_arg_value<std::vector<int32_t>>(const ExecuteServiceArgument &arg) { | ||||
|   return arg.int_array; | ||||
| } | ||||
| template<> std::vector<float> get_execute_arg_value<std::vector<float>>(const ExecuteServiceArgument &arg) { | ||||
|   | ||||
| @@ -182,6 +182,21 @@ void ComponentIterator::advance() { | ||||
|         } | ||||
|       } | ||||
|       break; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|     case IteratorState::SELECT: | ||||
|       if (this->at_ >= App.get_selects().size()) { | ||||
|         advance_platform = true; | ||||
|       } else { | ||||
|         auto *select = App.get_selects()[this->at_]; | ||||
|         if (select->is_internal()) { | ||||
|           success = true; | ||||
|           break; | ||||
|         } else { | ||||
|           success = this->on_select(select); | ||||
|         } | ||||
|       } | ||||
|       break; | ||||
| #endif | ||||
|     case IteratorState::MAX: | ||||
|       if (this->on_end()) { | ||||
|   | ||||
| @@ -50,6 +50,9 @@ class ComponentIterator { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   virtual bool on_number(number::Number *number) = 0; | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   virtual bool on_select(select::Select *select) = 0; | ||||
| #endif | ||||
|   virtual bool on_end(); | ||||
|  | ||||
| @@ -87,6 +90,9 @@ class ComponentIterator { | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|     NUMBER, | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|     SELECT, | ||||
| #endif | ||||
|     MAX, | ||||
|   } state_{IteratorState::NONE}; | ||||
|   | ||||
| @@ -4,10 +4,8 @@ from esphome.components import sensor | ||||
| from esphome.const import ( | ||||
|     CONF_DISTANCE, | ||||
|     CONF_LIGHTNING_ENERGY, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     STATE_CLASS_NONE, | ||||
|     UNIT_KILOMETER, | ||||
|     UNIT_EMPTY, | ||||
|     ICON_SIGNAL_DISTANCE_VARIANT, | ||||
|     ICON_FLASH, | ||||
| ) | ||||
| @@ -19,14 +17,15 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935), | ||||
|         cv.Optional(CONF_DISTANCE): sensor.sensor_schema( | ||||
|             UNIT_KILOMETER, | ||||
|             ICON_SIGNAL_DISTANCE_VARIANT, | ||||
|             1, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_NONE, | ||||
|             unit_of_measurement=UNIT_KILOMETER, | ||||
|             icon=ICON_SIGNAL_DISTANCE_VARIANT, | ||||
|             accuracy_decimals=1, | ||||
|             state_class=STATE_CLASS_NONE, | ||||
|         ), | ||||
|         cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|             icon=ICON_FLASH, | ||||
|             accuracy_decimals=1, | ||||
|             state_class=STATE_CLASS_NONE, | ||||
|         ), | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|   | ||||
| @@ -12,7 +12,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PERCENT, | ||||
| @@ -34,28 +33,28 @@ CONFIG_SCHEMA = ( | ||||
|             cv.GenerateID(): cv.declare_id(ATCMiThermometer), | ||||
|             cv.Required(CONF_MAC_ADDRESS): cv.mac_address, | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 0, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 0, | ||||
|                 DEVICE_CLASS_BATTERY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_BATTERY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( | ||||
|                 UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_VOLT, | ||||
|                 accuracy_decimals=3, | ||||
|                 device_class=DEVICE_CLASS_VOLTAGE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -39,7 +39,7 @@ static const uint16_t ATM90E32_STATUS_S0_OVPHASEBST = 1 << 11;  // Over voltage | ||||
| static const uint16_t ATM90E32_STATUS_S0_OVPHASECST = 1 << 10;  // Over voltage on phase C | ||||
| static const uint16_t ATM90E32_STATUS_S0_UREVWNST = 1 << 9;     // Voltage Phase Sequence Error status | ||||
| static const uint16_t ATM90E32_STATUS_S0_IREVWNST = 1 << 8;     // Current Phase Sequence Error status | ||||
| static const uint16_t ATM90E32_STATUS_S0_INOV0ST = 1 << 7;      // Calculated N line current greater tha INWarnTh reg | ||||
| static const uint16_t ATM90E32_STATUS_S0_INOV0ST = 1 << 7;      // Calculated N line current greater than INWarnTh reg | ||||
| static const uint16_t ATM90E32_STATUS_S0_TQNOLOADST = 1 << 6;   // All phase sum reactive power no-load condition status | ||||
| static const uint16_t ATM90E32_STATUS_S0_TPNOLOADST = 1 << 5;   // All phase sum active power no-load condition status | ||||
| static const uint16_t ATM90E32_STATUS_S0_TASNOLOADST = 1 << 4;  // All phase sum apparent power no-load status | ||||
|   | ||||
| @@ -12,13 +12,11 @@ from esphome.const import ( | ||||
|     CONF_FORWARD_ACTIVE_ENERGY, | ||||
|     CONF_REVERSE_ACTIVE_ENERGY, | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_ENERGY, | ||||
|     DEVICE_CLASS_POWER, | ||||
|     DEVICE_CLASS_POWER_FACTOR, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     ICON_LIGHTBULB, | ||||
|     ICON_CURRENT_AC, | ||||
|     LAST_RESET_TYPE_AUTO, | ||||
| @@ -27,7 +25,6 @@ from esphome.const import ( | ||||
|     UNIT_VOLT, | ||||
|     UNIT_AMPERE, | ||||
|     UNIT_WATT, | ||||
|     UNIT_EMPTY, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_VOLT_AMPS_REACTIVE, | ||||
|     UNIT_WATT_HOURS, | ||||
| @@ -65,47 +62,47 @@ ATM90E32Component = atm90e32_ns.class_( | ||||
| ATM90E32_PHASE_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( | ||||
|             UNIT_VOLT, | ||||
|             ICON_EMPTY, | ||||
|             2, | ||||
|             DEVICE_CLASS_VOLTAGE, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_VOLT, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_VOLTAGE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_CURRENT): sensor.sensor_schema( | ||||
|             UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT | ||||
|             unit_of_measurement=UNIT_AMPERE, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_CURRENT, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_POWER): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|             unit_of_measurement=UNIT_WATT, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_POWER, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema( | ||||
|             UNIT_VOLT_AMPS_REACTIVE, | ||||
|             ICON_LIGHTBULB, | ||||
|             2, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE, | ||||
|             icon=ICON_LIGHTBULB, | ||||
|             accuracy_decimals=2, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, | ||||
|             ICON_EMPTY, | ||||
|             2, | ||||
|             DEVICE_CLASS_POWER_FACTOR, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_POWER_FACTOR, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema( | ||||
|             UNIT_WATT_HOURS, | ||||
|             ICON_EMPTY, | ||||
|             2, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_AUTO, | ||||
|             unit_of_measurement=UNIT_WATT_HOURS, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_ENERGY, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|             last_reset_type=LAST_RESET_TYPE_AUTO, | ||||
|         ), | ||||
|         cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema( | ||||
|             UNIT_WATT_HOURS, | ||||
|             ICON_EMPTY, | ||||
|             2, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_AUTO, | ||||
|             unit_of_measurement=UNIT_WATT_HOURS, | ||||
|             accuracy_decimals=2, | ||||
|             device_class=DEVICE_CLASS_ENERGY, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|             last_reset_type=LAST_RESET_TYPE_AUTO, | ||||
|         ), | ||||
|         cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t, | ||||
|         cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t, | ||||
| @@ -120,18 +117,16 @@ CONFIG_SCHEMA = ( | ||||
|             cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA, | ||||
|             cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA, | ||||
|             cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( | ||||
|                 UNIT_HERTZ, | ||||
|                 ICON_CURRENT_AC, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_EMPTY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_HERTZ, | ||||
|                 icon=ICON_CURRENT_AC, | ||||
|                 accuracy_decimals=1, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True), | ||||
|             cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum( | ||||
|   | ||||
| @@ -47,7 +47,7 @@ bool BParasite::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { | ||||
|   uint16_t battery_millivolt = data[2] << 8 | data[3]; | ||||
|   float battery_voltage = battery_millivolt / 1000.0f; | ||||
|  | ||||
|   // Temperature in 1000 * Celcius. | ||||
|   // Temperature in 1000 * Celsius. | ||||
|   uint16_t temp_millicelcius = data[4] << 8 | data[5]; | ||||
|   float temp_celcius = temp_millicelcius / 1000.0f; | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PERCENT, | ||||
| @@ -33,28 +32,28 @@ CONFIG_SCHEMA = ( | ||||
|             cv.GenerateID(): cv.declare_id(BParasite), | ||||
|             cv.Required(CONF_MAC_ADDRESS): cv.mac_address, | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( | ||||
|                 UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_VOLT, | ||||
|                 accuracy_decimals=3, | ||||
|                 device_class=DEVICE_CLASS_VOLTAGE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_MOISTURE): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -5,7 +5,6 @@ from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_RESOLUTION, | ||||
|     DEVICE_CLASS_ILLUMINANCE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_LUX, | ||||
|     CONF_MEASUREMENT_DURATION, | ||||
| @@ -28,7 +27,10 @@ BH1750Sensor = bh1750_ns.class_( | ||||
| CONF_MEASUREMENT_TIME = "measurement_time" | ||||
| CONFIG_SCHEMA = ( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_LUX, | ||||
|         accuracy_decimals=1, | ||||
|         device_class=DEVICE_CLASS_ILLUMINANCE, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -12,7 +12,7 @@ class BinaryLightOutput : public light::LightOutput { | ||||
|   void set_output(output::BinaryOutput *output) { output_ = output; } | ||||
|   light::LightTraits get_traits() override { | ||||
|     auto traits = light::LightTraits(); | ||||
|     traits.set_supports_brightness(false); | ||||
|     traits.set_supported_color_modes({light::ColorMode::ON_OFF}); | ||||
|     return traits; | ||||
|   } | ||||
|   void write_state(light::LightState *state) override { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ from esphome.components import mqtt | ||||
| from esphome.const import ( | ||||
|     CONF_DELAY, | ||||
|     CONF_DEVICE_CLASS, | ||||
|     CONF_DISABLED_BY_DEFAULT, | ||||
|     CONF_FILTERS, | ||||
|     CONF_ID, | ||||
|     CONF_INTERNAL, | ||||
| @@ -315,7 +316,7 @@ def validate_multi_click_timing(value): | ||||
|  | ||||
| device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") | ||||
|  | ||||
| BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( | ||||
| BINARY_SENSOR_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(BinarySensor), | ||||
|         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id( | ||||
| @@ -377,6 +378,7 @@ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( | ||||
|  | ||||
| async def setup_binary_sensor_core_(var, config): | ||||
|     cg.add(var.set_name(config[CONF_NAME])) | ||||
|     cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT])) | ||||
|     if CONF_INTERNAL in config: | ||||
|         cg.add(var.set_internal(config[CONF_INTERNAL])) | ||||
|     if CONF_DEVICE_CLASS in config: | ||||
|   | ||||
| @@ -7,8 +7,6 @@ from esphome.const import ( | ||||
|     CONF_CHANNELS, | ||||
|     CONF_VALUE, | ||||
|     CONF_TYPE, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     UNIT_EMPTY, | ||||
|     ICON_CHECK_CIRCLE_OUTLINE, | ||||
|     CONF_BINARY_SENSOR, | ||||
|     CONF_GROUP, | ||||
| @@ -35,11 +33,9 @@ entry = { | ||||
| CONFIG_SCHEMA = cv.typed_schema( | ||||
|     { | ||||
|         CONF_GROUP: sensor.sensor_schema( | ||||
|             UNIT_EMPTY, | ||||
|             ICON_CHECK_CIRCLE_OUTLINE, | ||||
|             0, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_NONE, | ||||
|             icon=ICON_CHECK_CIRCLE_OUTLINE, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_NONE, | ||||
|         ).extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(BinarySensorMap), | ||||
|   | ||||
| @@ -25,7 +25,7 @@ class BLEClientNode { | ||||
|  public: | ||||
|   virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||
|                                    esp_ble_gattc_cb_param_t *param) = 0; | ||||
|   virtual void loop() = 0; | ||||
|   virtual void loop(){}; | ||||
|   void set_address(uint64_t address) { address_ = address; } | ||||
|   espbt::ESPBTClient *client; | ||||
|   // This should be transitioned to Established once the node no longer needs | ||||
|   | ||||
| @@ -2,12 +2,9 @@ import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor, ble_client, esp32_ble_tracker | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     CONF_ID, | ||||
|     CONF_LAMBDA, | ||||
|     STATE_CLASS_NONE, | ||||
|     UNIT_EMPTY, | ||||
|     ICON_EMPTY, | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_SERVICE_UUID, | ||||
| ) | ||||
| @@ -34,7 +31,8 @@ BLESensorNotifyTrigger = ble_client_ns.class_( | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         accuracy_decimals=0, | ||||
|         state_class=STATE_CLASS_NONE, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -8,7 +8,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_DECIBEL, | ||||
|     ICON_EMPTY, | ||||
| ) | ||||
|  | ||||
| DEPENDENCIES = ["esp32_ble_tracker"] | ||||
| @@ -20,11 +19,10 @@ BLERSSISensor = ble_rssi_ns.class_( | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_DECIBEL, | ||||
|         ICON_EMPTY, | ||||
|         0, | ||||
|         DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|         STATE_CLASS_MEASUREMENT, | ||||
|         unit_of_measurement=UNIT_DECIBEL, | ||||
|         accuracy_decimals=0, | ||||
|         device_class=DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -11,7 +11,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_PRESSURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_HECTOPASCAL, | ||||
| @@ -49,11 +48,10 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(BME280Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -62,11 +60,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|                 UNIT_HECTOPASCAL, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_PRESSURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_PRESSURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -75,11 +72,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
|   | ||||
| @@ -12,7 +12,6 @@ from esphome.const import ( | ||||
|     CONF_OVERSAMPLING, | ||||
|     CONF_PRESSURE, | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_PRESSURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
| @@ -20,7 +19,6 @@ from esphome.const import ( | ||||
|     UNIT_OHM, | ||||
|     ICON_GAS_CYLINDER, | ||||
|     UNIT_CELSIUS, | ||||
|     ICON_EMPTY, | ||||
|     UNIT_HECTOPASCAL, | ||||
|     UNIT_PERCENT, | ||||
| ) | ||||
| @@ -59,11 +57,10 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(BME680Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -72,11 +69,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|                 UNIT_HECTOPASCAL, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_PRESSURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_PRESSURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -85,11 +81,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -98,11 +93,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( | ||||
|                 UNIT_OHM, | ||||
|                 ICON_GAS_CYLINDER, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_EMPTY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_OHM, | ||||
|                 icon=ICON_GAS_CYLINDER, | ||||
|                 accuracy_decimals=1, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( | ||||
|                 IIR_FILTER_OPTIONS, upper=True | ||||
|   | ||||
| @@ -6,13 +6,11 @@ from esphome.const import ( | ||||
|     CONF_HUMIDITY, | ||||
|     CONF_PRESSURE, | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_PRESSURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_EMPTY, | ||||
|     UNIT_HECTOPASCAL, | ||||
|     UNIT_OHM, | ||||
|     UNIT_PARTS_PER_MILLION, | ||||
| @@ -54,54 +52,60 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), | ||||
|         cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|             UNIT_CELSIUS, | ||||
|             ICON_THERMOMETER, | ||||
|             1, | ||||
|             DEVICE_CLASS_TEMPERATURE, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_CELSIUS, | ||||
|             icon=ICON_THERMOMETER, | ||||
|             accuracy_decimals=1, | ||||
|             device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ).extend( | ||||
|             {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} | ||||
|         ), | ||||
|         cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|             UNIT_HECTOPASCAL, | ||||
|             ICON_GAUGE, | ||||
|             1, | ||||
|             DEVICE_CLASS_PRESSURE, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_HECTOPASCAL, | ||||
|             icon=ICON_GAUGE, | ||||
|             accuracy_decimals=1, | ||||
|             device_class=DEVICE_CLASS_PRESSURE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ).extend( | ||||
|             {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} | ||||
|         ), | ||||
|         cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|             UNIT_PERCENT, | ||||
|             ICON_WATER_PERCENT, | ||||
|             1, | ||||
|             DEVICE_CLASS_HUMIDITY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_PERCENT, | ||||
|             icon=ICON_WATER_PERCENT, | ||||
|             accuracy_decimals=1, | ||||
|             device_class=DEVICE_CLASS_HUMIDITY, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ).extend( | ||||
|             {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} | ||||
|         ), | ||||
|         cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( | ||||
|             UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|             unit_of_measurement=UNIT_OHM, | ||||
|             icon=ICON_GAS_CYLINDER, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_IAQ): sensor.sensor_schema( | ||||
|             UNIT_IAQ, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|             unit_of_measurement=UNIT_IAQ, | ||||
|             icon=ICON_GAUGE, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_IAQ_ACCURACY): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_ACCURACY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|             icon=ICON_ACCURACY, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema( | ||||
|             UNIT_PARTS_PER_MILLION, | ||||
|             ICON_TEST_TUBE, | ||||
|             1, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||
|             icon=ICON_TEST_TUBE, | ||||
|             accuracy_decimals=1, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema( | ||||
|             UNIT_PARTS_PER_MILLION, | ||||
|             ICON_TEST_TUBE, | ||||
|             1, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||
|             icon=ICON_TEST_TUBE, | ||||
|             accuracy_decimals=1, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|     } | ||||
| ) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     ICON_EMPTY, | ||||
|     UNIT_HECTOPASCAL, | ||||
| ) | ||||
|  | ||||
| @@ -25,18 +24,16 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(BMP085Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|                 UNIT_HECTOPASCAL, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_PRESSURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_PRESSURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     ICON_EMPTY, | ||||
|     UNIT_HECTOPASCAL, | ||||
|     CONF_IIR_FILTER, | ||||
|     CONF_OVERSAMPLING, | ||||
| @@ -46,11 +45,10 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(BMP280Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
| @@ -59,11 +57,10 @@ CONFIG_SCHEMA = ( | ||||
|                 } | ||||
|             ), | ||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||
|                 UNIT_HECTOPASCAL, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_PRESSURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_PRESSURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( | ||||
|   | ||||
| @@ -3,7 +3,6 @@ import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     ICON_RADIATOR, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_PARTS_PER_MILLION, | ||||
| @@ -28,18 +27,16 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(CCS811Component), | ||||
|             cv.Required(CONF_ECO2): sensor.sensor_schema( | ||||
|                 UNIT_PARTS_PER_MILLION, | ||||
|                 ICON_MOLECULE_CO2, | ||||
|                 0, | ||||
|                 DEVICE_CLASS_EMPTY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||
|                 icon=ICON_MOLECULE_CO2, | ||||
|                 accuracy_decimals=0, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Required(CONF_TVOC): sensor.sensor_schema( | ||||
|                 UNIT_PARTS_PER_BILLION, | ||||
|                 ICON_RADIATOR, | ||||
|                 0, | ||||
|                 DEVICE_CLASS_EMPTY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PARTS_PER_BILLION, | ||||
|                 icon=ICON_RADIATOR, | ||||
|                 accuracy_decimals=0, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_BASELINE): cv.hex_uint16_t, | ||||
|             cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), | ||||
|   | ||||
| @@ -6,6 +6,7 @@ from esphome.const import ( | ||||
|     CONF_AWAY, | ||||
|     CONF_CUSTOM_FAN_MODE, | ||||
|     CONF_CUSTOM_PRESET, | ||||
|     CONF_DISABLED_BY_DEFAULT, | ||||
|     CONF_ID, | ||||
|     CONF_INTERNAL, | ||||
|     CONF_MAX_TEMPERATURE, | ||||
| @@ -86,7 +87,7 @@ validate_climate_swing_mode = cv.enum(CLIMATE_SWING_MODES, upper=True) | ||||
| # Actions | ||||
| ControlAction = climate_ns.class_("ControlAction", automation.Action) | ||||
|  | ||||
| CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( | ||||
| CLIMATE_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(Climate), | ||||
|         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent), | ||||
| @@ -104,6 +105,7 @@ CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( | ||||
|  | ||||
| async def setup_climate_core_(var, config): | ||||
|     cg.add(var.set_name(config[CONF_NAME])) | ||||
|     cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT])) | ||||
|     if CONF_INTERNAL in config: | ||||
|         cg.add(var.set_internal(config[CONF_INTERNAL])) | ||||
|     visual = config[CONF_VISUAL] | ||||
|   | ||||
| @@ -63,9 +63,9 @@ class ClimateCall { | ||||
|    * For climate devices with two point target temperature control | ||||
|    */ | ||||
|   ClimateCall &set_target_temperature_high(optional<float> target_temperature_high); | ||||
|   ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead") | ||||
|   ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead", "v1.20") | ||||
|   ClimateCall &set_away(bool away); | ||||
|   ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead") | ||||
|   ESPDEPRECATED("set_away() is deprecated, please use .set_preset(CLIMATE_PRESET_AWAY) instead", "v1.20") | ||||
|   ClimateCall &set_away(optional<bool> away); | ||||
|   /// Set the fan mode of the climate device. | ||||
|   ClimateCall &set_fan_mode(ClimateFanMode fan_mode); | ||||
| @@ -96,7 +96,7 @@ class ClimateCall { | ||||
|   const optional<float> &get_target_temperature() const; | ||||
|   const optional<float> &get_target_temperature_low() const; | ||||
|   const optional<float> &get_target_temperature_high() const; | ||||
|   ESPDEPRECATED("get_away() is deprecated, please use .get_preset() instead") | ||||
|   ESPDEPRECATED("get_away() is deprecated, please use .get_preset() instead", "v1.20") | ||||
|   optional<bool> get_away() const; | ||||
|   const optional<ClimateFanMode> &get_fan_mode() const; | ||||
|   const optional<ClimateSwingMode> &get_swing_mode() const; | ||||
| @@ -193,7 +193,7 @@ class Climate : public Nameable { | ||||
|    * Away allows climate devices to have two different target temperature configs: | ||||
|    * one for normal mode and one for away mode. | ||||
|    */ | ||||
|   ESPDEPRECATED("away is deprecated, use preset instead") | ||||
|   ESPDEPRECATED("away is deprecated, use preset instead", "v1.20") | ||||
|   bool away{false}; | ||||
|  | ||||
|   /// The active fan mode of the climate device. | ||||
|   | ||||
| @@ -50,19 +50,19 @@ class ClimateTraits { | ||||
|   } | ||||
|   void set_supported_modes(std::set<ClimateMode> modes) { supported_modes_ = std::move(modes); } | ||||
|   void add_supported_mode(ClimateMode mode) { supported_modes_.insert(mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_auto_mode(bool supports_auto_mode) { set_mode_support_(CLIMATE_MODE_AUTO, supports_auto_mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_cool_mode(bool supports_cool_mode) { set_mode_support_(CLIMATE_MODE_COOL, supports_cool_mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_heat_mode(bool supports_heat_mode) { set_mode_support_(CLIMATE_MODE_HEAT, supports_heat_mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_heat_cool_mode(bool supported) { set_mode_support_(CLIMATE_MODE_HEAT_COOL, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_fan_only_mode(bool supports_fan_only_mode) { | ||||
|     set_mode_support_(CLIMATE_MODE_FAN_ONLY, supports_fan_only_mode); | ||||
|   } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||
|   void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } | ||||
|   bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } | ||||
|   const std::set<ClimateMode> get_supported_modes() const { return supported_modes_; } | ||||
| @@ -72,23 +72,23 @@ class ClimateTraits { | ||||
|  | ||||
|   void set_supported_fan_modes(std::set<ClimateFanMode> modes) { supported_fan_modes_ = std::move(modes); } | ||||
|   void add_supported_fan_mode(ClimateFanMode mode) { supported_fan_modes_.insert(mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_on(bool supported) { set_fan_mode_support_(CLIMATE_FAN_ON, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_off(bool supported) { set_fan_mode_support_(CLIMATE_FAN_OFF, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_auto(bool supported) { set_fan_mode_support_(CLIMATE_FAN_AUTO, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_low(bool supported) { set_fan_mode_support_(CLIMATE_FAN_LOW, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_medium(bool supported) { set_fan_mode_support_(CLIMATE_FAN_MEDIUM, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_high(bool supported) { set_fan_mode_support_(CLIMATE_FAN_HIGH, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_middle(bool supported) { set_fan_mode_support_(CLIMATE_FAN_MIDDLE, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_focus(bool supported) { set_fan_mode_support_(CLIMATE_FAN_FOCUS, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_fan_modes() instead", "v1.20") | ||||
|   void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } | ||||
|   bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } | ||||
|   bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } | ||||
| @@ -115,25 +115,25 @@ class ClimateTraits { | ||||
|   bool supports_custom_preset(const std::string &custom_preset) const { | ||||
|     return supported_custom_presets_.count(custom_preset); | ||||
|   } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_presets() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_presets() instead", "v1.20") | ||||
|   void set_supports_away(bool supports) { | ||||
|     if (supports) { | ||||
|       supported_presets_.insert(CLIMATE_PRESET_AWAY); | ||||
|       supported_presets_.insert(CLIMATE_PRESET_HOME); | ||||
|     } | ||||
|   } | ||||
|   ESPDEPRECATED("This method is deprecated, use supports_preset() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use supports_preset() instead", "v1.20") | ||||
|   bool get_supports_away() const { return supports_preset(CLIMATE_PRESET_AWAY); } | ||||
|  | ||||
|   void set_supported_swing_modes(std::set<ClimateSwingMode> modes) { supported_swing_modes_ = std::move(modes); } | ||||
|   void add_supported_swing_mode(ClimateSwingMode mode) { supported_swing_modes_.insert(mode); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead", "v1.20") | ||||
|   void set_supports_swing_mode_off(bool supported) { set_swing_mode_support_(CLIMATE_SWING_OFF, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead", "v1.20") | ||||
|   void set_supports_swing_mode_both(bool supported) { set_swing_mode_support_(CLIMATE_SWING_BOTH, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead", "v1.20") | ||||
|   void set_supports_swing_mode_vertical(bool supported) { set_swing_mode_support_(CLIMATE_SWING_VERTICAL, supported); } | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead") | ||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_swing_modes() instead", "v1.20") | ||||
|   void set_supports_swing_mode_horizontal(bool supported) { | ||||
|     set_swing_mode_support_(CLIMATE_SWING_HORIZONTAL, supported); | ||||
|   } | ||||
|   | ||||
							
								
								
									
										0
									
								
								esphome/components/color_temperature/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/color_temperature/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										38
									
								
								esphome/components/color_temperature/ct_light_output.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								esphome/components/color_temperature/ct_light_output.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/light/light_output.h" | ||||
| #include "esphome/components/output/float_output.h" | ||||
| #include "esphome/core/component.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace color_temperature { | ||||
|  | ||||
| class CTLightOutput : public light::LightOutput { | ||||
|  public: | ||||
|   void set_color_temperature(output::FloatOutput *color_temperature) { color_temperature_ = color_temperature; } | ||||
|   void set_brightness(output::FloatOutput *brightness) { brightness_ = brightness; } | ||||
|   void set_cold_white_temperature(float cold_white_temperature) { cold_white_temperature_ = cold_white_temperature; } | ||||
|   void set_warm_white_temperature(float warm_white_temperature) { warm_white_temperature_ = warm_white_temperature; } | ||||
|   light::LightTraits get_traits() override { | ||||
|     auto traits = light::LightTraits(); | ||||
|     traits.set_supported_color_modes({light::ColorMode::COLOR_TEMPERATURE}); | ||||
|     traits.set_min_mireds(this->cold_white_temperature_); | ||||
|     traits.set_max_mireds(this->warm_white_temperature_); | ||||
|     return traits; | ||||
|   } | ||||
|   void write_state(light::LightState *state) override { | ||||
|     float color_temperature, brightness; | ||||
|     state->current_values_as_ct(&color_temperature, &brightness); | ||||
|     this->color_temperature_->set_level(color_temperature); | ||||
|     this->brightness_->set_level(brightness); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   output::FloatOutput *color_temperature_; | ||||
|   output::FloatOutput *brightness_; | ||||
|   float cold_white_temperature_; | ||||
|   float warm_white_temperature_; | ||||
| }; | ||||
|  | ||||
| }  // namespace color_temperature | ||||
| }  // namespace esphome | ||||
							
								
								
									
										42
									
								
								esphome/components/color_temperature/light.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								esphome/components/color_temperature/light.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import light, output | ||||
| from esphome.const import ( | ||||
|     CONF_BRIGHTNESS, | ||||
|     CONF_COLOR_TEMPERATURE, | ||||
|     CONF_OUTPUT_ID, | ||||
|     CONF_COLD_WHITE_COLOR_TEMPERATURE, | ||||
|     CONF_WARM_WHITE_COLOR_TEMPERATURE, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
|  | ||||
| color_temperature_ns = cg.esphome_ns.namespace("color_temperature") | ||||
| CTLightOutput = color_temperature_ns.class_("CTLightOutput", light.LightOutput) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     light.RGB_LIGHT_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(CTLightOutput), | ||||
|             cv.Required(CONF_COLOR_TEMPERATURE): cv.use_id(output.FloatOutput), | ||||
|             cv.Required(CONF_BRIGHTNESS): cv.use_id(output.FloatOutput), | ||||
|             cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|             cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|         } | ||||
|     ), | ||||
|     light.validate_color_temperature_channels, | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) | ||||
|     await light.register_light(var, config) | ||||
|  | ||||
|     color_temperature = await cg.get_variable(config[CONF_COLOR_TEMPERATURE]) | ||||
|     cg.add(var.set_color_temperature(color_temperature)) | ||||
|  | ||||
|     brightness = await cg.get_variable(config[CONF_BRIGHTNESS]) | ||||
|     cg.add(var.set_brightness(brightness)) | ||||
|  | ||||
|     cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE])) | ||||
|     cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) | ||||
| @@ -4,6 +4,7 @@ from esphome import automation | ||||
| from esphome.automation import maybe_simple_id, Condition | ||||
| from esphome.components import mqtt | ||||
| from esphome.const import ( | ||||
|     CONF_DISABLED_BY_DEFAULT, | ||||
|     CONF_ID, | ||||
|     CONF_INTERNAL, | ||||
|     CONF_DEVICE_CLASS, | ||||
| @@ -63,7 +64,7 @@ CoverPublishAction = cover_ns.class_("CoverPublishAction", automation.Action) | ||||
| CoverIsOpenCondition = cover_ns.class_("CoverIsOpenCondition", Condition) | ||||
| CoverIsClosedCondition = cover_ns.class_("CoverIsClosedCondition", Condition) | ||||
|  | ||||
| COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( | ||||
| COVER_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(Cover), | ||||
|         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent), | ||||
| @@ -75,6 +76,7 @@ COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( | ||||
|  | ||||
| async def setup_cover_core_(var, config): | ||||
|     cg.add(var.set_name(config[CONF_NAME])) | ||||
|     cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT])) | ||||
|     if CONF_INTERNAL in config: | ||||
|         cg.add(var.set_internal(config[CONF_INTERNAL])) | ||||
|     if CONF_DEVICE_CLASS in config: | ||||
|   | ||||
| @@ -9,7 +9,6 @@ from esphome.const import ( | ||||
|     UNIT_VOLT, | ||||
|     UNIT_AMPERE, | ||||
|     UNIT_WATT, | ||||
|     ICON_EMPTY, | ||||
|     DEVICE_CLASS_POWER, | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
| @@ -80,13 +79,19 @@ CONFIG_SCHEMA = cv.All( | ||||
|             cv.Optional(CONF_VOLTAGE_HPF, default=True): cv.boolean, | ||||
|             cv.Optional(CONF_PULSE_ENERGY, default=10.0): validate_energy, | ||||
|             cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( | ||||
|                 UNIT_VOLT, ICON_EMPTY, 0, DEVICE_CLASS_VOLTAGE | ||||
|                 unit_of_measurement=UNIT_VOLT, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_VOLTAGE, | ||||
|             ), | ||||
|             cv.Optional(CONF_CURRENT): sensor.sensor_schema( | ||||
|                 UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT | ||||
|                 unit_of_measurement=UNIT_AMPERE, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_CURRENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_POWER): sensor.sensor_schema( | ||||
|                 UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER | ||||
|                 unit_of_measurement=UNIT_WATT, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_POWER, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     DEVICE_CLASS_POWER, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_VOLT, | ||||
|     UNIT_AMPERE, | ||||
| @@ -28,17 +27,22 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(CSE7766Component), | ||||
|             cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( | ||||
|                 UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_VOLT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_VOLTAGE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_CURRENT): sensor.sensor_schema( | ||||
|                 UNIT_AMPERE, | ||||
|                 ICON_EMPTY, | ||||
|                 2, | ||||
|                 DEVICE_CLASS_CURRENT, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_AMPERE, | ||||
|                 accuracy_decimals=2, | ||||
|                 device_class=DEVICE_CLASS_CURRENT, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_POWER): sensor.sensor_schema( | ||||
|                 UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|                 unit_of_measurement=UNIT_WATT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_POWER, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -5,7 +5,6 @@ from esphome.const import ( | ||||
|     CONF_SENSOR, | ||||
|     CONF_ID, | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_AMPERE, | ||||
| ) | ||||
| @@ -20,7 +19,10 @@ CTClampSensor = ct_clamp_ns.class_("CTClampSensor", sensor.Sensor, cg.PollingCom | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_AMPERE, | ||||
|         accuracy_decimals=2, | ||||
|         device_class=DEVICE_CLASS_CURRENT, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -16,10 +16,7 @@ class CWWWLightOutput : public light::LightOutput { | ||||
|   void set_constant_brightness(bool constant_brightness) { constant_brightness_ = constant_brightness; } | ||||
|   light::LightTraits get_traits() override { | ||||
|     auto traits = light::LightTraits(); | ||||
|     traits.set_supports_brightness(true); | ||||
|     traits.set_supports_rgb(false); | ||||
|     traits.set_supports_rgb_white_value(false); | ||||
|     traits.set_supports_color_temperature(true); | ||||
|     traits.set_supported_color_modes({light::ColorMode::COLD_WARM_WHITE}); | ||||
|     traits.set_min_mireds(this->cold_white_temperature_); | ||||
|     traits.set_max_mireds(this->warm_white_temperature_); | ||||
|     return traits; | ||||
| @@ -34,8 +31,8 @@ class CWWWLightOutput : public light::LightOutput { | ||||
|  protected: | ||||
|   output::FloatOutput *cold_white_; | ||||
|   output::FloatOutput *warm_white_; | ||||
|   float cold_white_temperature_; | ||||
|   float warm_white_temperature_; | ||||
|   float cold_white_temperature_{0}; | ||||
|   float warm_white_temperature_{0}; | ||||
|   bool constant_brightness_; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import light, output | ||||
| from esphome.const import ( | ||||
|     CONF_CONSTANT_BRIGHTNESS, | ||||
|     CONF_OUTPUT_ID, | ||||
|     CONF_COLD_WHITE, | ||||
|     CONF_WARM_WHITE, | ||||
| @@ -12,19 +13,20 @@ from esphome.const import ( | ||||
| cwww_ns = cg.esphome_ns.namespace("cwww") | ||||
| CWWWLightOutput = cwww_ns.class_("CWWWLightOutput", light.LightOutput) | ||||
|  | ||||
| CONF_CONSTANT_BRIGHTNESS = "constant_brightness" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     light.RGB_LIGHT_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(CWWWLightOutput), | ||||
|             cv.Required(CONF_COLD_WHITE): cv.use_id(output.FloatOutput), | ||||
|             cv.Required(CONF_WARM_WHITE): cv.use_id(output.FloatOutput), | ||||
|             cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|             cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|             cv.Optional(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|             cv.Optional(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature, | ||||
|             cv.Optional(CONF_CONSTANT_BRIGHTNESS, default=False): cv.boolean, | ||||
|         } | ||||
|     ), | ||||
|     cv.has_none_or_all_keys( | ||||
|         [CONF_COLD_WHITE_COLOR_TEMPERATURE, CONF_WARM_WHITE_COLOR_TEMPERATURE] | ||||
|     ), | ||||
|     light.validate_color_temperature_channels, | ||||
| ) | ||||
|  | ||||
| @@ -32,11 +34,19 @@ CONFIG_SCHEMA = cv.All( | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) | ||||
|     await light.register_light(var, config) | ||||
|  | ||||
|     cwhite = await cg.get_variable(config[CONF_COLD_WHITE]) | ||||
|     cg.add(var.set_cold_white(cwhite)) | ||||
|     cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE])) | ||||
|     if CONF_COLD_WHITE_COLOR_TEMPERATURE in config: | ||||
|         cg.add( | ||||
|             var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]) | ||||
|         ) | ||||
|  | ||||
|     wwhite = await cg.get_variable(config[CONF_WARM_WHITE]) | ||||
|     cg.add(var.set_warm_white(wwhite)) | ||||
|     cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) | ||||
|     if CONF_WARM_WHITE_COLOR_TEMPERATURE in config: | ||||
|         cg.add( | ||||
|             var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE]) | ||||
|         ) | ||||
|  | ||||
|     cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) | ||||
|   | ||||
| @@ -137,7 +137,7 @@ void DallasComponent::update() { | ||||
|       } | ||||
|  | ||||
|       if (!res) { | ||||
|         ESP_LOGW(TAG, "'%s' - Reseting bus for read failed!", sensor->get_name().c_str()); | ||||
|         ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str()); | ||||
|         sensor->publish_state(NAN); | ||||
|         this->status_set_warning(); | ||||
|         return; | ||||
|   | ||||
| @@ -7,7 +7,6 @@ from esphome.const import ( | ||||
|     CONF_INDEX, | ||||
|     CONF_RESOLUTION, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     CONF_ID, | ||||
| @@ -18,7 +17,10 @@ DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sen | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_CELSIUS, | ||||
|         accuracy_decimals=1, | ||||
|         device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ).extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(DallasTemperatureSensor), | ||||
|   | ||||
							
								
								
									
										451
									
								
								esphome/components/demo/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										451
									
								
								esphome/components/demo/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,451 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import ( | ||||
|     binary_sensor, | ||||
|     climate, | ||||
|     cover, | ||||
|     fan, | ||||
|     light, | ||||
|     number, | ||||
|     sensor, | ||||
|     switch, | ||||
|     text_sensor, | ||||
| ) | ||||
| from esphome.const import ( | ||||
|     CONF_ACCURACY_DECIMALS, | ||||
|     CONF_BINARY_SENSORS, | ||||
|     CONF_DEVICE_CLASS, | ||||
|     CONF_FORCE_UPDATE, | ||||
|     CONF_ICON, | ||||
|     CONF_ID, | ||||
|     CONF_INVERTED, | ||||
|     CONF_LAST_RESET_TYPE, | ||||
|     CONF_MAX_VALUE, | ||||
|     CONF_MIN_VALUE, | ||||
|     CONF_NAME, | ||||
|     CONF_OUTPUT_ID, | ||||
|     CONF_SENSORS, | ||||
|     CONF_STATE_CLASS, | ||||
|     CONF_STEP, | ||||
|     CONF_SWITCHES, | ||||
|     CONF_TEXT_SENSORS, | ||||
|     CONF_TYPE, | ||||
|     CONF_UNIT_OF_MEASUREMENT, | ||||
|     DEVICE_CLASS_ENERGY, | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
|     DEVICE_CLASS_MOISTURE, | ||||
|     DEVICE_CLASS_MOTION, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     ICON_BLUETOOTH, | ||||
|     ICON_BLUR, | ||||
|     ICON_EMPTY, | ||||
|     ICON_THERMOMETER, | ||||
|     LAST_RESET_TYPE_AUTO, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_EMPTY, | ||||
|     UNIT_PERCENT, | ||||
|     UNIT_WATT_HOURS, | ||||
| ) | ||||
|  | ||||
| AUTO_LOAD = [ | ||||
|     "binary_sensor", | ||||
|     "climate", | ||||
|     "cover", | ||||
|     "fan", | ||||
|     "light", | ||||
|     "number", | ||||
|     "sensor", | ||||
|     "switch", | ||||
|     "text_sensor", | ||||
| ] | ||||
|  | ||||
| demo_ns = cg.esphome_ns.namespace("demo") | ||||
| DemoBinarySensor = demo_ns.class_( | ||||
|     "DemoBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent | ||||
| ) | ||||
| DemoClimate = demo_ns.class_("DemoClimate", climate.Climate, cg.Component) | ||||
| DemoClimateType = demo_ns.enum("DemoClimateType", is_class=True) | ||||
| DemoCover = demo_ns.class_("DemoCover", cover.Cover, cg.Component) | ||||
| DemoCoverType = demo_ns.enum("DemoCoverType", is_class=True) | ||||
| DemoFan = demo_ns.class_("DemoFan", cg.Component) | ||||
| DemoFanType = demo_ns.enum("DemoFanType", is_class=True) | ||||
| DemoLight = demo_ns.class_("DemoLight", light.LightOutput, cg.Component) | ||||
| DemoLightType = demo_ns.enum("DemoLightType", is_class=True) | ||||
| DemoNumber = demo_ns.class_("DemoNumber", number.Number, cg.Component) | ||||
| DemoNumberType = demo_ns.enum("DemoNumberType", is_class=True) | ||||
| DemoSensor = demo_ns.class_("DemoSensor", sensor.Sensor, cg.PollingComponent) | ||||
| DemoSwitch = demo_ns.class_("DemoSwitch", switch.Switch, cg.Component) | ||||
| DemoTextSensor = demo_ns.class_( | ||||
|     "DemoTextSensor", text_sensor.TextSensor, cg.PollingComponent | ||||
| ) | ||||
|  | ||||
|  | ||||
| CLIMATE_TYPES = { | ||||
|     1: DemoClimateType.TYPE_1, | ||||
|     2: DemoClimateType.TYPE_2, | ||||
|     3: DemoClimateType.TYPE_3, | ||||
| } | ||||
| COVER_TYPES = { | ||||
|     1: DemoCoverType.TYPE_1, | ||||
|     2: DemoCoverType.TYPE_2, | ||||
|     3: DemoCoverType.TYPE_3, | ||||
|     4: DemoCoverType.TYPE_4, | ||||
| } | ||||
| FAN_TYPES = { | ||||
|     1: DemoFanType.TYPE_1, | ||||
|     2: DemoFanType.TYPE_2, | ||||
|     3: DemoFanType.TYPE_3, | ||||
|     4: DemoFanType.TYPE_4, | ||||
| } | ||||
| LIGHT_TYPES = { | ||||
|     1: DemoLightType.TYPE_1, | ||||
|     2: DemoLightType.TYPE_2, | ||||
|     3: DemoLightType.TYPE_3, | ||||
|     4: DemoLightType.TYPE_4, | ||||
|     5: DemoLightType.TYPE_5, | ||||
|     6: DemoLightType.TYPE_6, | ||||
|     7: DemoLightType.TYPE_7, | ||||
| } | ||||
| NUMBER_TYPES = { | ||||
|     1: DemoNumberType.TYPE_1, | ||||
|     2: DemoNumberType.TYPE_2, | ||||
|     3: DemoNumberType.TYPE_3, | ||||
| } | ||||
|  | ||||
|  | ||||
| CONF_CLIMATES = "climates" | ||||
| CONF_COVERS = "covers" | ||||
| CONF_FANS = "fans" | ||||
| CONF_LIGHTS = "lights" | ||||
| CONF_NUMBERS = "numbers" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Optional( | ||||
|             CONF_BINARY_SENSORS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Basement Floor Wet", | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_MOISTURE, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Movement Backyard", | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_MOTION, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             binary_sensor.BINARY_SENSOR_SCHEMA.extend( | ||||
|                 cv.polling_component_schema("60s") | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoBinarySensor), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_CLIMATES, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Heatpump", | ||||
|                     CONF_TYPE: 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo HVAC", | ||||
|                     CONF_TYPE: 2, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Ecobee", | ||||
|                     CONF_TYPE: 3, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             climate.CLIMATE_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoClimate), | ||||
|                     cv.Required(CONF_TYPE): cv.enum(CLIMATE_TYPES, int=True), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_COVERS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Kitchen Window", | ||||
|                     CONF_TYPE: 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Garage Door", | ||||
|                     CONF_TYPE: 2, | ||||
|                     CONF_DEVICE_CLASS: "garage", | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Living Room Window", | ||||
|                     CONF_TYPE: 3, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Hall Window", | ||||
|                     CONF_TYPE: 4, | ||||
|                     CONF_DEVICE_CLASS: "window", | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             cover.COVER_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoCover), | ||||
|                     cv.Required(CONF_TYPE): cv.enum(COVER_TYPES, int=True), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_FANS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Living Room Fan", | ||||
|                     CONF_TYPE: 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Ceiling Fan", | ||||
|                     CONF_TYPE: 2, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Percentage Limited Fan", | ||||
|                     CONF_TYPE: 3, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Percentage Full Fan", | ||||
|                     CONF_TYPE: 4, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             fan.FAN_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(DemoFan), | ||||
|                     cv.Required(CONF_TYPE): cv.enum(FAN_TYPES, int=True), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_LIGHTS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Binary Light", | ||||
|                     CONF_TYPE: 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Brightness Light", | ||||
|                     CONF_TYPE: 2, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo RGB Light", | ||||
|                     CONF_TYPE: 3, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo RGBW Light", | ||||
|                     CONF_TYPE: 4, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo RGBWW Light", | ||||
|                     CONF_TYPE: 5, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo CWWW Light", | ||||
|                     CONF_TYPE: 6, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo RGBW interlock Light", | ||||
|                     CONF_TYPE: 7, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             light.RGB_LIGHT_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(DemoLight), | ||||
|                     cv.Required(CONF_TYPE): cv.enum(LIGHT_TYPES, int=True), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_NUMBERS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Number 0-100", | ||||
|                     CONF_TYPE: 1, | ||||
|                     CONF_MIN_VALUE: 0, | ||||
|                     CONF_MAX_VALUE: 100, | ||||
|                     CONF_STEP: 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Number -50-50", | ||||
|                     CONF_TYPE: 2, | ||||
|                     CONF_MIN_VALUE: -50, | ||||
|                     CONF_MAX_VALUE: 50, | ||||
|                     CONF_STEP: 5, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Number 40-60", | ||||
|                     CONF_TYPE: 3, | ||||
|                     CONF_MIN_VALUE: 40, | ||||
|                     CONF_MAX_VALUE: 60, | ||||
|                     CONF_STEP: 0.2, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             number.NUMBER_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoNumber), | ||||
|                     cv.Required(CONF_TYPE): cv.enum(NUMBER_TYPES, int=True), | ||||
|                     cv.Required(CONF_MIN_VALUE): cv.float_, | ||||
|                     cv.Required(CONF_MAX_VALUE): cv.float_, | ||||
|                     cv.Required(CONF_STEP): cv.float_, | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_SENSORS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Plain Sensor", | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Temperature Sensor", | ||||
|                     CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS, | ||||
|                     CONF_ICON: ICON_THERMOMETER, | ||||
|                     CONF_ACCURACY_DECIMALS: 1, | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, | ||||
|                     CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Temperature Sensor", | ||||
|                     CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS, | ||||
|                     CONF_ICON: ICON_THERMOMETER, | ||||
|                     CONF_ACCURACY_DECIMALS: 1, | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, | ||||
|                     CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Force Update Sensor", | ||||
|                     CONF_UNIT_OF_MEASUREMENT: UNIT_PERCENT, | ||||
|                     CONF_ACCURACY_DECIMALS: 0, | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, | ||||
|                     CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, | ||||
|                     CONF_FORCE_UPDATE: True, | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Energy Sensor", | ||||
|                     CONF_UNIT_OF_MEASUREMENT: UNIT_WATT_HOURS, | ||||
|                     CONF_ACCURACY_DECIMALS: 0, | ||||
|                     CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, | ||||
|                     CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT, | ||||
|                     CONF_LAST_RESET_TYPE: LAST_RESET_TYPE_AUTO, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 0) | ||||
|             .extend(cv.polling_component_schema("60s")) | ||||
|             .extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoSensor), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_SWITCHES, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Switch 1", | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Switch 2", | ||||
|                     CONF_INVERTED: True, | ||||
|                     CONF_ICON: ICON_BLUETOOTH, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             switch.SWITCH_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoSwitch), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|         cv.Optional( | ||||
|             CONF_TEXT_SENSORS, | ||||
|             default=[ | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Text Sensor 1", | ||||
|                 }, | ||||
|                 { | ||||
|                     CONF_NAME: "Demo Text Sensor 2", | ||||
|                     CONF_ICON: ICON_BLUR, | ||||
|                 }, | ||||
|             ], | ||||
|         ): [ | ||||
|             text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|                 cv.polling_component_schema("60s") | ||||
|             ).extend( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DemoTextSensor), | ||||
|                 } | ||||
|             ) | ||||
|         ], | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     for conf in config[CONF_BINARY_SENSORS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await binary_sensor.register_binary_sensor(var, conf) | ||||
|  | ||||
|     for conf in config[CONF_CLIMATES]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await climate.register_climate(var, conf) | ||||
|         cg.add(var.set_type(conf[CONF_TYPE])) | ||||
|  | ||||
|     for conf in config[CONF_COVERS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await cover.register_cover(var, conf) | ||||
|         cg.add(var.set_type(conf[CONF_TYPE])) | ||||
|  | ||||
|     for conf in config[CONF_FANS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         fan_ = await fan.create_fan_state(conf) | ||||
|         cg.add(var.set_fan(fan_)) | ||||
|         cg.add(var.set_type(conf[CONF_TYPE])) | ||||
|  | ||||
|     for conf in config[CONF_LIGHTS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await light.register_light(var, conf) | ||||
|         cg.add(var.set_type(conf[CONF_TYPE])) | ||||
|  | ||||
|     for conf in config[CONF_NUMBERS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await number.register_number( | ||||
|             var, | ||||
|             conf, | ||||
|             min_value=conf[CONF_MIN_VALUE], | ||||
|             max_value=conf[CONF_MAX_VALUE], | ||||
|             step=conf[CONF_STEP], | ||||
|         ) | ||||
|         cg.add(var.set_type(conf[CONF_TYPE])) | ||||
|  | ||||
|     for conf in config[CONF_SENSORS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await sensor.register_sensor(var, conf) | ||||
|  | ||||
|     for conf in config[CONF_SWITCHES]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await switch.register_switch(var, conf) | ||||
|  | ||||
|     for conf in config[CONF_TEXT_SENSORS]: | ||||
|         var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|         await cg.register_component(var, conf) | ||||
|         await text_sensor.register_text_sensor(var, conf) | ||||
							
								
								
									
										22
									
								
								esphome/components/demo/demo_binary_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								esphome/components/demo/demo_binary_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| class DemoBinarySensor : public binary_sensor::BinarySensor, public PollingComponent { | ||||
|  public: | ||||
|   void setup() override { this->publish_initial_state(false); } | ||||
|   void update() override { | ||||
|     bool new_state = last_state_ = !last_state_; | ||||
|     this->publish_state(new_state); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   bool last_state_ = false; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										157
									
								
								esphome/components/demo/demo_climate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								esphome/components/demo/demo_climate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/climate/climate.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| enum class DemoClimateType { | ||||
|   TYPE_1, | ||||
|   TYPE_2, | ||||
|   TYPE_3, | ||||
| }; | ||||
|  | ||||
| class DemoClimate : public climate::Climate, public Component { | ||||
|  public: | ||||
|   void set_type(DemoClimateType type) { type_ = type; } | ||||
|   void setup() override { | ||||
|     switch (type_) { | ||||
|       case DemoClimateType::TYPE_1: | ||||
|         this->current_temperature = 20.0; | ||||
|         this->target_temperature = 21.0; | ||||
|         this->mode = climate::CLIMATE_MODE_HEAT; | ||||
|         this->action = climate::CLIMATE_ACTION_HEATING; | ||||
|         break; | ||||
|       case DemoClimateType::TYPE_2: | ||||
|         this->target_temperature = 21.5; | ||||
|         this->mode = climate::CLIMATE_MODE_AUTO; | ||||
|         this->action = climate::CLIMATE_ACTION_COOLING; | ||||
|         this->fan_mode = climate::CLIMATE_FAN_HIGH; | ||||
|         this->custom_preset = {"My Preset"}; | ||||
|         break; | ||||
|       case DemoClimateType::TYPE_3: | ||||
|         this->current_temperature = 21.5; | ||||
|         this->target_temperature_low = 21.0; | ||||
|         this->target_temperature_high = 22.5; | ||||
|         this->mode = climate::CLIMATE_MODE_HEAT_COOL; | ||||
|         this->custom_fan_mode = {"Auto Low"}; | ||||
|         this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; | ||||
|         this->preset = climate::CLIMATE_PRESET_AWAY; | ||||
|         break; | ||||
|     } | ||||
|     this->publish_state(); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void control(const climate::ClimateCall &call) override { | ||||
|     if (call.get_mode().has_value()) { | ||||
|       this->mode = *call.get_mode(); | ||||
|     } | ||||
|     if (call.get_target_temperature().has_value()) { | ||||
|       this->target_temperature = *call.get_target_temperature(); | ||||
|     } | ||||
|     if (call.get_target_temperature_low().has_value()) { | ||||
|       this->target_temperature_low = *call.get_target_temperature_low(); | ||||
|     } | ||||
|     if (call.get_target_temperature_high().has_value()) { | ||||
|       this->target_temperature_high = *call.get_target_temperature_high(); | ||||
|     } | ||||
|     if (call.get_fan_mode().has_value()) { | ||||
|       this->fan_mode = *call.get_fan_mode(); | ||||
|       this->custom_fan_mode.reset(); | ||||
|     } | ||||
|     if (call.get_swing_mode().has_value()) { | ||||
|       this->swing_mode = *call.get_swing_mode(); | ||||
|     } | ||||
|     if (call.get_custom_fan_mode().has_value()) { | ||||
|       this->custom_fan_mode = *call.get_custom_fan_mode(); | ||||
|       this->fan_mode.reset(); | ||||
|     } | ||||
|     if (call.get_preset().has_value()) { | ||||
|       this->preset = *call.get_preset(); | ||||
|       this->custom_preset.reset(); | ||||
|     } | ||||
|     if (call.get_custom_preset().has_value()) { | ||||
|       this->custom_preset = *call.get_custom_preset(); | ||||
|       this->preset.reset(); | ||||
|     } | ||||
|     this->publish_state(); | ||||
|   } | ||||
|   climate::ClimateTraits traits() override { | ||||
|     climate::ClimateTraits traits{}; | ||||
|     switch (type_) { | ||||
|       case DemoClimateType::TYPE_1: | ||||
|         traits.set_supports_current_temperature(true); | ||||
|         traits.set_supported_modes({ | ||||
|             climate::CLIMATE_MODE_OFF, | ||||
|             climate::CLIMATE_MODE_HEAT, | ||||
|         }); | ||||
|         traits.set_supports_action(true); | ||||
|         traits.set_visual_temperature_step(0.5); | ||||
|         break; | ||||
|       case DemoClimateType::TYPE_2: | ||||
|         traits.set_supports_current_temperature(false); | ||||
|         traits.set_supported_modes({ | ||||
|             climate::CLIMATE_MODE_OFF, | ||||
|             climate::CLIMATE_MODE_HEAT, | ||||
|             climate::CLIMATE_MODE_COOL, | ||||
|             climate::CLIMATE_MODE_AUTO, | ||||
|             climate::CLIMATE_MODE_DRY, | ||||
|             climate::CLIMATE_MODE_FAN_ONLY, | ||||
|         }); | ||||
|         traits.set_supports_action(true); | ||||
|         traits.set_supported_fan_modes({ | ||||
|             climate::CLIMATE_FAN_ON, | ||||
|             climate::CLIMATE_FAN_OFF, | ||||
|             climate::CLIMATE_FAN_AUTO, | ||||
|             climate::CLIMATE_FAN_LOW, | ||||
|             climate::CLIMATE_FAN_MEDIUM, | ||||
|             climate::CLIMATE_FAN_HIGH, | ||||
|             climate::CLIMATE_FAN_MIDDLE, | ||||
|             climate::CLIMATE_FAN_FOCUS, | ||||
|             climate::CLIMATE_FAN_DIFFUSE, | ||||
|         }); | ||||
|         traits.set_supported_custom_fan_modes({"Auto Low", "Auto High"}); | ||||
|         traits.set_supported_swing_modes({ | ||||
|             climate::CLIMATE_SWING_OFF, | ||||
|             climate::CLIMATE_SWING_BOTH, | ||||
|             climate::CLIMATE_SWING_VERTICAL, | ||||
|             climate::CLIMATE_SWING_HORIZONTAL, | ||||
|         }); | ||||
|         traits.set_supported_custom_presets({"My Preset"}); | ||||
|         break; | ||||
|       case DemoClimateType::TYPE_3: | ||||
|         traits.set_supports_current_temperature(true); | ||||
|         traits.set_supports_two_point_target_temperature(true); | ||||
|         traits.set_supported_modes({ | ||||
|             climate::CLIMATE_MODE_OFF, | ||||
|             climate::CLIMATE_MODE_COOL, | ||||
|             climate::CLIMATE_MODE_HEAT, | ||||
|             climate::CLIMATE_MODE_HEAT_COOL, | ||||
|         }); | ||||
|         traits.set_supported_custom_fan_modes({"Auto Low", "Auto High"}); | ||||
|         traits.set_supported_swing_modes({ | ||||
|             climate::CLIMATE_SWING_OFF, | ||||
|             climate::CLIMATE_SWING_HORIZONTAL, | ||||
|         }); | ||||
|         traits.set_supported_presets({ | ||||
|             climate::CLIMATE_PRESET_NONE, | ||||
|             climate::CLIMATE_PRESET_HOME, | ||||
|             climate::CLIMATE_PRESET_AWAY, | ||||
|             climate::CLIMATE_PRESET_BOOST, | ||||
|             climate::CLIMATE_PRESET_COMFORT, | ||||
|             climate::CLIMATE_PRESET_ECO, | ||||
|             climate::CLIMATE_PRESET_SLEEP, | ||||
|             climate::CLIMATE_PRESET_ACTIVITY, | ||||
|         }); | ||||
|         break; | ||||
|     } | ||||
|     return traits; | ||||
|   } | ||||
|  | ||||
|   DemoClimateType type_; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										86
									
								
								esphome/components/demo/demo_cover.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								esphome/components/demo/demo_cover.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/cover/cover.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| enum class DemoCoverType { | ||||
|   TYPE_1, | ||||
|   TYPE_2, | ||||
|   TYPE_3, | ||||
|   TYPE_4, | ||||
| }; | ||||
|  | ||||
| class DemoCover : public cover::Cover, public Component { | ||||
|  public: | ||||
|   void set_type(DemoCoverType type) { type_ = type; } | ||||
|   void setup() override { | ||||
|     switch (type_) { | ||||
|       case DemoCoverType::TYPE_1: | ||||
|         this->position = cover::COVER_OPEN; | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_2: | ||||
|         this->position = 0.7; | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_3: | ||||
|         this->position = 0.1; | ||||
|         this->tilt = 0.8; | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_4: | ||||
|         this->position = cover::COVER_CLOSED; | ||||
|         this->tilt = 1.0; | ||||
|         break; | ||||
|     } | ||||
|     this->publish_state(); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void control(const cover::CoverCall &call) override { | ||||
|     if (call.get_position().has_value()) { | ||||
|       float target = *call.get_position(); | ||||
|       this->current_operation = | ||||
|           target > this->position ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING; | ||||
|  | ||||
|       this->set_timeout("move", 2000, [this, target]() { | ||||
|         this->current_operation = cover::COVER_OPERATION_IDLE; | ||||
|         this->position = target; | ||||
|         this->publish_state(); | ||||
|       }); | ||||
|     } | ||||
|     if (call.get_tilt().has_value()) { | ||||
|       this->tilt = *call.get_tilt(); | ||||
|     } | ||||
|     if (call.get_stop()) { | ||||
|       this->cancel_timeout("move"); | ||||
|     } | ||||
|  | ||||
|     this->publish_state(); | ||||
|   } | ||||
|   cover::CoverTraits get_traits() override { | ||||
|     cover::CoverTraits traits{}; | ||||
|     switch (type_) { | ||||
|       case DemoCoverType::TYPE_1: | ||||
|         traits.set_is_assumed_state(true); | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_2: | ||||
|         traits.set_supports_position(true); | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_3: | ||||
|         traits.set_supports_position(true); | ||||
|         traits.set_supports_tilt(true); | ||||
|         break; | ||||
|       case DemoCoverType::TYPE_4: | ||||
|         traits.set_is_assumed_state(true); | ||||
|         traits.set_supports_tilt(true); | ||||
|         break; | ||||
|     } | ||||
|     return traits; | ||||
|   } | ||||
|  | ||||
|   DemoCoverType type_; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										54
									
								
								esphome/components/demo/demo_fan.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/demo/demo_fan.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/fan/fan_state.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| enum class DemoFanType { | ||||
|   TYPE_1, | ||||
|   TYPE_2, | ||||
|   TYPE_3, | ||||
|   TYPE_4, | ||||
| }; | ||||
|  | ||||
| class DemoFan : public Component { | ||||
|  public: | ||||
|   void set_type(DemoFanType type) { type_ = type; } | ||||
|   void set_fan(fan::FanState *fan) { fan_ = fan; } | ||||
|   void setup() override { | ||||
|     fan::FanTraits traits{}; | ||||
|  | ||||
|     // oscillation | ||||
|     // speed | ||||
|     // direction | ||||
|     // speed_count | ||||
|     switch (type_) { | ||||
|       case DemoFanType::TYPE_1: | ||||
|         break; | ||||
|       case DemoFanType::TYPE_2: | ||||
|         traits.set_oscillation(true); | ||||
|         break; | ||||
|       case DemoFanType::TYPE_3: | ||||
|         traits.set_direction(true); | ||||
|         traits.set_speed(true); | ||||
|         traits.set_supported_speed_count(5); | ||||
|         break; | ||||
|       case DemoFanType::TYPE_4: | ||||
|         traits.set_direction(true); | ||||
|         traits.set_speed(true); | ||||
|         traits.set_supported_speed_count(100); | ||||
|         traits.set_oscillation(true); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     this->fan_->set_traits(traits); | ||||
|   } | ||||
|  | ||||
|   fan::FanState *fan_; | ||||
|   DemoFanType type_; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										68
									
								
								esphome/components/demo/demo_light.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								esphome/components/demo/demo_light.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/light/light_output.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| enum class DemoLightType { | ||||
|   // binary | ||||
|   TYPE_1, | ||||
|   // brightness | ||||
|   TYPE_2, | ||||
|   // RGB | ||||
|   TYPE_3, | ||||
|   // RGBW | ||||
|   TYPE_4, | ||||
|   // RGBWW | ||||
|   TYPE_5, | ||||
|   // CWWW | ||||
|   TYPE_6, | ||||
|   // RGBW + color_interlock | ||||
|   TYPE_7, | ||||
| }; | ||||
|  | ||||
| class DemoLight : public light::LightOutput, public Component { | ||||
|  public: | ||||
|   void set_type(DemoLightType type) { type_ = type; } | ||||
|   light::LightTraits get_traits() override { | ||||
|     light::LightTraits traits{}; | ||||
|     switch (type_) { | ||||
|       case DemoLightType::TYPE_1: | ||||
|         traits.set_supported_color_modes({light::ColorMode::ON_OFF}); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_2: | ||||
|         traits.set_supported_color_modes({light::ColorMode::BRIGHTNESS}); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_3: | ||||
|         traits.set_supported_color_modes({light::ColorMode::RGB}); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_4: | ||||
|         traits.set_supported_color_modes({light::ColorMode::RGB_WHITE}); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_5: | ||||
|         traits.set_supported_color_modes({light::ColorMode::RGB_COLOR_TEMPERATURE}); | ||||
|         traits.set_min_mireds(153); | ||||
|         traits.set_max_mireds(500); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_6: | ||||
|         traits.set_supported_color_modes({light::ColorMode::COLD_WARM_WHITE}); | ||||
|         traits.set_min_mireds(153); | ||||
|         traits.set_max_mireds(500); | ||||
|         break; | ||||
|       case DemoLightType::TYPE_7: | ||||
|         traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::WHITE}); | ||||
|         break; | ||||
|     } | ||||
|     return traits; | ||||
|   } | ||||
|   void write_state(light::LightState *state) override { | ||||
|     // do nothing | ||||
|   } | ||||
|  | ||||
|   DemoLightType type_; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										39
									
								
								esphome/components/demo/demo_number.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								esphome/components/demo/demo_number.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/number/number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| enum class DemoNumberType { | ||||
|   TYPE_1, | ||||
|   TYPE_2, | ||||
|   TYPE_3, | ||||
| }; | ||||
|  | ||||
| class DemoNumber : public number::Number, public Component { | ||||
|  public: | ||||
|   void set_type(DemoNumberType type) { type_ = type; } | ||||
|   void setup() override { | ||||
|     switch (type_) { | ||||
|       case DemoNumberType::TYPE_1: | ||||
|         this->publish_state(50); | ||||
|         break; | ||||
|       case DemoNumberType::TYPE_2: | ||||
|         this->publish_state(-10); | ||||
|         break; | ||||
|       case DemoNumberType::TYPE_3: | ||||
|         this->publish_state(42); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override { this->publish_state(value); } | ||||
|  | ||||
|   DemoNumberType type_; | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										28
									
								
								esphome/components/demo/demo_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								esphome/components/demo/demo_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| class DemoSensor : public sensor::Sensor, public PollingComponent { | ||||
|  public: | ||||
|   void update() override { | ||||
|     float val = random_float(); | ||||
|     bool is_auto = this->last_reset_type == sensor::LAST_RESET_TYPE_AUTO; | ||||
|     if (is_auto) { | ||||
|       float base = isnan(this->state) ? 0.0f : this->state; | ||||
|       this->publish_state(base + val * 10); | ||||
|     } else { | ||||
|       if (val < 0.1) | ||||
|         this->publish_state(NAN); | ||||
|       else | ||||
|         this->publish_state(val * 100); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										22
									
								
								esphome/components/demo/demo_switch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								esphome/components/demo/demo_switch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/components/switch/switch.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| class DemoSwitch : public switch_::Switch, public Component { | ||||
|  public: | ||||
|   void setup() override { | ||||
|     bool initial = random_float() < 0.5; | ||||
|     this->publish_state(initial); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void write_state(bool state) override { this->publish_state(state); } | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
							
								
								
									
										25
									
								
								esphome/components/demo/demo_text_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								esphome/components/demo/demo_text_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/components/text_sensor/text_sensor.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace demo { | ||||
|  | ||||
| class DemoTextSensor : public text_sensor::TextSensor, public PollingComponent { | ||||
|  public: | ||||
|   void update() override { | ||||
|     float val = random_float(); | ||||
|     if (val < 0.33) { | ||||
|       this->publish_state("foo"); | ||||
|     } else if (val < 0.66) { | ||||
|       this->publish_state("bar"); | ||||
|     } else { | ||||
|       this->publish_state("foobar"); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace demo | ||||
| }  // namespace esphome | ||||
| @@ -116,7 +116,7 @@ DFPLAYER_SIMPLE_ACTION(PreviousAction, previous) | ||||
| template<typename... Ts> class PlayFileAction : public Action<Ts...>, public Parented<DFPlayer> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint16_t, file) | ||||
|   TEMPLATABLE_VALUE(boolean, loop) | ||||
|   TEMPLATABLE_VALUE(bool, loop) | ||||
|  | ||||
|   void play(Ts... x) override { | ||||
|     auto file = this->file_.value(x...); | ||||
| @@ -133,7 +133,7 @@ template<typename... Ts> class PlayFolderAction : public Action<Ts...>, public P | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint16_t, folder) | ||||
|   TEMPLATABLE_VALUE(uint16_t, file) | ||||
|   TEMPLATABLE_VALUE(boolean, loop) | ||||
|   TEMPLATABLE_VALUE(bool, loop) | ||||
|  | ||||
|   void play(Ts... x) override { | ||||
|     auto folder = this->folder_.value(x...); | ||||
|   | ||||
| @@ -203,7 +203,7 @@ bool HOT ICACHE_RAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, | ||||
|       const uint16_t raw_humidity = uint16_t(data[0]) * 10 + data[1]; | ||||
|       *humidity = raw_humidity / 10.0f; | ||||
|     } else { | ||||
|       // For compatibily with DHT11 models which might only use 2 bytes checksums, only use the data from these two | ||||
|       // For compatibility with DHT11 models which might only use 2 bytes checksums, only use the data from these two | ||||
|       // bytes | ||||
|       *temperature = data[2]; | ||||
|       *humidity = data[0]; | ||||
|   | ||||
| @@ -8,7 +8,6 @@ from esphome.const import ( | ||||
|     CONF_MODEL, | ||||
|     CONF_PIN, | ||||
|     CONF_TEMPERATURE, | ||||
|     ICON_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     UNIT_PERCENT, | ||||
| @@ -36,14 +35,16 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|         cv.GenerateID(): cv.declare_id(DHT), | ||||
|         cv.Required(CONF_PIN): pins.gpio_input_pin_schema, | ||||
|         cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|             UNIT_CELSIUS, | ||||
|             ICON_EMPTY, | ||||
|             1, | ||||
|             DEVICE_CLASS_TEMPERATURE, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             unit_of_measurement=UNIT_CELSIUS, | ||||
|             accuracy_decimals=1, | ||||
|             device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|             UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY, STATE_CLASS_MEASUREMENT | ||||
|             unit_of_measurement=UNIT_PERCENT, | ||||
|             accuracy_decimals=0, | ||||
|             device_class=DEVICE_CLASS_HUMIDITY, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_MODEL, default="auto detect"): cv.enum( | ||||
|             DHT_MODELS, upper=True, space="_" | ||||
|   | ||||
| @@ -7,7 +7,6 @@ from esphome.const import ( | ||||
|     CONF_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     ICON_EMPTY, | ||||
|     UNIT_PERCENT, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     DEVICE_CLASS_HUMIDITY, | ||||
| @@ -23,18 +22,16 @@ CONFIG_SCHEMA = ( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(DHT12Component), | ||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||
|                 UNIT_CELSIUS, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_TEMPERATURE, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||
|                 UNIT_PERCENT, | ||||
|                 ICON_EMPTY, | ||||
|                 1, | ||||
|                 DEVICE_CLASS_HUMIDITY, | ||||
|                 STATE_CLASS_MEASUREMENT, | ||||
|                 unit_of_measurement=UNIT_PERCENT, | ||||
|                 accuracy_decimals=1, | ||||
|                 device_class=DEVICE_CLASS_HUMIDITY, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|   | ||||
| @@ -14,7 +14,7 @@ const Color COLOR_OFF(0, 0, 0, 0); | ||||
| const Color COLOR_ON(255, 255, 255, 255); | ||||
|  | ||||
| void DisplayBuffer::init_internal_(uint32_t buffer_length) { | ||||
|   this->buffer_ = new uint8_t[buffer_length]; | ||||
|   this->buffer_ = new (std::nothrow) uint8_t[buffer_length]; | ||||
|   if (this->buffer_ == nullptr) { | ||||
|     ESP_LOGE(TAG, "Could not allocate buffer for display!"); | ||||
|     return; | ||||
| @@ -461,7 +461,7 @@ bool Image::get_pixel(int x, int y) const { | ||||
| } | ||||
| Color Image::get_color_pixel(int x, int y) const { | ||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t pos = (x + y * this->width_) * 3; | ||||
|   const uint32_t color32 = (pgm_read_byte(this->data_start_ + pos + 2) << 0) | | ||||
|                            (pgm_read_byte(this->data_start_ + pos + 1) << 8) | | ||||
| @@ -470,7 +470,7 @@ Color Image::get_color_pixel(int x, int y) const { | ||||
| } | ||||
| Color Image::get_grayscale_pixel(int x, int y) const { | ||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t pos = (x + y * this->width_); | ||||
|   const uint8_t gray = pgm_read_byte(this->data_start_ + pos); | ||||
|   return Color(gray | gray << 8 | gray << 16 | gray << 24); | ||||
| @@ -493,10 +493,10 @@ bool Animation::get_pixel(int x, int y) const { | ||||
| } | ||||
| Color Animation::get_color_pixel(int x, int y) const { | ||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; | ||||
|   if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t pos = (x + y * this->width_ + frame_index) * 3; | ||||
|   const uint32_t color32 = (pgm_read_byte(this->data_start_ + pos + 2) << 0) | | ||||
|                            (pgm_read_byte(this->data_start_ + pos + 1) << 8) | | ||||
| @@ -505,10 +505,10 @@ Color Animation::get_color_pixel(int x, int y) const { | ||||
| } | ||||
| Color Animation::get_grayscale_pixel(int x, int y) const { | ||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; | ||||
|   if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_) | ||||
|     return 0; | ||||
|     return Color::BLACK; | ||||
|   const uint32_t pos = (x + y * this->width_ + frame_index); | ||||
|   const uint8_t gray = pgm_read_byte(this->data_start_ + pos); | ||||
|   return Color(gray | gray << 8 | gray << 16 | gray << 24); | ||||
|   | ||||
							
								
								
									
										59
									
								
								esphome/components/dsmr/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								esphome/components/dsmr/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import uart | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_UART_ID, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@glmnet", "@zuidwijk"] | ||||
|  | ||||
| DEPENDENCIES = ["uart"] | ||||
| AUTO_LOAD = ["sensor", "text_sensor"] | ||||
|  | ||||
| CONF_DSMR_ID = "dsmr_id" | ||||
| CONF_DECRYPTION_KEY = "decryption_key" | ||||
|  | ||||
| # Hack to prevent compile error due to ambiguity with lib namespace | ||||
| dsmr_ns = cg.esphome_ns.namespace("esphome::dsmr") | ||||
| Dsmr = dsmr_ns.class_("Dsmr", cg.Component, uart.UARTDevice) | ||||
|  | ||||
|  | ||||
| def _validate_key(value): | ||||
|     value = cv.string_strict(value) | ||||
|     parts = [value[i : i + 2] for i in range(0, len(value), 2)] | ||||
|     if len(parts) != 16: | ||||
|         raise cv.Invalid("Decryption key must consist of 16 hexadecimal numbers") | ||||
|     parts_int = [] | ||||
|     if any(len(part) != 2 for part in parts): | ||||
|         raise cv.Invalid("Decryption key must be format XX") | ||||
|     for part in parts: | ||||
|         try: | ||||
|             parts_int.append(int(part, 16)) | ||||
|         except ValueError: | ||||
|             # pylint: disable=raise-missing-from | ||||
|             raise cv.Invalid("Decryption key must be hex values from 00 to FF") | ||||
|  | ||||
|     return "".join(f"{part:02X}" for part in parts_int) | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(Dsmr), | ||||
|         cv.Optional(CONF_DECRYPTION_KEY): _validate_key, | ||||
|     } | ||||
| ).extend(uart.UART_DEVICE_SCHEMA) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     uart_component = await cg.get_variable(config[CONF_UART_ID]) | ||||
|     var = cg.new_Pvariable(config[CONF_ID], uart_component) | ||||
|     if CONF_DECRYPTION_KEY in config: | ||||
|         cg.add(var.set_decryption_key(config[CONF_DECRYPTION_KEY])) | ||||
|     await cg.register_component(var, config) | ||||
|  | ||||
|     # DSMR Parser | ||||
|     cg.add_library("glmnet/Dsmr", "0.3") | ||||
|  | ||||
|     # Crypto | ||||
|     cg.add_library("rweather/Crypto", "0.2.0") | ||||
							
								
								
									
										182
									
								
								esphome/components/dsmr/dsmr.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								esphome/components/dsmr/dsmr.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,182 @@ | ||||
| #include "dsmr.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include <AES.h> | ||||
| #include <Crypto.h> | ||||
| #include <GCM.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace dsmr { | ||||
|  | ||||
| static const char *const TAG = "dsmr"; | ||||
|  | ||||
| void Dsmr::loop() { | ||||
|   if (this->decryption_key_.empty()) | ||||
|     this->receive_telegram_(); | ||||
|   else | ||||
|     this->receive_encrypted_(); | ||||
| } | ||||
|  | ||||
| void Dsmr::receive_telegram_() { | ||||
|   while (available()) { | ||||
|     const char c = read(); | ||||
|  | ||||
|     if (c == '/') {  // header: forward slash | ||||
|       ESP_LOGV(TAG, "Header found"); | ||||
|       header_found_ = true; | ||||
|       footer_found_ = false; | ||||
|       telegram_len_ = 0; | ||||
|     } | ||||
|  | ||||
|     if (!header_found_) | ||||
|       continue; | ||||
|     if (telegram_len_ >= MAX_TELEGRAM_LENGTH) {  // Buffer overflow | ||||
|       header_found_ = false; | ||||
|       footer_found_ = false; | ||||
|       ESP_LOGE(TAG, "Error: Message larger than buffer"); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     telegram_[telegram_len_] = c; | ||||
|     telegram_len_++; | ||||
|     if (c == '!') {  // footer: exclamation mark | ||||
|       ESP_LOGV(TAG, "Footer found"); | ||||
|       footer_found_ = true; | ||||
|     } else { | ||||
|       if (footer_found_ && c == 10) {  // last \n after footer | ||||
|         header_found_ = false; | ||||
|         // Parse message | ||||
|         if (parse_telegram()) | ||||
|           return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Dsmr::receive_encrypted_() { | ||||
|   // Encrypted buffer | ||||
|   uint8_t buffer[MAX_TELEGRAM_LENGTH]; | ||||
|   size_t buffer_length = 0; | ||||
|  | ||||
|   size_t packet_size = 0; | ||||
|   while (available()) { | ||||
|     const char c = read(); | ||||
|  | ||||
|     if (!header_found_) { | ||||
|       if ((uint8_t) c == 0xdb) { | ||||
|         ESP_LOGV(TAG, "Start byte 0xDB found"); | ||||
|         header_found_ = true; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Sanity check | ||||
|     if (!header_found_ || buffer_length >= MAX_TELEGRAM_LENGTH) { | ||||
|       if (buffer_length == 0) { | ||||
|         ESP_LOGE(TAG, "First byte of encrypted telegram should be 0xDB, aborting."); | ||||
|       } else { | ||||
|         ESP_LOGW(TAG, "Unexpected data"); | ||||
|       } | ||||
|       this->status_momentary_warning("unexpected_data"); | ||||
|       this->flush(); | ||||
|       while (available()) | ||||
|         read(); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     buffer[buffer_length++] = c; | ||||
|  | ||||
|     if (packet_size == 0 && buffer_length > 20) { | ||||
|       // Complete header + a few bytes of data | ||||
|       packet_size = buffer[11] << 8 | buffer[12]; | ||||
|     } | ||||
|     if (buffer_length == packet_size + 13 && packet_size > 0) { | ||||
|       ESP_LOGV(TAG, "Encrypted data: %d bytes", buffer_length); | ||||
|  | ||||
|       GCM<AES128> *gcmaes128{new GCM<AES128>()}; | ||||
|       gcmaes128->setKey(this->decryption_key_.data(), gcmaes128->keySize()); | ||||
|       // the iv is 8 bytes of the system title + 4 bytes frame counter | ||||
|       // system title is at byte 2 and frame counter at byte 15 | ||||
|       for (int i = 10; i < 14; i++) | ||||
|         buffer[i] = buffer[i + 4]; | ||||
|       constexpr uint16_t iv_size{12}; | ||||
|       gcmaes128->setIV(&buffer[2], iv_size); | ||||
|       gcmaes128->decrypt(reinterpret_cast<uint8_t *>(this->telegram_), | ||||
|                          // the ciphertext start at byte 18 | ||||
|                          &buffer[18], | ||||
|                          // cipher size | ||||
|                          buffer_length - 17); | ||||
|       delete gcmaes128; | ||||
|  | ||||
|       telegram_len_ = strnlen(this->telegram_, sizeof(this->telegram_)); | ||||
|       ESP_LOGV(TAG, "Decrypted data length: %d", telegram_len_); | ||||
|       ESP_LOGVV(TAG, "Decrypted data %s", this->telegram_); | ||||
|  | ||||
|       parse_telegram(); | ||||
|       telegram_len_ = 0; | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!available()) { | ||||
|       // baud rate is 115200 for encrypted data, this means a few byte should arrive every time | ||||
|       // program runs faster than buffer loading then available() might return false in the middle | ||||
|       delay(4);  // Wait for data | ||||
|     } | ||||
|   } | ||||
|   if (buffer_length > 0) | ||||
|     ESP_LOGW(TAG, "Timeout while waiting for encrypted data or invalid data received."); | ||||
| } | ||||
|  | ||||
| bool Dsmr::parse_telegram() { | ||||
|   MyData data; | ||||
|   ESP_LOGV(TAG, "Trying to parse"); | ||||
|   ::dsmr::ParseResult<void> res = | ||||
|       ::dsmr::P1Parser::parse(&data, telegram_, telegram_len_, | ||||
|                               false);  // Parse telegram according to data definition. Ignore unknown values. | ||||
|   if (res.err) { | ||||
|     // Parsing error, show it | ||||
|     auto err_str = res.fullError(telegram_, telegram_ + telegram_len_); | ||||
|     ESP_LOGE(TAG, "%s", err_str.c_str()); | ||||
|     return false; | ||||
|   } else { | ||||
|     this->status_clear_warning(); | ||||
|     publish_sensors(data); | ||||
|     return true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Dsmr::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "dsmr:"); | ||||
|  | ||||
| #define DSMR_LOG_SENSOR(s) LOG_SENSOR("  ", #s, this->s_##s##_); | ||||
|   DSMR_SENSOR_LIST(DSMR_LOG_SENSOR, ) | ||||
|  | ||||
| #define DSMR_LOG_TEXT_SENSOR(s) LOG_TEXT_SENSOR("  ", #s, this->s_##s##_); | ||||
|   DSMR_TEXT_SENSOR_LIST(DSMR_LOG_TEXT_SENSOR, ) | ||||
| } | ||||
|  | ||||
| void Dsmr::set_decryption_key(const std::string &decryption_key) { | ||||
|   if (decryption_key.length() == 0) { | ||||
|     ESP_LOGI(TAG, "Disabling decryption"); | ||||
|     this->decryption_key_.clear(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (decryption_key.length() != 32) { | ||||
|     ESP_LOGE(TAG, "Error, decryption key must be 32 character long."); | ||||
|     return; | ||||
|   } | ||||
|   this->decryption_key_.clear(); | ||||
|  | ||||
|   ESP_LOGI(TAG, "Decryption key is set."); | ||||
|   // Verbose level prints decryption key | ||||
|   ESP_LOGV(TAG, "Using decryption key: %s", decryption_key.c_str()); | ||||
|  | ||||
|   char temp[3] = {0}; | ||||
|   for (int i = 0; i < 16; i++) { | ||||
|     strncpy(temp, &(decryption_key.c_str()[i * 2]), 2); | ||||
|     decryption_key_.push_back(std::strtoul(temp, nullptr, 16)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace dsmr | ||||
| }  // namespace esphome | ||||
							
								
								
									
										104
									
								
								esphome/components/dsmr/dsmr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								esphome/components/dsmr/dsmr.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/text_sensor/text_sensor.h" | ||||
| #include "esphome/components/uart/uart.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/defines.h" | ||||
|  | ||||
| // don't include <dsmr.h> because it puts everything in global namespace | ||||
| #include <dsmr/parser.h> | ||||
| #include <dsmr/fields.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace dsmr { | ||||
|  | ||||
| static constexpr uint32_t MAX_TELEGRAM_LENGTH = 1500; | ||||
| static constexpr uint32_t POLL_TIMEOUT = 1000; | ||||
|  | ||||
| using namespace ::dsmr::fields; | ||||
|  | ||||
| // DSMR_**_LIST generated by ESPHome and written in esphome/core/defines | ||||
|  | ||||
| #if !defined(DSMR_SENSOR_LIST) && !defined(DSMR_TEXT_SENSOR_LIST) | ||||
| // Neither set, set it to a dummy value to not break build | ||||
| #define DSMR_TEXT_SENSOR_LIST(F, SEP) F(identification) | ||||
| #endif | ||||
|  | ||||
| #if defined(DSMR_SENSOR_LIST) && defined(DSMR_TEXT_SENSOR_LIST) | ||||
| #define DSMR_BOTH , | ||||
| #else | ||||
| #define DSMR_BOTH | ||||
| #endif | ||||
|  | ||||
| #ifndef DSMR_SENSOR_LIST | ||||
| #define DSMR_SENSOR_LIST(F, SEP) | ||||
| #endif | ||||
|  | ||||
| #ifndef DSMR_TEXT_SENSOR_LIST | ||||
| #define DSMR_TEXT_SENSOR_LIST(F, SEP) | ||||
| #endif | ||||
|  | ||||
| #define DSMR_DATA_SENSOR(s) s | ||||
| #define DSMR_COMMA , | ||||
|  | ||||
| using MyData = ::dsmr::ParsedData<DSMR_TEXT_SENSOR_LIST(DSMR_DATA_SENSOR, DSMR_COMMA) | ||||
|                                       DSMR_BOTH DSMR_SENSOR_LIST(DSMR_DATA_SENSOR, DSMR_COMMA)>; | ||||
|  | ||||
| class Dsmr : public Component, public uart::UARTDevice { | ||||
|  public: | ||||
|   Dsmr(uart::UARTComponent *uart) : uart::UARTDevice(uart) {} | ||||
|  | ||||
|   void loop() override; | ||||
|  | ||||
|   bool parse_telegram(); | ||||
|  | ||||
|   void publish_sensors(MyData &data) { | ||||
| #define DSMR_PUBLISH_SENSOR(s) \ | ||||
|   if (data.s##_present && this->s_##s##_ != nullptr) \ | ||||
|     s_##s##_->publish_state(data.s); | ||||
|     DSMR_SENSOR_LIST(DSMR_PUBLISH_SENSOR, ) | ||||
|  | ||||
| #define DSMR_PUBLISH_TEXT_SENSOR(s) \ | ||||
|   if (data.s##_present && this->s_##s##_ != nullptr) \ | ||||
|     s_##s##_->publish_state(data.s.c_str()); | ||||
|     DSMR_TEXT_SENSOR_LIST(DSMR_PUBLISH_TEXT_SENSOR, ) | ||||
|   }; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_decryption_key(const std::string &decryption_key); | ||||
|  | ||||
| // Sensor setters | ||||
| #define DSMR_SET_SENSOR(s) \ | ||||
|   void set_##s(sensor::Sensor *sensor) { s_##s##_ = sensor; } | ||||
|   DSMR_SENSOR_LIST(DSMR_SET_SENSOR, ) | ||||
|  | ||||
| #define DSMR_SET_TEXT_SENSOR(s) \ | ||||
|   void set_##s(text_sensor::TextSensor *sensor) { s_##s##_ = sensor; } | ||||
|   DSMR_TEXT_SENSOR_LIST(DSMR_SET_TEXT_SENSOR, ) | ||||
|  | ||||
|  protected: | ||||
|   void receive_telegram_(); | ||||
|   void receive_encrypted_(); | ||||
|  | ||||
|   // Telegram buffer | ||||
|   char telegram_[MAX_TELEGRAM_LENGTH]; | ||||
|   int telegram_len_{0}; | ||||
|  | ||||
|   // Serial parser | ||||
|   bool header_found_{false}; | ||||
|   bool footer_found_{false}; | ||||
|  | ||||
| // Sensor member pointers | ||||
| #define DSMR_DECLARE_SENSOR(s) sensor::Sensor *s_##s##_{nullptr}; | ||||
|   DSMR_SENSOR_LIST(DSMR_DECLARE_SENSOR, ) | ||||
|  | ||||
| #define DSMR_DECLARE_TEXT_SENSOR(s) text_sensor::TextSensor *s_##s##_{nullptr}; | ||||
|   DSMR_TEXT_SENSOR_LIST(DSMR_DECLARE_TEXT_SENSOR, ) | ||||
|  | ||||
|   std::vector<uint8_t> decryption_key_{}; | ||||
| }; | ||||
| }  // namespace dsmr | ||||
| }  // namespace esphome | ||||
							
								
								
									
										210
									
								
								esphome/components/dsmr/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								esphome/components/dsmr/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_CURRENT, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_ENERGY, | ||||
|     DEVICE_CLASS_POWER, | ||||
|     DEVICE_CLASS_VOLTAGE, | ||||
|     ICON_EMPTY, | ||||
|     LAST_RESET_TYPE_NEVER, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     STATE_CLASS_NONE, | ||||
|     UNIT_AMPERE, | ||||
|     UNIT_EMPTY, | ||||
|     UNIT_VOLT, | ||||
|     UNIT_WATT, | ||||
| ) | ||||
| from . import Dsmr, CONF_DSMR_ID | ||||
|  | ||||
| AUTO_LOAD = ["dsmr"] | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_DSMR_ID): cv.use_id(Dsmr), | ||||
|         cv.Optional("energy_delivered_lux"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("energy_delivered_tariff1"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("energy_delivered_tariff2"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("energy_returned_lux"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("energy_returned_tariff1"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("energy_returned_tariff2"): sensor.sensor_schema( | ||||
|             "kWh", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_ENERGY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("total_imported_energy"): sensor.sensor_schema( | ||||
|             "kvarh", ICON_EMPTY, 3, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("total_exported_energy"): sensor.sensor_schema( | ||||
|             "kvarh", ICON_EMPTY, 3, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("power_delivered"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_returned"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_delivered"): sensor.sensor_schema( | ||||
|             "kvar", ICON_EMPTY, 3, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("reactive_power_returned"): sensor.sensor_schema( | ||||
|             "kvar", ICON_EMPTY, 3, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("electricity_threshold"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_switch_position"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_failures"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_long_failures"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_sags_l1"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_sags_l2"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("electricity_sags_l3"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_swells_l1"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("electricity_swells_l2"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("electricity_swells_l3"): sensor.sensor_schema( | ||||
|             UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("current_l1"): sensor.sensor_schema( | ||||
|             UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("current_l2"): sensor.sensor_schema( | ||||
|             UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("current_l3"): sensor.sensor_schema( | ||||
|             UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_delivered_l1"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_delivered_l2"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_delivered_l3"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_returned_l1"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_returned_l2"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("power_returned_l3"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_delivered_l1"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_delivered_l2"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_delivered_l3"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_returned_l1"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_returned_l2"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("reactive_power_returned_l3"): sensor.sensor_schema( | ||||
|             UNIT_WATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT | ||||
|         ), | ||||
|         cv.Optional("voltage_l1"): sensor.sensor_schema( | ||||
|             UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("voltage_l2"): sensor.sensor_schema( | ||||
|             UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("voltage_l3"): sensor.sensor_schema( | ||||
|             UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE | ||||
|         ), | ||||
|         cv.Optional("gas_delivered"): sensor.sensor_schema( | ||||
|             "m³", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|         cv.Optional("gas_delivered_be"): sensor.sensor_schema( | ||||
|             "m³", | ||||
|             ICON_EMPTY, | ||||
|             3, | ||||
|             DEVICE_CLASS_EMPTY, | ||||
|             STATE_CLASS_MEASUREMENT, | ||||
|             LAST_RESET_TYPE_NEVER, | ||||
|         ), | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     hub = await cg.get_variable(config[CONF_DSMR_ID]) | ||||
|  | ||||
|     sensors = [] | ||||
|     for key, conf in config.items(): | ||||
|         if not isinstance(conf, dict): | ||||
|             continue | ||||
|         id = conf.get("id") | ||||
|         if id and id.type == sensor.Sensor: | ||||
|             s = await sensor.new_sensor(conf) | ||||
|             cg.add(getattr(hub, f"set_{key}")(s)) | ||||
|             sensors.append(f"F({key})") | ||||
|  | ||||
|     cg.add_define("DSMR_SENSOR_LIST(F, sep)", cg.RawExpression(" sep ".join(sensors))) | ||||
							
								
								
									
										94
									
								
								esphome/components/dsmr/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								esphome/components/dsmr/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import text_sensor | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
| ) | ||||
| from . import Dsmr, CONF_DSMR_ID | ||||
|  | ||||
| AUTO_LOAD = ["dsmr"] | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_DSMR_ID): cv.use_id(Dsmr), | ||||
|         cv.Optional("identification"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("p1_version"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("p1_version_be"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("timestamp"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("electricity_tariff"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("electricity_failure_log"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("message_short"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("message_long"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("gas_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("thermal_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("water_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional("sub_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( | ||||
|             { | ||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), | ||||
|             } | ||||
|         ), | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     hub = await cg.get_variable(config[CONF_DSMR_ID]) | ||||
|  | ||||
|     text_sensors = [] | ||||
|     for key, conf in config.items(): | ||||
|         if not isinstance(conf, dict): | ||||
|             continue | ||||
|         id = conf.get("id") | ||||
|         if id and id.type == text_sensor.TextSensor: | ||||
|             var = cg.new_Pvariable(conf[CONF_ID]) | ||||
|             await text_sensor.register_text_sensor(var, conf) | ||||
|             cg.add(getattr(hub, f"set_{key}")(var)) | ||||
|             text_sensors.append(f"F({key})") | ||||
|  | ||||
|     cg.add_define( | ||||
|         "DSMR_TEXT_SENSOR_LIST(F, sep)", cg.RawExpression(" sep ".join(text_sensors)) | ||||
|     ) | ||||
| @@ -5,7 +5,6 @@ from esphome.components import sensor | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_PIN, | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_PERCENT, | ||||
|     ICON_PERCENT, | ||||
| @@ -18,7 +17,10 @@ DutyCycleSensor = duty_cycle_ns.class_( | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     sensor.sensor_schema( | ||||
|         UNIT_PERCENT, ICON_PERCENT, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT | ||||
|         unit_of_measurement=UNIT_PERCENT, | ||||
|         icon=ICON_PERCENT, | ||||
|         accuracy_decimals=1, | ||||
|         state_class=STATE_CLASS_MEASUREMENT, | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|   | ||||
| @@ -50,7 +50,7 @@ void E131Component::loop() { | ||||
|     } | ||||
|  | ||||
|     if (!packet_(payload, universe, packet)) { | ||||
|       ESP_LOGV(TAG, "Invalid packet recevied of size %zu.", payload.size()); | ||||
|       ESP_LOGV(TAG, "Invalid packet received of size %zu.", payload.size()); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,8 @@ | ||||
| namespace esphome { | ||||
| namespace esp32_ble { | ||||
|  | ||||
| static const char *const TAG = "esp32_ble"; | ||||
|  | ||||
| BLEAdvertising::BLEAdvertising() { | ||||
|   this->advertising_data_.set_scan_rsp = false; | ||||
|   this->advertising_data_.include_name = true; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user