"""The test for the threshold sensor platform."""
import unittest

from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, STATE_UNKNOWN, TEMP_CELSIUS
from homeassistant.setup import setup_component

from tests.common import get_test_home_assistant


class TestThresholdSensor(unittest.TestCase):
    """Test the threshold sensor."""

    def setup_method(self, method):
        """Set up things to be run when tests are started."""
        self.hass = get_test_home_assistant()

    def teardown_method(self, method):
        """Stop everything that was started."""
        self.hass.stop()

    def test_sensor_upper(self):
        """Test if source is above threshold."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "upper": "15",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set(
            "sensor.test_monitored", 16, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
        )
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "sensor.test_monitored" == state.attributes.get("entity_id")
        assert 16 == state.attributes.get("sensor_value")
        assert "above" == state.attributes.get("position")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")
        assert 0.0 == state.attributes.get("hysteresis")
        assert "upper" == state.attributes.get("type")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 14)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 15)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "off"

    def test_sensor_lower(self):
        """Test if source is below threshold."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "lower": "15",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set("sensor.test_monitored", 16)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "above" == state.attributes.get("position")
        assert float(config["binary_sensor"]["lower"]) == state.attributes.get("lower")
        assert 0.0 == state.attributes.get("hysteresis")
        assert "lower" == state.attributes.get("type")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 14)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "on"

    def test_sensor_hysteresis(self):
        """Test if source is above threshold using hysteresis."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "upper": "15",
                "hysteresis": "2.5",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set("sensor.test_monitored", 20)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "above" == state.attributes.get("position")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")
        assert 2.5 == state.attributes.get("hysteresis")
        assert "upper" == state.attributes.get("type")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 13)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 12)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 17)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 18)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "on"

    def test_sensor_in_range_no_hysteresis(self):
        """Test if source is within the range."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "lower": "10",
                "upper": "20",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set(
            "sensor.test_monitored", 16, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
        )
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "sensor.test_monitored" == state.attributes.get("entity_id")
        assert 16 == state.attributes.get("sensor_value")
        assert "in_range" == state.attributes.get("position")
        assert float(config["binary_sensor"]["lower"]) == state.attributes.get("lower")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")
        assert 0.0 == state.attributes.get("hysteresis")
        assert "range" == state.attributes.get("type")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 9)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "below" == state.attributes.get("position")
        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 21)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "above" == state.attributes.get("position")
        assert state.state == "off"

    def test_sensor_in_range_with_hysteresis(self):
        """Test if source is within the range."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "lower": "10",
                "upper": "20",
                "hysteresis": "2",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set(
            "sensor.test_monitored", 16, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
        )
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "sensor.test_monitored" == state.attributes.get("entity_id")
        assert 16 == state.attributes.get("sensor_value")
        assert "in_range" == state.attributes.get("position")
        assert float(config["binary_sensor"]["lower"]) == state.attributes.get("lower")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")
        assert float(config["binary_sensor"]["hysteresis"]) == state.attributes.get(
            "hysteresis"
        )
        assert "range" == state.attributes.get("type")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 8)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "in_range" == state.attributes.get("position")
        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 7)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "below" == state.attributes.get("position")
        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 12)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "below" == state.attributes.get("position")
        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 13)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "in_range" == state.attributes.get("position")
        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 22)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "in_range" == state.attributes.get("position")
        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", 23)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "above" == state.attributes.get("position")
        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 18)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "above" == state.attributes.get("position")
        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 17)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "in_range" == state.attributes.get("position")
        assert state.state == "on"

    def test_sensor_in_range_unknown_state(self):
        """Test if source is within the range."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "lower": "10",
                "upper": "20",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set(
            "sensor.test_monitored", 16, {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}
        )
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "sensor.test_monitored" == state.attributes.get("entity_id")
        assert 16 == state.attributes.get("sensor_value")
        assert "in_range" == state.attributes.get("position")
        assert float(config["binary_sensor"]["lower"]) == state.attributes.get("lower")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")
        assert 0.0 == state.attributes.get("hysteresis")
        assert "range" == state.attributes.get("type")

        assert state.state == "on"

        self.hass.states.set("sensor.test_monitored", STATE_UNKNOWN)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "unknown" == state.attributes.get("position")
        assert state.state == "off"

    def test_sensor_lower_zero_threshold(self):
        """Test if a lower threshold of zero is set."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "lower": "0",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set("sensor.test_monitored", 16)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "lower" == state.attributes.get("type")
        assert float(config["binary_sensor"]["lower"]) == state.attributes.get("lower")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", -3)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "on"

    def test_sensor_upper_zero_threshold(self):
        """Test if an upper threshold of zero is set."""
        config = {
            "binary_sensor": {
                "platform": "threshold",
                "upper": "0",
                "entity_id": "sensor.test_monitored",
            }
        }

        assert setup_component(self.hass, "binary_sensor", config)

        self.hass.states.set("sensor.test_monitored", -10)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert "upper" == state.attributes.get("type")
        assert float(config["binary_sensor"]["upper"]) == state.attributes.get("upper")

        assert state.state == "off"

        self.hass.states.set("sensor.test_monitored", 2)
        self.hass.block_till_done()

        state = self.hass.states.get("binary_sensor.threshold")

        assert state.state == "on"
