text: """Support for Wireless Sensor Tags."""
  import logging
  
  from requests.exceptions import ConnectTimeout, HTTPError
  import voluptuous as vol
  from wirelesstagpy import NotificationConfig as NC, WirelessTags, WirelessTagsException
  
  from homeassistant import util
  from homeassistant.const import (
      ATTR_BATTERY_LEVEL,
      ATTR_VOLTAGE,
      CONF_PASSWORD,
      CONF_USERNAME,
      UNIT_PERCENTAGE,
      VOLT,
  )
  import homeassistant.helpers.config_validation as cv
  from homeassistant.helpers.dispatcher import dispatcher_send
  from homeassistant.helpers.entity import Entity
  
  _LOGGER = logging.getLogger(__name__)
  
  
  # Strength of signal in dBm
  ATTR_TAG_SIGNAL_STRENGTH = "signal_strength"
  # Indicates if tag is out of range or not
  ATTR_TAG_OUT_OF_RANGE = "out_of_range"
  # Number in percents from max power of tag receiver
  ATTR_TAG_POWER_CONSUMPTION = "power_consumption"
  
  
  NOTIFICATION_ID = "wirelesstag_notification"
  NOTIFICATION_TITLE = "Wireless Sensor Tag Setup"
  
  DOMAIN = "wirelesstag"
  DEFAULT_ENTITY_NAMESPACE = "wirelesstag"
  
  # Template for signal - first parameter is tag_id,
  # second, tag manager mac address
  SIGNAL_TAG_UPDATE = "wirelesstag.tag_info_updated_{}_{}"
  
  # Template for signal - tag_id, sensor type and
  # tag manager mac address
  SIGNAL_BINARY_EVENT_UPDATE = "wirelesstag.binary_event_updated_{}_{}_{}"
  
  CONFIG_SCHEMA = vol.Schema(
      {
          DOMAIN: vol.Schema(
              {
                  vol.Required(CONF_USERNAME): cv.string,
                  vol.Required(CONF_PASSWORD): cv.string,
              }
          )
      },
      extra=vol.ALLOW_EXTRA,
  )
  
  
  class WirelessTagPlatform:
      """Principal object to manage all registered in HA tags."""
  
      def __init__(self, hass, api):
          """Designated initializer for wirelesstags platform."""
          self.hass = hass
          self.api = api
          self.tags = {}
          self._local_base_url = None
  
      @property
      def tag_manager_macs(self):
          """Return list of tag managers mac addresses in user account."""
          return self.api.mac_addresses
  
      def load_tags(self):
          """Load tags from remote server."""
          self.tags = self.api.load_tags()
          return self.tags
  
      def arm(self, switch):
          """Arm entity sensor monitoring."""
          func_name = f"arm_{switch.sensor_type}"
          arm_func = getattr(self.api, func_name)
          if arm_func is not None:
              arm_func(switch.tag_id, switch.tag_manager_mac)
  
      def disarm(self, switch):
          """Disarm entity sensor monitoring."""
          func_name = f"disarm_{switch.sensor_type}"
          disarm_func = getattr(self.api, func_name)
          if disarm_func is not None:
              disarm_func(switch.tag_id, switch.tag_manager_mac)
  
      def make_notifications(self, binary_sensors, mac):
          """Create configurations for push notifications."""
          _LOGGER.info("Creating configurations for push notifications")
          configs = []
  
          bi_url = self.binary_event_callback_url
          for bi_sensor in binary_sensors:
              configs.extend(bi_sensor.event.build_notifications(bi_url, mac))
  
          update_url = self.update_callback_url
  
          update_config = NC.make_config_for_update_event(update_url, mac)
  
          configs.append(update_config)
          return configs
  
      def install_push_notifications(self, binary_sensors):
          """Register local push notification from tag manager."""
          _LOGGER.info("Registering local push notifications")
          for mac in self.tag_manager_macs:
              configs = self.make_notifications(binary_sensors, mac)
              # install notifications for all tags in tag manager
              # specified by mac
              result = self.api.install_push_notification(0, configs, True, mac)
              if not result:
                  self.hass.components.persistent_notification.create(
                      "Error: failed to install local push notifications <br />",
                      title="Wireless Sensor Tag Setup Local Push Notifications",
                      notification_id="wirelesstag_failed_push_notification",
                  )
              else:
                  _LOGGER.info(
                      "Installed push notifications for all tags in %s", mac,
                  )
  
      @property
      def local_base_url(self):
          """Define base url of hass in local network."""
          if self._local_base_url is None:
              self._local_base_url = f"http://{util.get_local_ip()}"
  
              port = self.hass.config.api.port
              if port is not None:
                  self._local_base_url += f":{port}"
          return self._local_base_url
  
      @property
      def update_callback_url(self):
          """Return url for local push notifications(update event)."""
          return f"{self.local_base_url}/api/events/wirelesstag_update_tags"
  
      @property
      def binary_event_callback_url(self):
          """Return url for local push notifications(binary event)."""
          return f"{self.local_base_url}/api/events/wirelesstag_binary_event"
  
      def handle_update_tags_event(self, event):
          """Handle push event from wireless tag manager."""
          _LOGGER.info("push notification for update arrived: %s", event)
          try:
              tag_id = event.data.get("id")
              mac = event.data.get("mac")
              dispatcher_send(self.hass, SIGNAL_TAG_UPDATE.format(tag_id, mac), event)
          except Exception as ex:  # pylint: disable=broad-except
              _LOGGER.error(
                  "Unable to handle tag update event:\
                            %s error: %s",
                  str(event),
                  str(ex),
              )
  
      def handle_binary_event(self, event):
          """Handle push notifications for binary (on/off) events."""
          _LOGGER.info("Push notification for binary event arrived: %s", event)
          try:
              tag_id = event.data.get("id")
              event_type = event.data.get("type")
              mac = event.data.get("mac")
              dispatcher_send(
                  self.hass,
                  SIGNAL_BINARY_EVENT_UPDATE.format(tag_id, event_type, mac),
                  event,
              )
          except Exception as ex:  # pylint: disable=broad-except
              _LOGGER.error(
                  "Unable to handle tag binary event:\
                            %s error: %s",
                  str(event),
                  str(ex),
              )
  
  
  def setup(hass, config):
      """Set up the Wireless Sensor Tag component."""
      conf = config[DOMAIN]
      username = conf.get(CONF_USERNAME)
      password = conf.get(CONF_PASSWORD)
  
      try:
          wirelesstags = WirelessTags(username=username, password=password)
  
          platform = WirelessTagPlatform(hass, wirelesstags)
          platform.load_tags()
          hass.data[DOMAIN] = platform
      except (ConnectTimeout, HTTPError, WirelessTagsException) as ex:
          _LOGGER.error("Unable to connect to wirelesstag.net service: %s", str(ex))
          hass.components.persistent_notification.create(
              f"Error: {ex}<br />Please restart hass after fixing this.",
              title=NOTIFICATION_TITLE,
              notification_id=NOTIFICATION_ID,
          )
          return False
  
      # listen to custom events
      hass.bus.listen(
          "wirelesstag_update_tags", hass.data[DOMAIN].handle_update_tags_event
      )
      hass.bus.listen("wirelesstag_binary_event", hass.data[DOMAIN].handle_binary_event)
  
      return True
  
  
  class WirelessTagBaseSensor(Entity):
      """Base class for HA implementation for Wireless Sensor Tag."""
  
      def __init__(self, api, tag):
          """Initialize a base sensor for Wireless Sensor Tag platform."""
          self._api = api
          self._tag = tag
          self._uuid = self._tag.uuid
          self.tag_id = self._tag.tag_id
          self.tag_manager_mac = self._tag.tag_manager_mac
          self._name = self._tag.name
          self._state = None
  
      @property
      def should_poll(self):
          """Return the polling state."""
          return True
  
      @property
      def name(self):
          """Return the name of the sensor."""
          return self._name
  
      @property
      def principal_value(self):
          """Return base value.
  
          Subclasses need override based on type of sensor.
          """
          return 0
  
      def updated_state_value(self):
          """Return formatted value.
  
          The default implementation formats principal value.
          """
          return self.decorate_value(self.principal_value)
  
      # pylint: disable=no-self-use
      def decorate_value(self, value):
          """Decorate input value to be well presented for end user."""
          return f"{value:.1f}"
  
      @property
      def available(self):
          """Return True if entity is available."""
          return self._tag.is_alive
  
      def update(self):
          """Update state."""
          if not self.should_poll:
              return
  
          updated_tags = self._api.load_tags()
          updated_tag = updated_tags[self._uuid]
          if updated_tag is None:
              _LOGGER.error('Unable to update tag: "%s"', self.name)
              return
  
          self._tag = updated_tag
          self._state = self.updated_state_value()
  
      @property
      def device_state_attributes(self):
          """Return the state attributes."""
          return {
              ATTR_BATTERY_LEVEL: int(self._tag.battery_remaining * 100),
              ATTR_VOLTAGE: f"{self._tag.battery_volts:.2f}{VOLT}",
              ATTR_TAG_SIGNAL_STRENGTH: f"{self._tag.signal_strength}dBm",
              ATTR_TAG_OUT_OF_RANGE: not self._tag.is_in_range,
              ATTR_TAG_POWER_CONSUMPTION: f"{self._tag.power_consumption:.2f}{UNIT_PERCENTAGE}",
          }
  