text: """Support for Bbox Bouygues Modem Router."""
  from __future__ import annotations
  
  from datetime import timedelta
  import logging
  
  import pybbox
  import requests
  import voluptuous as vol
  
  from homeassistant.components.sensor import (
      PLATFORM_SCHEMA,
      SensorEntity,
      SensorEntityDescription,
  )
  from homeassistant.const import (
      ATTR_ATTRIBUTION,
      CONF_MONITORED_VARIABLES,
      CONF_NAME,
      DATA_RATE_MEGABITS_PER_SECOND,
      DEVICE_CLASS_TIMESTAMP,
  )
  import homeassistant.helpers.config_validation as cv
  from homeassistant.util import Throttle
  from homeassistant.util.dt import utcnow
  
  _LOGGER = logging.getLogger(__name__)
  
  ATTRIBUTION = "Powered by Bouygues Telecom"
  
  DEFAULT_NAME = "Bbox"
  
  MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
  
  SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
      SensorEntityDescription(
          key="down_max_bandwidth",
          name="Maximum Download Bandwidth",
          native_unit_of_measurement=DATA_RATE_MEGABITS_PER_SECOND,
          icon="mdi:download",
      ),
      SensorEntityDescription(
          key="up_max_bandwidth",
          name="Maximum Upload Bandwidth",
          native_unit_of_measurement=DATA_RATE_MEGABITS_PER_SECOND,
          icon="mdi:upload",
      ),
      SensorEntityDescription(
          key="current_down_bandwidth",
          name="Currently Used Download Bandwidth",
          native_unit_of_measurement=DATA_RATE_MEGABITS_PER_SECOND,
          icon="mdi:download",
      ),
      SensorEntityDescription(
          key="current_up_bandwidth",
          name="Currently Used Upload Bandwidth",
          native_unit_of_measurement=DATA_RATE_MEGABITS_PER_SECOND,
          icon="mdi:upload",
      ),
      SensorEntityDescription(
          key="number_of_reboots",
          name="Number of reboot",
          icon="mdi:restart",
      ),
  )
  
  SENSOR_TYPES_UPTIME: tuple[SensorEntityDescription, ...] = (
      SensorEntityDescription(
          key="uptime",
          name="Uptime",
          icon="mdi:clock",
      ),
  )
  
  SENSOR_KEYS: list[str] = [desc.key for desc in (*SENSOR_TYPES, *SENSOR_TYPES_UPTIME)]
  
  PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
      {
          vol.Required(CONF_MONITORED_VARIABLES): vol.All(
              cv.ensure_list, [vol.In(SENSOR_KEYS)]
          ),
          vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
      }
  )
  
  
  def setup_platform(hass, config, add_entities, discovery_info=None):
      """Set up the Bbox sensor."""
      # Create a data fetcher to support all of the configured sensors. Then make
      # the first call to init the data.
      try:
          bbox_data = BboxData()
          bbox_data.update()
      except requests.exceptions.HTTPError as error:
          _LOGGER.error(error)
          return False
  
      name = config[CONF_NAME]
  
      monitored_variables = config[CONF_MONITORED_VARIABLES]
      entities: list[BboxSensor | BboxUptimeSensor] = [
          BboxSensor(bbox_data, name, description)
          for description in SENSOR_TYPES
          if description.key in monitored_variables
      ]
      entities.extend(
          [
              BboxUptimeSensor(bbox_data, name, description)
              for description in SENSOR_TYPES_UPTIME
              if description.key in monitored_variables
          ]
      )
  
      add_entities(entities, True)
  
  
  class BboxUptimeSensor(SensorEntity):
      """Bbox uptime sensor."""
  
      _attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
      _attr_device_class = DEVICE_CLASS_TIMESTAMP
  
      def __init__(self, bbox_data, name, description: SensorEntityDescription):
          """Initialize the sensor."""
          self.entity_description = description
          self._attr_name = f"{name} {description.name}"
          self.bbox_data = bbox_data
  
      def update(self):
          """Get the latest data from Bbox and update the state."""
          self.bbox_data.update()
          uptime = utcnow() - timedelta(
              seconds=self.bbox_data.router_infos["device"]["uptime"]
          )
          self._attr_native_value = uptime.replace(microsecond=0).isoformat()
  
  
  class BboxSensor(SensorEntity):
      """Implementation of a Bbox sensor."""
  
      _attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
  
      def __init__(self, bbox_data, name, description: SensorEntityDescription):
          """Initialize the sensor."""
          self.entity_description = description
          self._attr_name = f"{name} {description.name}"
          self.bbox_data = bbox_data
  
      def update(self):
          """Get the latest data from Bbox and update the state."""
          self.bbox_data.update()
          sensor_type = self.entity_description.key
          if sensor_type == "down_max_bandwidth":
              self._attr_native_value = round(
                  self.bbox_data.data["rx"]["maxBandwidth"] / 1000, 2
              )
          elif sensor_type == "up_max_bandwidth":
              self._attr_native_value = round(
                  self.bbox_data.data["tx"]["maxBandwidth"] / 1000, 2
              )
          elif sensor_type == "current_down_bandwidth":
              self._attr_native_value = round(
                  self.bbox_data.data["rx"]["bandwidth"] / 1000, 2
              )
          elif sensor_type == "current_up_bandwidth":
              self._attr_native_value = round(
                  self.bbox_data.data["tx"]["bandwidth"] / 1000, 2
              )
          elif sensor_type == "number_of_reboots":
              self._attr_native_value = self.bbox_data.router_infos["device"][
                  "numberofboots"
              ]
  
  
  class BboxData:
      """Get data from the Bbox."""
  
      def __init__(self):
          """Initialize the data object."""
          self.data = None
          self.router_infos = None
  
      @Throttle(MIN_TIME_BETWEEN_UPDATES)
      def update(self):
          """Get the latest data from the Bbox."""
  
          try:
              box = pybbox.Bbox()
              self.data = box.get_ip_stats()
              self.router_infos = box.get_bbox_info()
          except requests.exceptions.HTTPError as error:
              _LOGGER.error(error)
              self.data = None
              self.router_infos = None
              return False
  