From f2a3f758af05e6ca0e9dc9ebbda3c477994e680b Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Mon, 24 Jan 2022 03:10:42 -0700 Subject: [PATCH] Add diagnostics to RainMachine (#64788) --- .../components/rainmachine/diagnostics.py | 52 ++ tests/components/rainmachine/conftest.py | 64 +- .../rainmachine/fixtures/programs_data.json | 284 +++++++++ .../fixtures/provision_settings_data.json | 84 +++ .../fixtures/restrictions_current_data.json | 10 + .../fixtures/restrictions_universal_data.json | 10 + .../rainmachine/fixtures/zones_data.json | 182 ++++++ .../rainmachine/test_diagnostics.py | 592 ++++++++++++++++++ 8 files changed, 1273 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/rainmachine/diagnostics.py create mode 100644 tests/components/rainmachine/fixtures/programs_data.json create mode 100644 tests/components/rainmachine/fixtures/provision_settings_data.json create mode 100644 tests/components/rainmachine/fixtures/restrictions_current_data.json create mode 100644 tests/components/rainmachine/fixtures/restrictions_universal_data.json create mode 100644 tests/components/rainmachine/fixtures/zones_data.json create mode 100644 tests/components/rainmachine/test_diagnostics.py diff --git a/homeassistant/components/rainmachine/diagnostics.py b/homeassistant/components/rainmachine/diagnostics.py new file mode 100644 index 00000000000..e5e249d41f4 --- /dev/null +++ b/homeassistant/components/rainmachine/diagnostics.py @@ -0,0 +1,52 @@ +"""Diagnostics support for RainMachine.""" +from __future__ import annotations + +from typing import Any + +from regenmaschine.controller import Controller + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_PASSWORD +from homeassistant.core import HomeAssistant +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + +from .const import DATA_CONTROLLER, DATA_COORDINATOR, DOMAIN + +TO_REDACT = { + CONF_LATITUDE, + CONF_LONGITUDE, + CONF_PASSWORD, +} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: ConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + data = hass.data[DOMAIN][entry.entry_id] + coordinators: dict[str, DataUpdateCoordinator] = data[DATA_COORDINATOR] + controller: Controller = data[DATA_CONTROLLER] + + return { + "entry": { + "title": entry.title, + "data": async_redact_data(entry.data, TO_REDACT), + "options": dict(entry.options), + }, + "data": { + "coordinator": async_redact_data( + { + api_category: controller.data + for api_category, controller in coordinators.items() + }, + TO_REDACT, + ), + "controller": { + "api_version": controller.api_version, + "hardware_version": controller.hardware_version, + "name": controller.name, + "software_version": controller.software_version, + }, + }, + } diff --git a/tests/components/rainmachine/conftest.py b/tests/components/rainmachine/conftest.py index 486cd385b4d..3a32b3b7c9a 100644 --- a/tests/components/rainmachine/conftest.py +++ b/tests/components/rainmachine/conftest.py @@ -1,4 +1,5 @@ """Define test fixtures for RainMachine.""" +import json from unittest.mock import AsyncMock, patch import pytest @@ -7,15 +8,12 @@ from homeassistant.components.rainmachine import DOMAIN from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL from homeassistant.setup import async_setup_component -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, load_fixture @pytest.fixture(name="client") -def client_fixture(controller_mac): +def client_fixture(controller, controller_mac): """Define a regenmaschine client.""" - controller = AsyncMock() - controller.name = "My RainMachine" - controller.mac = controller_mac return AsyncMock(load_local=AsyncMock(), controllers={controller_mac: controller}) @@ -38,12 +36,68 @@ def config_entry_fixture(hass, config, controller_mac): return entry +@pytest.fixture(name="controller") +def controller_fixture( + controller_mac, + data_programs, + data_provision_settings, + data_restrictions_current, + data_restrictions_universal, + data_zones, +): + """Define a regenmaschine controller.""" + controller = AsyncMock() + controller.api_version = "4.5.0" + controller.hardware_version = 3 + controller.name = "My RainMachine" + controller.mac = controller_mac + controller.software_version = "4.0.925" + + controller.programs.all.return_value = data_programs + controller.provisioning.settings.return_value = data_provision_settings + controller.restrictions.current.return_value = data_restrictions_current + controller.restrictions.universal.return_value = data_restrictions_universal + controller.zones.all.return_value = data_zones + + return controller + + @pytest.fixture(name="controller_mac") def controller_mac_fixture(): """Define a controller MAC address.""" return "aa:bb:cc:dd:ee:ff" +@pytest.fixture(name="data_programs", scope="session") +def data_programs_fixture(): + """Define program data.""" + return json.loads(load_fixture("programs_data.json", "rainmachine")) + + +@pytest.fixture(name="data_provision_settings", scope="session") +def data_provision_settings_fixture(): + """Define provisioning settings data.""" + return json.loads(load_fixture("provision_settings_data.json", "rainmachine")) + + +@pytest.fixture(name="data_restrictions_current", scope="session") +def data_restrictions_current_fixture(): + """Define current restrictions settings data.""" + return json.loads(load_fixture("restrictions_current_data.json", "rainmachine")) + + +@pytest.fixture(name="data_restrictions_universal", scope="session") +def data_restrictions_universal_fixture(): + """Define universal restrictions settings data.""" + return json.loads(load_fixture("restrictions_universal_data.json", "rainmachine")) + + +@pytest.fixture(name="data_zones", scope="session") +def data_zones_fixture(): + """Define zone data.""" + return json.loads(load_fixture("zones_data.json", "rainmachine")) + + @pytest.fixture(name="setup_rainmachine") async def setup_rainmachine_fixture(hass, client, config): """Define a fixture to set up RainMachine.""" diff --git a/tests/components/rainmachine/fixtures/programs_data.json b/tests/components/rainmachine/fixtures/programs_data.json new file mode 100644 index 00000000000..522ebd3bade --- /dev/null +++ b/tests/components/rainmachine/fixtures/programs_data.json @@ -0,0 +1,284 @@ +[ + { + "uid": 1, + "name": "Morning", + "active": true, + "startTime": "06:00", + "cycles": 0, + "soak": 0, + "cs_on": false, + "delay": 0, + "delay_on": false, + "status": 0, + "startTimeParams": { + "offsetSign": 0, + "type": 0, + "offsetMinutes": 0 + }, + "frequency": { + "type": 0, + "param": "0" + }, + "coef": 0, + "ignoreInternetWeather": false, + "futureField1": 0, + "freq_modified": 0, + "useWaterSense": false, + "nextRun": "2018-06-04", + "startDate": "2018-04-28", + "endDate": null, + "yearlyRecurring": true, + "simulationExpired": false, + "wateringTimes": [ + { + "id": 1, + "order": -1, + "name": "Landscaping", + "duration": 0, + "active": true, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 2, + "order": -1, + "name": "Flower Box", + "duration": 0, + "active": true, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 3, + "order": -1, + "name": "TEST", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 4, + "order": -1, + "name": "Zone 4", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 5, + "order": -1, + "name": "Zone 5", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 6, + "order": -1, + "name": "Zone 6", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 7, + "order": -1, + "name": "Zone 7", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 8, + "order": -1, + "name": "Zone 8", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 9, + "order": -1, + "name": "Zone 9", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 10, + "order": -1, + "name": "Zone 10", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 11, + "order": -1, + "name": "Zone 11", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 12, + "order": -1, + "name": "Zone 12", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + } + ] + }, + { + "uid": 2, + "name": "Evening", + "active": false, + "startTime": "06:00", + "cycles": 0, + "soak": 0, + "cs_on": false, + "delay": 0, + "delay_on": false, + "status": 0, + "startTimeParams": { + "offsetSign": 0, + "type": 0, + "offsetMinutes": 0 + }, + "frequency": { + "type": 0, + "param": "0" + }, + "coef": 0, + "ignoreInternetWeather": false, + "futureField1": 0, + "freq_modified": 0, + "useWaterSense": false, + "nextRun": "2018-06-04", + "startDate": "2018-04-28", + "endDate": null, + "yearlyRecurring": true, + "simulationExpired": false, + "wateringTimes": [ + { + "id": 1, + "order": -1, + "name": "Landscaping", + "duration": 0, + "active": true, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 2, + "order": -1, + "name": "Flower Box", + "duration": 0, + "active": true, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 3, + "order": -1, + "name": "TEST", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 4, + "order": -1, + "name": "Zone 4", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 5, + "order": -1, + "name": "Zone 5", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 6, + "order": -1, + "name": "Zone 6", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 7, + "order": -1, + "name": "Zone 7", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 8, + "order": -1, + "name": "Zone 8", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 9, + "order": -1, + "name": "Zone 9", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 10, + "order": -1, + "name": "Zone 10", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 11, + "order": -1, + "name": "Zone 11", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + }, + { + "id": 12, + "order": -1, + "name": "Zone 12", + "duration": 0, + "active": false, + "userPercentage": 1, + "minRuntimeCoef": 1 + } + ] + } +] diff --git a/tests/components/rainmachine/fixtures/provision_settings_data.json b/tests/components/rainmachine/fixtures/provision_settings_data.json new file mode 100644 index 00000000000..d62f9f4df1d --- /dev/null +++ b/tests/components/rainmachine/fixtures/provision_settings_data.json @@ -0,0 +1,84 @@ +{ + "system": { + "httpEnabled": true, + "rainSensorSnoozeDuration": 0, + "uiUnitsMetric": false, + "programZonesShowInactive": false, + "programSingleSchedule": false, + "standaloneMode": false, + "masterValveAfter": 0, + "touchSleepTimeout": 10, + "selfTest": false, + "useSoftwareRainSensor": false, + "defaultZoneWateringDuration": 300, + "maxLEDBrightness": 40, + "simulatorHistorySize": 0, + "vibration": false, + "masterValveBefore": 0, + "touchProgramToRun": null, + "useRainSensor": false, + "wizardHasRun": true, + "waterLogHistorySize": 365, + "netName": "Home", + "softwareRainSensorMinQPF": 5, + "touchAdvanced": false, + "useBonjourService": true, + "hardwareVersion": 3, + "touchLongPressTimeout": 3, + "showRestrictionsOnLed": false, + "parserDataSizeInDays": 6, + "programListShowInactive": true, + "parserHistorySize": 365, + "allowAlexaDiscovery": false, + "automaticUpdates": true, + "minLEDBrightness": 0, + "minWateringDurationThreshold": 0, + "localValveCount": 12, + "touchAuthAPSeconds": 60, + "useCommandLineArguments": false, + "databasePath": "/rainmachine-app/DB/Default", + "touchCyclePrograms": true, + "zoneListShowInactive": true, + "rainSensorRainStart": null, + "zoneDuration": [ + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300 + ], + "rainSensorIsNormallyClosed": true, + "useCorrectionForPast": true, + "useMasterValve": false, + "runParsersBeforePrograms": true, + "maxWateringCoef": 2, + "mixerHistorySize": 365 + }, + "location": { + "elevation": 1593.45141602, + "doyDownloaded": true, + "zip": null, + "windSensitivity": 0.5, + "krs": 0.16, + "stationID": 9172, + "stationSource": "station", + "et0Average": 6.578, + "latitude": 21.037234682342, + "state": "Default", + "stationName": "MY STATION", + "wsDays": 2, + "stationDownloaded": true, + "address": "Default", + "rainSensitivity": 0.8, + "timezone": "America/Los Angeles", + "longitude": -87.12872612, + "name": "Home" + } +} diff --git a/tests/components/rainmachine/fixtures/restrictions_current_data.json b/tests/components/rainmachine/fixtures/restrictions_current_data.json new file mode 100644 index 00000000000..4bc93a9ddf4 --- /dev/null +++ b/tests/components/rainmachine/fixtures/restrictions_current_data.json @@ -0,0 +1,10 @@ +{ + "hourly": false, + "freeze": false, + "month": false, + "weekDay": false, + "rainDelay": false, + "rainDelayCounter": -1, + "rainSensor": false +} + diff --git a/tests/components/rainmachine/fixtures/restrictions_universal_data.json b/tests/components/rainmachine/fixtures/restrictions_universal_data.json new file mode 100644 index 00000000000..fa3cdbf4c47 --- /dev/null +++ b/tests/components/rainmachine/fixtures/restrictions_universal_data.json @@ -0,0 +1,10 @@ +{ + "hotDaysExtraWatering": false, + "freezeProtectEnabled": true, + "freezeProtectTemp": 2, + "noWaterInWeekDays": "0000000", + "noWaterInMonths": "000000000000", + "rainDelayStartTime": 1524854551, + "rainDelayDuration": 0 +} + diff --git a/tests/components/rainmachine/fixtures/zones_data.json b/tests/components/rainmachine/fixtures/zones_data.json new file mode 100644 index 00000000000..7df01f17ba6 --- /dev/null +++ b/tests/components/rainmachine/fixtures/zones_data.json @@ -0,0 +1,182 @@ +[ + { + "uid": 1, + "name": "Landscaping", + "state": 0, + "active": true, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 4, + "master": false, + "waterSense": false + }, + { + "uid": 2, + "name": "Flower Box", + "state": 0, + "active": true, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 5, + "master": false, + "waterSense": false + }, + { + "uid": 3, + "name": "TEST", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 9, + "master": false, + "waterSense": false + }, + { + "uid": 4, + "name": "Zone 4", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 5, + "name": "Zone 5", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 6, + "name": "Zone 6", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 7, + "name": "Zone 7", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 8, + "name": "Zone 8", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 9, + "name": "Zone 9", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 10, + "name": "Zone 10", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 11, + "name": "Zone 11", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + }, + { + "uid": 12, + "name": "Zone 12", + "state": 0, + "active": false, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": false, + "type": 2, + "master": false, + "waterSense": false + } +] diff --git a/tests/components/rainmachine/test_diagnostics.py b/tests/components/rainmachine/test_diagnostics.py new file mode 100644 index 00000000000..575e596abc2 --- /dev/null +++ b/tests/components/rainmachine/test_diagnostics.py @@ -0,0 +1,592 @@ +"""Test RainMachine diagnostics.""" +from homeassistant.components.diagnostics import REDACTED + +from tests.components.diagnostics import get_diagnostics_for_config_entry + + +async def test_entry_diagnostics(hass, config_entry, hass_client, setup_rainmachine): + """Test config entry diagnostics.""" + assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { + "entry": { + "title": "Mock Title", + "data": { + "ip_address": "192.168.1.100", + "password": REDACTED, + "port": 8080, + "ssl": True, + }, + "options": {}, + }, + "data": { + "coordinator": { + "programs": [ + { + "uid": 1, + "name": "Morning", + "active": True, + "startTime": "06:00", + "cycles": 0, + "soak": 0, + "cs_on": False, + "delay": 0, + "delay_on": False, + "status": 0, + "startTimeParams": { + "offsetSign": 0, + "type": 0, + "offsetMinutes": 0, + }, + "frequency": {"type": 0, "param": "0"}, + "coef": 0, + "ignoreInternetWeather": False, + "futureField1": 0, + "freq_modified": 0, + "useWaterSense": False, + "nextRun": "2018-06-04", + "startDate": "2018-04-28", + "endDate": None, + "yearlyRecurring": True, + "simulationExpired": False, + "wateringTimes": [ + { + "id": 1, + "order": -1, + "name": "Landscaping", + "duration": 0, + "active": True, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 2, + "order": -1, + "name": "Flower Box", + "duration": 0, + "active": True, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 3, + "order": -1, + "name": "TEST", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 4, + "order": -1, + "name": "Zone 4", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 5, + "order": -1, + "name": "Zone 5", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 6, + "order": -1, + "name": "Zone 6", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 7, + "order": -1, + "name": "Zone 7", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 8, + "order": -1, + "name": "Zone 8", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 9, + "order": -1, + "name": "Zone 9", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 10, + "order": -1, + "name": "Zone 10", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 11, + "order": -1, + "name": "Zone 11", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 12, + "order": -1, + "name": "Zone 12", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + ], + }, + { + "uid": 2, + "name": "Evening", + "active": False, + "startTime": "06:00", + "cycles": 0, + "soak": 0, + "cs_on": False, + "delay": 0, + "delay_on": False, + "status": 0, + "startTimeParams": { + "offsetSign": 0, + "type": 0, + "offsetMinutes": 0, + }, + "frequency": {"type": 0, "param": "0"}, + "coef": 0, + "ignoreInternetWeather": False, + "futureField1": 0, + "freq_modified": 0, + "useWaterSense": False, + "nextRun": "2018-06-04", + "startDate": "2018-04-28", + "endDate": None, + "yearlyRecurring": True, + "simulationExpired": False, + "wateringTimes": [ + { + "id": 1, + "order": -1, + "name": "Landscaping", + "duration": 0, + "active": True, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 2, + "order": -1, + "name": "Flower Box", + "duration": 0, + "active": True, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 3, + "order": -1, + "name": "TEST", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 4, + "order": -1, + "name": "Zone 4", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 5, + "order": -1, + "name": "Zone 5", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 6, + "order": -1, + "name": "Zone 6", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 7, + "order": -1, + "name": "Zone 7", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 8, + "order": -1, + "name": "Zone 8", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 9, + "order": -1, + "name": "Zone 9", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 10, + "order": -1, + "name": "Zone 10", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 11, + "order": -1, + "name": "Zone 11", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + { + "id": 12, + "order": -1, + "name": "Zone 12", + "duration": 0, + "active": False, + "userPercentage": 1, + "minRuntimeCoef": 1, + }, + ], + }, + ], + "provision.settings": { + "system": { + "httpEnabled": True, + "rainSensorSnoozeDuration": 0, + "uiUnitsMetric": False, + "programZonesShowInactive": False, + "programSingleSchedule": False, + "standaloneMode": False, + "masterValveAfter": 0, + "touchSleepTimeout": 10, + "selfTest": False, + "useSoftwareRainSensor": False, + "defaultZoneWateringDuration": 300, + "maxLEDBrightness": 40, + "simulatorHistorySize": 0, + "vibration": False, + "masterValveBefore": 0, + "touchProgramToRun": None, + "useRainSensor": False, + "wizardHasRun": True, + "waterLogHistorySize": 365, + "netName": "Home", + "softwareRainSensorMinQPF": 5, + "touchAdvanced": False, + "useBonjourService": True, + "hardwareVersion": 3, + "touchLongPressTimeout": 3, + "showRestrictionsOnLed": False, + "parserDataSizeInDays": 6, + "programListShowInactive": True, + "parserHistorySize": 365, + "allowAlexaDiscovery": False, + "automaticUpdates": True, + "minLEDBrightness": 0, + "minWateringDurationThreshold": 0, + "localValveCount": 12, + "touchAuthAPSeconds": 60, + "useCommandLineArguments": False, + "databasePath": "/rainmachine-app/DB/Default", + "touchCyclePrograms": True, + "zoneListShowInactive": True, + "rainSensorRainStart": None, + "zoneDuration": [ + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + 300, + ], + "rainSensorIsNormallyClosed": True, + "useCorrectionForPast": True, + "useMasterValve": False, + "runParsersBeforePrograms": True, + "maxWateringCoef": 2, + "mixerHistorySize": 365, + }, + "location": { + "elevation": 1593.45141602, + "doyDownloaded": True, + "zip": None, + "windSensitivity": 0.5, + "krs": 0.16, + "stationID": 9172, + "stationSource": "station", + "et0Average": 6.578, + "latitude": REDACTED, + "state": "Default", + "stationName": "MY STATION", + "wsDays": 2, + "stationDownloaded": True, + "address": "Default", + "rainSensitivity": 0.8, + "timezone": "America/Los Angeles", + "longitude": REDACTED, + "name": "Home", + }, + }, + "restrictions.current": { + "hourly": False, + "freeze": False, + "month": False, + "weekDay": False, + "rainDelay": False, + "rainDelayCounter": -1, + "rainSensor": False, + }, + "restrictions.universal": { + "hotDaysExtraWatering": False, + "freezeProtectEnabled": True, + "freezeProtectTemp": 2, + "noWaterInWeekDays": "0000000", + "noWaterInMonths": "000000000000", + "rainDelayStartTime": 1524854551, + "rainDelayDuration": 0, + }, + "zones": [ + { + "uid": 1, + "name": "Landscaping", + "state": 0, + "active": True, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 4, + "master": False, + "waterSense": False, + }, + { + "uid": 2, + "name": "Flower Box", + "state": 0, + "active": True, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 5, + "master": False, + "waterSense": False, + }, + { + "uid": 3, + "name": "TEST", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 9, + "master": False, + "waterSense": False, + }, + { + "uid": 4, + "name": "Zone 4", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 5, + "name": "Zone 5", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 6, + "name": "Zone 6", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 7, + "name": "Zone 7", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 8, + "name": "Zone 8", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 9, + "name": "Zone 9", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 10, + "name": "Zone 10", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 11, + "name": "Zone 11", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + { + "uid": 12, + "name": "Zone 12", + "state": 0, + "active": False, + "userDuration": 0, + "machineDuration": 0, + "remaining": 0, + "cycle": 0, + "noOfCycles": 0, + "restriction": False, + "type": 2, + "master": False, + "waterSense": False, + }, + ], + }, + "controller": { + "api_version": "4.5.0", + "hardware_version": 3, + "name": "My RainMachine", + "software_version": "4.0.925", + }, + }, + }