Skip to content

Commit

Permalink
Hide non-essential coordinator config fields
Browse files Browse the repository at this point in the history
  • Loading branch information
rgc99 committed Jan 21, 2024
1 parent b298799 commit f45bc36
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 50 deletions.
1 change: 1 addition & 0 deletions custom_components/irrigation_unlimited/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
CONF_QUEUE_MANUAL = "queue_manual"
CONF_USER = "user"
CONF_TOGGLE = "toggle"
CONF_EXTENDED_CONFIG = "extended_config"

# Defaults
DEFAULT_NAME = DOMAIN
Expand Down
114 changes: 64 additions & 50 deletions custom_components/irrigation_unlimited/irrigation_unlimited.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
CONF_QUEUE_MANUAL,
CONF_USER,
CONF_TOGGLE,
CONF_EXTENDED_CONFIG,
)

_LOGGER: Logger = getLogger(__package__)
Expand Down Expand Up @@ -2153,26 +2154,27 @@ def finalise(self, turn_off: bool) -> None:
self.clear()
self._finalised = True

def as_dict(self) -> OrderedDict:
def as_dict(self, extended=False) -> OrderedDict:
"""Return this zone as a dict"""
if self.runs.current_run is not None:
current_duration = self.runs.current_run.duration
else:
current_duration = timedelta(0)
result = OrderedDict()
result[CONF_INDEX] = self._index
result[CONF_NAME] = self.name
result[CONF_STATE] = STATE_ON if self.is_on else STATE_OFF
result[CONF_ENABLED] = self.enabled
result[ATTR_SUSPENDED] = self.suspended
result[CONF_ICON] = self.icon
result[CONF_ZONE_ID] = self._zone_id
result[CONF_ENTITY_BASE] = self.entity_base
result[ATTR_STATUS] = self.status
result[ATTR_ADJUSTMENT] = str(self._adjustment)
result[ATTR_CURRENT_DURATION] = current_duration
result[CONF_SCHEDULES] = [sch.as_dict() for sch in self._schedules]
result[ATTR_SWITCH_ENTITIES] = self._switch.switch_entity_id
if extended:
if self.runs.current_run is not None:
current_duration = self.runs.current_run.duration
else:
current_duration = timedelta(0)
result[CONF_ICON] = self.icon
result[CONF_ZONE_ID] = self._zone_id
result[CONF_ENTITY_BASE] = self.entity_base
result[ATTR_STATUS] = self.status
result[ATTR_CURRENT_DURATION] = current_duration
result[CONF_SCHEDULES] = [sch.as_dict() for sch in self._schedules]
result[ATTR_SWITCH_ENTITIES] = self._switch.switch_entity_id
return result

def timeline(self) -> list:
Expand Down Expand Up @@ -2510,24 +2512,31 @@ def build_zones() -> None:
build_zones()
return self

def as_dict(self, duration_factor: float, sqr: "IUSequenceRun" = None) -> dict:
def as_dict(
self, duration_factor: float, extended=False, sqr: "IUSequenceRun" = None
) -> dict:
"""Return this sequence zone as a dict"""
result = OrderedDict()
result[CONF_INDEX] = self._index
result[CONF_STATE] = STATE_ON if self.is_on else STATE_OFF
result[CONF_ENABLED] = self.enabled
result[ATTR_SUSPENDED] = self.suspended
result[CONF_ICON] = self.icon()
result[ATTR_STATUS] = self.status()
result[CONF_DELAY] = self._sequence.zone_delay(self, sqr)
result[ATTR_BASE_DURATION] = self._sequence.zone_duration_base(self, sqr)
result[ATTR_ADJUSTED_DURATION] = self._sequence.zone_duration(self, sqr)
result[ATTR_FINAL_DURATION] = self._sequence.zone_duration_final(
self, duration_factor, sqr
)
result[CONF_ZONES] = list(zone.index + self.ZONE_OFFSET for zone in self._zones)
result[ATTR_CURRENT_DURATION] = self._sequence.runs.active_zone_duration(self)
result[ATTR_ADJUSTMENT] = str(self._adjustment)
if extended:
result[CONF_ICON] = self.icon()
result[ATTR_STATUS] = self.status()
result[CONF_DELAY] = self._sequence.zone_delay(self, sqr)
result[ATTR_BASE_DURATION] = self._sequence.zone_duration_base(self, sqr)
result[ATTR_ADJUSTED_DURATION] = self._sequence.zone_duration(self, sqr)
result[ATTR_FINAL_DURATION] = self._sequence.zone_duration_final(
self, duration_factor, sqr
)
result[CONF_ZONES] = list(
zone.index + self.ZONE_OFFSET for zone in self._zones
)
result[ATTR_CURRENT_DURATION] = self._sequence.runs.active_zone_duration(
self
)
return result

def muster(self, stime: datetime) -> IURQStatus:
Expand Down Expand Up @@ -3657,7 +3666,7 @@ def load(self, config: OrderedDict) -> "IUSequence":
self._dirty = True
return self

def as_dict(self, sqr: IUSequenceRun = None) -> OrderedDict:
def as_dict(self, extended=False, sqr: IUSequenceRun = None) -> OrderedDict:
"""Return this sequence as a dict"""
total_delay = self.total_delay(sqr)
total_duration = self.total_duration(sqr)
Expand All @@ -3671,20 +3680,21 @@ def as_dict(self, sqr: IUSequenceRun = None) -> OrderedDict:
result[CONF_STATE] = STATE_ON if self.is_on else STATE_OFF
result[CONF_ENABLED] = self._enabled
result[ATTR_SUSPENDED] = self.suspended
result[ATTR_ICON] = self.icon
result[ATTR_STATUS] = self.status
result[ATTR_DEFAULT_DURATION] = self._duration
result[ATTR_DEFAULT_DELAY] = self._delay
result[ATTR_DURATION_FACTOR] = duration_factor
result[ATTR_TOTAL_DELAY] = total_delay
result[ATTR_TOTAL_DURATION] = total_duration
result[ATTR_ADJUSTED_DURATION] = total_duration_adjusted
result[ATTR_CURRENT_DURATION] = self.runs.current_duration
result[ATTR_ADJUSTMENT] = str(self._adjustment)
result[CONF_SCHEDULES] = [sch.as_dict() for sch in self._schedules]
result[CONF_SEQUENCE_ZONES] = [
szn.as_dict(duration_factor) for szn in self._zones
szn.as_dict(duration_factor, extended) for szn in self._zones
]
if extended:
result[ATTR_ICON] = self.icon
result[ATTR_STATUS] = self.status
result[ATTR_DEFAULT_DURATION] = self._duration
result[ATTR_DEFAULT_DELAY] = self._delay
result[ATTR_DURATION_FACTOR] = duration_factor
result[ATTR_TOTAL_DELAY] = total_delay
result[ATTR_TOTAL_DURATION] = total_duration
result[ATTR_ADJUSTED_DURATION] = total_duration_adjusted
result[ATTR_CURRENT_DURATION] = self.runs.current_duration
result[CONF_SCHEDULES] = [sch.as_dict() for sch in self._schedules]
return result

def muster(self, stime: datetime) -> IURQStatus:
Expand Down Expand Up @@ -4190,20 +4200,21 @@ def finalise(self, turn_off: bool) -> None:
self.clear()
self._finalised = True

def as_dict(self) -> OrderedDict:
def as_dict(self, extended=False) -> OrderedDict:
"""Return this controller as a dict"""
result = OrderedDict()
result[CONF_INDEX] = self._index
result[CONF_NAME] = self._name
result[CONF_CONTROLLER_ID] = self._controller_id
result[CONF_ENTITY_BASE] = self.entity_base
result[CONF_STATE] = STATE_ON if self.is_on else STATE_OFF
result[CONF_ENABLED] = self._enabled
result[ATTR_SUSPENDED] = self.suspended
result[CONF_ICON] = self.icon
result[ATTR_STATUS] = self.status
result[CONF_ZONES] = [zone.as_dict() for zone in self._zones]
result[CONF_SEQUENCES] = [seq.as_dict() for seq in self._sequences]
result[CONF_ZONES] = [zone.as_dict(extended) for zone in self._zones]
result[CONF_SEQUENCES] = [seq.as_dict(extended) for seq in self._sequences]
result[CONF_STATE] = STATE_ON if self.is_on else STATE_OFF
if extended:
result[CONF_CONTROLLER_ID] = self._controller_id
result[CONF_ENTITY_BASE] = self.entity_base
result[CONF_ICON] = self.icon
result[ATTR_STATUS] = self.status
return result

def sequence_runs(self) -> list[IUSequenceRun]:
Expand Down Expand Up @@ -4655,6 +4666,7 @@ def service_cancel(self, data: MappingProxyType, stime: datetime) -> bool:
self.request_update(True)
return changed


class IUEvent:
"""This class represents a single event"""

Expand Down Expand Up @@ -5688,6 +5700,9 @@ def __init__(self, hass: HomeAssistant) -> None:
self._hass = hass
# Config parameters
self._refresh_interval: timedelta = None
self._sync_switches: bool = True
self._rename_entities = False
self._extended_config = False
# Private variables
self._controllers: list[IUController] = []
self._is_on: bool = False
Expand All @@ -5705,8 +5720,6 @@ def __init__(self, hass: HomeAssistant) -> None:
self._clock = IUClock(self._hass, self, self._async_timer)
self._history = IUHistory(self._hass, self.service_history)
self._restored_from_configuration: bool = False
self._sync_switches: bool = True
self._rename_entities = False
self._finalised = False

@property
Expand Down Expand Up @@ -5767,7 +5780,7 @@ def finalised(self) -> bool:
@property
def configuration(self) -> str:
"""Return the system configuration as JSON"""
return json.dumps(self.as_dict(), cls=IUJSONEncoder)
return json.dumps(self.as_dict(self._extended_config), cls=IUJSONEncoder)

@property
def restored_from_configuration(self) -> bool:
Expand Down Expand Up @@ -5832,6 +5845,7 @@ def load(self, config: OrderedDict) -> "IUCoordinator":
)
self._sync_switches = config.get(CONF_SYNC_SWITCHES, True)
self._rename_entities = config.get(CONF_RENAME_ENTITIES, self._rename_entities)
self._extended_config = config.get(CONF_EXTENDED_CONFIG, self._extended_config)

cidx: int = 0
for cidx, controller_config in enumerate(config[CONF_CONTROLLERS]):
Expand All @@ -5852,11 +5866,11 @@ def load(self, config: OrderedDict) -> "IUCoordinator":

return self

def as_dict(self) -> OrderedDict:
def as_dict(self, extended=False) -> OrderedDict:
"""Returns the coordinator as a dict"""
result = OrderedDict()
result[CONF_VERSION] = "1.0.0"
result[CONF_CONTROLLERS] = [ctr.as_dict() for ctr in self._controllers]
result[CONF_VERSION] = "1.0.1"
result[CONF_CONTROLLERS] = [ctr.as_dict(extended) for ctr in self._controllers]
return result

def muster(self, stime: datetime, force: bool) -> IURQStatus:
Expand Down Expand Up @@ -6182,7 +6196,7 @@ def service_call(
elif zone is not None:
zone.service_cancel(data1, stime)
else:
changed =controller.service_cancel(data1, stime)
changed = controller.service_cancel(data1, stime)
elif service == SERVICE_TIME_ADJUST:
render_positive_time_period(data1, CONF_ACTUAL)
render_positive_time_period(data1, CONF_INCREASE)
Expand Down
2 changes: 2 additions & 0 deletions custom_components/irrigation_unlimited/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
CONF_QUEUE_MANUAL,
CONF_USER,
CONF_TOGGLE,
CONF_EXTENDED_CONFIG,
)

IU_ID = r"^[a-z0-9]+(_[a-z0-9]+)*$"
Expand Down Expand Up @@ -364,6 +365,7 @@ def _parse_dd_mmm(value: str) -> date | None:
vol.Optional(CONF_TESTING): TEST_SCHEMA,
vol.Optional(CONF_HISTORY): HISTORY_SCHEMA,
vol.Optional(CONF_CLOCK): CLOCK_SCHEMA,
vol.Optional(CONF_EXTENDED_CONFIG): cv.boolean,
}
)

Expand Down
43 changes: 43 additions & 0 deletions tests/configs/test_coordinator_extended.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
irrigation_unlimited:
refresh_interval: 2000
extended_config: true
controllers:
- name: "Test controller 1"
zones:
- name: "Zone 1"
- name: "Zone 2"
- name: "Zibe 3"
enabled: false
sequences:
- name: "Sequence 1"
delay: "0:01:00"
schedules:
- time: '06:05'
weekday: [sun, wed, fri]
month: [jan, apr, jul, oct]
day: odd
zones:
- zone_id: 1
duration: "0:06:00"
- zone_id: 2
duration: "0:12:00"
- zone_id: 3
duration: "0:18:00"
testing:
enabled: true
output_events: false
show_log: false
autoplay: false
times:
- name: "1-Sequence 1"
start: "2024-01-21 06:00"
end: "2024-01-21 06:30"
results:
- {t: '2024-01-21 06:05:00', c: 1, z: 0, s: 1}
- {t: '2024-01-21 06:05:00', c: 1, z: 1, s: 1}
- {t: '2024-01-21 06:11:00', c: 1, z: 1, s: 0}
- {t: '2024-01-21 06:11:00', c: 1, z: 0, s: 0}
- {t: '2024-01-21 06:12:00', c: 1, z: 0, s: 1}
- {t: '2024-01-21 06:12:00', c: 1, z: 2, s: 1}
- {t: '2024-01-21 06:24:00', c: 1, z: 2, s: 0}
- {t: '2024-01-21 06:24:00', c: 1, z: 0, s: 0}
50 changes: 50 additions & 0 deletions tests/test_coordinator_entity.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test irrigation_unlimited coordinator entity operations."""
import json
from datetime import datetime
import homeassistant.core as ha
import homeassistant.util.dt as dt
Expand Down Expand Up @@ -92,3 +93,52 @@ async def test_coordinator_entity(
mk_local("2021-01-04 06:05:00"),
]
exam.check_summary()


async def test_coordinator_config_essential(
hass: ha.HomeAssistant, skip_dependencies, skip_history
):
"""Test coordinator configuration attribute essential keys."""

async with IUExam(hass, "test_coordinator_entity.yaml") as exam:
await exam.begin_test(1)

# Check essential keys are in configuration
config = json.loads(
hass.states.get("irrigation_unlimited.coordinator").attributes[
"configuration"
]
)

controller_keys = ("state", "index", "enabled", "suspended", "name")
zone_keys = ("state", "index", "enabled", "suspended", "adjustment", "name")
sequence_keys = ("state", "index", "enabled", "suspended", "adjustment", "name")
sqz_keys = ("state", "index", "enabled", "suspended", "adjustment")
assert len(config["controllers"]) > 0
for controller in config["controllers"]:
assert all(key in controller for key in controller_keys)
assert len(controller["zones"]) > 0
for zone in controller["zones"]:
assert all(key in zone for key in zone_keys)
assert len(controller["sequences"]) > 0
for sequence in controller["sequences"]:
assert all(key in sequence for key in sequence_keys)
assert len(sequence["sequence_zones"]) > 0
for sqz in sequence["sequence_zones"]:
assert all(key in sqz for key in sqz_keys)

await exam.finish_test()

exam.check_summary()


async def test_coordinator_config_extended(
hass: ha.HomeAssistant, skip_dependencies, skip_history
):
"""Test coordinator configuration attribute extended keys."""

async with IUExam(hass, "test_coordinator_extended.yaml") as exam:
await exam.begin_test(1)
await exam.finish_test()

exam.check_summary()

0 comments on commit f45bc36

Please sign in to comment.