docs: def fillPelicanHole(site, username, password, tstat_name, start_time, end_time):
      """Fill a hole in a Pelican thermostat's data stream.
  
      Arguments:
          site -- The thermostat's Pelican site name
          username -- The Pelican username for the site
          password -- The Pelican password for the site
          tstat_name -- The name of the thermostat, as identified by Pelican
          start_time -- The start of the data hole in UTC, e.g. "2018-01-29 15:00:00"
          end_time -- The end of the data hole in UTC, e.g. "2018-01-29 16:00:00"
  
      Returns:
          A Pandas dataframe with historical Pelican data that falls between the
          specified start and end times.
  
      Note that this function assumes the Pelican thermostat's local time zone is
      US/Pacific. It will properly handle PST vs. PDT.
      """
  
      start = datetime.strptime(start_time, _INPUT_TIME_FORMAT).replace(tzinfo=pytz.utc).astimezone(_pelican_time)
      end = datetime.strptime(end_time, _INPUT_TIME_FORMAT).replace(tzinfo=pytz.utc).astimezone(_pelican_time)
  
      heat_needs_fan = _lookupHeatNeedsFan(site, username, password, tstat_name)
      if heat_needs_fan is None:
          return None
  
      # Pelican's API only allows a query covering a time range of up to 1 month
      # So we may need run multiple requests for historical data
      history_blocks = []
      while start < end:
          block_start = start
          block_end = min(start + timedelta(days=30), end)
          blocks = _lookupHistoricalData(site, username, password, tstat_name, block_start, block_end)
          if blocks is None:
              return None
          history_blocks.extend(blocks)
          start += timedelta(days=30, minutes=1)
  
      output_rows = []
      for block in history_blocks:
          runStatus = block.find("runStatus").text
          if runStatus.startswith("Heat"):
              fanState = (heatNeedsFan == "Yes")
          else:
              fanState = (runStatus != "Off")
  
          api_time = datetime.strptime(block.find("timestamp").text, "%Y-%m-%dT%H:%M").replace(tzinfo=_pelican_time)
          # Need to convert seconds to nanoseconds
          timestamp = int(api_time.timestamp() * 10**9)
  
          output_rows.append({
              "temperature": float(block.find("temperature").text),
              "relative_humidity": float(block.find("humidity").text),
              "heating_setpoint": float(block.find("heatSetting").text),
              "cooling_setpoint": float(block.find("coolSetting").text),
              # Driver explicitly uses "Schedule" field, but we don't have this in history
              "override": block.find("setBy").text != "Schedule",
              "fan": fanState,
              "mode": _mode_name_mappings[block.find("system").text],
              "state": _state_mappings.get(runStatus, 0),
              "time": timestamp,
          })
      df = pd.DataFrame(output_rows)
      df.drop_duplicates(subset="time", keep="first", inplace=True)
      return df