diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index c591fe218f1..ca320cb1c33 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -714,6 +714,41 @@ def tangent(value): return value +def arc_sine(value): + """Filter to get arc sine of the value.""" + try: + return math.asin(float(value)) + except (ValueError, TypeError): + return value + + +def arc_cosine(value): + """Filter to get arc cosine of the value.""" + try: + return math.acos(float(value)) + except (ValueError, TypeError): + return value + + +def arc_tangent(value): + """Filter to get arc tangent of the value.""" + try: + return math.atan(float(value)) + except (ValueError, TypeError): + return value + + +def arc_tangent2(*args): + """Filter to calculate four quadrant arc tangent of y / x.""" + try: + if len(args) == 1 and isinstance(args[0], (list, tuple)): + args = args[0] + + return math.atan2(float(args[0]), float(args[1])) + except (ValueError, TypeError): + return args + + def square_root(value): """Filter to get square root of the value.""" try: @@ -872,6 +907,10 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment): self.filters["sin"] = sine self.filters["cos"] = cosine self.filters["tan"] = tangent + self.filters["asin"] = arc_sine + self.filters["acos"] = arc_cosine + self.filters["atan"] = arc_tangent + self.filters["atan2"] = arc_tangent2 self.filters["sqrt"] = square_root self.filters["as_timestamp"] = forgiving_as_timestamp self.filters["timestamp_custom"] = timestamp_custom @@ -899,6 +938,10 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment): self.globals["pi"] = math.pi self.globals["tau"] = math.pi * 2 self.globals["e"] = math.e + self.globals["asin"] = arc_sine + self.globals["acos"] = arc_cosine + self.globals["atan"] = arc_tangent + self.globals["atan2"] = arc_tangent2 self.globals["float"] = forgiving_float self.globals["now"] = dt_util.now self.globals["utcnow"] = dt_util.utcnow diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index d1beb4eb47b..cc1f7707df6 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -349,6 +349,101 @@ def test_sqrt(hass): ) +def test_arc_sine(hass): + """Test arcus sine.""" + tests = [ + (-2.0, "-2.0"), # value error + (-1.0, "-1.571"), + (-0.5, "-0.524"), + (0.0, "0.0"), + (0.5, "0.524"), + (1.0, "1.571"), + (2.0, "2.0"), # value error + ('"error"', "error"), + ] + + for value, expected in tests: + assert ( + template.Template("{{ %s | asin | round(3) }}" % value, hass).async_render() + == expected + ) + + +def test_arc_cos(hass): + """Test arcus cosine.""" + tests = [ + (-2.0, "-2.0"), # value error + (-1.0, "3.142"), + (-0.5, "2.094"), + (0.0, "1.571"), + (0.5, "1.047"), + (1.0, "0.0"), + (2.0, "2.0"), # value error + ('"error"', "error"), + ] + + for value, expected in tests: + assert ( + template.Template("{{ %s | acos | round(3) }}" % value, hass).async_render() + == expected + ) + + +def test_arc_tan(hass): + """Test arcus tangent.""" + tests = [ + (-10.0, "-1.471"), + (-2.0, "-1.107"), + (-1.0, "-0.785"), + (-0.5, "-0.464"), + (0.0, "0.0"), + (0.5, "0.464"), + (1.0, "0.785"), + (2.0, "1.107"), + (10.0, "1.471"), + ('"error"', "error"), + ] + + for value, expected in tests: + assert ( + template.Template("{{ %s | atan | round(3) }}" % value, hass).async_render() + == expected + ) + + +def test_arc_tan2(hass): + """Test two parameter version of arcus tangent.""" + tests = [ + (-10.0, -10.0, "-2.356"), + (-10.0, 0.0, "-1.571"), + (-10.0, 10.0, "-0.785"), + (0.0, -10.0, "3.142"), + (0.0, 0.0, "0.0"), + (0.0, 10.0, "0.0"), + (10.0, -10.0, "2.356"), + (10.0, 0.0, "1.571"), + (10.0, 10.0, "0.785"), + (-4.0, 3.0, "-0.927"), + (-1.0, 2.0, "-0.464"), + (2.0, 1.0, "1.107"), + ('"duck"', '"goose"', "('duck', 'goose')"), + ] + + for y, x, expected in tests: + assert ( + template.Template( + "{{ (%s, %s) | atan2 | round(3) }}" % (y, x), hass + ).async_render() + == expected + ) + assert ( + template.Template( + "{{ atan2(%s, %s) | round(3) }}" % (y, x), hass + ).async_render() + == expected + ) + + def test_strptime(hass): """Test the parse timestamp method.""" tests = [