Beispiel #1
0
async def ws_get_statistics_during_period(
    opp: OpenPeerPower, connection: websocket_api.ActiveConnection, msg: dict
) -> None:
    """Handle statistics websocket command."""
    start_time_str = msg["start_time"]
    end_time_str = msg.get("end_time")

    start_time = dt_util.parse_datetime(start_time_str)
    if start_time:
        start_time = dt_util.as_utc(start_time)
    else:
        connection.send_error(msg["id"], "invalid_start_time", "Invalid start_time")
        return

    if end_time_str:
        end_time = dt_util.parse_datetime(end_time_str)
        if end_time:
            end_time = dt_util.as_utc(end_time)
        else:
            connection.send_error(msg["id"], "invalid_end_time", "Invalid end_time")
            return
    else:
        end_time = None

    statistics = await opp.async_add_executor_job(
        statistics_during_period,
        opp,
        start_time,
        end_time,
        msg.get("statistic_id"),
    )
    connection.send_result(msg["id"], {"statistics": statistics})
Beispiel #2
0
    async def async_update(self):
        """Get the latest data and updates the states."""
        # Get previous values of start and end
        p_start, p_end = self._period

        # Parse templates
        self.update_period()
        start, end = self._period

        # Convert times to UTC
        start = dt_util.as_utc(start)
        end = dt_util.as_utc(end)
        p_start = dt_util.as_utc(p_start)
        p_end = dt_util.as_utc(p_end)
        now = datetime.datetime.now()

        # Compute integer timestamps
        start_timestamp = math.floor(dt_util.as_timestamp(start))
        end_timestamp = math.floor(dt_util.as_timestamp(end))
        p_start_timestamp = math.floor(dt_util.as_timestamp(p_start))
        p_end_timestamp = math.floor(dt_util.as_timestamp(p_end))
        now_timestamp = math.floor(dt_util.as_timestamp(now))

        # If period has not changed and current time after the period end...
        if (start_timestamp == p_start_timestamp
                and end_timestamp == p_end_timestamp
                and end_timestamp <= now_timestamp):
            # Don't compute anything as the value cannot have changed
            return

        await self.opp.async_add_executor_job(self._update, start, end,
                                              now_timestamp, start_timestamp,
                                              end_timestamp)
Beispiel #3
0
 def _update_from_status_info(self, status_info):
     """Update the internal state from the provided information."""
     self._status = status_info.status
     self._last_update = (dt.as_utc(status_info.last_update)
                          if status_info.last_update else None)
     if status_info.last_update_successful:
         self._last_update_successful = dt.as_utc(
             status_info.last_update_successful)
     else:
         self._last_update_successful = None
     self._last_timestamp = status_info.last_timestamp
     self._total = status_info.total
     self._created = status_info.created
     self._updated = status_info.updated
     self._removed = status_info.removed
Beispiel #4
0
 async def async_update(self) -> None:
     """Update entity."""
     local = dt_util.start_of_local_day().replace(microsecond=0)
     start = dt_util.as_utc(local)
     end = start + timedelta(days=self._days)
     self._upcoming = await self.sonarr.calendar(start=start.isoformat(),
                                                 end=end.isoformat())
Beispiel #5
0
def compile_statistics(instance: Recorder, start: datetime.datetime) -> bool:
    """Compile statistics."""
    start = dt_util.as_utc(start)
    end = start + timedelta(hours=1)
    _LOGGER.debug(
        "Compiling statistics for %s-%s",
        start,
        end,
    )
    platform_stats = []
    for domain, platform in instance.opp.data[DOMAIN].items():
        if not hasattr(platform, "compile_statistics"):
            continue
        platform_stats.append(
            platform.compile_statistics(instance.opp, start, end))
        _LOGGER.debug("Statistics for %s during %s-%s: %s", domain, start, end,
                      platform_stats[-1])

    with session_scope(
            session=instance.get_session()) as session:  # type: ignore
        for stats in platform_stats:
            for entity_id, stat in stats.items():
                session.add(
                    Statistics.from_stats(DOMAIN, entity_id, start, stat))

    return True
Beispiel #6
0
 def timers(self):
     """Get the list of added timers of the vacuum cleaner."""
     return [{
         "enabled": timer.enabled,
         "cron": timer.cron,
         "next_schedule": as_utc(timer.next_schedule),
     } for timer in self._timers]
    async def get(self, request, datetime=None):
        """Retrieve logbook entries."""
        if datetime:
            datetime = dt_util.parse_datetime(datetime)

            if datetime is None:
                return self.json_message("Invalid datetime", HTTP_BAD_REQUEST)
        else:
            datetime = dt_util.start_of_local_day()

        period = request.query.get("period")
        if period is None:
            period = 1
        else:
            period = int(period)

        entity_id = request.query.get("entity")
        start_day = dt_util.as_utc(datetime) - timedelta(days=period - 1)
        end_day = start_day + timedelta(days=period)
        opp = request.app["opp"]

        def json_events():
            """Fetch events and generate JSON."""
            return self.json(
                _get_events(opp, self.config, start_day, end_day, entity_id))

        return await opp.async_add_job(json_events)
Beispiel #8
0
    def see_device(address, name, new_device=False, battery=None):
        """Mark a device as seen."""
        if name is not None:
            name = name.strip("\x00")

        if new_device:
            if address in new_devices:
                new_devices[address]["seen"] += 1
                if name:
                    new_devices[address]["name"] = name
                else:
                    name = new_devices[address]["name"]
                _LOGGER.debug("Seen %s %s times", address, new_devices[address]["seen"])
                if new_devices[address]["seen"] < MIN_SEEN_NEW:
                    return
                _LOGGER.debug("Adding %s to tracked devices", address)
                devs_to_track.append(address)
                if battery_track_interval > timedelta(0):
                    devs_track_battery[address] = dt_util.as_utc(
                        datetime.fromtimestamp(0)
                    )
            else:
                _LOGGER.debug("Seen %s for the first time", address)
                new_devices[address] = {"seen": 1, "name": name}
                return

        see(
            mac=BLE_PREFIX + address,
            host_name=name,
            source_type=SOURCE_TYPE_BLUETOOTH_LE,
            battery=battery,
        )
Beispiel #9
0
def async_track_point_in_utc_time(opp: OpenPeerPower, action: Callable[...,
                                                                       Any],
                                  point_in_time: datetime) -> CALLBACK_TYPE:
    """Add a listener that fires once after a specific point in UTC time."""
    # Ensure point_in_time is UTC
    point_in_time = dt_util.as_utc(point_in_time)

    @callback
    def point_in_time_listener(event: Event) -> None:
        """Listen for matching time_changed events."""
        now = event.data[ATTR_NOW]

        if now < point_in_time or hasattr(point_in_time_listener, "run"):
            return

        # Set variable so that we will never run twice.
        # Because the event bus might have to wait till a thread comes
        # available to execute this listener it might occur that the
        # listener gets lined up twice to be executed. This will make
        # sure the second time it does nothing.
        setattr(point_in_time_listener, "run", True)
        async_unsub()

        opp.async_run_job(action, now)

    async_unsub = opp.bus.async_listen(EVENT_TIME_CHANGED,
                                       point_in_time_listener)

    return async_unsub
Beispiel #10
0
    async def async_zone_svc_request(self, service: dict, data: dict) -> None:
        """Process a service request (setpoint override) for a zone."""
        if service == SVC_RESET_ZONE_OVERRIDE:
            await self._evo_broker.call_client_api(
                self._evo_device.cancel_temp_override()
            )
            return

        # otherwise it is SVC_SET_ZONE_OVERRIDE
        temperature = max(min(data[ATTR_ZONE_TEMP], self.max_temp), self.min_temp)

        if ATTR_DURATION_UNTIL in data:
            duration = data[ATTR_DURATION_UNTIL]
            if duration.total_seconds() == 0:
                await self._update_schedule()
                until = dt_util.parse_datetime(self.setpoints.get("next_sp_from", ""))
            else:
                until = dt_util.now() + data[ATTR_DURATION_UNTIL]
        else:
            until = None  # indefinitely

        until = dt_util.as_utc(until) if until else None
        await self._evo_broker.call_client_api(
            self._evo_device.set_temperature(temperature, until=until)
        )
Beispiel #11
0
def _process_timestamp(ts):
    """Process a timestamp into datetime object."""
    if ts is None:
        return None
    if ts.tzinfo is None:
        return dt_util.UTC.localize(ts)
    return dt_util.as_utc(ts)
Beispiel #12
0
 def _naive_time_to_utc_datetime(self, naive_time):
     """Convert naive time from config to utc_datetime with current day."""
     # get the current local date from utc time
     current_local_date = (dt_util.utcnow().astimezone(
         dt_util.get_time_zone(self.opp.config.time_zone)).date())
     # calculate utc datetime corresponding to local time
     return dt_util.as_utc(datetime.combine(current_local_date, naive_time))
Beispiel #13
0
    def update(self):
        """Get the latest data from BOM."""
        if not self.should_update():
            _LOGGER.debug(
                "BOM was updated %s minutes ago, skipping update as"
                " < 35 minutes, Now: %s, LastUpdate: %s",
                (dt_util.utcnow() - self.last_updated),
                dt_util.utcnow(),
                self.last_updated,
            )
            return

        try:
            result = requests.get(self._build_url(), timeout=10).json()
            self._data = result["observations"]["data"]

            # set lastupdate using self._data[0] as the first element in the
            # array is the latest date in the json
            self.last_updated = dt_util.as_utc(
                datetime.datetime.strptime(
                    str(self._data[0]["local_date_time_full"]),
                    "%Y%m%d%H%M%S"))
            return

        except ValueError as err:
            _LOGGER.error("Check BOM %s", err.args)
            self._data = None
            raise
Beispiel #14
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")
Beispiel #15
0
def test_now():
    """Test the now method."""
    dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))

    assert abs(
        dt_util.as_utc(dt_util.now()).replace(tzinfo=None) -
        datetime.utcnow()) < timedelta(seconds=1)
Beispiel #16
0
def _process_timestamp(ts):
    """Process a timestamp into datetime object."""
    if ts is None:
        return None
    if ts.tzinfo is None:
        return ts.replace(tzinfo=dt_util.UTC)
    return dt_util.as_utc(ts)
Beispiel #17
0
    async def get(self, request, datetime=None):
        """Retrieve logbook entries."""
        if datetime:
            datetime = dt_util.parse_datetime(datetime)

            if datetime is None:
                return self.json_message("Invalid datetime", HTTP_BAD_REQUEST)
        else:
            datetime = dt_util.start_of_local_day()

        period = request.query.get("period")
        if period is None:
            period = 1
        else:
            period = int(period)

        entity_ids = request.query.get("entity")
        if entity_ids:
            try:
                entity_ids = cv.entity_ids(entity_ids)
            except vol.Invalid:
                raise InvalidEntityFormatError(
                    f"Invalid entity id(s) encountered: {entity_ids}. "
                    "Format should be <domain>.<object_id>") from vol.Invalid

        end_time = request.query.get("end_time")
        if end_time is None:
            start_day = dt_util.as_utc(datetime) - timedelta(days=period - 1)
            end_day = start_day + timedelta(days=period)
        else:
            start_day = datetime
            end_day = dt_util.parse_datetime(end_time)
            if end_day is None:
                return self.json_message("Invalid end_time", HTTP_BAD_REQUEST)

        opp = request.app["opp"]

        entity_matches_only = "entity_matches_only" in request.query
        context_id = request.query.get("context_id")

        if entity_ids and context_id:
            return self.json_message("Can't combine entity with context_id",
                                     HTTP_BAD_REQUEST)

        def json_events():
            """Fetch events and generate JSON."""
            return self.json(
                _get_events(
                    opp,
                    start_day,
                    end_day,
                    entity_ids,
                    self.filters,
                    self.entities_filter,
                    entity_matches_only,
                    context_id,
                ))

        return await opp.async_add_executor_job(json_events)
Beispiel #18
0
def test_as_utc_with_local_object():
    """Test the UTC time with local object."""
    dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
    localnow = dt_util.now()
    utcnow = dt_util.as_utc(localnow)

    assert localnow == utcnow
    assert localnow.tzinfo != utcnow.tzinfo
Beispiel #19
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))
Beispiel #20
0
def _parse_due_date(data: dict, gmt_string) -> datetime:
    """Parse the due date dict into a datetime object."""
    # Add time information to date only strings.
    if len(data["date"]) == 10:
        data["date"] += "T00:00:00"
    if dt.parse_datetime(data["date"]).tzinfo is None:
        data["date"] += gmt_string
    return dt.as_utc(dt.parse_datetime(data["date"]))
Beispiel #21
0
    def update_from_latest_data(self) -> None:
        """Update the state."""
        pickup_event = self.coordinator.data[0]
        next_pickup_event = self.coordinator.data[1]

        self._state = as_utc(pickup_event.date).isoformat()
        self._attributes.update({
            ATTR_PICKUP_TYPES:
            async_get_pickup_type_names(self._entry,
                                        pickup_event.pickup_types),
            ATTR_AREA_NAME:
            pickup_event.area_name,
            ATTR_NEXT_PICKUP_TYPES:
            async_get_pickup_type_names(self._entry,
                                        next_pickup_event.pickup_types),
            ATTR_NEXT_PICKUP_DATE:
            as_utc(next_pickup_event.date).isoformat(),
        })
Beispiel #22
0
 def _set_state(self, state, timestamp):
     """Set sensor state."""
     if state < self._attr_state and self._sensor_name in [
         "accumulated consumption",
         "accumulated production",
         "accumulated cost",
     ]:
         self._attr_last_reset = dt_util.as_utc(
             timestamp.replace(hour=0, minute=0, second=0, microsecond=0)
         )
     if state < self._attr_state and self._sensor_name in [
         "accumulated consumption current hour",
         "accumulated production current hour",
     ]:
         self._attr_last_reset = dt_util.as_utc(
             timestamp.replace(minute=0, second=0, microsecond=0)
         )
     self._attr_state = state
     self.async_write_op_state()
Beispiel #23
0
def async_track_point_in_time(opp: OpenPeerPower, action: Callable[..., None],
                              point_in_time: datetime) -> CALLBACK_TYPE:
    """Add a listener that fires once after a specific point in time."""
    utc_point_in_time = dt_util.as_utc(point_in_time)

    @callback
    def utc_converter(utc_now: datetime) -> None:
        """Convert passed in UTC now to local now."""
        opp.async_run_job(action, dt_util.as_local(utc_now))

    return async_track_point_in_utc_time(opp, utc_converter, utc_point_in_time)
Beispiel #24
0
 def state_updated(self, state, **kwargs):
     """Handle state updates."""
     self._state = state
     if "last_reset" in kwargs:
         try:
             last_reset = dt_util.as_utc(
                 dt_util.parse_datetime(kwargs["last_reset"]))
             if last_reset is None:
                 raise ValueError
             self._attr_last_reset = last_reset
         except ValueError:
             _LOGGER.warning("Invalid last_reset timestamp '%s'",
                             kwargs["last_reset"])
     self.async_write_op_state()
Beispiel #25
0
def async_fire_time_changed(opp: OpenPeerPower,
                            datetime_: datetime,
                            fire_all: bool = False) -> None:
    """Fire a time changes event."""
    opp.bus.async_fire(EVENT_TIME_CHANGED,
                       {"now": date_util.as_utc(datetime_)})

    for task in list(opp.loop._scheduled):
        if not isinstance(task, asyncio.TimerHandle):
            continue
        if task.cancelled():
            continue

        mock_seconds_into_future = datetime_.timestamp() - time.time()
        future_seconds = task.when() - opp.loop.time()

        if fire_all or mock_seconds_into_future >= future_seconds:
            with patch(
                    "openpeerpower.helpers.event.time_tracker_utcnow",
                    return_value=date_util.as_utc(datetime_),
            ):
                task._run()
                task.cancel()
Beispiel #26
0
    def __init__(
        self, tibber_home, sensor_name, device_class, unit, initial_state, state_class
    ):
        """Initialize the sensor."""
        super().__init__(tibber_home)
        self._sensor_name = sensor_name
        self._model = "Tibber Pulse"
        self._device_name = f"{self._model} {self._home_name}"

        self._attr_device_class = device_class
        self._attr_name = f"{self._sensor_name} {self._home_name}"
        self._attr_state = initial_state
        self._attr_unique_id = f"{self._tibber_home.home_id}_rt_{self._sensor_name}"
        self._attr_unit_of_measurement = unit
        self._attr_state_class = state_class
        if sensor_name in [
            "last meter consumption",
            "last meter production",
        ]:
            self._attr_last_reset = datetime.fromtimestamp(0)
        elif self._sensor_name in [
            "accumulated consumption",
            "accumulated production",
            "accumulated cost",
        ]:
            self._attr_last_reset = dt_util.as_utc(
                dt_util.now().replace(hour=0, minute=0, second=0, microsecond=0)
            )
        elif self._sensor_name in [
            "accumulated consumption current hour",
            "accumulated production current hour",
        ]:
            self._attr_last_reset = dt_util.as_utc(
                dt_util.now().replace(minute=0, second=0, microsecond=0)
            )
        else:
            self._attr_last_reset = None
Beispiel #27
0
    def _update_info(self, now=None):
        for person in self.service.get_all_people():
            try:
                dev_id = "google_maps_{0}".format(slugify(person.id))
            except TypeError:
                _LOGGER.warning("No location(s) shared with this account")
                return

            if (
                self.max_gps_accuracy is not None
                and person.accuracy > self.max_gps_accuracy
            ):
                _LOGGER.info(
                    "Ignoring %s update because expected GPS "
                    "accuracy %s is not met: %s",
                    person.nickname,
                    self.max_gps_accuracy,
                    person.accuracy,
                )
                continue

            last_seen = dt_util.as_utc(person.datetime)
            if last_seen < self._prev_seen.get(dev_id, last_seen):
                _LOGGER.warning(
                    "Ignoring %s update because timestamp "
                    "is older than last timestamp",
                    person.nickname,
                )
                _LOGGER.debug("%s < %s", last_seen, self._prev_seen[dev_id])
                continue
            self._prev_seen[dev_id] = last_seen

            attrs = {
                ATTR_ADDRESS: person.address,
                ATTR_FULL_NAME: person.full_name,
                ATTR_ID: person.id,
                ATTR_LAST_SEEN: last_seen,
                ATTR_NICKNAME: person.nickname,
                ATTR_BATTERY_CHARGING: person.charging,
                ATTR_BATTERY_LEVEL: person.battery_level,
            }
            self.see(
                dev_id=dev_id,
                gps=(person.latitude, person.longitude),
                picture=person.picture_url,
                source_type=SOURCE_TYPE_GPS,
                gps_accuracy=person.accuracy,
                attributes=attrs,
            )
Beispiel #28
0
 def _update_from_feed(self, feed_entry, last_update,
                       last_update_successful):
     """Update the internal state from the provided feed entry."""
     self._title = feed_entry.title
     # Convert distance if not metric system.
     if self._unit_system == CONF_UNIT_SYSTEM_IMPERIAL:
         self._distance = round(
             IMPERIAL_SYSTEM.length(feed_entry.distance_to_home,
                                    LENGTH_KILOMETERS),
             1,
         )
     else:
         self._distance = round(feed_entry.distance_to_home, 1)
     self._latitude = round(feed_entry.coordinates[0], 5)
     self._longitude = round(feed_entry.coordinates[1], 5)
     self._attribution = feed_entry.attribution
     self._alert_level = feed_entry.alert_level
     self._activity = feed_entry.activity
     self._hazards = feed_entry.hazards
     self._feed_last_update = dt.as_utc(
         last_update) if last_update else None
     self._feed_last_update_successful = (dt.as_utc(last_update_successful)
                                          if last_update_successful else
                                          None)
Beispiel #29
0
    async def async_set_temperature(self, **kwargs) -> None:
        """Set a new target temperature."""
        temperature = kwargs["temperature"]
        until = kwargs.get("until")

        if until is None:
            if self._evo_device.setpointStatus["setpointMode"] == EVO_FOLLOW:
                await self._update_schedule()
                until = dt_util.parse_datetime(self.setpoints.get("next_sp_from", ""))
            elif self._evo_device.setpointStatus["setpointMode"] == EVO_TEMPOVER:
                until = dt_util.parse_datetime(self._evo_device.setpointStatus["until"])

        until = dt_util.as_utc(until) if until else None
        await self._evo_broker.call_client_api(
            self._evo_device.set_temperature(temperature, until=until)
        )
Beispiel #30
0
async def test_if_fires_using_multiple_at(opp, calls):
    """Test for firing at."""

    now = dt_util.now()

    trigger_dt = now.replace(hour=5, minute=0, second=0,
                             microsecond=0) + timedelta(2)
    time_that_will_not_match_right_away = trigger_dt - timedelta(minutes=1)

    with patch(
            "openpeerpower.util.dt.utcnow",
            return_value=dt_util.as_utc(time_that_will_not_match_right_away),
    ):
        assert await async_setup_component(
            opp,
            automation.DOMAIN,
            {
                automation.DOMAIN: {
                    "trigger": {
                        "platform": "time",
                        "at": ["5:00:00", "6:00:00"]
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "{{ trigger.platform }} - {{ trigger.now.hour }}"
                        },
                    },
                }
            },
        )
        await opp.async_block_till_done()

    async_fire_time_changed(opp, trigger_dt + timedelta(seconds=1))
    await opp.async_block_till_done()

    assert len(calls) == 1
    assert calls[0].data["some"] == "time - 5"

    async_fire_time_changed(opp, trigger_dt + timedelta(hours=1, seconds=1))
    await opp.async_block_till_done()

    assert len(calls) == 2
    assert calls[1].data["some"] == "time - 6"