Esempio n. 1
0
    def test_update_error(self, mock_session, mock_request):
        """Test updating feed results in error."""
        home_coordinates = (-31.0, 151.0)
        mock_session.return_value.__enter__.return_value.send.return_value.ok = False

        feed = GenericFeed(home_coordinates, None)
        status, entries = feed.update()
        assert status == UPDATE_ERROR
        self.assertIsNone(feed.last_timestamp)
    def test_update_with_request_exception(self, mock_session, mock_request):
        """Test updating feed raises exception."""
        home_coordinates = (-31.0, 151.0)
        mock_session.return_value.__enter__.return_value.send\
            .side_effect = requests.exceptions.RequestException

        feed = GenericFeed(home_coordinates, None)
        status, entries = feed.update()
        assert status == UPDATE_ERROR
        self.assertIsNone(entries)
    def test_update_with_json_decode_error(self, mock_session, mock_request):
        """Test updating feed raises exception."""
        home_coordinates = (-31.0, 151.0)
        mock_session.return_value.__enter__.return_value.send\
            .side_effect = JSONDecodeError("", "", 0)

        feed = GenericFeed(home_coordinates, None)
        status, entries = feed.update()
        assert status == UPDATE_ERROR
        self.assertIsNone(entries)
Esempio n. 4
0
    def test_update_ok_with_filtering(self, mock_session, mock_request):
        """Test updating feed is ok."""
        home_coordinates = (-37.0, 150.0)
        mock_session.return_value.__enter__.return_value.send.return_value.ok = True
        mock_session.return_value.__enter__.return_value.send.return_value.text = (
            load_fixture("generic_feed_1.json")
        )

        feed = GenericFeed(home_coordinates, None, filter_radius=90.0)
        status, entries = feed.update()
        assert status == UPDATE_OK
        self.assertIsNotNone(entries)
        assert len(entries) == 4
        self.assertAlmostEqual(entries[0].distance_to_home, 82.0, 1)
        self.assertAlmostEqual(entries[1].distance_to_home, 77.0, 1)
        self.assertAlmostEqual(entries[2].distance_to_home, 84.6, 1)
Esempio n. 5
0
    def test_update_ok(self, mock_session, mock_request):
        """Test updating feed is ok."""
        home_coordinates = (-31.0, 151.0)
        mock_session.return_value.__enter__.return_value.send.return_value.ok = True
        mock_session.return_value.__enter__.return_value.send.return_value.text = (
            load_fixture("generic_feed_1.json")
        )

        feed = GenericFeed(home_coordinates, None)
        assert (
            repr(feed) == "<GenericFeed(home=(-31.0, 151.0), url=None, " "radius=None)>"
        )
        status, entries = feed.update()
        assert status == UPDATE_OK
        self.assertIsNotNone(entries)
        assert len(entries) == 5

        feed_entry = entries[0]
        assert feed_entry.title == "Title 1"
        assert feed_entry.external_id == "3456"
        assert feed_entry.coordinates == (-37.2345, 149.1234)
        self.assertAlmostEqual(feed_entry.distance_to_home, 714.4, 1)
        assert repr(feed_entry) == "<GenericFeedEntry(id=3456)>"

        feed_entry = entries[1]
        assert feed_entry.title == "Title 2"
        assert feed_entry.external_id == "4567"

        feed_entry = entries[2]
        assert feed_entry.title == "Title 3"
        assert feed_entry.external_id == "Title 3"

        feed_entry = entries[3]
        self.assertIsNone(feed_entry.title)
        assert feed_entry.external_id == hash(feed_entry.coordinates)

        feed_entry = entries[4]
        assert feed_entry.title == "Title 5"
        assert feed_entry.external_id == "7890"
Esempio n. 6
0
class GeoJsonFeedManager:
    """Feed Manager for GeoJSON feeds."""

    def __init__(self, hass, add_entities, scan_interval, url, radius_in_km):
        """Initialize the GeoJSON Feed Manager."""
        from geojson_client.generic_feed import GenericFeed

        self._hass = hass
        self._feed = GenericFeed(
            (hass.config.latitude, hass.config.longitude),
            filter_radius=radius_in_km, url=url)
        self._add_entities = add_entities
        self._scan_interval = scan_interval
        self.feed_entries = {}
        self._managed_external_ids = set()

    def startup(self):
        """Start up this manager."""
        self._update()
        self._init_regular_updates()

    def _init_regular_updates(self):
        """Schedule regular updates at the specified interval."""
        track_time_interval(
            self._hass, lambda now: self._update(), self._scan_interval)

    def _update(self):
        """Update the feed and then update connected entities."""
        import geojson_client

        status, feed_entries = self._feed.update()
        if status == geojson_client.UPDATE_OK:
            _LOGGER.debug("Data retrieved %s", feed_entries)
            # Keep a copy of all feed entries for future lookups by entities.
            self.feed_entries = {entry.external_id: entry
                                 for entry in feed_entries}
            # For entity management the external ids from the feed are used.
            feed_external_ids = set(self.feed_entries)
            remove_external_ids = self._managed_external_ids.difference(
                feed_external_ids)
            self._remove_entities(remove_external_ids)
            update_external_ids = self._managed_external_ids.intersection(
                feed_external_ids)
            self._update_entities(update_external_ids)
            create_external_ids = feed_external_ids.difference(
                self._managed_external_ids)
            self._generate_new_entities(create_external_ids)
        elif status == geojson_client.UPDATE_OK_NO_DATA:
            _LOGGER.debug(
                "Update successful, but no data received from %s", self._feed)
        else:
            _LOGGER.warning(
                "Update not successful, no data received from %s", self._feed)
            # Remove all entities.
            self._remove_entities(self._managed_external_ids.copy())

    def _generate_new_entities(self, external_ids):
        """Generate new entities for events."""
        new_entities = []
        for external_id in external_ids:
            new_entity = GeoJsonLocationEvent(self, external_id)
            _LOGGER.debug("New entity added %s", external_id)
            new_entities.append(new_entity)
            self._managed_external_ids.add(external_id)
        # Add new entities to HA.
        self._add_entities(new_entities, True)

    def _update_entities(self, external_ids):
        """Update entities."""
        for external_id in external_ids:
            _LOGGER.debug("Existing entity found %s", external_id)
            dispatcher_send(
                self._hass, SIGNAL_UPDATE_ENTITY.format(external_id))

    def _remove_entities(self, external_ids):
        """Remove entities."""
        for external_id in external_ids:
            _LOGGER.debug("Entity not current anymore %s", external_id)
            self._managed_external_ids.remove(external_id)
            dispatcher_send(
                self._hass, SIGNAL_DELETE_ENTITY.format(external_id))
class GeoJsonFeedManager:
    """Feed Manager for GeoJSON feeds."""

    def __init__(self, hass, add_entities, scan_interval, url, radius_in_km):
        """Initialize the GeoJSON Feed Manager."""
        from geojson_client.generic_feed import GenericFeed

        self._hass = hass
        self._feed = GenericFeed(
            (hass.config.latitude, hass.config.longitude),
            filter_radius=radius_in_km, url=url)
        self._add_entities = add_entities
        self._scan_interval = scan_interval
        self.feed_entries = {}
        self._managed_external_ids = set()

    def startup(self):
        """Start up this manager."""
        self._update()
        self._init_regular_updates()

    def _init_regular_updates(self):
        """Schedule regular updates at the specified interval."""
        track_time_interval(
            self._hass, lambda now: self._update(), self._scan_interval)

    def _update(self):
        """Update the feed and then update connected entities."""
        import geojson_client

        status, feed_entries = self._feed.update()
        if status == geojson_client.UPDATE_OK:
            _LOGGER.debug("Data retrieved %s", feed_entries)
            # Keep a copy of all feed entries for future lookups by entities.
            self.feed_entries = {entry.external_id: entry
                                 for entry in feed_entries}
            # For entity management the external ids from the feed are used.
            feed_external_ids = set(self.feed_entries)
            remove_external_ids = self._managed_external_ids.difference(
                feed_external_ids)
            self._remove_entities(remove_external_ids)
            update_external_ids = self._managed_external_ids.intersection(
                feed_external_ids)
            self._update_entities(update_external_ids)
            create_external_ids = feed_external_ids.difference(
                self._managed_external_ids)
            self._generate_new_entities(create_external_ids)
        elif status == geojson_client.UPDATE_OK_NO_DATA:
            _LOGGER.debug(
                "Update successful, but no data received from %s", self._feed)
        else:
            _LOGGER.warning(
                "Update not successful, no data received from %s", self._feed)
            # Remove all entities.
            self._remove_entities(self._managed_external_ids.copy())

    def _generate_new_entities(self, external_ids):
        """Generate new entities for events."""
        new_entities = []
        for external_id in external_ids:
            new_entity = GeoJsonLocationEvent(self, external_id)
            _LOGGER.debug("New entity added %s", external_id)
            new_entities.append(new_entity)
            self._managed_external_ids.add(external_id)
        # Add new entities to HA.
        self._add_entities(new_entities, True)

    def _update_entities(self, external_ids):
        """Update entities."""
        for external_id in external_ids:
            _LOGGER.debug("Existing entity found %s", external_id)
            dispatcher_send(
                self._hass, SIGNAL_UPDATE_ENTITY.format(external_id))

    def _remove_entities(self, external_ids):
        """Remove entities."""
        for external_id in external_ids:
            _LOGGER.debug("Entity not current anymore %s", external_id)
            self._managed_external_ids.remove(external_id)
            dispatcher_send(
                self._hass, SIGNAL_DELETE_ENTITY.format(external_id))
class GeoJsonFeedManager:
    """Feed Manager for GeoJSON feeds."""

    def __init__(self, hass, add_entities, scan_interval, url, radius_in_km):
        """Initialize the GeoJSON Feed Manager."""
        from geojson_client.generic_feed import GenericFeed
        self._hass = hass
        self._feed = GenericFeed((hass.config.latitude, hass.config.longitude),
                                 filter_radius=radius_in_km, url=url)
        self._add_entities = add_entities
        self._scan_interval = scan_interval
        self._feed_entries = []
        self._managed_entities = []
        hass.bus.listen_once(
            EVENT_HOMEASSISTANT_START, lambda _: self._update())
        self._init_regular_updates()

    def _init_regular_updates(self):
        """Schedule regular updates at the specified interval."""
        track_time_interval(self._hass, lambda now: self._update(),
                            self._scan_interval)

    def _update(self):
        """Update the feed and then update connected entities."""
        import geojson_client
        status, feed_entries = self._feed.update()
        if status == geojson_client.UPDATE_OK:
            _LOGGER.debug("Data retrieved %s", feed_entries)
            # Keep a copy of all feed entries for future lookups by entities.
            self._feed_entries = feed_entries.copy()
            keep_entries = self._update_or_remove_entities(feed_entries)
            self._generate_new_entities(keep_entries)
        elif status == geojson_client.UPDATE_OK_NO_DATA:
            _LOGGER.debug("Update successful, but no data received from %s",
                          self._feed)
        else:
            _LOGGER.warning("Update not successful, no data received from %s",
                            self._feed)
            # Remove all entities.
            self._update_or_remove_entities([])

    def _update_or_remove_entities(self, feed_entries):
        """Update existing entries and remove obsolete entities."""
        _LOGGER.debug("Entries for updating: %s", feed_entries)
        remove_entry = None
        # Remove obsolete entities for events that have disappeared
        managed_entities = self._managed_entities.copy()
        for entity in managed_entities:
            # Remove entry from previous iteration - if applicable.
            if remove_entry:
                feed_entries.remove(remove_entry)
                remove_entry = None
            for entry in feed_entries:
                if entity.external_id == entry.external_id:
                    # Existing entity - update details.
                    _LOGGER.debug("Existing entity found %s", entity)
                    remove_entry = entry
                    entity.schedule_update_ha_state(True)
                    break
            else:
                # Remove obsolete entity.
                _LOGGER.debug("Entity not current anymore %s", entity)
                self._managed_entities.remove(entity)
                self._hass.add_job(entity.async_remove())
        # Remove entry from very last iteration - if applicable.
        if remove_entry:
            feed_entries.remove(remove_entry)
        # Return the remaining entries that new entities must be created for.
        return feed_entries

    def _generate_new_entities(self, entries):
        """Generate new entities for events."""
        new_entities = []
        for entry in entries:
            new_entity = GeoJsonLocationEvent(self, entry)
            _LOGGER.debug("New entity added %s", new_entity)
            new_entities.append(new_entity)
        # Add new entities to HA and keep track of them in this manager.
        self._add_entities(new_entities, True)
        self._managed_entities.extend(new_entities)

    def get_feed_entry(self, external_id):
        """Return a feed entry identified by external id."""
        return next((entry for entry in self._feed_entries
                     if entry.external_id == external_id), None)
Esempio n. 9
0
class GeoJsonFeedManager:
    """Feed Manager for GeoJSON feeds."""
    def __init__(self, hass, add_entities, scan_interval, url, radius_in_km):
        """Initialize the GeoJSON Feed Manager."""
        from geojson_client.generic_feed import GenericFeed
        self._hass = hass
        self._feed = GenericFeed((hass.config.latitude, hass.config.longitude),
                                 filter_radius=radius_in_km,
                                 url=url)
        self._add_entities = add_entities
        self._scan_interval = scan_interval
        self._feed_entries = []
        self._managed_entities = []
        hass.bus.listen_once(EVENT_HOMEASSISTANT_START,
                             lambda _: self._update())
        self._init_regular_updates()

    def _init_regular_updates(self):
        """Schedule regular updates at the specified interval."""
        track_time_interval(self._hass, lambda now: self._update(),
                            self._scan_interval)

    def _update(self):
        """Update the feed and then update connected entities."""
        import geojson_client
        status, feed_entries = self._feed.update()
        if status == geojson_client.UPDATE_OK:
            _LOGGER.debug("Data retrieved %s", feed_entries)
            # Keep a copy of all feed entries for future lookups by entities.
            self._feed_entries = feed_entries.copy()
            keep_entries = self._update_or_remove_entities(feed_entries)
            self._generate_new_entities(keep_entries)
        elif status == geojson_client.UPDATE_OK_NO_DATA:
            _LOGGER.debug("Update successful, but no data received from %s",
                          self._feed)
        else:
            _LOGGER.warning("Update not successful, no data received from %s",
                            self._feed)
            # Remove all entities.
            self._update_or_remove_entities([])

    def _update_or_remove_entities(self, feed_entries):
        """Update existing entries and remove obsolete entities."""
        _LOGGER.debug("Entries for updating: %s", feed_entries)
        remove_entry = None
        # Remove obsolete entities for events that have disappeared
        managed_entities = self._managed_entities.copy()
        for entity in managed_entities:
            # Remove entry from previous iteration - if applicable.
            if remove_entry:
                feed_entries.remove(remove_entry)
                remove_entry = None
            for entry in feed_entries:
                if entity.external_id == entry.external_id:
                    # Existing entity - update details.
                    _LOGGER.debug("Existing entity found %s", entity)
                    remove_entry = entry
                    entity.schedule_update_ha_state(True)
                    break
            else:
                # Remove obsolete entity.
                _LOGGER.debug("Entity not current anymore %s", entity)
                self._managed_entities.remove(entity)
                self._hass.add_job(entity.async_remove())
        # Remove entry from very last iteration - if applicable.
        if remove_entry:
            feed_entries.remove(remove_entry)
        # Return the remaining entries that new entities must be created for.
        return feed_entries

    def _generate_new_entities(self, entries):
        """Generate new entities for events."""
        new_entities = []
        for entry in entries:
            new_entity = GeoJsonLocationEvent(self, entry)
            _LOGGER.debug("New entity added %s", new_entity)
            new_entities.append(new_entity)
        # Add new entities to HA and keep track of them in this manager.
        self._add_entities(new_entities, True)
        self._managed_entities.extend(new_entities)

    def get_feed_entry(self, external_id):
        """Return a feed entry identified by external id."""
        return next((entry for entry in self._feed_entries
                     if entry.external_id == external_id), None)