core/tests/components/plant/test_init.py

246 lines
8.5 KiB
Python

"""Unit tests for platform/plant.py."""
import asyncio
import unittest
import pytest
from datetime import datetime, timedelta
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
STATE_PROBLEM,
STATE_OK,
)
from homeassistant.components import recorder
import homeassistant.components.plant as plant
from homeassistant.setup import setup_component
from tests.common import get_test_home_assistant, init_recorder_component
GOOD_DATA = {
"moisture": 50,
"battery": 90,
"temperature": 23.4,
"conductivity": 777,
"brightness": 987,
}
BRIGHTNESS_ENTITY = "sensor.mqtt_plant_brightness"
MOISTURE_ENTITY = "sensor.mqtt_plant_moisture"
GOOD_CONFIG = {
"sensors": {
"moisture": MOISTURE_ENTITY,
"battery": "sensor.mqtt_plant_battery",
"temperature": "sensor.mqtt_plant_temperature",
"conductivity": "sensor.mqtt_plant_conductivity",
"brightness": BRIGHTNESS_ENTITY,
},
"min_moisture": 20,
"max_moisture": 60,
"min_battery": 17,
"min_conductivity": 500,
"min_temperature": 15,
"min_brightness": 500,
}
class _MockState:
def __init__(self, state=None):
self.state = state
class TestPlant(unittest.TestCase):
"""Tests for component "plant"."""
def setUp(self):
"""Create test instance of home assistant."""
self.hass = get_test_home_assistant()
self.hass.start()
def tearDown(self):
"""Stop everything that was started."""
self.hass.stop()
@asyncio.coroutine
def test_valid_data(self):
"""Test processing valid data."""
sensor = plant.Plant("my plant", GOOD_CONFIG)
sensor.hass = self.hass
for reading, value in GOOD_DATA.items():
sensor.state_changed(
GOOD_CONFIG["sensors"][reading], None, _MockState(value)
)
assert sensor.state == "ok"
attrib = sensor.state_attributes
for reading, value in GOOD_DATA.items():
# battery level has a different name in
# the JSON format than in hass
assert attrib[reading] == value
@asyncio.coroutine
def test_low_battery(self):
"""Test processing with low battery data and limit set."""
sensor = plant.Plant("other plant", GOOD_CONFIG)
sensor.hass = self.hass
assert sensor.state_attributes["problem"] == "none"
sensor.state_changed(
"sensor.mqtt_plant_battery", _MockState(45), _MockState(10)
)
assert sensor.state == "problem"
assert sensor.state_attributes["problem"] == "battery low"
def test_initial_states(self):
"""Test plant initialises attributes if sensor already exists."""
self.hass.states.set(MOISTURE_ENTITY, 5, {ATTR_UNIT_OF_MEASUREMENT: "us/cm"})
plant_name = "some_plant"
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert 5 == state.attributes[plant.READING_MOISTURE]
def test_update_states(self):
"""Test updating the state of a sensor.
Make sure that plant processes this correctly.
"""
plant_name = "some_plant"
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.states.set(MOISTURE_ENTITY, 5, {ATTR_UNIT_OF_MEASUREMENT: "us/cm"})
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert STATE_PROBLEM == state.state
assert 5 == state.attributes[plant.READING_MOISTURE]
def test_unavailable_state(self):
"""Test updating the state with unavailable.
Make sure that plant processes this correctly.
"""
plant_name = "some_plant"
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.states.set(
MOISTURE_ENTITY, STATE_UNAVAILABLE, {ATTR_UNIT_OF_MEASUREMENT: "us/cm"}
)
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert state.state == STATE_PROBLEM
assert state.attributes[plant.READING_MOISTURE] == STATE_UNAVAILABLE
def test_state_problem_if_unavailable(self):
"""Test updating the state with unavailable after setting it to valid value.
Make sure that plant processes this correctly.
"""
plant_name = "some_plant"
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.states.set(MOISTURE_ENTITY, 42, {ATTR_UNIT_OF_MEASUREMENT: "us/cm"})
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert state.state == STATE_OK
assert state.attributes[plant.READING_MOISTURE] == 42
self.hass.states.set(
MOISTURE_ENTITY, STATE_UNAVAILABLE, {ATTR_UNIT_OF_MEASUREMENT: "us/cm"}
)
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert state.state == STATE_PROBLEM
assert state.attributes[plant.READING_MOISTURE] == STATE_UNAVAILABLE
@pytest.mark.skipif(
plant.ENABLE_LOAD_HISTORY is False,
reason="tests for loading from DB are unstable, thus"
"this feature is turned of until tests become"
"stable",
)
def test_load_from_db(self):
"""Test bootstrapping the brightness history from the database.
This test can should only be executed if the loading of the history
is enabled via plant.ENABLE_LOAD_HISTORY.
"""
init_recorder_component(self.hass)
plant_name = "wise_plant"
for value in [20, 30, 10]:
self.hass.states.set(
BRIGHTNESS_ENTITY, value, {ATTR_UNIT_OF_MEASUREMENT: "Lux"}
)
self.hass.block_till_done()
# wait for the recorder to really store the data
self.hass.data[recorder.DATA_INSTANCE].block_till_done()
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert STATE_UNKNOWN == state.state
max_brightness = state.attributes.get(plant.ATTR_MAX_BRIGHTNESS_HISTORY)
assert 30 == max_brightness
def test_brightness_history(self):
"""Test the min_brightness check."""
plant_name = "some_plant"
assert setup_component(
self.hass, plant.DOMAIN, {plant.DOMAIN: {plant_name: GOOD_CONFIG}}
)
self.hass.states.set(BRIGHTNESS_ENTITY, 100, {ATTR_UNIT_OF_MEASUREMENT: "lux"})
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert STATE_PROBLEM == state.state
self.hass.states.set(BRIGHTNESS_ENTITY, 600, {ATTR_UNIT_OF_MEASUREMENT: "lux"})
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert STATE_OK == state.state
self.hass.states.set(BRIGHTNESS_ENTITY, 100, {ATTR_UNIT_OF_MEASUREMENT: "lux"})
self.hass.block_till_done()
state = self.hass.states.get("plant." + plant_name)
assert STATE_OK == state.state
class TestDailyHistory(unittest.TestCase):
"""Test the DailyHistory helper class."""
def test_no_data(self):
"""Test with empty history."""
dh = plant.DailyHistory(3)
assert dh.max is None
def test_one_day(self):
"""Test storing data for the same day."""
dh = plant.DailyHistory(3)
values = [-2, 10, 0, 5, 20]
for i in range(len(values)):
dh.add_measurement(values[i])
max_value = max(values[0 : i + 1])
assert 1 == len(dh._days)
assert dh.max == max_value
def test_multiple_days(self):
"""Test storing data for different days."""
dh = plant.DailyHistory(3)
today = datetime.now()
today_minus_1 = today - timedelta(days=1)
today_minus_2 = today_minus_1 - timedelta(days=1)
today_minus_3 = today_minus_2 - timedelta(days=1)
days = [today_minus_3, today_minus_2, today_minus_1, today]
values = [10, 1, 7, 3]
max_values = [10, 10, 10, 7]
for i in range(len(days)):
dh.add_measurement(values[i], days[i])
assert max_values[i] == dh.max