diff --git a/.coveragerc b/.coveragerc index c94199d6451..83285b9bd6c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -8,15 +8,6 @@ omit = homeassistant/scripts/*.py # omit pieces of code that rely on external devices being present - homeassistant/components/abode/__init__.py - homeassistant/components/abode/alarm_control_panel.py - homeassistant/components/abode/binary_sensor.py - homeassistant/components/abode/camera.py - homeassistant/components/abode/cover.py - homeassistant/components/abode/light.py - homeassistant/components/abode/lock.py - homeassistant/components/abode/sensor.py - homeassistant/components/abode/switch.py homeassistant/components/acer_projector/switch.py homeassistant/components/actiontec/device_tracker.py homeassistant/components/adguard/__init__.py diff --git a/tests/components/abode/common.py b/tests/components/abode/common.py new file mode 100644 index 00000000000..aabc732daa2 --- /dev/null +++ b/tests/components/abode/common.py @@ -0,0 +1,25 @@ +"""Common methods used across tests for Abode.""" +from unittest.mock import patch + +from homeassistant.components.abode import DOMAIN as ABODE_DOMAIN +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.setup import async_setup_component + +from tests.common import MockConfigEntry + + +async def setup_platform(hass, platform): + """Set up the Abode platform.""" + mock_entry = MockConfigEntry( + domain=ABODE_DOMAIN, + data={CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}, + ) + mock_entry.add_to_hass(hass) + + with patch("homeassistant.components.abode.ABODE_PLATFORMS", [platform]), patch( + "abodepy.event_controller.sio" + ), patch("abodepy.utils.save_cache"): + assert await async_setup_component(hass, ABODE_DOMAIN, {}) + await hass.async_block_till_done() + + return mock_entry diff --git a/tests/components/abode/conftest.py b/tests/components/abode/conftest.py new file mode 100644 index 00000000000..92f9bb09681 --- /dev/null +++ b/tests/components/abode/conftest.py @@ -0,0 +1,22 @@ +"""Configuration for Abode tests.""" +import abodepy.helpers.constants as CONST +import pytest + +from tests.common import load_fixture + + +@pytest.fixture(autouse=True) +def requests_mock_fixture(requests_mock): + """Fixture to provide a requests mocker.""" + # Mocks the login response for abodepy. + requests_mock.post(CONST.LOGIN_URL, text=load_fixture("abode_login.json")) + # Mocks the oauth claims response for abodepy. + requests_mock.get( + CONST.OAUTH_TOKEN_URL, text=load_fixture("abode_oauth_claims.json") + ) + # Mocks the panel response for abodepy. + requests_mock.get(CONST.PANEL_URL, text=load_fixture("abode_panel.json")) + # Mocks the automations response for abodepy. + requests_mock.get(CONST.AUTOMATION_URL, text=load_fixture("abode_automation.json")) + # Mocks the devices response for abodepy. + requests_mock.get(CONST.DEVICES_URL, text=load_fixture("abode_devices.json")) diff --git a/tests/components/abode/test_alarm_control_panel.py b/tests/components/abode/test_alarm_control_panel.py new file mode 100644 index 00000000000..ca546157c93 --- /dev/null +++ b/tests/components/abode/test_alarm_control_panel.py @@ -0,0 +1,140 @@ +"""Tests for the Abode alarm control panel device.""" +from unittest.mock import PropertyMock, patch + +import abodepy.helpers.constants as CONST + +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_FRIENDLY_NAME, + ATTR_SUPPORTED_FEATURES, + SERVICE_ALARM_ARM_AWAY, + SERVICE_ALARM_ARM_HOME, + SERVICE_ALARM_DISARM, + STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_DISARMED, +) + +from .common import setup_platform + +DEVICE_ID = "alarm_control_panel.abode_alarm" + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, ALARM_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get(DEVICE_ID) + # Abode alarm device unique_id is the MAC address + assert entry.unique_id == "001122334455" + + +async def test_attributes(hass): + """Test the alarm control panel attributes are correct.""" + await setup_platform(hass, ALARM_DOMAIN) + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_ALARM_DISARMED + assert state.attributes.get(ATTR_DEVICE_ID) == "area_1" + assert not state.attributes.get("battery_backup") + assert not state.attributes.get("cellular_backup") + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Abode Alarm" + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 3 + + +async def test_set_alarm_away(hass): + """Test the alarm control panel can be set to away.""" + with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback: + with patch("abodepy.ALARM.AbodeAlarm.set_away") as mock_set_away: + await setup_platform(hass, ALARM_DOMAIN) + + await hass.services.async_call( + ALARM_DOMAIN, + SERVICE_ALARM_ARM_AWAY, + {ATTR_ENTITY_ID: DEVICE_ID}, + blocking=True, + ) + await hass.async_block_till_done() + mock_set_away.assert_called_once() + + with patch( + "abodepy.ALARM.AbodeAlarm.mode", new_callable=PropertyMock, + ) as mock_mode: + mock_mode.return_value = CONST.MODE_AWAY + + update_callback = mock_callback.call_args[0][1] + await hass.async_add_executor_job(update_callback, "area_1") + await hass.async_block_till_done() + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_ALARM_ARMED_AWAY + + +async def test_set_alarm_home(hass): + """Test the alarm control panel can be set to home.""" + with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback: + with patch("abodepy.ALARM.AbodeAlarm.set_home") as mock_set_home: + await setup_platform(hass, ALARM_DOMAIN) + + await hass.services.async_call( + ALARM_DOMAIN, + SERVICE_ALARM_ARM_HOME, + {ATTR_ENTITY_ID: DEVICE_ID}, + blocking=True, + ) + await hass.async_block_till_done() + mock_set_home.assert_called_once() + + with patch( + "abodepy.ALARM.AbodeAlarm.mode", new_callable=PropertyMock + ) as mock_mode: + mock_mode.return_value = CONST.MODE_HOME + + update_callback = mock_callback.call_args[0][1] + await hass.async_add_executor_job(update_callback, "area_1") + await hass.async_block_till_done() + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_ALARM_ARMED_HOME + + +async def test_set_alarm_standby(hass): + """Test the alarm control panel can be set to standby.""" + with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback: + with patch("abodepy.ALARM.AbodeAlarm.set_standby") as mock_set_standby: + await setup_platform(hass, ALARM_DOMAIN) + await hass.services.async_call( + ALARM_DOMAIN, + SERVICE_ALARM_DISARM, + {ATTR_ENTITY_ID: DEVICE_ID}, + blocking=True, + ) + await hass.async_block_till_done() + mock_set_standby.assert_called_once() + + with patch( + "abodepy.ALARM.AbodeAlarm.mode", new_callable=PropertyMock + ) as mock_mode: + mock_mode.return_value = CONST.MODE_STANDBY + + update_callback = mock_callback.call_args[0][1] + await hass.async_add_executor_job(update_callback, "area_1") + await hass.async_block_till_done() + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_ALARM_DISARMED + + +async def test_state_unknown(hass): + """Test an unknown alarm control panel state.""" + with patch("abodepy.ALARM.AbodeAlarm.mode", new_callable=PropertyMock) as mock_mode: + await setup_platform(hass, ALARM_DOMAIN) + await hass.async_block_till_done() + + mock_mode.return_value = None + + state = hass.states.get(DEVICE_ID) + assert state.state == "unknown" diff --git a/tests/components/abode/test_binary_sensor.py b/tests/components/abode/test_binary_sensor.py new file mode 100644 index 00000000000..aced7f33e73 --- /dev/null +++ b/tests/components/abode/test_binary_sensor.py @@ -0,0 +1,39 @@ +"""Tests for the Abode binary sensor device.""" +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.abode.const import ATTRIBUTION +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_DOOR, + DOMAIN as BINARY_SENSOR_DOMAIN, +) +from homeassistant.const import ( + ATTR_ATTRIBUTION, + ATTR_DEVICE_CLASS, + ATTR_FRIENDLY_NAME, + STATE_OFF, +) + +from .common import setup_platform + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, BINARY_SENSOR_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get("binary_sensor.front_door") + assert entry.unique_id == "2834013428b6035fba7d4054aa7b25a3" + + +async def test_attributes(hass): + """Test the binary sensor attributes are correct.""" + await setup_platform(hass, BINARY_SENSOR_DOMAIN) + + state = hass.states.get("binary_sensor.front_door") + assert state.state == STATE_OFF + assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION + assert state.attributes.get(ATTR_DEVICE_ID) == "RF:01430030" + assert not state.attributes.get("battery_low") + assert not state.attributes.get("no_response") + assert state.attributes.get("device_type") == "Door Contact" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Front Door" + assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_DOOR diff --git a/tests/components/abode/test_camera.py b/tests/components/abode/test_camera.py new file mode 100644 index 00000000000..8b11671a456 --- /dev/null +++ b/tests/components/abode/test_camera.py @@ -0,0 +1,40 @@ +"""Tests for the Abode camera device.""" +from unittest.mock import patch + +from homeassistant.components.abode.const import DOMAIN as ABODE_DOMAIN +from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN +from homeassistant.const import ATTR_ENTITY_ID, STATE_IDLE + +from .common import setup_platform + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, CAMERA_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get("camera.test_cam") + assert entry.unique_id == "d0a3a1c316891ceb00c20118aae2a133" + + +async def test_attributes(hass): + """Test the camera attributes are correct.""" + await setup_platform(hass, CAMERA_DOMAIN) + + state = hass.states.get("camera.test_cam") + assert state.state == STATE_IDLE + + +async def test_capture_image(hass): + """Test the camera capture image service.""" + await setup_platform(hass, CAMERA_DOMAIN) + + with patch("abodepy.AbodeCamera.capture") as mock_capture: + await hass.services.async_call( + ABODE_DOMAIN, + "capture_image", + {ATTR_ENTITY_ID: "camera.test_cam"}, + blocking=True, + ) + await hass.async_block_till_done() + mock_capture.assert_called_once() diff --git a/tests/components/abode/test_cover.py b/tests/components/abode/test_cover.py new file mode 100644 index 00000000000..bb1b8fceffb --- /dev/null +++ b/tests/components/abode/test_cover.py @@ -0,0 +1,65 @@ +"""Tests for the Abode cover device.""" +from unittest.mock import patch + +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.cover import DOMAIN as COVER_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_FRIENDLY_NAME, + SERVICE_CLOSE_COVER, + SERVICE_OPEN_COVER, + STATE_CLOSED, +) + +from .common import setup_platform + +DEVICE_ID = "cover.garage_door" + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, COVER_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get(DEVICE_ID) + assert entry.unique_id == "61cbz3b542d2o33ed2fz02721bda3324" + + +async def test_attributes(hass): + """Test the cover attributes are correct.""" + await setup_platform(hass, COVER_DOMAIN) + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_CLOSED + assert state.attributes.get(ATTR_DEVICE_ID) == "ZW:00000007" + assert not state.attributes.get("battery_low") + assert not state.attributes.get("no_response") + assert state.attributes.get("device_type") == "Secure Barrier" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Garage Door" + + +async def test_open(hass): + """Test the cover can be opened.""" + await setup_platform(hass, COVER_DOMAIN) + + with patch("abodepy.AbodeCover.open_cover") as mock_open: + await hass.services.async_call( + COVER_DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + mock_open.assert_called_once() + + +async def test_close(hass): + """Test the cover can be closed.""" + await setup_platform(hass, COVER_DOMAIN) + + with patch("abodepy.AbodeCover.close_cover") as mock_close: + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DEVICE_ID}, + blocking=True, + ) + await hass.async_block_till_done() + mock_close.assert_called_once() diff --git a/tests/components/abode/test_init.py b/tests/components/abode/test_init.py new file mode 100644 index 00000000000..3f73ccd77ce --- /dev/null +++ b/tests/components/abode/test_init.py @@ -0,0 +1,43 @@ +"""Tests for the Abode module.""" +from unittest.mock import patch + +from homeassistant.components.abode import ( + DOMAIN as ABODE_DOMAIN, + SERVICE_CAPTURE_IMAGE, + SERVICE_SETTINGS, + SERVICE_TRIGGER_AUTOMATION, +) +from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN + +from .common import setup_platform + + +async def test_change_settings(hass): + """Test change_setting service.""" + await setup_platform(hass, ALARM_DOMAIN) + + with patch("abodepy.Abode.set_setting") as mock_set_setting: + await hass.services.async_call( + ABODE_DOMAIN, + SERVICE_SETTINGS, + {"setting": "confirm_snd", "value": "loud"}, + blocking=True, + ) + await hass.async_block_till_done() + mock_set_setting.assert_called_once() + + +async def test_unload_entry(hass): + """Test unloading the Abode entry.""" + mock_entry = await setup_platform(hass, ALARM_DOMAIN) + + with patch("abodepy.Abode.logout") as mock_logout, patch( + "abodepy.event_controller.AbodeEventController.stop" + ) as mock_events_stop: + assert await hass.config_entries.async_unload(mock_entry.entry_id) + mock_logout.assert_called_once() + mock_events_stop.assert_called_once() + + assert not hass.services.has_service(ABODE_DOMAIN, SERVICE_SETTINGS) + assert not hass.services.has_service(ABODE_DOMAIN, SERVICE_CAPTURE_IMAGE) + assert not hass.services.has_service(ABODE_DOMAIN, SERVICE_TRIGGER_AUTOMATION) diff --git a/tests/components/abode/test_light.py b/tests/components/abode/test_light.py new file mode 100644 index 00000000000..f0eee4b209b --- /dev/null +++ b/tests/components/abode/test_light.py @@ -0,0 +1,119 @@ +"""Tests for the Abode light device.""" +from unittest.mock import patch + +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + ATTR_COLOR_TEMP, + ATTR_RGB_COLOR, + DOMAIN as LIGHT_DOMAIN, +) +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_FRIENDLY_NAME, + ATTR_SUPPORTED_FEATURES, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_ON, +) + +from .common import setup_platform + +DEVICE_ID = "light.living_room_lamp" + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, LIGHT_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get(DEVICE_ID) + assert entry.unique_id == "741385f4388b2637df4c6b398fe50581" + + +async def test_attributes(hass): + """Test the light attributes are correct.""" + await setup_platform(hass, LIGHT_DOMAIN) + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_ON + assert state.attributes.get(ATTR_BRIGHTNESS) == 204 + assert state.attributes.get(ATTR_RGB_COLOR) == (0, 63, 255) + assert state.attributes.get(ATTR_COLOR_TEMP) == 280 + assert state.attributes.get(ATTR_DEVICE_ID) == "ZB:db5b1a" + assert not state.attributes.get("battery_low") + assert not state.attributes.get("no_response") + assert state.attributes.get("device_type") == "RGB Dimmer" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Living Room Lamp" + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 19 + + +async def test_switch_off(hass): + """Test the light can be turned off.""" + await setup_platform(hass, LIGHT_DOMAIN) + + with patch("abodepy.AbodeLight.switch_off") as mock_switch_off: + assert await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + mock_switch_off.assert_called_once() + + +async def test_switch_on(hass): + """Test the light can be turned on.""" + await setup_platform(hass, LIGHT_DOMAIN) + + with patch("abodepy.AbodeLight.switch_on") as mock_switch_on: + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + mock_switch_on.assert_called_once() + + +async def test_set_brightness(hass): + """Test the brightness can be set.""" + await setup_platform(hass, LIGHT_DOMAIN) + + with patch("abodepy.AbodeLight.set_level") as mock_set_level: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: DEVICE_ID, "brightness": 100}, + blocking=True, + ) + await hass.async_block_till_done() + # Brightness is converted in abode.light.AbodeLight.turn_on + mock_set_level.assert_called_once_with(39) + + +async def test_set_color(hass): + """Test the color can be set.""" + await setup_platform(hass, LIGHT_DOMAIN) + + with patch("abodepy.AbodeLight.set_color") as mock_set_color: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: DEVICE_ID, "hs_color": [240, 100]}, + blocking=True, + ) + await hass.async_block_till_done() + mock_set_color.assert_called_once_with((240.0, 100.0)) + + +async def test_set_color_temp(hass): + """Test the color temp can be set.""" + await setup_platform(hass, LIGHT_DOMAIN) + + with patch("abodepy.AbodeLight.set_color_temp") as mock_set_color_temp: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: DEVICE_ID, "color_temp": 309}, + blocking=True, + ) + await hass.async_block_till_done() + # Color temp is converted in abode.light.AbodeLight.turn_on + mock_set_color_temp.assert_called_once_with(3236) diff --git a/tests/components/abode/test_lock.py b/tests/components/abode/test_lock.py new file mode 100644 index 00000000000..45e17861d33 --- /dev/null +++ b/tests/components/abode/test_lock.py @@ -0,0 +1,62 @@ +"""Tests for the Abode lock device.""" +from unittest.mock import patch + +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_FRIENDLY_NAME, + SERVICE_LOCK, + SERVICE_UNLOCK, + STATE_LOCKED, +) + +from .common import setup_platform + +DEVICE_ID = "lock.test_lock" + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, LOCK_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get(DEVICE_ID) + assert entry.unique_id == "51cab3b545d2o34ed7fz02731bda5324" + + +async def test_attributes(hass): + """Test the lock attributes are correct.""" + await setup_platform(hass, LOCK_DOMAIN) + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_LOCKED + assert state.attributes.get(ATTR_DEVICE_ID) == "ZW:00000004" + assert not state.attributes.get("battery_low") + assert not state.attributes.get("no_response") + assert state.attributes.get("device_type") == "Door Lock" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Test Lock" + + +async def test_lock(hass): + """Test the lock can be locked.""" + await setup_platform(hass, LOCK_DOMAIN) + + with patch("abodepy.AbodeLock.lock") as mock_lock: + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_LOCK, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + mock_lock.assert_called_once() + + +async def test_unlock(hass): + """Test the lock can be unlocked.""" + await setup_platform(hass, LOCK_DOMAIN) + + with patch("abodepy.AbodeLock.unlock") as mock_unlock: + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_UNLOCK, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + mock_unlock.assert_called_once() diff --git a/tests/components/abode/test_sensor.py b/tests/components/abode/test_sensor.py new file mode 100644 index 00000000000..bfe20be0b8c --- /dev/null +++ b/tests/components/abode/test_sensor.py @@ -0,0 +1,44 @@ +"""Tests for the Abode sensor device.""" +from homeassistant.components.abode import ATTR_DEVICE_ID +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + ATTR_FRIENDLY_NAME, + ATTR_UNIT_OF_MEASUREMENT, + DEVICE_CLASS_HUMIDITY, +) + +from .common import setup_platform + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, SENSOR_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get("sensor.environment_sensor_humidity") + assert entry.unique_id == "13545b21f4bdcd33d9abd461f8443e65-humidity" + + +async def test_attributes(hass): + """Test the sensor attributes are correct.""" + await setup_platform(hass, SENSOR_DOMAIN) + + state = hass.states.get("sensor.environment_sensor_humidity") + assert state.state == "32.0" + assert state.attributes.get(ATTR_DEVICE_ID) == "RF:02148e70" + assert not state.attributes.get("battery_low") + assert not state.attributes.get("no_response") + assert state.attributes.get("device_type") == "LM" + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "%" + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Environment Sensor Humidity" + assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_HUMIDITY + + state = hass.states.get("sensor.environment_sensor_lux") + assert state.state == "1.0" + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "lux" + + state = hass.states.get("sensor.environment_sensor_temperature") + # Abodepy device JSON reports 19.5, but Home Assistant shows 19.4 + assert state.state == "19.4" + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "°C" diff --git a/tests/components/abode/test_switch.py b/tests/components/abode/test_switch.py new file mode 100644 index 00000000000..3ec9648d87d --- /dev/null +++ b/tests/components/abode/test_switch.py @@ -0,0 +1,125 @@ +"""Tests for the Abode switch device.""" +from unittest.mock import patch + +from homeassistant.components.abode import ( + DOMAIN as ABODE_DOMAIN, + SERVICE_TRIGGER_AUTOMATION, +) +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_OFF, + STATE_ON, +) + +from .common import setup_platform + +AUTOMATION_ID = "switch.test_automation" +AUTOMATION_UID = "47fae27488f74f55b964a81a066c3a01" +DEVICE_ID = "switch.test_switch" +DEVICE_UID = "0012a4d3614cb7e2b8c9abea31d2fb2a" + + +async def test_entity_registry(hass): + """Tests that the devices are registered in the entity registry.""" + await setup_platform(hass, SWITCH_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get(AUTOMATION_ID) + assert entry.unique_id == AUTOMATION_UID + + entry = entity_registry.async_get(DEVICE_ID) + assert entry.unique_id == DEVICE_UID + + +async def test_attributes(hass): + """Test the switch attributes are correct.""" + await setup_platform(hass, SWITCH_DOMAIN) + + state = hass.states.get(DEVICE_ID) + assert state.state == STATE_OFF + + +async def test_switch_on(hass): + """Test the switch can be turned on.""" + await setup_platform(hass, SWITCH_DOMAIN) + + with patch("abodepy.AbodeSwitch.switch_on") as mock_switch_on: + assert await hass.services.async_call( + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + + mock_switch_on.assert_called_once() + + +async def test_switch_off(hass): + """Test the switch can be turned off.""" + await setup_platform(hass, SWITCH_DOMAIN) + + with patch("abodepy.AbodeSwitch.switch_off") as mock_switch_off: + assert await hass.services.async_call( + SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: DEVICE_ID}, blocking=True + ) + await hass.async_block_till_done() + + mock_switch_off.assert_called_once() + + +async def test_automation_attributes(hass): + """Test the automation attributes are correct.""" + await setup_platform(hass, SWITCH_DOMAIN) + + state = hass.states.get(AUTOMATION_ID) + # State is set based on "enabled" key in automation JSON. + assert state.state == STATE_ON + + +async def test_turn_automation_off(hass): + """Test the automation can be turned off.""" + with patch("abodepy.AbodeAutomation.enable") as mock_trigger: + await setup_platform(hass, SWITCH_DOMAIN) + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: AUTOMATION_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + mock_trigger.assert_called_once_with(False) + + +async def test_turn_automation_on(hass): + """Test the automation can be turned on.""" + with patch("abodepy.AbodeAutomation.enable") as mock_trigger: + await setup_platform(hass, SWITCH_DOMAIN) + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: AUTOMATION_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + mock_trigger.assert_called_once_with(True) + + +async def test_trigger_automation(hass, requests_mock): + """Test the trigger automation service.""" + await setup_platform(hass, SWITCH_DOMAIN) + + with patch("abodepy.AbodeAutomation.trigger") as mock: + await hass.services.async_call( + ABODE_DOMAIN, + SERVICE_TRIGGER_AUTOMATION, + {ATTR_ENTITY_ID: AUTOMATION_ID}, + blocking=True, + ) + await hass.async_block_till_done() + + mock.assert_called_once() diff --git a/tests/fixtures/abode_automation.json b/tests/fixtures/abode_automation.json new file mode 100644 index 00000000000..fb1c00faff9 --- /dev/null +++ b/tests/fixtures/abode_automation.json @@ -0,0 +1,38 @@ +{ + "name": "Test Automation", + "enabled": "True", + "version": 2, + "id": "47fae27488f74f55b964a81a066c3a01", + "subType": "", + "actions": [ + { + "directive": { + "trait": "panel.traits.panelMode", + "name": "panel.directives.arm", + "state": { + "panelMode": "AWAY" + } + } + } + ], + "conditions": {}, + "triggers": { + "operator": "OR", + "expressions": [ + { + "mobileDevices": [ + "89381", + "658" + ], + "property": { + "trait": "mobile.traits.location", + "name": "location", + "rule": { + "location": "31675", + "equalTo": "LAST_OUT" + } + } + } + ] + } +} \ No newline at end of file diff --git a/tests/fixtures/abode_automation_changed.json b/tests/fixtures/abode_automation_changed.json new file mode 100644 index 00000000000..39b874c4dfc --- /dev/null +++ b/tests/fixtures/abode_automation_changed.json @@ -0,0 +1,38 @@ +{ + "name": "Test Automation", + "enabled": "False", + "version": 2, + "id": "47fae27488f74f55b964a81a066c3a01", + "subType": "", + "actions": [ + { + "directive": { + "trait": "panel.traits.panelMode", + "name": "panel.directives.arm", + "state": { + "panelMode": "AWAY" + } + } + } + ], + "conditions": {}, + "triggers": { + "operator": "OR", + "expressions": [ + { + "mobileDevices": [ + "89381", + "658" + ], + "property": { + "trait": "mobile.traits.location", + "name": "location", + "rule": { + "location": "31675", + "equalTo": "LAST_OUT" + } + } + } + ] + } +} \ No newline at end of file diff --git a/tests/fixtures/abode_devices.json b/tests/fixtures/abode_devices.json new file mode 100644 index 00000000000..370b264427a --- /dev/null +++ b/tests/fixtures/abode_devices.json @@ -0,0 +1,799 @@ +[ + { + "id": "RF:01430030", + "type_tag": "device_type.door_contact", + "type": "Door Contact", + "name": "Front Door", + "area": "1", + "zone": "15", + "sort_order": "", + "is_window": "1", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "3", + "sresp_entry_0": "3", + "sresp_exit_0": "0", + "group_name": "Doors and Windows", + "group_id": "397972", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "1", + "sresp_entry_1": "1", + "sresp_exit_1": "0", + "sresp_mode_2": "1", + "sresp_entry_2": "1", + "sresp_exit_2": "0", + "sresp_mode_3": "1", + "uuid": "2834013428b6035fba7d4054aa7b25a3", + "sresp_entry_3": "1", + "sresp_exit_3": "0", + "sresp_mode_4": "1", + "sresp_entry_4": "1", + "sresp_exit_4": "0", + "version": "", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "Closed", + "status_display": "Closed", + "statuses": { + "open": "0" + }, + "status_ex": "", + "actions": [], + "status_icons": { + "Open": "assets/icons/WindowOpened.svg", + "Closed": "assets/icons/WindowClosed.svg" + }, + "icon": "assets/icons/doorsensor-a.svg", + "sresp_trigger": "0", + "sresp_restore": "0" + }, + { + "id": "RF:01c34a30", + "type_tag": "device_type.povs", + "type": "Occupancy", + "name": "Hallway Motion", + "area": "1", + "zone": "17", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Ungrouped", + "group_id": "1", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "5", + "sresp_entry_1": "4", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "4", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "ba2c7e8d4430da8d34c31425a2823fe0", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "Online", + "status_display": "Online", + "statuses": { + "motion": "0" + }, + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/motioncamera-a.svg", + "sresp_trigger": "0", + "sresp_restore": "0", + "occupancy_timer": null, + "sensitivity": null, + "model": "L1", + "is_motion_sensor": true + }, + { + "id": "SR:PIR", + "type_tag": "device_type.pir", + "type": "Motion Sensor", + "name": "Living Room Motion", + "area": "1", + "zone": "2", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Motion", + "group_id": "397973", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "5", + "sresp_entry_1": "4", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "4", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "2f1bc34ceadac032af4fc9189ef821a8", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "", + "origin": "abode", + "has_subscription": null, + "onboard": "1", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "Online", + "status_display": "Online", + "statuses": [], + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/motioncamera-a.svg", + "schar_obpir_sens": "15", + "schar_obpir_pulse": "2", + "sensitivity": "15", + "model": "L1" + }, + { + "id": "ZB:db5b1a", + "type_tag": "device_type.hue", + "type": "RGB Dimmer", + "name": "Living Room Lamp", + "area": "1", + "zone": "21", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Ungrouped", + "group_id": "1", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "741385f4388b2637df4c6b398fe50581", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "LCT014", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/control/light/ZB:db5b1a", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "On", + "status_display": "On", + "statuses": { + "saturation": 100, + "hue": 225, + "level": "79", + "switch": "1", + "color_temp": 3571, + "color_mode": "0" + }, + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/bulb-1.svg", + "statusEx": "0" + }, + { + "id": "ZB:db5b1b", + "type_tag": "device_type.hue", + "type": "Dimmer", + "name": "Test Dimmer Only Device", + "area": "1", + "zone": "21", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Ungrouped", + "group_id": "1", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "641385f4388b2637df4c6b398fe50581", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "LCT014", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/control/light/ZB:db5b1b", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "On", + "status_display": "On", + "statuses": { + "saturation": 100, + "hue": 225, + "level": "100", + "switch": "1", + "color_temp": 3571, + "color_mode": "2" + }, + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/bulb-1.svg", + "statusEx": "0" + }, + { + "id": "ZB:db5b1c", + "type_tag": "device_type.dimmer", + "type": "Light", + "name": "Test Non-dimmer Device", + "area": "1", + "zone": "21", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Ungrouped", + "group_id": "1", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "641385f4388b2637df4c6b398fe50583", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "LCT014", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/control/light/ZB:db5b1c", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "On", + "status_display": "On", + "statuses": { + "switch": "1" + }, + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/bulb-1.svg", + "statusEx": "0" + }, + { + "id": "RF:02148e70", + "type_tag": "device_type.lm", + "type": "LM", + "name": "Environment Sensor", + "area": "1", + "zone": "24", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Ungrouped", + "group_id": "1", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "13545b21f4bdcd33d9abd461f8443e65", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "67 \u00b0F", + "status_display": "Online", + "statuses": { + "temperature": "67 \u00b0F", + "temp": "19.5", + "lux": "1 lx", + "humidity": "32 %" + }, + "status_ex": "", + "actions": [ + { + "label": "High Humidity Alarm", + "value": "a=1&z=24&trigger=HMH;" + }, + { + "label": "Low Humidity Alarm", + "value": "a=1&z=24&trigger=HML;" + }, + { + "label": "High Temperature Alarm", + "value": "a=1&z=24&trigger=TSH;" + }, + { + "label": "Low Temperature Alarm", + "value": "a=1&z=24&trigger=TSL;" + } + ], + "status_icons": [], + "icon": "assets/icons/occupancy-sensor.svg", + "statusEx": "1" + }, + { + "id": "ZW:0000000b", + "type_tag": "device_type.power_switch_sensor", + "type": "Power Switch Sensor", + "name": "Test Switch", + "area": "1", + "zone": "23", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Lighting", + "group_id": "377075", + "default_group_id": "1", + "sort_id": "7", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "0012a4d3614cb7e2b8c9abea31d2fb2a", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "006349523032", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/control/power_switch/ZW:0000000b", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "Off", + "status_display": "OFF", + "statuses": { + "switch": "0" + }, + "status_ex": "", + "actions": [], + "status_icons": [], + "icon": "assets/icons/plug.svg" + }, + { + "id": "XF:b0c5ba27592a", + "type_tag": "device_type.ipcam", + "type": "IP Cam", + "name": "Test Cam", + "area": "1", + "zone": "1", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "1", + "sresp_24hr": "5", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Streaming Camera", + "group_id": "397893", + "default_group_id": "1", + "sort_id": "10000", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "d0a3a1c316891ceb00c20118aae2a133", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "1.0.2.22G_6.8E_homekit_2.0.9_s2 ABODE oz", + "origin": "abode", + "has_subscription": null, + "onboard": "1", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/cams/XF:b0c5ba27592a/record", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "Online", + "status_display": "Online", + "statuses": [], + "status_ex": "", + "actions": [ + { + "label": "Capture Video", + "value": "a=1&z=1&req=vid;" + }, + { + "label": "Turn off Live Video", + "value": "a=1&z=1&privacy=on;" + }, + { + "label": "Turn on Live Video", + "value": "a=1&z=1&privacy=off;" + } + ], + "status_icons": [], + "icon": "assets/icons/streaming-camaera-new.svg", + "control_url_snapshot": "api/v1/cams/XF:b0c5ba27592a/capture", + "ptt_supported": true, + "is_new_camera": 1, + "stream_quality": 2, + "camera_mac": "A0:C1:B2:C3:45:6D", + "privacy": "1", + "enable_audio": "1", + "alarm_video": "25", + "pre_alarm_video": "5", + "mic_volume": "75", + "speaker_volume": "75", + "mic_default_volume": 40, + "speaker_default_volume": 46, + "bandwidth": { + "slider_labels": [ + { + "name": "High", + "value": 3 + }, + { + "name": "Medium", + "value": 2 + }, + { + "name": "Low", + "value": 1 + } + ], + "min": 1, + "max": 3, + "step": 1 + }, + "volume": { + "min": 0, + "max": 100, + "step": 1 + }, + "video_flip": "0", + "hframe": "480P" + }, + { + "id": "ZW:00000004", + "type_tag": "device_type.door_lock", + "type": "Door Lock", + "name": "Test Lock", + "area": "1", + "zone": "16", + "sort_order": "", + "is_window": "", + "bypass": "0", + "schar_24hr": "0", + "sresp_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "group_name": "Doors/Windows", + "group_id": "377028", + "default_group_id": "1", + "sort_id": "1", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "51cab3b545d2o34ed7fz02731bda5324", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "sresp_mode_4": "0", + "sresp_entry_4": "0", + "sresp_exit_4": "0", + "version": "", + "origin": "abode", + "has_subscription": null, + "onboard": "0", + "s2_grnt_keys": "", + "s2_dsk": "", + "s2_propty": "", + "s2_keys_valid": "", + "zwave_secure_protocol": "", + "control_url": "api/v1/control/lock/ZW:00000004", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0, + "jammed": 0, + "zwave_fault": 0 + }, + "status": "LockClosed", + "status_display": "LockClosed", + "statuses": { + "open": "0" + }, + "status_ex": "", + "actions": [ + { + "label": "Lock", + "value": "a=1&z=16&sw=on;" + }, + { + "label": "Unlock", + "value": "a=1&z=16&sw=off;" + } + ], + "status_icons": { + "LockOpen": "assets/icons/unlocked-red.svg", + "LockClosed": "assets/icons/locked-green.svg" + }, + "icon": "assets/icons/automation-lock.svg", + "automation_settings": null + }, + { + "id": "ZW:00000007", + "type_tag": "device_type.secure_barrier", + "type": "Secure Barrier", + "name": "Garage Door", + "area": "1", + "zone": "11", + "sort_order": "0", + "is_window": "0", + "bypass": "0", + "schar_24hr": "0", + "sresp_mode_0": "0", + "sresp_entry_0": "0", + "sresp_exit_0": "0", + "sresp_mode_1": "0", + "sresp_entry_1": "0", + "sresp_exit_1": "0", + "sresp_mode_2": "0", + "sresp_entry_2": "0", + "sresp_exit_2": "0", + "sresp_mode_3": "0", + "uuid": "61cbz3b542d2o33ed2fz02721bda3324", + "sresp_entry_3": "0", + "sresp_exit_3": "0", + "capture_mode": null, + "origin": "abode", + "control_url": "api/v1/control/power_switch/ZW:00000007", + "deep_link": null, + "status_color": "#5cb85c", + "faults": { + "low_battery": 0, + "tempered": 0, + "supervision": 0, + "out_of_order": 0, + "no_response": 0 + }, + "status": "Closed", + "statuses": { + "hvac_mode": null + }, + "status_ex": "", + "actions": [ + { + "label": "Close", + "value": "a=1&z=11&sw=off;" + }, + { + "label": "Open", + "value": "a=1&z=11&sw=on;" + } + ], + "status_icons": { + "Open": "assets/icons/garage-door-red.svg", + "Closed": "assets/icons/garage-door-green.svg" + }, + "icon": "assets/icons/garage-door.svg" + } +] \ No newline at end of file diff --git a/tests/fixtures/abode_login.json b/tests/fixtures/abode_login.json new file mode 100644 index 00000000000..fb0ed1fd4ff --- /dev/null +++ b/tests/fixtures/abode_login.json @@ -0,0 +1,115 @@ +{ + "token": "web-1eb04ba2236d85f49d4b9b4bb91665f2", + "expired_at": "2017-06-05 00:14:12", + "initiate_screen": "timeline", + "user": { + "id": "user@email.com", + "email": "user@email.com", + "first_name": "John", + "last_name": "Doe", + "phone": "5555551212", + "profile_pic": "https://website.com/default-image.svg", + "address": "555 None St.", + "city": "New York City", + "state": "NY", + "zip": "10108", + "country": "US", + "longitude": "0", + "latitude": "0", + "timezone": "America/New_York_City", + "verified": "1", + "plan": "Basic", + "plan_id": "0", + "plan_active": "1", + "cms_code": "1111", + "cms_active": "0", + "cms_started_at": "", + "cms_expiry": "", + "cms_ondemand": "", + "step": "-1", + "cms_permit_no": "", + "opted_plan_id": "", + "stripe_account": "1", + "plan_effective_from": "", + "agreement": "1", + "associate_users": "1", + "owner": "1" + }, + "panel": { + "version": "ABGW 0.0.2.17F ABGW-L1-XA36J 3.1.2.6.1 Z-Wave 3.95", + "report_account": "5555", + "online": "1", + "initialized": "1", + "net_version": "ABGW 0.0.2.17F", + "rf_version": "ABGW-L1-XA36J", + "zigbee_version": "3.1.2.6.1", + "z_wave_version": "Z-Wave 3.95", + "timezone": "America/New_York", + "ac_fail": "0", + "battery": "1", + "ip": "192.168.1.1", + "jam": "0", + "rssi": "2", + "setup_zone_1": "1", + "setup_zone_2": "1", + "setup_zone_3": "1", + "setup_zone_4": "1", + "setup_zone_5": "1", + "setup_zone_6": "1", + "setup_zone_7": "1", + "setup_zone_8": "1", + "setup_zone_9": "1", + "setup_zone_10": "1", + "setup_gateway": "1", + "setup_contacts": "1", + "setup_billing": "1", + "setup_users": "1", + "is_cellular": "False", + "plan_set_id": "1", + "dealer_id": "0", + "tz_diff": "-04:00", + "is_demo": "0", + "rf51_version": "ABGW-L1-XA36J", + "model": "L1", + "mac": "00:11:22:33:44:55", + "xml_version": "3", + "dealer_name": "abode", + "id": "0", + "dealer_address": "2625 Middlefield Road #900 Palo Alto CA 94306", + "dealer_domain": "https://my.goabode.com", + "domain_alias": "https://test.goabode.com", + "dealer_support_url": "https://support.goabode.com", + "app_launch_url": "https://goabode.app.link/abode", + "has_wifi": "0", + "mode": { + "area_1": "standby", + "area_2": "standby" + } + }, + "permissions": { + "premium_streaming": "0", + "guest_app": "0", + "family_app": "0", + "multiple_accounts": "1", + "google_voice": "1", + "nest": "1", + "alexa": "1", + "ifttt": "1", + "no_associates": "100", + "no_contacts": "2", + "no_devices": "155", + "no_ipcam": "100", + "no_quick_action": "25", + "no_automation": "75", + "media_storage": "3", + "cellular_backup": "0", + "cms_duration": "", + "cms_included": "0" + }, + "integrations": { + "nest": { + "is_connected": 0, + "is_home_selected": 0 + } + } +} \ No newline at end of file diff --git a/tests/fixtures/abode_oauth_claims.json b/tests/fixtures/abode_oauth_claims.json new file mode 100644 index 00000000000..2b313b9aa3e --- /dev/null +++ b/tests/fixtures/abode_oauth_claims.json @@ -0,0 +1,5 @@ +{ + "token_type": "Bearer", + "access_token": "ohyeahthisisanoauthtoken", + "expires_in": 3600 +} \ No newline at end of file diff --git a/tests/fixtures/abode_panel.json b/tests/fixtures/abode_panel.json new file mode 100644 index 00000000000..5a50ffe6fe7 --- /dev/null +++ b/tests/fixtures/abode_panel.json @@ -0,0 +1,185 @@ +{ + "version": "Z3 1.0.2.22G_6.8E_homekit_2.0.9_s2 ABODE oz 19200_UITRF1BD_BL.A30.20181117 4.1.2.6.2 Z-Wave 6.02 Bridge controller library", + "report_account": "12345", + "online": "1", + "initialized": "1", + "net_version": "1.0.2.22G_6.8E_homekit_2.0.9_s2 ABODE oz", + "rf_version": "19200_UITRF1BD_BL.A30.20181117", + "zigbee_version": "4.1.2.6.2", + "z_wave_version": "Z-Wave 6.02 Bridge controller library", + "timezone": "America/Los_Angeles", + "ac_fail": "0", + "battery": "0", + "ip": "", + "jam": "0", + "rssi": "1", + "setup_zone_1": "1", + "setup_zone_2": "1", + "setup_zone_3": "1", + "setup_zone_4": "1", + "setup_zone_5": "1", + "setup_zone_6": "1", + "setup_zone_7": "1", + "setup_zone_8": "1", + "setup_zone_9": "1", + "setup_zone_10": "1", + "setup_gateway": "1", + "setup_contacts": "1", + "setup_billing": "1", + "setup_users": "1", + "is_cellular": "0", + "plan_set_id": "7", + "dealer_id": "0", + "tz_diff": "-08:00", + "model": "Z3", + "has_wifi": "1", + "has_s2_support": "1", + "mode": { + "area_1": "standby", + "area_1_label": "Standby", + "area_2": "standby", + "area_2_label": "Standby" + }, + "areas": { + "1": { + "mode": "0", + "modes": { + "0": { + "area": "1", + "mode": "0", + "read_only": "1", + "is_set": "1", + "name": "standby", + "color": null, + "icon_id": null, + "entry1": null, + "entry2": null, + "exit": null, + "icon_path": null + }, + "1": { + "area": "1", + "mode": "1", + "read_only": "1", + "is_set": "1", + "name": "away", + "color": null, + "icon_id": null, + "entry1": "30", + "entry2": "60", + "exit": "30", + "icon_path": null + }, + "2": { + "area": "1", + "mode": "2", + "read_only": "1", + "is_set": "1", + "name": "home", + "color": null, + "icon_id": null, + "entry1": "30", + "entry2": "60", + "exit": "0", + "icon_path": null + }, + "3": { + "area": "1", + "mode": "3", + "read_only": "0", + "is_set": "0", + "name": null, + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + }, + "4": { + "area": "1", + "mode": "4", + "read_only": "0", + "is_set": "0", + "name": null, + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + } + } + }, + "2": { + "mode": "0", + "modes": { + "0": { + "area": "2", + "mode": "0", + "read_only": "1", + "is_set": "1", + "name": "standby", + "color": null, + "icon_id": null, + "entry1": null, + "entry2": null, + "exit": null, + "icon_path": null + }, + "1": { + "area": "2", + "mode": "1", + "read_only": "1", + "is_set": "1", + "name": "away", + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + }, + "2": { + "area": "2", + "mode": "2", + "read_only": "1", + "is_set": "1", + "name": "home", + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + }, + "3": { + "area": "2", + "mode": "3", + "read_only": "0", + "is_set": "0", + "name": null, + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + }, + "4": { + "area": "2", + "mode": "4", + "read_only": "0", + "is_set": "0", + "name": null, + "color": null, + "icon_id": null, + "entry1": "60", + "entry2": "60", + "exit": "60", + "icon_path": null + } + } + } + } +} \ No newline at end of file