From 7a242bb4ed9cb78f8a78be3e8cc091c895caa52e Mon Sep 17 00:00:00 2001
From: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Date: Fri, 18 Feb 2022 10:39:59 +1300
Subject: [PATCH] Binary Sensor codegen tidyup (#3217)

---
 esphome/components/apds9960/binary_sensor.py  | 11 +++--
 esphome/components/as3935/binary_sensor.py    |  2 +-
 esphome/components/binary_sensor/__init__.py  | 40 ++++++++++++++++++-
 .../components/ble_presence/binary_sensor.py  |  8 ++--
 esphome/components/ble_scanner/text_sensor.py |  2 +-
 esphome/components/cap1188/binary_sensor.py   |  8 ++--
 .../custom/binary_sensor/__init__.py          |  2 +-
 esphome/components/daly_bms/binary_sensor.py  | 18 ++-------
 esphome/components/demo/__init__.py           | 11 ++---
 .../components/esp32_touch/binary_sensor.py   |  3 +-
 .../fingerprint_grow/binary_sensor.py         |  2 +-
 .../components/gpio/binary_sensor/__init__.py | 20 +++++-----
 .../homeassistant/binary_sensor/__init__.py   | 22 +++++-----
 .../binary_sensor/__init__.py                 |  4 +-
 esphome/components/mpr121/binary_sensor.py    |  8 ++--
 .../nextion/binary_sensor/__init__.py         |  4 +-
 .../nextion/text_sensor/__init__.py           |  2 +-
 .../pipsolar/binary_sensor/__init__.py        | 11 ++---
 esphome/components/pn532/binary_sensor.py     |  8 ++--
 esphome/components/rc522/binary_sensor.py     |  8 ++--
 esphome/components/rdm6300/binary_sensor.py   |  8 ++--
 esphome/components/remote_base/__init__.py    |  2 +-
 esphome/components/sim800l/binary_sensor.py   | 14 ++-----
 esphome/components/status/binary_sensor.py    | 20 +++-------
 .../sx1509/binary_sensor/__init__.py          |  8 ++--
 .../teleinfo/text_sensor/__init__.py          |  2 +-
 .../template/binary_sensor/__init__.py        | 18 +++++----
 esphome/components/text_sensor/__init__.py    |  7 ++--
 .../touchscreen/binary_sensor/__init__.py     | 11 +++--
 .../components/ttp229_bsf/binary_sensor.py    |  8 ++--
 .../components/ttp229_lsf/binary_sensor.py    |  8 ++--
 .../components/tuya/binary_sensor/__init__.py | 23 ++++++-----
 esphome/components/wifi_info/text_sensor.py   | 10 ++---
 .../components/xiaomi_cgpr1/binary_sensor.py  | 25 +++++-------
 .../xiaomi_mjyd02yla/binary_sensor.py         | 24 +++++------
 .../xiaomi_mue4094rt/binary_sensor.py         | 18 +++++----
 .../components/xiaomi_wx08zm/binary_sensor.py | 10 ++---
 esphome/components/xpt2046/binary_sensor.py   |  8 ++--
 38 files changed, 196 insertions(+), 222 deletions(-)

diff --git a/esphome/components/apds9960/binary_sensor.py b/esphome/components/apds9960/binary_sensor.py
index 4a5c69f6a9..04dc6f4d5d 100644
--- a/esphome/components/apds9960/binary_sensor.py
+++ b/esphome/components/apds9960/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_DIRECTION, CONF_DEVICE_CLASS, DEVICE_CLASS_MOVING
+from esphome.const import CONF_DIRECTION, DEVICE_CLASS_MOVING
 from . import APDS9960, CONF_APDS9960_ID
 
 DEPENDENCIES = ["apds9960"]
@@ -13,13 +13,12 @@ DIRECTIONS = {
     "RIGHT": "set_right_direction",
 }
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
+    device_class=DEVICE_CLASS_MOVING
+).extend(
     {
-        cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
         cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
-        cv.Optional(
-            CONF_DEVICE_CLASS, default=DEVICE_CLASS_MOVING
-        ): binary_sensor.device_class,
+        cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
     }
 )
 
diff --git a/esphome/components/as3935/binary_sensor.py b/esphome/components/as3935/binary_sensor.py
index 11b2ac812c..3081d2115f 100644
--- a/esphome/components/as3935/binary_sensor.py
+++ b/esphome/components/as3935/binary_sensor.py
@@ -5,7 +5,7 @@ from . import AS3935, CONF_AS3935_ID
 
 DEPENDENCIES = ["as3935"]
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend(
     {
         cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
     }
diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py
index c6065ddae4..40f95d72f9 100644
--- a/esphome/components/binary_sensor/__init__.py
+++ b/esphome/components/binary_sensor/__init__.py
@@ -1,5 +1,6 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
+from esphome.cpp_generator import MockObjClass
 from esphome.cpp_helpers import setup_entity
 from esphome import automation, core
 from esphome.automation import Condition, maybe_simple_id
@@ -7,7 +8,9 @@ from esphome.components import mqtt
 from esphome.const import (
     CONF_DELAY,
     CONF_DEVICE_CLASS,
+    CONF_ENTITY_CATEGORY,
     CONF_FILTERS,
+    CONF_ICON,
     CONF_ID,
     CONF_INVALID_COOLDOWN,
     CONF_INVERTED,
@@ -314,7 +317,7 @@ def validate_multi_click_timing(value):
     return timings
 
 
-device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
+validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
 
 
 BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
@@ -323,7 +326,7 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex
         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
             mqtt.MQTTBinarySensorComponent
         ),
-        cv.Optional(CONF_DEVICE_CLASS): device_class,
+        cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
         cv.Optional(CONF_FILTERS): validate_filters,
         cv.Optional(CONF_ON_PRESS): automation.validate_automation(
             {
@@ -376,6 +379,39 @@ BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).ex
     }
 )
 
+_UNDEF = object()
+
+
+def binary_sensor_schema(
+    class_: MockObjClass = _UNDEF,
+    *,
+    icon: str = _UNDEF,
+    entity_category: str = _UNDEF,
+    device_class: str = _UNDEF,
+) -> cv.Schema:
+    schema = BINARY_SENSOR_SCHEMA
+    if class_ is not _UNDEF:
+        schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
+    if icon is not _UNDEF:
+        schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
+    if entity_category is not _UNDEF:
+        schema = schema.extend(
+            {
+                cv.Optional(
+                    CONF_ENTITY_CATEGORY, default=entity_category
+                ): cv.entity_category
+            }
+        )
+    if device_class is not _UNDEF:
+        schema = schema.extend(
+            {
+                cv.Optional(
+                    CONF_DEVICE_CLASS, default=device_class
+                ): validate_device_class
+            }
+        )
+    return schema
+
 
 async def setup_binary_sensor_core_(var, config):
     await setup_entity(var, config)
diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py
index 2a242c3aca..67f2c3516f 100644
--- a/esphome/components/ble_presence/binary_sensor.py
+++ b/esphome/components/ble_presence/binary_sensor.py
@@ -7,7 +7,6 @@ from esphome.const import (
     CONF_IBEACON_MAJOR,
     CONF_IBEACON_MINOR,
     CONF_IBEACON_UUID,
-    CONF_ID,
 )
 
 DEPENDENCIES = ["esp32_ble_tracker"]
@@ -30,9 +29,9 @@ def _validate(config):
 
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(BLEPresenceDevice)
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(BLEPresenceDevice),
             cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
             cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
             cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
@@ -48,10 +47,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
     await esp32_ble_tracker.register_ble_device(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     if CONF_MAC_ADDRESS in config:
         cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
diff --git a/esphome/components/ble_scanner/text_sensor.py b/esphome/components/ble_scanner/text_sensor.py
index 31dccdf119..743403c6a4 100644
--- a/esphome/components/ble_scanner/text_sensor.py
+++ b/esphome/components/ble_scanner/text_sensor.py
@@ -13,7 +13,7 @@ BLEScanner = ble_scanner_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    text_sensor.text_sensor_schema(klass=BLEScanner)
+    text_sensor.text_sensor_schema(BLEScanner)
     .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
     .extend(cv.COMPONENT_SCHEMA)
 )
diff --git a/esphome/components/cap1188/binary_sensor.py b/esphome/components/cap1188/binary_sensor.py
index c249eb7330..7950774340 100644
--- a/esphome/components/cap1188/binary_sensor.py
+++ b/esphome/components/cap1188/binary_sensor.py
@@ -1,15 +1,14 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_CHANNEL, CONF_ID
+from esphome.const import CONF_CHANNEL
 from . import cap1188_ns, CAP1188Component, CONF_CAP1188_ID
 
 DEPENDENCIES = ["cap1188"]
 CAP1188Channel = cap1188_ns.class_("CAP1188Channel", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(CAP1188Channel).extend(
     {
-        cv.GenerateID(): cv.declare_id(CAP1188Channel),
         cv.GenerateID(CONF_CAP1188_ID): cv.use_id(CAP1188Component),
         cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
     }
@@ -17,8 +16,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
     hub = await cg.get_variable(config[CONF_CAP1188_ID])
     cg.add(var.set_channel(config[CONF_CHANNEL]))
 
diff --git a/esphome/components/custom/binary_sensor/__init__.py b/esphome/components/custom/binary_sensor/__init__.py
index 18d613d4c1..8d6d621b3a 100644
--- a/esphome/components/custom/binary_sensor/__init__.py
+++ b/esphome/components/custom/binary_sensor/__init__.py
@@ -11,7 +11,7 @@ CONFIG_SCHEMA = cv.Schema(
         cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
         cv.Required(CONF_LAMBDA): cv.returning_lambda,
         cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(
-            binary_sensor.BINARY_SENSOR_SCHEMA
+            binary_sensor.binary_sensor_schema()
         ),
     }
 )
diff --git a/esphome/components/daly_bms/binary_sensor.py b/esphome/components/daly_bms/binary_sensor.py
index 23330cd945..7b252b5e89 100644
--- a/esphome/components/daly_bms/binary_sensor.py
+++ b/esphome/components/daly_bms/binary_sensor.py
@@ -1,7 +1,6 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_ID
 from . import DalyBmsComponent, CONF_BMS_DALY_ID
 
 CONF_CHARGING_MOS_ENABLED = "charging_mos_enabled"
@@ -18,18 +17,10 @@ CONFIG_SCHEMA = cv.All(
             cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
             cv.Optional(
                 CONF_CHARGING_MOS_ENABLED
-            ): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-                {
-                    cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
-                }
-            ),
+            ): binary_sensor.binary_sensor_schema(),
             cv.Optional(
                 CONF_DISCHARGING_MOS_ENABLED
-            ): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-                {
-                    cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
-                }
-            ),
+            ): binary_sensor.binary_sensor_schema(),
         }
     ).extend(cv.COMPONENT_SCHEMA)
 )
@@ -38,9 +29,8 @@ CONFIG_SCHEMA = cv.All(
 async def setup_conf(config, key, hub):
     if key in config:
         conf = config[key]
-        sens = cg.new_Pvariable(conf[CONF_ID])
-        await binary_sensor.register_binary_sensor(sens, conf)
-        cg.add(getattr(hub, f"set_{key}_binary_sensor")(sens))
+        var = await binary_sensor.new_binary_sensor(conf)
+        cg.add(getattr(hub, f"set_{key}_binary_sensor")(var))
 
 
 async def to_code(config):
diff --git a/esphome/components/demo/__init__.py b/esphome/components/demo/__init__.py
index 77b1680d26..7aa742919a 100644
--- a/esphome/components/demo/__init__.py
+++ b/esphome/components/demo/__init__.py
@@ -132,12 +132,8 @@ CONFIG_SCHEMA = cv.Schema(
                 },
             ],
         ): [
-            binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+            binary_sensor.binary_sensor_schema(DemoBinarySensor).extend(
                 cv.polling_component_schema("60s")
-            ).extend(
-                {
-                    cv.GenerateID(): cv.declare_id(DemoBinarySensor),
-                }
             )
         ],
         cv.Optional(
@@ -372,7 +368,7 @@ CONFIG_SCHEMA = cv.Schema(
                 },
             ],
         ): [
-            text_sensor.text_sensor_schema(klass=DemoTextSensor).extend(
+            text_sensor.text_sensor_schema(DemoTextSensor).extend(
                 cv.polling_component_schema("60s")
             )
         ],
@@ -382,9 +378,8 @@ CONFIG_SCHEMA = cv.Schema(
 
 async def to_code(config):
     for conf in config[CONF_BINARY_SENSORS]:
-        var = cg.new_Pvariable(conf[CONF_ID])
+        var = await binary_sensor.new_binary_sensor(conf)
         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])
diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py
index bd3e06545d..326f559830 100644
--- a/esphome/components/esp32_touch/binary_sensor.py
+++ b/esphome/components/esp32_touch/binary_sensor.py
@@ -39,9 +39,8 @@ ESP32TouchBinarySensor = esp32_touch_ns.class_(
     "ESP32TouchBinarySensor", binary_sensor.BinarySensor
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(ESP32TouchBinarySensor).extend(
     {
-        cv.GenerateID(): cv.declare_id(ESP32TouchBinarySensor),
         cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_id(ESP32TouchComponent),
         cv.Required(CONF_PIN): validate_touch_pad,
         cv.Required(CONF_THRESHOLD): cv.uint16_t,
diff --git a/esphome/components/fingerprint_grow/binary_sensor.py b/esphome/components/fingerprint_grow/binary_sensor.py
index f432ef92cc..8572919e36 100644
--- a/esphome/components/fingerprint_grow/binary_sensor.py
+++ b/esphome/components/fingerprint_grow/binary_sensor.py
@@ -6,7 +6,7 @@ from . import CONF_FINGERPRINT_GROW_ID, FingerprintGrowComponent
 
 DEPENDENCIES = ["fingerprint_grow"]
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend(
     {
         cv.GenerateID(CONF_FINGERPRINT_GROW_ID): cv.use_id(FingerprintGrowComponent),
         cv.Optional(CONF_ICON, default=ICON_KEY_PLUS): cv.icon,
diff --git a/esphome/components/gpio/binary_sensor/__init__.py b/esphome/components/gpio/binary_sensor/__init__.py
index 4d91b81a44..786c3f4b96 100644
--- a/esphome/components/gpio/binary_sensor/__init__.py
+++ b/esphome/components/gpio/binary_sensor/__init__.py
@@ -2,25 +2,27 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome import pins
 from esphome.components import binary_sensor
-from esphome.const import CONF_ID, CONF_PIN
+from esphome.const import CONF_PIN
 from .. import gpio_ns
 
 GPIOBinarySensor = gpio_ns.class_(
     "GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-    {
-        cv.GenerateID(): cv.declare_id(GPIOBinarySensor),
-        cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
-    }
-).extend(cv.COMPONENT_SCHEMA)
+CONFIG_SCHEMA = (
+    binary_sensor.binary_sensor_schema(GPIOBinarySensor)
+    .extend(
+        {
+            cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
+        }
+    )
+    .extend(cv.COMPONENT_SCHEMA)
+)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     pin = await cg.gpio_pin_expression(config[CONF_PIN])
     cg.add(var.set_pin(pin))
diff --git a/esphome/components/homeassistant/binary_sensor/__init__.py b/esphome/components/homeassistant/binary_sensor/__init__.py
index 4972466aac..a4f854c16e 100644
--- a/esphome/components/homeassistant/binary_sensor/__init__.py
+++ b/esphome/components/homeassistant/binary_sensor/__init__.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_ID
+from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID
 from .. import homeassistant_ns
 
 DEPENDENCIES = ["api"]
@@ -9,19 +9,21 @@ HomeassistantBinarySensor = homeassistant_ns.class_(
     "HomeassistantBinarySensor", binary_sensor.BinarySensor, cg.Component
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-    {
-        cv.GenerateID(): cv.declare_id(HomeassistantBinarySensor),
-        cv.Required(CONF_ENTITY_ID): cv.entity_id,
-        cv.Optional(CONF_ATTRIBUTE): cv.string,
-    }
-).extend(cv.COMPONENT_SCHEMA)
+CONFIG_SCHEMA = (
+    binary_sensor.binary_sensor_schema(HomeassistantBinarySensor)
+    .extend(
+        {
+            cv.Required(CONF_ENTITY_ID): cv.entity_id,
+            cv.Optional(CONF_ATTRIBUTE): cv.string,
+        }
+    )
+    .extend(cv.COMPONENT_SCHEMA)
+)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
     if CONF_ATTRIBUTE in config:
diff --git a/esphome/components/modbus_controller/binary_sensor/__init__.py b/esphome/components/modbus_controller/binary_sensor/__init__.py
index 557d76479d..5315167479 100644
--- a/esphome/components/modbus_controller/binary_sensor/__init__.py
+++ b/esphome/components/modbus_controller/binary_sensor/__init__.py
@@ -29,11 +29,11 @@ ModbusBinarySensor = modbus_controller_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(cv.COMPONENT_SCHEMA)
+    binary_sensor.binary_sensor_schema(ModbusBinarySensor)
+    .extend(cv.COMPONENT_SCHEMA)
     .extend(ModbusItemBaseSchema)
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(ModbusBinarySensor),
             cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
         }
     ),
diff --git a/esphome/components/mpr121/binary_sensor.py b/esphome/components/mpr121/binary_sensor.py
index 20b80e063e..131fbcfc5b 100644
--- a/esphome/components/mpr121/binary_sensor.py
+++ b/esphome/components/mpr121/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_CHANNEL, CONF_ID
+from esphome.const import CONF_CHANNEL
 from . import (
     mpr121_ns,
     MPR121Component,
@@ -13,9 +13,8 @@ from . import (
 DEPENDENCIES = ["mpr121"]
 MPR121Channel = mpr121_ns.class_("MPR121Channel", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(MPR121Channel).extend(
     {
-        cv.GenerateID(): cv.declare_id(MPR121Channel),
         cv.GenerateID(CONF_MPR121_ID): cv.use_id(MPR121Component),
         cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=11),
         cv.Optional(CONF_TOUCH_THRESHOLD): cv.int_range(min=0x05, max=0x30),
@@ -25,8 +24,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
     hub = await cg.get_variable(config[CONF_MPR121_ID])
     cg.add(var.set_channel(config[CONF_CHANNEL]))
 
diff --git a/esphome/components/nextion/binary_sensor/__init__.py b/esphome/components/nextion/binary_sensor/__init__.py
index 090fae3429..8b4a45cc60 100644
--- a/esphome/components/nextion/binary_sensor/__init__.py
+++ b/esphome/components/nextion/binary_sensor/__init__.py
@@ -20,9 +20,9 @@ NextionBinarySensor = nextion_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(NextionBinarySensor)
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(NextionBinarySensor),
             cv.Optional(CONF_PAGE_ID): cv.uint8_t,
             cv.Optional(CONF_COMPONENT_ID): cv.uint8_t,
         }
diff --git a/esphome/components/nextion/text_sensor/__init__.py b/esphome/components/nextion/text_sensor/__init__.py
index 9b8518d8c4..826ff2354e 100644
--- a/esphome/components/nextion/text_sensor/__init__.py
+++ b/esphome/components/nextion/text_sensor/__init__.py
@@ -17,7 +17,7 @@ NextionTextSensor = nextion_ns.class_(
 )
 
 CONFIG_SCHEMA = (
-    text_sensor.text_sensor_schema(klass=NextionTextSensor)
+    text_sensor.text_sensor_schema(NextionTextSensor)
     .extend(CONFIG_TEXT_COMPONENT_SCHEMA)
     .extend(cv.polling_component_schema("never"))
 )
diff --git a/esphome/components/pipsolar/binary_sensor/__init__.py b/esphome/components/pipsolar/binary_sensor/__init__.py
index 5c6af3bffc..f4b34fd594 100644
--- a/esphome/components/pipsolar/binary_sensor/__init__.py
+++ b/esphome/components/pipsolar/binary_sensor/__init__.py
@@ -1,9 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import (
-    CONF_ID,
-)
+
 from .. import PIPSOLAR_COMPONENT_SCHEMA, CONF_PIPSOLAR_ID
 
 DEPENDENCIES = ["uart"]
@@ -130,7 +128,7 @@ TYPES = [
 ]
 
 CONFIG_SCHEMA = PIPSOLAR_COMPONENT_SCHEMA.extend(
-    {cv.Optional(type): binary_sensor.BINARY_SENSOR_SCHEMA for type in TYPES}
+    {cv.Optional(type): binary_sensor.binary_sensor_schema() for type in TYPES}
 )
 
 
@@ -139,6 +137,5 @@ async def to_code(config):
     for type in TYPES:
         if type in config:
             conf = config[type]
-            sens = cg.new_Pvariable(conf[CONF_ID])
-            await binary_sensor.register_binary_sensor(sens, conf)
-            cg.add(getattr(paren, f"set_{type}")(sens))
+            var = await binary_sensor.new_binary_sensor(conf)
+            cg.add(getattr(paren, f"set_{type}")(var))
diff --git a/esphome/components/pn532/binary_sensor.py b/esphome/components/pn532/binary_sensor.py
index 9a5816b322..9bcae30750 100644
--- a/esphome/components/pn532/binary_sensor.py
+++ b/esphome/components/pn532/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_UID, CONF_ID
+from esphome.const import CONF_UID
 from esphome.core import HexInt
 from . import pn532_ns, PN532, CONF_PN532_ID
 
@@ -31,9 +31,8 @@ def validate_uid(value):
 
 PN532BinarySensor = pn532_ns.class_("PN532BinarySensor", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(PN532BinarySensor).extend(
     {
-        cv.GenerateID(): cv.declare_id(PN532BinarySensor),
         cv.GenerateID(CONF_PN532_ID): cv.use_id(PN532),
         cv.Required(CONF_UID): validate_uid,
     }
@@ -41,8 +40,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
 
     hub = await cg.get_variable(config[CONF_PN532_ID])
     cg.add(hub.register_tag(var))
diff --git a/esphome/components/rc522/binary_sensor.py b/esphome/components/rc522/binary_sensor.py
index 67d3068599..716c0eca76 100644
--- a/esphome/components/rc522/binary_sensor.py
+++ b/esphome/components/rc522/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_UID, CONF_ID
+from esphome.const import CONF_UID
 from esphome.core import HexInt
 from . import rc522_ns, RC522, CONF_RC522_ID
 
@@ -31,9 +31,8 @@ def validate_uid(value):
 
 RC522BinarySensor = rc522_ns.class_("RC522BinarySensor", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(RC522BinarySensor).extend(
     {
-        cv.GenerateID(): cv.declare_id(RC522BinarySensor),
         cv.GenerateID(CONF_RC522_ID): cv.use_id(RC522),
         cv.Required(CONF_UID): validate_uid,
     }
@@ -41,8 +40,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
 
     hub = await cg.get_variable(config[CONF_RC522_ID])
     cg.add(hub.register_tag(var))
diff --git a/esphome/components/rdm6300/binary_sensor.py b/esphome/components/rdm6300/binary_sensor.py
index c99a2bfc06..cd808b92cc 100644
--- a/esphome/components/rdm6300/binary_sensor.py
+++ b/esphome/components/rdm6300/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor, rdm6300
-from esphome.const import CONF_UID, CONF_ID
+from esphome.const import CONF_UID
 from . import rdm6300_ns
 
 DEPENDENCIES = ["rdm6300"]
@@ -11,9 +11,8 @@ RDM6300BinarySensor = rdm6300_ns.class_(
     "RDM6300BinarySensor", binary_sensor.BinarySensor
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(RDM6300BinarySensor).extend(
     {
-        cv.GenerateID(): cv.declare_id(RDM6300BinarySensor),
         cv.GenerateID(CONF_RDM6300_ID): cv.use_id(rdm6300.RDM6300Component),
         cv.Required(CONF_UID): cv.uint32_t,
     }
@@ -21,8 +20,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
 
     hub = await cg.get_variable(config[CONF_RDM6300_ID])
     cg.add(hub.register_card(var))
diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py
index 9bf03aaf28..531761ee95 100644
--- a/esphome/components/remote_base/__init__.py
+++ b/esphome/components/remote_base/__init__.py
@@ -165,7 +165,7 @@ def declare_protocol(name):
 
 
 BINARY_SENSOR_REGISTRY = Registry(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema().extend(
         {
             cv.GenerateID(CONF_RECEIVER_ID): cv.use_id(RemoteReceiverBase),
         }
diff --git a/esphome/components/sim800l/binary_sensor.py b/esphome/components/sim800l/binary_sensor.py
index 7cee04374b..f046d031ea 100644
--- a/esphome/components/sim800l/binary_sensor.py
+++ b/esphome/components/sim800l/binary_sensor.py
@@ -2,8 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
 from esphome.const import (
-    CONF_DEVICE_CLASS,
-    CONF_ENTITY_CATEGORY,
     DEVICE_CLASS_CONNECTIVITY,
     ENTITY_CATEGORY_DIAGNOSTIC,
 )
@@ -15,15 +13,9 @@ CONF_REGISTERED = "registered"
 
 CONFIG_SCHEMA = {
     cv.GenerateID(CONF_SIM800L_ID): cv.use_id(Sim800LComponent),
-    cv.Optional(CONF_REGISTERED): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-        {
-            cv.Optional(
-                CONF_DEVICE_CLASS, default=DEVICE_CLASS_CONNECTIVITY
-            ): binary_sensor.device_class,
-            cv.Optional(
-                CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_DIAGNOSTIC
-            ): cv.entity_category,
-        }
+    cv.Optional(CONF_REGISTERED): binary_sensor.binary_sensor_schema(
+        device_class=DEVICE_CLASS_CONNECTIVITY,
+        entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
     ),
 }
 
diff --git a/esphome/components/status/binary_sensor.py b/esphome/components/status/binary_sensor.py
index 9367706388..1f2b7c9d18 100644
--- a/esphome/components/status/binary_sensor.py
+++ b/esphome/components/status/binary_sensor.py
@@ -2,9 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
 from esphome.const import (
-    CONF_ENTITY_CATEGORY,
-    CONF_ID,
-    CONF_DEVICE_CLASS,
     DEVICE_CLASS_CONNECTIVITY,
     ENTITY_CATEGORY_DIAGNOSTIC,
 )
@@ -14,20 +11,13 @@ StatusBinarySensor = status_ns.class_(
     "StatusBinarySensor", binary_sensor.BinarySensor, cg.Component
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-    {
-        cv.GenerateID(): cv.declare_id(StatusBinarySensor),
-        cv.Optional(
-            CONF_DEVICE_CLASS, default=DEVICE_CLASS_CONNECTIVITY
-        ): binary_sensor.device_class,
-        cv.Optional(
-            CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_DIAGNOSTIC
-        ): cv.entity_category,
-    }
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
+    StatusBinarySensor,
+    device_class=DEVICE_CLASS_CONNECTIVITY,
+    entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
 ).extend(cv.COMPONENT_SCHEMA)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
diff --git a/esphome/components/sx1509/binary_sensor/__init__.py b/esphome/components/sx1509/binary_sensor/__init__.py
index 1560af8e99..bbf0e5d0bc 100644
--- a/esphome/components/sx1509/binary_sensor/__init__.py
+++ b/esphome/components/sx1509/binary_sensor/__init__.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_ID
+
 from .. import SX1509Component, sx1509_ns, CONF_SX1509_ID
 
 CONF_ROW = "row"
@@ -11,9 +11,8 @@ DEPENDENCIES = ["sx1509"]
 
 SX1509BinarySensor = sx1509_ns.class_("SX1509BinarySensor", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(SX1509BinarySensor).extend(
     {
-        cv.GenerateID(): cv.declare_id(SX1509BinarySensor),
         cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component),
         cv.Required(CONF_ROW): cv.int_range(min=0, max=4),
         cv.Required(CONF_COL): cv.int_range(min=0, max=4),
@@ -22,8 +21,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
     hub = await cg.get_variable(config[CONF_SX1509_ID])
     cg.add(var.set_row_col(config[CONF_ROW], config[CONF_COL]))
 
diff --git a/esphome/components/teleinfo/text_sensor/__init__.py b/esphome/components/teleinfo/text_sensor/__init__.py
index 848b08d742..df8e4c21fc 100644
--- a/esphome/components/teleinfo/text_sensor/__init__.py
+++ b/esphome/components/teleinfo/text_sensor/__init__.py
@@ -8,7 +8,7 @@ TeleInfoTextSensor = teleinfo_ns.class_(
     "TeleInfoTextSensor", text_sensor.TextSensor, cg.Component
 )
 
-CONFIG_SCHEMA = text_sensor.text_sensor_schema(klass=TeleInfoTextSensor).extend(
+CONFIG_SCHEMA = text_sensor.text_sensor_schema(TeleInfoTextSensor).extend(
     TELEINFO_LISTENER_SCHEMA
 )
 
diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py
index 8f551e3215..4ce89503de 100644
--- a/esphome/components/template/binary_sensor/__init__.py
+++ b/esphome/components/template/binary_sensor/__init__.py
@@ -9,18 +9,20 @@ TemplateBinarySensor = template_ns.class_(
     "TemplateBinarySensor", binary_sensor.BinarySensor, cg.Component
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-    {
-        cv.GenerateID(): cv.declare_id(TemplateBinarySensor),
-        cv.Optional(CONF_LAMBDA): cv.returning_lambda,
-    }
-).extend(cv.COMPONENT_SCHEMA)
+CONFIG_SCHEMA = (
+    binary_sensor.binary_sensor_schema(TemplateBinarySensor)
+    .extend(
+        {
+            cv.Optional(CONF_LAMBDA): cv.returning_lambda,
+        }
+    )
+    .extend(cv.COMPONENT_SCHEMA)
+)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     if CONF_LAMBDA in config:
         template_ = await cg.process_lambda(
diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py
index de72579402..f2f382ceaa 100644
--- a/esphome/components/text_sensor/__init__.py
+++ b/esphome/components/text_sensor/__init__.py
@@ -137,13 +137,14 @@ _UNDEF = object()
 
 
 def text_sensor_schema(
-    klass: MockObjClass = _UNDEF,
+    class_: MockObjClass = _UNDEF,
+    *,
     icon: str = _UNDEF,
     entity_category: str = _UNDEF,
 ) -> cv.Schema:
     schema = TEXT_SENSOR_SCHEMA
-    if klass is not _UNDEF:
-        schema = schema.extend({cv.GenerateID(): cv.declare_id(klass)})
+    if class_ is not _UNDEF:
+        schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
     if icon is not _UNDEF:
         schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon})
     if entity_category is not _UNDEF:
diff --git a/esphome/components/touchscreen/binary_sensor/__init__.py b/esphome/components/touchscreen/binary_sensor/__init__.py
index 9dba821d4d..73cbf1df7e 100644
--- a/esphome/components/touchscreen/binary_sensor/__init__.py
+++ b/esphome/components/touchscreen/binary_sensor/__init__.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 
 from esphome.components import binary_sensor
-from esphome.const import CONF_ID
 
 from .. import touchscreen_ns, CONF_TOUCHSCREEN_ID, Touchscreen, TouchListener
 
@@ -34,23 +33,23 @@ def validate_coords(config):
 
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(TouchscreenBinarySensor)
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(TouchscreenBinarySensor),
             cv.GenerateID(CONF_TOUCHSCREEN_ID): cv.use_id(Touchscreen),
             cv.Required(CONF_X_MIN): cv.int_range(min=0, max=2000),
             cv.Required(CONF_X_MAX): cv.int_range(min=0, max=2000),
             cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=2000),
             cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=2000),
         }
-    ).extend(cv.COMPONENT_SCHEMA),
+    )
+    .extend(cv.COMPONENT_SCHEMA),
     validate_coords,
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
     await cg.register_parented(var, config[CONF_TOUCHSCREEN_ID])
 
diff --git a/esphome/components/ttp229_bsf/binary_sensor.py b/esphome/components/ttp229_bsf/binary_sensor.py
index 75540fe0e8..8a0c7fce48 100644
--- a/esphome/components/ttp229_bsf/binary_sensor.py
+++ b/esphome/components/ttp229_bsf/binary_sensor.py
@@ -1,15 +1,14 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_CHANNEL, CONF_ID
+from esphome.const import CONF_CHANNEL
 from . import ttp229_bsf_ns, TTP229BSFComponent, CONF_TTP229_ID
 
 DEPENDENCIES = ["ttp229_bsf"]
 TTP229BSFChannel = ttp229_bsf_ns.class_("TTP229BSFChannel", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TTP229BSFChannel).extend(
     {
-        cv.GenerateID(): cv.declare_id(TTP229BSFChannel),
         cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229BSFComponent),
         cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15),
     }
@@ -17,8 +16,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
 
     cg.add(var.set_channel(config[CONF_CHANNEL]))
     hub = await cg.get_variable(config[CONF_TTP229_ID])
diff --git a/esphome/components/ttp229_lsf/binary_sensor.py b/esphome/components/ttp229_lsf/binary_sensor.py
index b52a9e8575..5fba0096de 100644
--- a/esphome/components/ttp229_lsf/binary_sensor.py
+++ b/esphome/components/ttp229_lsf/binary_sensor.py
@@ -1,15 +1,14 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_CHANNEL, CONF_ID
+from esphome.const import CONF_CHANNEL
 from . import ttp229_lsf_ns, TTP229LSFComponent, CONF_TTP229_ID
 
 DEPENDENCIES = ["ttp229_lsf"]
 TTP229Channel = ttp229_lsf_ns.class_("TTP229Channel", binary_sensor.BinarySensor)
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(TTP229Channel).extend(
     {
-        cv.GenerateID(): cv.declare_id(TTP229Channel),
         cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229LSFComponent),
         cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15),
     }
@@ -17,8 +16,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
 
     cg.add(var.set_channel(config[CONF_CHANNEL]))
     hub = await cg.get_variable(config[CONF_TTP229_ID])
diff --git a/esphome/components/tuya/binary_sensor/__init__.py b/esphome/components/tuya/binary_sensor/__init__.py
index cd4a2db89f..856b5eb323 100644
--- a/esphome/components/tuya/binary_sensor/__init__.py
+++ b/esphome/components/tuya/binary_sensor/__init__.py
@@ -1,7 +1,8 @@
 from esphome.components import binary_sensor
 import esphome.config_validation as cv
 import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_SENSOR_DATAPOINT
+from esphome.const import CONF_SENSOR_DATAPOINT
+
 from .. import tuya_ns, CONF_TUYA_ID, Tuya
 
 DEPENDENCIES = ["tuya"]
@@ -11,19 +12,21 @@ TuyaBinarySensor = tuya_ns.class_(
     "TuyaBinarySensor", binary_sensor.BinarySensor, cg.Component
 )
 
-CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-    {
-        cv.GenerateID(): cv.declare_id(TuyaBinarySensor),
-        cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
-        cv.Required(CONF_SENSOR_DATAPOINT): cv.uint8_t,
-    }
-).extend(cv.COMPONENT_SCHEMA)
+CONFIG_SCHEMA = (
+    binary_sensor.binary_sensor_schema(TuyaBinarySensor)
+    .extend(
+        {
+            cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
+            cv.Required(CONF_SENSOR_DATAPOINT): cv.uint8_t,
+        }
+    )
+    .extend(cv.COMPONENT_SCHEMA)
+)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     paren = await cg.get_variable(config[CONF_TUYA_ID])
     cg.add(var.set_tuya_parent(paren))
diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py
index 58250c3759..54993d48ee 100644
--- a/esphome/components/wifi_info/text_sensor.py
+++ b/esphome/components/wifi_info/text_sensor.py
@@ -32,19 +32,19 @@ MacAddressWifiInfo = wifi_info_ns.class_(
 CONFIG_SCHEMA = cv.Schema(
     {
         cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema(
-            klass=IPAddressWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
+            IPAddressWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
         ).extend(cv.polling_component_schema("1s")),
         cv.Optional(CONF_SCAN_RESULTS): text_sensor.text_sensor_schema(
-            klass=ScanResultsWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
+            ScanResultsWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
         ).extend(cv.polling_component_schema("60s")),
         cv.Optional(CONF_SSID): text_sensor.text_sensor_schema(
-            klass=SSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
+            SSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
         ).extend(cv.polling_component_schema("1s")),
         cv.Optional(CONF_BSSID): text_sensor.text_sensor_schema(
-            klass=BSSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
+            BSSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
         ).extend(cv.polling_component_schema("1s")),
         cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema(
-            klass=MacAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
+            MacAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
         ),
     }
 )
diff --git a/esphome/components/xiaomi_cgpr1/binary_sensor.py b/esphome/components/xiaomi_cgpr1/binary_sensor.py
index 4297b7fc3b..1b878ca800 100644
--- a/esphome/components/xiaomi_cgpr1/binary_sensor.py
+++ b/esphome/components/xiaomi_cgpr1/binary_sensor.py
@@ -4,9 +4,7 @@ from esphome.components import sensor, binary_sensor, esp32_ble_tracker
 from esphome.const import (
     CONF_BATTERY_LEVEL,
     CONF_BINDKEY,
-    CONF_DEVICE_CLASS,
     CONF_MAC_ADDRESS,
-    CONF_ID,
     DEVICE_CLASS_BATTERY,
     DEVICE_CLASS_ILLUMINANCE,
     DEVICE_CLASS_MOTION,
@@ -31,15 +29,11 @@ XiaomiCGPR1 = xiaomi_cgpr1_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(XiaomiCGPR1, device_class=DEVICE_CLASS_MOTION)
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(XiaomiCGPR1),
             cv.Required(CONF_BINDKEY): cv.bind_key,
             cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
-            cv.Optional(
-                CONF_DEVICE_CLASS,
-                default=DEVICE_CLASS_MOTION,
-            ): binary_sensor.device_class,
             cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
                 unit_of_measurement=UNIT_PERCENT,
                 accuracy_decimals=0,
@@ -64,21 +58,20 @@ CONFIG_SCHEMA = cv.All(
 )
 
 
-def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    yield cg.register_component(var, config)
-    yield esp32_ble_tracker.register_ble_device(var, config)
-    yield binary_sensor.register_binary_sensor(var, config)
+async def to_code(config):
+    var = await binary_sensor.new_binary_sensor(config)
+    await cg.register_component(var, config)
+    await esp32_ble_tracker.register_ble_device(var, config)
 
     cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
     cg.add(var.set_bindkey(config[CONF_BINDKEY]))
 
     if CONF_IDLE_TIME in config:
-        sens = yield sensor.new_sensor(config[CONF_IDLE_TIME])
+        sens = await sensor.new_sensor(config[CONF_IDLE_TIME])
         cg.add(var.set_idle_time(sens))
     if CONF_BATTERY_LEVEL in config:
-        sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
+        sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL])
         cg.add(var.set_battery_level(sens))
     if CONF_ILLUMINANCE in config:
-        sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE])
+        sens = await sensor.new_sensor(config[CONF_ILLUMINANCE])
         cg.add(var.set_illuminance(sens))
diff --git a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
index 6a7d6aae79..9a4b50df91 100644
--- a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
+++ b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
@@ -3,13 +3,13 @@ import esphome.config_validation as cv
 from esphome.components import sensor, binary_sensor, esp32_ble_tracker
 from esphome.const import (
     CONF_MAC_ADDRESS,
-    CONF_ID,
     CONF_BINDKEY,
-    CONF_DEVICE_CLASS,
     CONF_LIGHT,
     CONF_BATTERY_LEVEL,
     DEVICE_CLASS_BATTERY,
     DEVICE_CLASS_ILLUMINANCE,
+    DEVICE_CLASS_LIGHT,
+    DEVICE_CLASS_MOTION,
     ENTITY_CATEGORY_DIAGNOSTIC,
     STATE_CLASS_MEASUREMENT,
     UNIT_PERCENT,
@@ -32,14 +32,13 @@ XiaomiMJYD02YLA = xiaomi_mjyd02yla_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(
+        XiaomiMJYD02YLA, device_class=DEVICE_CLASS_MOTION
+    )
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(XiaomiMJYD02YLA),
             cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
             cv.Required(CONF_BINDKEY): cv.bind_key,
-            cv.Optional(
-                CONF_DEVICE_CLASS, default="motion"
-            ): binary_sensor.device_class,
             cv.Optional(CONF_IDLE_TIME): sensor.sensor_schema(
                 unit_of_measurement=UNIT_MINUTE,
                 icon=ICON_TIMELAPSE,
@@ -58,12 +57,8 @@ CONFIG_SCHEMA = cv.All(
                 device_class=DEVICE_CLASS_ILLUMINANCE,
                 state_class=STATE_CLASS_MEASUREMENT,
             ),
-            cv.Optional(CONF_LIGHT): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
-                {
-                    cv.Optional(
-                        CONF_DEVICE_CLASS, default="light"
-                    ): binary_sensor.device_class,
-                }
+            cv.Optional(CONF_LIGHT): binary_sensor.binary_sensor_schema(
+                device_class=DEVICE_CLASS_LIGHT
             ),
         }
     )
@@ -73,10 +68,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
     await esp32_ble_tracker.register_ble_device(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
     cg.add(var.set_bindkey(config[CONF_BINDKEY]))
diff --git a/esphome/components/xiaomi_mue4094rt/binary_sensor.py b/esphome/components/xiaomi_mue4094rt/binary_sensor.py
index 5d19263c9c..94d85213ff 100644
--- a/esphome/components/xiaomi_mue4094rt/binary_sensor.py
+++ b/esphome/components/xiaomi_mue4094rt/binary_sensor.py
@@ -1,7 +1,11 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor, esp32_ble_tracker
-from esphome.const import CONF_MAC_ADDRESS, CONF_DEVICE_CLASS, CONF_TIMEOUT, CONF_ID
+from esphome.const import (
+    CONF_MAC_ADDRESS,
+    CONF_TIMEOUT,
+    DEVICE_CLASS_MOTION,
+)
 
 
 DEPENDENCIES = ["esp32_ble_tracker"]
@@ -16,13 +20,12 @@ XiaomiMUE4094RT = xiaomi_mue4094rt_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(
+        XiaomiMUE4094RT, device_class=DEVICE_CLASS_MOTION
+    )
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(XiaomiMUE4094RT),
             cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
-            cv.Optional(
-                CONF_DEVICE_CLASS, default="motion"
-            ): binary_sensor.device_class,
             cv.Optional(
                 CONF_TIMEOUT, default="5s"
             ): cv.positive_time_period_milliseconds,
@@ -34,10 +37,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
     await esp32_ble_tracker.register_ble_device(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
     cg.add(var.set_time(config[CONF_TIMEOUT]))
diff --git a/esphome/components/xiaomi_wx08zm/binary_sensor.py b/esphome/components/xiaomi_wx08zm/binary_sensor.py
index 8667794923..504dff9d66 100644
--- a/esphome/components/xiaomi_wx08zm/binary_sensor.py
+++ b/esphome/components/xiaomi_wx08zm/binary_sensor.py
@@ -10,12 +10,11 @@ from esphome.const import (
     STATE_CLASS_MEASUREMENT,
     UNIT_PERCENT,
     ICON_BUG,
-    CONF_ID,
 )
 
 
 DEPENDENCIES = ["esp32_ble_tracker"]
-AUTO_LOAD = ["xiaomi_ble"]
+AUTO_LOAD = ["xiaomi_ble", "sensor"]
 
 xiaomi_wx08zm_ns = cg.esphome_ns.namespace("xiaomi_wx08zm")
 XiaomiWX08ZM = xiaomi_wx08zm_ns.class_(
@@ -26,9 +25,9 @@ XiaomiWX08ZM = xiaomi_wx08zm_ns.class_(
 )
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(XiaomiWX08ZM)
+    .extend(
         {
-            cv.GenerateID(): cv.declare_id(XiaomiWX08ZM),
             cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
             cv.Optional(CONF_TABLET): sensor.sensor_schema(
                 unit_of_measurement=UNIT_PERCENT,
@@ -51,10 +50,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await binary_sensor.new_binary_sensor(config)
     await cg.register_component(var, config)
     await esp32_ble_tracker.register_ble_device(var, config)
-    await binary_sensor.register_binary_sensor(var, config)
 
     cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
 
diff --git a/esphome/components/xpt2046/binary_sensor.py b/esphome/components/xpt2046/binary_sensor.py
index 6959d6c342..6ec09a2295 100644
--- a/esphome/components/xpt2046/binary_sensor.py
+++ b/esphome/components/xpt2046/binary_sensor.py
@@ -1,7 +1,7 @@
 import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import binary_sensor
-from esphome.const import CONF_ID
+
 from . import (
     xpt2046_ns,
     XPT2046Component,
@@ -27,9 +27,8 @@ def validate_xpt2046_button(config):
 
 
 CONFIG_SCHEMA = cv.All(
-    binary_sensor.BINARY_SENSOR_SCHEMA.extend(
+    binary_sensor.binary_sensor_schema(XPT2046Button).extend(
         {
-            cv.GenerateID(): cv.declare_id(XPT2046Button),
             cv.GenerateID(CONF_XPT2046_ID): cv.use_id(XPT2046Component),
             cv.Required(CONF_X_MIN): cv.int_range(min=0, max=4095),
             cv.Required(CONF_X_MAX): cv.int_range(min=0, max=4095),
@@ -42,8 +41,7 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-    await binary_sensor.register_binary_sensor(var, config)
+    var = await binary_sensor.new_binary_sensor(config)
     hub = await cg.get_variable(config[CONF_XPT2046_ID])
     cg.add(
         var.set_area(