Skip to content

Commit

Permalink
Fixed Canary temperature sensor and remapped air quality value (#11355)
Browse files Browse the repository at this point in the history
* Fixed Canary temperature sensor and remapped air quality value

* Addressed review comment

* - Fixed canary tests and added more tests
- Removed py-canary requirements from tests

* Noop to trigger a build again

* - Removed py-canary requirements from tests

* Addressed PR comment

* - Updated tests
- Removed py-canary from gen_requirements_all.py

* - Fixed hound violation

* Added back py-canary to gen_requirements_all.py as it's still need in tests

* Added back py-canary to test requirements as it's still need in tests

* Address PR comment
  • Loading branch information
snjoetw authored and MartinHjelmare committed Jan 28, 2018
1 parent c7efe5b commit b3bf6c4
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 48 deletions.
7 changes: 7 additions & 0 deletions homeassistant/components/canary.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ def get_readings(self, device_id):
"""Return a list of readings based on device_id."""
return self._readings_by_device_id.get(device_id, [])

def get_reading(self, device_id, sensor_type):
"""Return reading for device_id and sensor type."""
readings = self._readings_by_device_id.get(device_id, [])
return next((
reading.value for reading in readings
if reading.sensor_type == sensor_type), None)

def set_location_mode(self, location_id, mode_name, is_private=False):
"""Set location mode."""
self._api.set_location_mode(location_id, mode_name, is_private)
Expand Down
74 changes: 55 additions & 19 deletions homeassistant/components/sensor/canary.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,38 @@
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.canary/
"""

from homeassistant.components.canary import DATA_CANARY
from homeassistant.const import TEMP_FAHRENHEIT, TEMP_CELSIUS
from homeassistant.const import TEMP_CELSIUS
from homeassistant.helpers.entity import Entity

DEPENDENCIES = ['canary']

SENSOR_VALUE_PRECISION = 1
SENSOR_VALUE_PRECISION = 2
ATTR_AIR_QUALITY = "air_quality"

# Sensor types are defined like so:
# sensor type name, unit_of_measurement, icon
SENSOR_TYPES = [
["temperature", TEMP_CELSIUS, "mdi:thermometer"],
["humidity", "%", "mdi:water-percent"],
["air_quality", None, "mdi:weather-windy"],
]

STATE_AIR_QUALITY_NORMAL = "normal"
STATE_AIR_QUALITY_ABNORMAL = "abnormal"
STATE_AIR_QUALITY_VERY_ABNORMAL = "very_abnormal"


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Canary sensors."""
data = hass.data[DATA_CANARY]
devices = []

from canary.api import SensorType
for location in data.locations:
for device in location.devices:
if device.is_online:
for sensor_type in SensorType:
for sensor_type in SENSOR_TYPES:
devices.append(CanarySensor(data, sensor_type, location,
device))

Expand All @@ -37,10 +50,9 @@ def __init__(self, data, sensor_type, location, device):
self._data = data
self._sensor_type = sensor_type
self._device_id = device.device_id
self._is_celsius = location.is_celsius
self._sensor_value = None

sensor_type_name = sensor_type.value.replace("_", " ").title()
sensor_type_name = sensor_type[0].replace("_", " ").title()
self._name = '{} {} {}'.format(location.name,
device.name,
sensor_type_name)
Expand All @@ -59,27 +71,51 @@ def state(self):
def unique_id(self):
"""Return the unique ID of this sensor."""
return "sensor_canary_{}_{}".format(self._device_id,
self._sensor_type.value)
self._sensor_type[0])

@property
def unit_of_measurement(self):
"""Return the unit of measurement this sensor expresses itself in."""
from canary.api import SensorType
if self._sensor_type == SensorType.TEMPERATURE:
return TEMP_CELSIUS if self._is_celsius else TEMP_FAHRENHEIT
elif self._sensor_type == SensorType.HUMIDITY:
return "%"
elif self._sensor_type == SensorType.AIR_QUALITY:
return ""
"""Return the unit of measurement."""
return self._sensor_type[1]

@property
def icon(self):
"""Icon for the sensor."""
return self._sensor_type[2]

@property
def device_state_attributes(self):
"""Return the state attributes."""
if self._sensor_type[0] == "air_quality" \
and self._sensor_value is not None:
air_quality = None
if self._sensor_value <= .4:
air_quality = STATE_AIR_QUALITY_VERY_ABNORMAL
elif self._sensor_value <= .59:
air_quality = STATE_AIR_QUALITY_ABNORMAL
elif self._sensor_value <= 1.0:
air_quality = STATE_AIR_QUALITY_NORMAL

return {
ATTR_AIR_QUALITY: air_quality
}

return None

def update(self):
"""Get the latest state of the sensor."""
self._data.update()

readings = self._data.get_readings(self._device_id)
value = next((
reading.value for reading in readings
if reading.sensor_type == self._sensor_type), None)
from canary.api import SensorType
canary_sensor_type = None
if self._sensor_type[0] == "air_quality":
canary_sensor_type = SensorType.AIR_QUALITY
elif self._sensor_type[0] == "temperature":
canary_sensor_type = SensorType.TEMPERATURE
elif self._sensor_type[0] == "humidity":
canary_sensor_type = SensorType.HUMIDITY

value = self._data.get_reading(self._device_id, canary_sensor_type)

if value is not None:
self._sensor_value = round(float(value), SENSOR_VALUE_PRECISION)
104 changes: 75 additions & 29 deletions tests/components/sensor/test_canary.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import unittest
from unittest.mock import Mock

from canary.api import SensorType
from homeassistant.components.canary import DATA_CANARY
from homeassistant.components.sensor import canary
from homeassistant.components.sensor.canary import CanarySensor
from homeassistant.components.sensor.canary import CanarySensor, \
SENSOR_TYPES, ATTR_AIR_QUALITY, STATE_AIR_QUALITY_NORMAL, \
STATE_AIR_QUALITY_ABNORMAL, STATE_AIR_QUALITY_VERY_ABNORMAL
from tests.common import (get_test_home_assistant)
from tests.components.test_canary import mock_device, mock_reading, \
mock_location
from tests.components.test_canary import mock_device, mock_location

VALID_CONFIG = {
"canary": {
Expand Down Expand Up @@ -55,67 +55,113 @@ def test_setup_sensors(self):

self.assertEqual(6, len(self.DEVICES))

def test_celsius_temperature_sensor(self):
"""Test temperature sensor with celsius."""
def test_temperature_sensor(self):
"""Test temperature sensor with fahrenheit."""
device = mock_device(10, "Family Room")
location = mock_location("Home", True)
location = mock_location("Home", False)

data = Mock()
data.get_readings.return_value = [
mock_reading(SensorType.TEMPERATURE, 21.1234)]
data.get_reading.return_value = 21.1234

sensor = CanarySensor(data, SensorType.TEMPERATURE, location, device)
sensor = CanarySensor(data, SENSOR_TYPES[0], location, device)
sensor.update()

self.assertEqual("Home Family Room Temperature", sensor.name)
self.assertEqual("sensor_canary_10_temperature", sensor.unique_id)
self.assertEqual("°C", sensor.unit_of_measurement)
self.assertEqual(21.1, sensor.state)
self.assertEqual(21.12, sensor.state)

def test_fahrenheit_temperature_sensor(self):
def test_temperature_sensor_with_none_sensor_value(self):
"""Test temperature sensor with fahrenheit."""
device = mock_device(10, "Family Room")
location = mock_location("Home", False)

data = Mock()
data.get_readings.return_value = [
mock_reading(SensorType.TEMPERATURE, 21.1567)]
data.get_reading.return_value = None

sensor = CanarySensor(data, SensorType.TEMPERATURE, location, device)
sensor = CanarySensor(data, SENSOR_TYPES[0], location, device)
sensor.update()

self.assertEqual("Home Family Room Temperature", sensor.name)
self.assertEqual("°F", sensor.unit_of_measurement)
self.assertEqual(21.2, sensor.state)
self.assertEqual(None, sensor.state)

def test_humidity_sensor(self):
"""Test humidity sensor."""
device = mock_device(10, "Family Room")
location = mock_location("Home")

data = Mock()
data.get_readings.return_value = [
mock_reading(SensorType.HUMIDITY, 50.4567)]
data.get_reading.return_value = 50.4567

sensor = CanarySensor(data, SensorType.HUMIDITY, location, device)
sensor = CanarySensor(data, SENSOR_TYPES[1], location, device)
sensor.update()

self.assertEqual("Home Family Room Humidity", sensor.name)
self.assertEqual("%", sensor.unit_of_measurement)
self.assertEqual(50.5, sensor.state)
self.assertEqual(50.46, sensor.state)

def test_air_quality_sensor_with_very_abnormal_reading(self):
"""Test air quality sensor."""
device = mock_device(10, "Family Room")
location = mock_location("Home")

data = Mock()
data.get_reading.return_value = 0.4

def test_air_quality_sensor(self):
sensor = CanarySensor(data, SENSOR_TYPES[2], location, device)
sensor.update()

self.assertEqual("Home Family Room Air Quality", sensor.name)
self.assertEqual(None, sensor.unit_of_measurement)
self.assertEqual(0.4, sensor.state)

air_quality = sensor.device_state_attributes[ATTR_AIR_QUALITY]
self.assertEqual(STATE_AIR_QUALITY_VERY_ABNORMAL, air_quality)

def test_air_quality_sensor_with_abnormal_reading(self):
"""Test air quality sensor."""
device = mock_device(10, "Family Room")
location = mock_location("Home")

data = Mock()
data.get_readings.return_value = [
mock_reading(SensorType.AIR_QUALITY, 50.4567)]
data.get_reading.return_value = 0.59

sensor = CanarySensor(data, SensorType.AIR_QUALITY, location, device)
sensor = CanarySensor(data, SENSOR_TYPES[2], location, device)
sensor.update()

self.assertEqual("Home Family Room Air Quality", sensor.name)
self.assertEqual("", sensor.unit_of_measurement)
self.assertEqual(50.5, sensor.state)
self.assertEqual(None, sensor.unit_of_measurement)
self.assertEqual(0.59, sensor.state)

air_quality = sensor.device_state_attributes[ATTR_AIR_QUALITY]
self.assertEqual(STATE_AIR_QUALITY_ABNORMAL, air_quality)

def test_air_quality_sensor_with_normal_reading(self):
"""Test air quality sensor."""
device = mock_device(10, "Family Room")
location = mock_location("Home")

data = Mock()
data.get_reading.return_value = 1.0

sensor = CanarySensor(data, SENSOR_TYPES[2], location, device)
sensor.update()

self.assertEqual("Home Family Room Air Quality", sensor.name)
self.assertEqual(None, sensor.unit_of_measurement)
self.assertEqual(1.0, sensor.state)

air_quality = sensor.device_state_attributes[ATTR_AIR_QUALITY]
self.assertEqual(STATE_AIR_QUALITY_NORMAL, air_quality)

def test_air_quality_sensor_with_none_sensor_value(self):
"""Test air quality sensor."""
device = mock_device(10, "Family Room")
location = mock_location("Home")

data = Mock()
data.get_reading.return_value = None

sensor = CanarySensor(data, SENSOR_TYPES[2], location, device)
sensor.update()

self.assertEqual(None, sensor.state)
self.assertEqual(None, sensor.device_state_attributes)

0 comments on commit b3bf6c4

Please sign in to comment.