mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 07:25:52 -05:00
Add Evil Genius Labs integration (#58720)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
co-authored by
Martin Hjelmare
parent
089353e949
commit
296f678d52
@@ -0,0 +1 @@
|
||||
"""Tests for the Evil Genius Labs integration."""
|
||||
@@ -0,0 +1,49 @@
|
||||
"""Test helpers for Evil Genius Labs."""
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def data_fixture():
|
||||
"""Fixture data."""
|
||||
data = json.loads(load_fixture("data.json", "evil_genius_labs"))
|
||||
return {item["name"]: item for item in data}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def info_fixture():
|
||||
"""Fixture info."""
|
||||
return json.loads(load_fixture("info.json", "evil_genius_labs"))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config_entry(hass):
|
||||
"""Evil genius labs config entry."""
|
||||
entry = MockConfigEntry(domain="evil_genius_labs", data={"host": "192.168.1.113"})
|
||||
entry.add_to_hass(hass)
|
||||
return entry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def setup_evil_genius_labs(
|
||||
hass, config_entry, data_fixture, info_fixture, platforms
|
||||
):
|
||||
"""Test up Evil Genius Labs instance."""
|
||||
with patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_data",
|
||||
return_value=data_fixture,
|
||||
), patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_info",
|
||||
return_value=info_fixture,
|
||||
), patch(
|
||||
"homeassistant.components.evil_genius_labs.PLATFORMS", platforms
|
||||
):
|
||||
assert await async_setup_component(hass, "evil_genius_labs", {})
|
||||
await hass.async_block_till_done()
|
||||
yield
|
||||
@@ -0,0 +1,331 @@
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"label": "Name",
|
||||
"type": "Label",
|
||||
"value": "Fibonacci256-23D4"
|
||||
},
|
||||
{ "name": "power", "label": "Power", "type": "Boolean", "value": 1 },
|
||||
{
|
||||
"name": "brightness",
|
||||
"label": "Brightness",
|
||||
"type": "Number",
|
||||
"value": 128,
|
||||
"min": 1,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "pattern",
|
||||
"label": "Pattern",
|
||||
"type": "Select",
|
||||
"value": 70,
|
||||
"options": [
|
||||
"Pride",
|
||||
"Pride Fibonacci",
|
||||
"Color Waves",
|
||||
"Color Waves Fibonacci",
|
||||
"Pride Playground",
|
||||
"Pride Playground Fibonacci",
|
||||
"Color Waves Playground",
|
||||
"Color Waves Playground Fibonacci",
|
||||
"Wheel",
|
||||
"Swirl Fibonacci",
|
||||
"Fire Fibonacci",
|
||||
"Water Fibonacci",
|
||||
"Emitter Fibonacci",
|
||||
"Pacifica",
|
||||
"Pacifica Fibonacci",
|
||||
"Angle Palette",
|
||||
"Radius Palette",
|
||||
"X Axis Palette",
|
||||
"Y Axis Palette",
|
||||
"XY Axis Palette",
|
||||
"Angle Gradient Palette",
|
||||
"Radius Gradient Palette",
|
||||
"X Axis Gradient Palette",
|
||||
"Y Axis Gradient Palette",
|
||||
"XY Axis Gradient Palette",
|
||||
"Fire Noise",
|
||||
"Fire Noise 2",
|
||||
"Lava Noise",
|
||||
"Rainbow Noise",
|
||||
"Rainbow Stripe Noise",
|
||||
"Party Noise",
|
||||
"Forest Noise",
|
||||
"Cloud Noise",
|
||||
"Ocean Noise",
|
||||
"Black & White Noise",
|
||||
"Black & Blue Noise",
|
||||
"Analog Clock",
|
||||
"Spiral Analog Clock 13",
|
||||
"Spiral Analog Clock 21",
|
||||
"Spiral Analog Clock 34",
|
||||
"Spiral Analog Clock 55",
|
||||
"Spiral Analog Clock 89",
|
||||
"Spiral Analog Clock 21 & 34",
|
||||
"Spiral Analog Clock 13, 21 & 34",
|
||||
"Spiral Analog Clock 34, 21 & 13",
|
||||
"Pride Playground",
|
||||
"Color Waves Playground",
|
||||
"Rainbow Twinkles",
|
||||
"Snow Twinkles",
|
||||
"Cloud Twinkles",
|
||||
"Incandescent Twinkles",
|
||||
"Retro C9 Twinkles",
|
||||
"Red & White Twinkles",
|
||||
"Blue & White Twinkles",
|
||||
"Red, Green & White Twinkles",
|
||||
"Fairy Light Twinkles",
|
||||
"Snow 2 Twinkles",
|
||||
"Holly Twinkles",
|
||||
"Ice Twinkles",
|
||||
"Party Twinkles",
|
||||
"Forest Twinkles",
|
||||
"Lava Twinkles",
|
||||
"Fire Twinkles",
|
||||
"Cloud 2 Twinkles",
|
||||
"Ocean Twinkles",
|
||||
"Rainbow",
|
||||
"Rainbow With Glitter",
|
||||
"Solid Rainbow",
|
||||
"Confetti",
|
||||
"Sinelon",
|
||||
"Beat",
|
||||
"Juggle",
|
||||
"Fire",
|
||||
"Water",
|
||||
"Strand Test",
|
||||
"Solid Color"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "palette",
|
||||
"label": "Palette",
|
||||
"type": "Select",
|
||||
"value": 0,
|
||||
"options": [
|
||||
"Rainbow",
|
||||
"Rainbow Stripe",
|
||||
"Cloud",
|
||||
"Lava",
|
||||
"Ocean",
|
||||
"Forest",
|
||||
"Party",
|
||||
"Heat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "speed",
|
||||
"label": "Speed",
|
||||
"type": "Number",
|
||||
"value": 30,
|
||||
"min": 1,
|
||||
"max": 255
|
||||
},
|
||||
{ "name": "autoplaySection", "label": "Autoplay", "type": "Section" },
|
||||
{ "name": "autoplay", "label": "Autoplay", "type": "Boolean", "value": 0 },
|
||||
{
|
||||
"name": "autoplayDuration",
|
||||
"label": "Autoplay Duration",
|
||||
"type": "Number",
|
||||
"value": 10,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{ "name": "clock", "label": "Clock", "type": "Section" },
|
||||
{ "name": "showClock", "label": "Show Clock", "type": "Boolean", "value": 0 },
|
||||
{
|
||||
"name": "clockBackgroundFade",
|
||||
"label": "Background Fade",
|
||||
"type": "Number",
|
||||
"value": 240,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{ "name": "solidColorSection", "label": "Solid Color", "type": "Section" },
|
||||
{
|
||||
"name": "solidColor",
|
||||
"label": "Color",
|
||||
"type": "Color",
|
||||
"value": "0,0,255"
|
||||
},
|
||||
{ "name": "prideSection", "label": "Pride & ColorWaves", "type": "Section" },
|
||||
{
|
||||
"name": "saturationBpm",
|
||||
"label": "Saturation BPM",
|
||||
"type": "Number",
|
||||
"value": 87,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "saturationMin",
|
||||
"label": "Saturation Min",
|
||||
"type": "Number",
|
||||
"value": 220,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "saturationMax",
|
||||
"label": "Saturation Max",
|
||||
"type": "Number",
|
||||
"value": 250,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightDepthBpm",
|
||||
"label": "Brightness Depth BPM",
|
||||
"type": "Number",
|
||||
"value": 1,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightDepthMin",
|
||||
"label": "Brightness Depth Min",
|
||||
"type": "Number",
|
||||
"value": 96,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightDepthMax",
|
||||
"label": "Brightness Depth Max",
|
||||
"type": "Number",
|
||||
"value": 224,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightThetaIncBpm",
|
||||
"label": "Bright Theta Inc BPM",
|
||||
"type": "Number",
|
||||
"value": 203,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightThetaIncMin",
|
||||
"label": "Bright Theta Inc Min",
|
||||
"type": "Number",
|
||||
"value": 25,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "brightThetaIncMax",
|
||||
"label": "Bright Theta Inc Max",
|
||||
"type": "Number",
|
||||
"value": 40,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "msMultiplierBpm",
|
||||
"label": "Time Multiplier BPM",
|
||||
"type": "Number",
|
||||
"value": 147,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "msMultiplierMin",
|
||||
"label": "Time Multiplier Min",
|
||||
"type": "Number",
|
||||
"value": 23,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "msMultiplierMax",
|
||||
"label": "Time Multiplier Max",
|
||||
"type": "Number",
|
||||
"value": 60,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "hueIncBpm",
|
||||
"label": "Hue Inc BPM",
|
||||
"type": "Number",
|
||||
"value": 113,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "hueIncMin",
|
||||
"label": "Hue Inc Min",
|
||||
"type": "Number",
|
||||
"value": 1,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "hueIncMax",
|
||||
"label": "Hue Inc Max",
|
||||
"type": "Number",
|
||||
"value": 12,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "sHueBpm",
|
||||
"label": "S Hue BPM",
|
||||
"type": "Number",
|
||||
"value": 2,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "sHueMin",
|
||||
"label": "S Hue Min",
|
||||
"type": "Number",
|
||||
"value": 5,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "sHueMax",
|
||||
"label": "S Hue Max",
|
||||
"type": "Number",
|
||||
"value": 9,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{ "name": "fireSection", "label": "Fire & Water", "type": "Section" },
|
||||
{
|
||||
"name": "cooling",
|
||||
"label": "Cooling",
|
||||
"type": "Number",
|
||||
"value": 49,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{
|
||||
"name": "sparking",
|
||||
"label": "Sparking",
|
||||
"type": "Number",
|
||||
"value": 60,
|
||||
"min": 0,
|
||||
"max": 255
|
||||
},
|
||||
{ "name": "twinklesSection", "label": "Twinkles", "type": "Section" },
|
||||
{
|
||||
"name": "twinkleSpeed",
|
||||
"label": "Twinkle Speed",
|
||||
"type": "Number",
|
||||
"value": 4,
|
||||
"min": 0,
|
||||
"max": 8
|
||||
},
|
||||
{
|
||||
"name": "twinkleDensity",
|
||||
"label": "Twinkle Density",
|
||||
"type": "Number",
|
||||
"value": 5,
|
||||
"min": 0,
|
||||
"max": 8
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"millis": 62099724,
|
||||
"vcc": 3005,
|
||||
"wiFiChipId": "1923d4",
|
||||
"flashChipId": "1640d8",
|
||||
"flashChipSize": 4194304,
|
||||
"flashChipRealSize": 4194304,
|
||||
"sdkVersion": "2.2.2-dev(38a443e)",
|
||||
"coreVersion": "2_7_4",
|
||||
"bootVersion": 6,
|
||||
"cpuFreqMHz": 160,
|
||||
"freeHeap": 21936,
|
||||
"sketchSize": 476352,
|
||||
"freeSketchSpace": 1617920,
|
||||
"resetReason": "External System",
|
||||
"isConnected": true,
|
||||
"wiFiSsidDefault": "My Wi-Fi",
|
||||
"wiFiSSID": "My Wi-Fi",
|
||||
"localIP": "192.168.1.113",
|
||||
"gatewayIP": "192.168.1.1",
|
||||
"subnetMask": "255.255.255.0",
|
||||
"dnsIP": "192.168.1.1",
|
||||
"hostname": "ESP-1923D4",
|
||||
"macAddress": "BC:FF:4D:19:23:D4",
|
||||
"autoConnect": true,
|
||||
"softAPSSID": "FaryLink_1923D4",
|
||||
"softAPIP": "(IP unset)",
|
||||
"BSSID": "FC:EC:DA:77:1A:CE",
|
||||
"softAPmacAddress": "BE:FF:4D:19:23:D4"
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
"""Test the Evil Genius Labs config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import aiohttp
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.evil_genius_labs.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
|
||||
|
||||
|
||||
async def test_form(hass: HomeAssistant, data_fixture, info_fixture) -> None:
|
||||
"""Test we get the form."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] is None
|
||||
|
||||
with patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_data",
|
||||
return_value=data_fixture,
|
||||
), patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_info",
|
||||
return_value=info_fixture,
|
||||
), patch(
|
||||
"homeassistant.components.evil_genius_labs.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result2["title"] == "Fibonacci256-23D4"
|
||||
assert result2["data"] == {
|
||||
"host": "1.1.1.1",
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
|
||||
"""Test we handle cannot connect error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_data",
|
||||
side_effect=aiohttp.ClientError,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_FORM
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_form_unknown(hass: HomeAssistant) -> None:
|
||||
"""Test we handle unknown error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"pyevilgenius.EvilGeniusDevice.get_data",
|
||||
side_effect=ValueError("BOOM"),
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "1.1.1.1",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == RESULT_TYPE_FORM
|
||||
assert result2["errors"] == {"base": "unknown"}
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Test evil genius labs init."""
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.evil_genius_labs import PLATFORMS
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platforms", [PLATFORMS])
|
||||
async def test_setup_unload_entry(hass, setup_evil_genius_labs, config_entry):
|
||||
"""Test setting up and unloading a config entry."""
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
assert config_entry.state == config_entries.ConfigEntryState.NOT_LOADED
|
||||
@@ -0,0 +1,76 @@
|
||||
"""Test Evil Genius Labs light."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platforms", [("light",)])
|
||||
async def test_works(hass, setup_evil_genius_labs):
|
||||
"""Test it works."""
|
||||
state = hass.states.get("light.fibonacci256_23d4")
|
||||
assert state is not None
|
||||
assert state.state == "on"
|
||||
assert state.attributes["brightness"] == 128
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platforms", [("light",)])
|
||||
async def test_turn_on_color(hass, setup_evil_genius_labs):
|
||||
"""Test turning on with a color."""
|
||||
with patch(
|
||||
"pyevilgenius.EvilGeniusDevice.set_path_value"
|
||||
) as mock_set_path_value, patch(
|
||||
"pyevilgenius.EvilGeniusDevice.set_rgb_color"
|
||||
) as mock_set_rgb_color:
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{
|
||||
"entity_id": "light.fibonacci256_23d4",
|
||||
"brightness": 100,
|
||||
"rgb_color": (10, 20, 30),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_set_path_value.mock_calls) == 2
|
||||
mock_set_path_value.mock_calls[0][1] == ("brightness", 100)
|
||||
mock_set_path_value.mock_calls[1][1] == ("power", 1)
|
||||
|
||||
assert len(mock_set_rgb_color.mock_calls) == 1
|
||||
mock_set_rgb_color.mock_calls[0][1] == (10, 20, 30)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platforms", [("light",)])
|
||||
async def test_turn_on_effect(hass, setup_evil_genius_labs):
|
||||
"""Test turning on with an effect."""
|
||||
with patch("pyevilgenius.EvilGeniusDevice.set_path_value") as mock_set_path_value:
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{
|
||||
"entity_id": "light.fibonacci256_23d4",
|
||||
"effect": "Pride Playground",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_set_path_value.mock_calls) == 2
|
||||
mock_set_path_value.mock_calls[0][1] == ("pattern", 4)
|
||||
mock_set_path_value.mock_calls[1][1] == ("power", 1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platforms", [("light",)])
|
||||
async def test_turn_off(hass, setup_evil_genius_labs):
|
||||
"""Test turning off."""
|
||||
with patch("pyevilgenius.EvilGeniusDevice.set_path_value") as mock_set_path_value:
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_off",
|
||||
{
|
||||
"entity_id": "light.fibonacci256_23d4",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_set_path_value.mock_calls) == 1
|
||||
mock_set_path_value.mock_calls[0][1] == ("power", 0)
|
||||
Reference in New Issue
Block a user