예제 #1
0
    def __init__(self, config: dict) -> None:
        """Initialize a select input."""
        self._config = config
        self.editable = True
        self._current_datetime = None

        initial = config.get(CONF_INITIAL)
        if not initial:
            return

        if self.has_date and self.has_time:
            current_datetime = dt_util.parse_datetime(initial)

        elif self.has_date:
            date = dt_util.parse_date(initial)
            current_datetime = py_datetime.datetime.combine(date, DEFAULT_TIME)

        else:
            time = dt_util.parse_time(initial)
            current_datetime = py_datetime.datetime.combine(
                py_datetime.date.today(), time)

        # If the user passed in an initial value with a timezone, convert it to right tz
        if current_datetime.tzinfo is not None:
            self._current_datetime = current_datetime.astimezone(
                dt_util.DEFAULT_TIME_ZONE)
        else:
            self._current_datetime = current_datetime.replace(
                tzinfo=dt_util.DEFAULT_TIME_ZONE)
예제 #2
0
    def update(self):
        """Update probe data."""
        self.api.login(self.username, self.password)
        _LOGGER.debug("Updating data for %s", self.device_id)
        try:
            if self.growatt_type == "total":
                total_info = self.api.plant_info(self.device_id)
                del total_info["deviceList"]
                # PlantMoneyText comes in as "3.1/€" remove anything that isn't part of the number
                total_info["plantMoneyText"] = re.sub(
                    r"[^\d.,]", "", total_info["plantMoneyText"])
                self.data = total_info
            elif self.growatt_type == "inverter":
                inverter_info = self.api.inverter_detail(self.device_id)
                self.data = inverter_info
            elif self.growatt_type == "storage":
                storage_info_detail = self.api.storage_params(
                    self.device_id)["storageDetailBean"]
                storage_energy_overview = self.api.storage_energy_overview(
                    self.plant_id, self.device_id)
                self.data = {**storage_info_detail, **storage_energy_overview}
            elif self.growatt_type == "mix":
                mix_info = self.api.mix_info(self.device_id)
                mix_totals = self.api.mix_totals(self.device_id, self.plant_id)
                mix_system_status = self.api.mix_system_status(
                    self.device_id, self.plant_id)

                mix_detail = self.api.mix_detail(self.device_id, self.plant_id)
                # Get the chart data and work out the time of the last entry, use this as the last time data was published to the Growatt Server
                mix_chart_entries = mix_detail["chartData"]
                sorted_keys = sorted(mix_chart_entries)

                # Create datetime from the latest entry
                date_now = dt.now().date()
                last_updated_time = dt.parse_time(str(sorted_keys[-1]))
                combined_timestamp = datetime.datetime.combine(
                    date_now, last_updated_time)
                # Convert datetime to UTC
                combined_timestamp_utc = dt.as_utc(combined_timestamp)
                mix_detail[
                    "lastdataupdate"] = combined_timestamp_utc.isoformat()

                # Dashboard data is largely inaccurate for mix system but it is the only call with the ability to return the combined
                # imported from grid value that is the combination of charging AND load consumption
                dashboard_data = self.api.dashboard_data(self.plant_id)
                # Dashboard values have units e.g. "kWh" as part of their returned string, so we remove it
                dashboard_values_for_mix = {
                    # etouser is already used by the results from 'mix_detail' so we rebrand it as 'etouser_combined'
                    "etouser_combined":
                    dashboard_data["etouser"].replace("kWh", "")
                }
                self.data = {
                    **mix_info,
                    **mix_totals,
                    **mix_system_status,
                    **mix_detail,
                    **dashboard_values_for_mix,
                }
        except json.decoder.JSONDecodeError:
            _LOGGER.error("Unable to fetch data from Growatt server")
예제 #3
0
def convert_time_to_isodate(timestr: str) -> str:
    """Take a string like 08:00:00 and combine it with the current date."""
    combined = datetime.combine(dt.start_of_local_day(),
                                dt.parse_time(timestr))
    if combined < datetime.now():
        combined = combined + timedelta(days=1)
    return combined.isoformat()
예제 #4
0
def convert_time_to_utc(timestr):
    """Take a string like 08:00:00 and convert it to a unix timestamp."""
    combined = datetime.combine(dt_util.start_of_local_day(),
                                dt_util.parse_time(timestr))
    if combined < datetime.now():
        combined = combined + timedelta(days=1)
    return dt_util.as_timestamp(combined)
예제 #5
0
 def state(self) -> datetime:
     """Return the state of the sensor."""
     device = self.device
     time = dt_util.parse_time(device.changeableValues.nextPeriodTime)
     now = dt_util.utcnow()
     if time <= now.time():
         now = now + timedelta(days=1)
     return dt_util.as_utc(datetime.combine(now.date(), time))
예제 #6
0
    def parse_time_at_default_timezone(time_str: str) -> time | None:
        """Parse a time string and add default timezone."""
        parsed_time = dt_util.parse_time(time_str)

        if parsed_time is None:
            return None

        return (dt_util.start_of_local_day().replace(
            hour=parsed_time.hour,
            minute=parsed_time.minute,
            second=parsed_time.second,
        ).timetz())
예제 #7
0
def time(value: Any) -> time_sys:
    """Validate and transform a time."""
    if isinstance(value, time_sys):
        return value

    try:
        time_val = dt_util.parse_time(value)
    except TypeError as err:
        raise vol.Invalid("Not a parseable type") from err

    if time_val is None:
        raise vol.Invalid(f"Invalid time specified: {value}")

    return time_val
예제 #8
0
 def __init__(self, config: typing.Dict) -> None:
     """Initialize a select input."""
     self._config = config
     self.editable = True
     self._current_datetime = None
     initial = config.get(CONF_INITIAL)
     if initial:
         if self.has_date and self.has_time:
             self._current_datetime = dt_util.parse_datetime(initial)
         elif self.has_date:
             date = dt_util.parse_date(initial)
             self._current_datetime = datetime.datetime.combine(date, DEFAULT_TIME)
         else:
             time = dt_util.parse_time(initial)
             self._current_datetime = datetime.datetime.combine(DEFAULT_DATE, time)
예제 #9
0
    async def async_added_to_opp(self):
        """Run when entity about to be added."""
        await super().async_added_to_opp()

        # Priority 1: Initial value
        if self.state is not None:
            return

        default_value = py_datetime.datetime.today().strftime(
            "%Y-%m-%d 00:00:00")

        # Priority 2: Old state
        old_state = await self.async_get_last_state()
        if old_state is None:
            self._current_datetime = dt_util.parse_datetime(default_value)
            return

        if self.has_date and self.has_time:
            date_time = dt_util.parse_datetime(old_state.state)
            if date_time is None:
                current_datetime = dt_util.parse_datetime(default_value)
            else:
                current_datetime = date_time

        elif self.has_date:
            date = dt_util.parse_date(old_state.state)
            if date is None:
                current_datetime = dt_util.parse_datetime(default_value)
            else:
                current_datetime = py_datetime.datetime.combine(
                    date, DEFAULT_TIME)

        else:
            time = dt_util.parse_time(old_state.state)
            if time is None:
                current_datetime = dt_util.parse_datetime(default_value)
            else:
                current_datetime = py_datetime.datetime.combine(
                    py_datetime.date.today(), time)

        self._current_datetime = current_datetime.replace(
            tzinfo=dt_util.DEFAULT_TIME_ZONE)
예제 #10
0
    async def async_added_to_opp(self):
        """Run when entity about to be added."""
        await super().async_added_to_opp()

        # Priority 1: Initial value
        if self.state is not None:
            return

        # Priority 2: Old state
        old_state = await self.async_get_last_state()
        if old_state is None:
            self._current_datetime = dt_util.parse_datetime(DEFAULT_VALUE)
            return

        if self.has_date and self.has_time:
            self._current_datetime = dt_util.parse_datetime(old_state.state)
        elif self.has_date:
            date = dt_util.parse_date(old_state.state)
            self._current_datetime = datetime.datetime.combine(date, DEFAULT_TIME)
        else:
            time = dt_util.parse_time(old_state.state)
            self._current_datetime = datetime.datetime.combine(DEFAULT_DATE, time)
예제 #11
0
def is_valid_time(string: str) -> bool:
    """Test if string dt is a valid time."""
    return dt_util.parse_time(string) is not None