Skip to content

Commit

Permalink
Add flow; volume to controller
Browse files Browse the repository at this point in the history
  • Loading branch information
rgc99 committed Oct 31, 2023
1 parent d035160 commit 6382705
Show file tree
Hide file tree
Showing 8 changed files with 1,842 additions and 1,173 deletions.
6 changes: 5 additions & 1 deletion custom_components/irrigation_unlimited/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
RES_NOT_RUNNING,
RES_NONE,
ATTR_VOLUME,
ATTR_FLOW_RATE,
)


Expand Down Expand Up @@ -134,7 +135,7 @@ def is_on(self):

@property
def should_poll(self):
"""Indicate that we nee to poll data"""
"""Indicate that we need to poll data"""
return False

@property
Expand Down Expand Up @@ -175,6 +176,8 @@ def extra_state_attributes(self):
else:
attr[ATTR_NEXT_SCHEDULE] = "deprecated (use next_zone)"
attr[ATTR_NEXT_ZONE] = RES_NONE
attr[ATTR_VOLUME] = self._controller.volume.total
attr[ATTR_FLOW_RATE] = self._controller.volume.flow_rate
attr |= self._controller.user
return attr

Expand Down Expand Up @@ -260,5 +263,6 @@ def extra_state_attributes(self):
if self._zone.show_timeline:
attr[ATTR_TIMELINE] = self._zone.timeline()
attr[ATTR_VOLUME] = self._zone.volume.total
attr[ATTR_FLOW_RATE] = self._zone.volume.flow_rate
attr |= self._zone.user
return attr
1 change: 1 addition & 0 deletions custom_components/irrigation_unlimited/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
ATTR_TICK_LOG = "tick_log"
ATTR_SUSPENDED = "suspended"
ATTR_VOLUME = "volume"
ATTR_FLOW_RATE = "flow_rate"
ATTR_SWITCH_ENTITIES = "switch_entity_id"

# Resources
Expand Down
60 changes: 46 additions & 14 deletions custom_components/irrigation_unlimited/irrigation_unlimited.py
Original file line number Diff line number Diff line change
Expand Up @@ -1519,23 +1519,40 @@ def call_switch(self, state: bool, stime: datetime = None) -> None:
class IUVolume:
"""Irrigation Unlimited Volume class"""

# pylint: disable=too-many-instance-attributes

def __init__(self, hass: HomeAssistant, coordinator: "IUCoordinator") -> None:
# Passed parameters
self._hass = hass
self._coordinator = coordinator
# Config parameters
self._sensor_id: str = None
self._rounding = 3
self._volume_rounding = 3
self._volume_scale = 1
self._flow_rounding = 3
self._flow_scale = 3600
# Private variables
self._callback_remove: CALLBACK_TYPE = None
self._start: float = None
self._total: float = None
self._start_volume: float = None
self._total_volume: float = None
self._start_time: datetime = None
self._duration: timedelta = None

@property
def total(self) -> str | None:
def total(self) -> float | None:
"""Return the total value"""
if self._total is not None:
return format(self._total, f".{self._rounding}f")
if self._total_volume is not None:
return round(self._total_volume * self._volume_scale, self._volume_rounding)
return None

@property
def flow_rate(self) -> str | None:
"""Return the flow rate"""
if self._total_volume is not None and self._duration is not None:
rate = (
self._total_volume * self._flow_scale / self._duration.total_seconds()
)
return round(rate, self._flow_rounding)
return None

def load(self, config: OrderedDict, all_zones: OrderedDict) -> "IUSwitch":
Expand All @@ -1545,7 +1562,7 @@ def load_params(config: OrderedDict) -> None:
if config is None:
return
self._sensor_id = config.get(CONF_ENTITY_ID, self._sensor_id)
self._rounding = config.get(CONF_PRECISION, self._rounding)
self._volume_rounding = config.get(CONF_PRECISION, self._volume_rounding)

if all_zones is not None:
load_params(all_zones.get(CONF_VOLUME))
Expand All @@ -1564,19 +1581,21 @@ def sensor_state_change(event: HAEvent):
value = float(sensor.state)
except ValueError:
return
self._total = value - self._start
self._total_volume = value - self._start_volume

self._start = self._total = None
self._start_volume = self._total_volume = None
self._start_time = self._duration = None
sensor = self._hass.states.get(self._sensor_id)
if sensor is not None:
try:
self._start = float(sensor.state)
self._start_volume = float(sensor.state)
except ValueError:
self._coordinator.logger.log_invalid_meter_value(stime, sensor.state)
else:
self._callback_remove = async_track_state_change_event(
self._hass, self._sensor_id, sensor_state_change
)
self._start_time = stime
else:
self._coordinator.logger.log_invalid_meter_id(stime, self._sensor_id)

Expand All @@ -1585,7 +1604,7 @@ def end_record(self, stime: datetime) -> None:
if self._callback_remove is not None:
self._callback_remove()
self._callback_remove = None
if self._start is not None:
if self._start_volume is not None:
sensor = self._hass.states.get(self._sensor_id)
if sensor is not None:
try:
Expand All @@ -1594,12 +1613,14 @@ def end_record(self, stime: datetime) -> None:
self._coordinator.logger.log_invalid_meter_value(
stime, sensor.state
)
self._total = None
self._total_volume = None
else:
self._total = value - self._start
self._total_volume = value - self._start_volume
self._duration = stime - self._start_time
else:
self._coordinator.logger.log_invalid_meter_id(stime, self._sensor_id)
self._total = None
self._total_volume = None
self._duration = None


class IUZone(IUBase):
Expand Down Expand Up @@ -3118,6 +3139,7 @@ def __init__(
self._sensor_update_required: bool = False
self._sensor_last_update: datetime = None
self._suspend_until: datetime = None
self._volume = IUVolume(hass, coordinator)
self._user = IUUser()
self._dirty: bool = True

Expand Down Expand Up @@ -3252,6 +3274,11 @@ def user(self) -> dict:
"""Return the arbitrary user information"""
return self._user

@property
def volume(self) -> IUVolume:
"""Return the volume for this zone"""
return self._volume

def _status(self) -> str:
"""Return status of the controller"""
if self._initialised:
Expand Down Expand Up @@ -3364,6 +3391,7 @@ def load(self, config: OrderedDict) -> "IUController":
self._sequences.clear()

self._switch.load(config, None)
self._volume.load(config, None)
self._user.load(config, None)
self._dirty = True
return self
Expand Down Expand Up @@ -3602,6 +3630,10 @@ def check_run(self, stime: datetime) -> bool:
self._is_on = not self._is_on
self.request_update(False)
self.call_switch(self._is_on, stime)
if self._is_on:
self._volume.start_record(stime)
else:
self._volume.end_record(stime)

# Handle on zones after master
for zone in (self._zones[i] for i in zones_changed):
Expand Down
1 change: 1 addition & 0 deletions custom_components/irrigation_unlimited/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ def _parse_dd_mmm(value: str) -> date | None:
vol.Optional(CONF_ALL_ZONES_CONFIG): vol.All(ALL_ZONES_SCHEMA),
vol.Optional(CONF_QUEUE_MANUAL): cv.boolean,
vol.Optional(CONF_CHECK_BACK): vol.All(CHECK_BACK_SCHEMA),
vol.Optional(CONF_VOLUME): vol.All(VOLUME_SCHEMA),
vol.Optional(CONF_USER): vol.All(USER_SCHEMA),
}
)
Expand Down
18 changes: 17 additions & 1 deletion tests/configs/test_volume.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ irrigation_unlimited:
show_log: false
autoplay: false
times:
- name: "1-Sequence 1"
- name: "1-Low level logging"
start: "2021-01-04 06:00"
end: "2021-01-04 07:00"
results:
Expand Down Expand Up @@ -138,3 +138,19 @@ irrigation_unlimited:
- {t: '2021-01-04 06:25', c: 1, z: 3, s: 1}
- {t: '2021-01-04 06:43', c: 1, z: 3, s: 0}
- {t: '2021-01-04 06:43', c: 1, z: 0, s: 0}
- name: "7-Sequence 1"
start: "2021-01-04 06:00"
end: "2021-01-04 07:00"
results:
- {t: '2021-01-04 06:05', c: 1, z: 0, s: 1}
- {t: '2021-01-04 06:05', c: 1, z: 1, s: 1}
- {t: '2021-01-04 06:11', c: 1, z: 1, s: 0}
- {t: '2021-01-04 06:11', c: 1, z: 0, s: 0}
- {t: '2021-01-04 06:12', c: 1, z: 0, s: 1}
- {t: '2021-01-04 06:12', c: 1, z: 2, s: 1}
- {t: '2021-01-04 06:24', c: 1, z: 2, s: 0}
- {t: '2021-01-04 06:24', c: 1, z: 0, s: 0}
- {t: '2021-01-04 06:25', c: 1, z: 0, s: 1}
- {t: '2021-01-04 06:25', c: 1, z: 3, s: 1}
- {t: '2021-01-04 06:43', c: 1, z: 3, s: 0}
- {t: '2021-01-04 06:43', c: 1, z: 0, s: 0}
118 changes: 60 additions & 58 deletions tests/configs/test_volume_extensive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ default_config:
homeassistant:
unit_system: metric
time_zone: Europe/Paris
name: Paris
name: Eiffel Tower
latitude: 48.864716
longitude: 2.349014
elevation: 0
Expand All @@ -12,11 +12,13 @@ homeassistant:
input_text:
dummy_sensor:
name: Dummy Sensor
initial: 236.064
initial: 259.485

irrigation_unlimited:
controllers:
- name: "Controleur 1"
volume:
entity_id: "input_text.dummy_sensor"
all_zones_config:
show:
timeline: true
Expand Down Expand Up @@ -96,11 +98,11 @@ irrigation_unlimited:
- zone_id: 5 # Un carré
duration: "00:20"
- zone_id: 6 # Petits fruits
duration: "00:30"
duration: "00:40"
- zone_id: 7 # Haie - Céanothe
duration: "00:40"
- zone_id: 8 # Pommiers
duration: "00:20"
duration: "00:30"
- zone_id: 10 # Haies pelouse
duration: "00:25"
- zone_id: 11 # If cour carrée
Expand Down Expand Up @@ -129,58 +131,58 @@ irrigation_unlimited:
autoplay: false
times:
- name: "1-Normal run"
start: "2023-09-26 21:55"
end: "2023-09-27 02:30"
start: "2023-10-13 21:55"
end: "2023-10-14 03:40"
results:
- {t: '2023-09-26 22:00:00', c: 1, z: 0, s: 1}
- {t: '2023-09-26 22:00:00', c: 1, z: 1, s: 1}
- {t: '2023-09-26 22:20:42', c: 1, z: 1, s: 0}
- {t: '2023-09-26 22:20:42', c: 1, z: 0, s: 0}
- {t: '2023-09-26 22:20:43', c: 1, z: 0, s: 1}
- {t: '2023-09-26 22:20:43', c: 1, z: 2, s: 1}
- {t: '2023-09-26 22:34:31', c: 1, z: 2, s: 0}
- {t: '2023-09-26 22:34:31', c: 1, z: 0, s: 0}
- {t: '2023-09-26 22:34:32', c: 1, z: 0, s: 1}
- {t: '2023-09-26 22:34:32', c: 1, z: 9, s: 1}
- {t: '2023-09-26 22:55:14', c: 1, z: 9, s: 0}
- {t: '2023-09-26 22:55:14', c: 1, z: 0, s: 0}
- {t: '2023-09-26 22:55:15', c: 1, z: 0, s: 1}
- {t: '2023-09-26 22:55:15', c: 1, z: 4, s: 1}
- {t: '2023-09-26 23:15:57', c: 1, z: 4, s: 0}
- {t: '2023-09-26 23:15:57', c: 1, z: 0, s: 0}
- {t: '2023-09-26 23:15:58', c: 1, z: 0, s: 1}
- {t: '2023-09-26 23:15:58', c: 1, z: 5, s: 1}
- {t: '2023-09-26 23:29:46', c: 1, z: 5, s: 0}
- {t: '2023-09-26 23:29:46', c: 1, z: 0, s: 0}
- {t: '2023-09-26 23:29:47', c: 1, z: 0, s: 1}
- {t: '2023-09-26 23:29:47', c: 1, z: 6, s: 1}
- {t: '2023-09-26 23:50:29', c: 1, z: 6, s: 0}
- {t: '2023-09-26 23:50:29', c: 1, z: 0, s: 0}
- {t: '2023-09-26 23:50:30', c: 1, z: 0, s: 1}
- {t: '2023-09-26 23:50:30', c: 1, z: 7, s: 1}
- {t: '2023-09-27 00:18:06', c: 1, z: 7, s: 0}
- {t: '2023-09-27 00:18:06', c: 1, z: 0, s: 0}
- {t: '2023-09-27 00:18:07', c: 1, z: 0, s: 1}
- {t: '2023-09-27 00:18:07', c: 1, z: 8, s: 1}
- {t: '2023-09-27 00:31:55', c: 1, z: 8, s: 0}
- {t: '2023-09-27 00:31:55', c: 1, z: 0, s: 0}
- {t: '2023-09-27 00:31:56', c: 1, z: 0, s: 1}
- {t: '2023-09-27 00:31:56', c: 1, z: 10, s: 1}
- {t: '2023-09-27 00:49:11', c: 1, z: 10, s: 0}
- {t: '2023-09-27 00:49:11', c: 1, z: 0, s: 0}
- {t: '2023-09-27 00:49:12', c: 1, z: 0, s: 1}
- {t: '2023-09-27 00:49:12', c: 1, z: 11, s: 1}
- {t: '2023-09-27 00:56:06', c: 1, z: 11, s: 0}
- {t: '2023-09-27 00:56:06', c: 1, z: 0, s: 0}
- {t: '2023-09-27 00:56:07', c: 1, z: 0, s: 1}
- {t: '2023-09-27 00:56:07', c: 1, z: 12, s: 1}
- {t: '2023-09-27 01:16:49', c: 1, z: 12, s: 0}
- {t: '2023-09-27 01:16:49', c: 1, z: 0, s: 0}
- {t: '2023-09-27 01:16:50', c: 1, z: 0, s: 1}
- {t: '2023-09-27 01:16:50', c: 1, z: 13, s: 1}
- {t: '2023-09-27 01:37:32', c: 1, z: 13, s: 0}
- {t: '2023-09-27 01:37:32', c: 1, z: 0, s: 0}
- {t: '2023-09-27 01:37:33', c: 1, z: 0, s: 1}
- {t: '2023-09-27 01:37:33', c: 1, z: 3, s: 1}
- {t: '2023-09-27 02:05:09', c: 1, z: 3, s: 0}
- {t: '2023-09-27 02:05:09', c: 1, z: 0, s: 0}
- {t: '2023-10-13 22:00:00', c: 1, z: 0, s: 1}
- {t: '2023-10-13 22:00:00', c: 1, z: 1, s: 1}
- {t: '2023-10-13 22:27:00', c: 1, z: 1, s: 0}
- {t: '2023-10-13 22:27:00', c: 1, z: 0, s: 0}
- {t: '2023-10-13 22:27:01', c: 1, z: 0, s: 1}
- {t: '2023-10-13 22:27:01', c: 1, z: 2, s: 1}
- {t: '2023-10-13 22:45:01', c: 1, z: 2, s: 0}
- {t: '2023-10-13 22:45:01', c: 1, z: 0, s: 0}
- {t: '2023-10-13 22:45:02', c: 1, z: 0, s: 1}
- {t: '2023-10-13 22:45:02', c: 1, z: 9, s: 1}
- {t: '2023-10-13 23:12:02', c: 1, z: 9, s: 0}
- {t: '2023-10-13 23:12:02', c: 1, z: 0, s: 0}
- {t: '2023-10-13 23:12:03', c: 1, z: 0, s: 1}
- {t: '2023-10-13 23:12:03', c: 1, z: 4, s: 1}
- {t: '2023-10-13 23:39:03', c: 1, z: 4, s: 0}
- {t: '2023-10-13 23:39:03', c: 1, z: 0, s: 0}
- {t: '2023-10-13 23:39:04', c: 1, z: 0, s: 1}
- {t: '2023-10-13 23:39:04', c: 1, z: 5, s: 1}
- {t: '2023-10-13 23:57:04', c: 1, z: 5, s: 0}
- {t: '2023-10-13 23:57:04', c: 1, z: 0, s: 0}
- {t: '2023-10-13 23:57:05', c: 1, z: 0, s: 1}
- {t: '2023-10-13 23:57:05', c: 1, z: 6, s: 1}
- {t: '2023-10-14 00:33:05', c: 1, z: 6, s: 0}
- {t: '2023-10-14 00:33:05', c: 1, z: 0, s: 0}
- {t: '2023-10-14 00:33:06', c: 1, z: 0, s: 1}
- {t: '2023-10-14 00:33:06', c: 1, z: 7, s: 1}
- {t: '2023-10-14 01:09:06', c: 1, z: 7, s: 0}
- {t: '2023-10-14 01:09:06', c: 1, z: 0, s: 0}
- {t: '2023-10-14 01:09:07', c: 1, z: 0, s: 1}
- {t: '2023-10-14 01:09:07', c: 1, z: 8, s: 1}
- {t: '2023-10-14 01:36:07', c: 1, z: 8, s: 0}
- {t: '2023-10-14 01:36:07', c: 1, z: 0, s: 0}
- {t: '2023-10-14 01:36:08', c: 1, z: 0, s: 1}
- {t: '2023-10-14 01:36:08', c: 1, z: 10, s: 1}
- {t: '2023-10-14 01:58:38', c: 1, z: 10, s: 0}
- {t: '2023-10-14 01:58:38', c: 1, z: 0, s: 0}
- {t: '2023-10-14 01:58:39', c: 1, z: 0, s: 1}
- {t: '2023-10-14 01:58:39', c: 1, z: 11, s: 1}
- {t: '2023-10-14 02:07:39', c: 1, z: 11, s: 0}
- {t: '2023-10-14 02:07:39', c: 1, z: 0, s: 0}
- {t: '2023-10-14 02:07:40', c: 1, z: 0, s: 1}
- {t: '2023-10-14 02:07:40', c: 1, z: 12, s: 1}
- {t: '2023-10-14 02:34:40', c: 1, z: 12, s: 0}
- {t: '2023-10-14 02:34:40', c: 1, z: 0, s: 0}
- {t: '2023-10-14 02:34:41', c: 1, z: 0, s: 1}
- {t: '2023-10-14 02:34:41', c: 1, z: 13, s: 1}
- {t: '2023-10-14 03:01:41', c: 1, z: 13, s: 0}
- {t: '2023-10-14 03:01:41', c: 1, z: 0, s: 0}
- {t: '2023-10-14 03:01:42', c: 1, z: 0, s: 1}
- {t: '2023-10-14 03:01:42', c: 1, z: 3, s: 1}
- {t: '2023-10-14 03:37:42', c: 1, z: 3, s: 0}
- {t: '2023-10-14 03:37:42', c: 1, z: 0, s: 0}
Loading

0 comments on commit 6382705

Please sign in to comment.