Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ omit =
homeassistant/components/sensor/sochain.py
homeassistant/components/sensor/sonarr.py
homeassistant/components/sensor/speedtest.py
homeassistant/components/sensor/spotcrime.py
homeassistant/components/sensor/steam_online.py
homeassistant/components/sensor/supervisord.py
homeassistant/components/sensor/swiss_hydrological_data.py
Expand Down
124 changes: 124 additions & 0 deletions homeassistant/components/sensor/spotcrime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""
Sensor for Spot Crime.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.spotcrime/
"""

from datetime import timedelta
from collections import defaultdict
import logging

import voluptuous as vol

from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
CONF_INCLUDE, CONF_EXCLUDE, CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE,
ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_RADIUS, CONF_DAYS)
from homeassistant.helpers.entity import Entity
from homeassistant.util import slugify
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['spotcrime==1.0.2']

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'spotcrime'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This platform is part of the sensor domain. So don't overwrite that. If you need a constant to be used multiple times, just rename it to something else.


EVENT_INCIDENT = '{}_incident'.format(DOMAIN)

SCAN_INTERVAL = timedelta(minutes=30)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_RADIUS): vol.Coerce(float),
vol.Inclusive(CONF_LATITUDE, 'coordinates'): cv.latitude,
vol.Inclusive(CONF_LONGITUDE, 'coordinates'): cv.longitude,
vol.Optional(CONF_DAYS): cv.positive_int,
vol.Optional(CONF_INCLUDE): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_EXCLUDE): vol.All(cv.ensure_list, [cv.string])
})


# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Crime Reports platform."""
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
name = config.get(CONF_NAME)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is required in the config schema, so don't use dict.get. Do:

name = config[CONF_NAME]

radius = config.get(CONF_RADIUS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

days = config.get(CONF_DAYS)
include = config.get(CONF_INCLUDE)
exclude = config.get(CONF_EXCLUDE)

add_devices([SpotCrimeSensor(
hass, name, latitude, longitude, radius, include,
exclude, days)], True)


class SpotCrimeSensor(Entity):
"""Representation of a Spot Crime Sensor."""

def __init__(self, hass, name, latitude, longitude, radius,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't pass in hass. It will be set on the entity when it has been added to home assistant.

include, exclude, days):
"""Initialize the Spot Crime sensor."""
import spotcrime
self._hass = hass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

self._name = name
self._include = include
self._exclude = exclude
self.days = days
self._spotcrime = spotcrime.SpotCrime(
(latitude, longitude), radius, None, None, self.days)
self._attributes = None
self._state = None
self._previous_incidents = set()

@property
def name(self):
"""Return the name of the sensor."""
return self._name

@property
def state(self):
"""Return the state of the sensor."""
return self._state

@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes

def _incident_event(self, incident):
data = {
'type': incident.get('type'),
'timestamp': incident.get('timestamp'),
'address': incident.get('location')
}
if incident.get('coordinates'):
data.update({
ATTR_LATITUDE: incident.get('lat'),
ATTR_LONGITUDE: incident.get('lon')
})
self._hass.bus.fire(EVENT_INCIDENT, data)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use self.hass.


def update(self):
"""Update device state."""
import spotcrime

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'spotcrime' imported but unused

incident_counts = defaultdict(int)
incidents = self._spotcrime.get_incidents()
fire_events = len(self._previous_incidents) > 0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to define a new variable here. Just check if self._previous_incidents is truthy below.

if len(incidents) < len(self._previous_incidents):
self._previous_incidents = set()
for incident in incidents:
incident_type = slugify(incident.get('type'))
incident_counts[incident_type] += 1
if (fire_events and incident.get('id')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (self._previous_incidents and incident.get('id')
        not in self._previous_incidents):

not in self._previous_incidents):
self._incident_event(incident)
self._previous_incidents.add(incident.get('id'))
self._attributes = {
ATTR_ATTRIBUTION: spotcrime.ATTRIBUTION

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do this in init instead.

}
self._attributes.update(incident_counts)
self._state = len(incidents)
1 change: 1 addition & 0 deletions homeassistant/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
CONF_CUSTOMIZE = 'customize'
CONF_CUSTOMIZE_DOMAIN = 'customize_domain'
CONF_CUSTOMIZE_GLOB = 'customize_glob'
CONF_DAYS = 'days'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do that only if you can replace it and use it on other components/platform

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should I remove or how should I change it to be correct?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @pvizeli is saying that const.py is for constants that are broadly applicable; as far as we know, CONF_DAYS is only useful to your platform at the moment. So, until it's determined otherwise, it's best placed within spotcrime.py.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @bachya, I see now. I did not understand well enough how to bring in the configuration variables. Some of the information at this link gave me a better idea: https://community.home-assistant.io/t/help-using-config-get-for-custom-platform-switch/4092/2. I am working to do it the correct way now.

CONF_DELAY_TIME = 'delay_time'
CONF_DEVICE = 'device'
CONF_DEVICE_CLASS = 'device_class'
Expand Down
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,9 @@ somecomfort==0.5.0
# homeassistant.components.sensor.speedtest
speedtest-cli==1.0.7

# homeassistant.components.sensor.spotcrime
spotcrime==1.0.2

# homeassistant.components.recorder
# homeassistant.scripts.db_migrator
# homeassistant.components.sensor.sql
Expand Down