Skip to content

Commit

Permalink
Merge pull request #86 from basbruss/service_call
Browse files Browse the repository at this point in the history
Add auto position changes from within integration
  • Loading branch information
basbruss authored Apr 3, 2024
2 parents a66dd59 + d6dffe5 commit 9f9f44c
Show file tree
Hide file tree
Showing 14 changed files with 1,206 additions and 859 deletions.
2 changes: 1 addition & 1 deletion config/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ cover:
service: input_number.set_value
data:
entity_id: "input_number.cover_position_tilt"
value: "{{tilt}}"
value: "{{tilt}}"
17 changes: 7 additions & 10 deletions custom_components/adaptive_cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@
async_track_state_change,
)

from .blueprint import configure_blueprint
from .const import (
CONF_ENTITIES,
CONF_PRESENCE_ENTITY,
CONF_TEMP_ENTITY,
CONF_WEATHER_ENTITY,
DOMAIN,
)
from .coordinator import AdaptiveDataUpdateCoordinator

PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR]
PLATFORMS_SW = [Platform.SENSOR, Platform.SWITCH, Platform.BINARY_SENSOR]
CONF_ENTITIES = ["sun.sun"]
PLATFORMS = [Platform.SENSOR, Platform.SWITCH, Platform.BINARY_SENSOR]
CONF_SUN = ["sun.sun"]


async def async_initialize_integration(
Expand All @@ -42,10 +41,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_temp_entity = entry.options.get(CONF_TEMP_ENTITY)
_presence_entity = entry.options.get(CONF_PRESENCE_ENTITY)
_weather_entity = entry.options.get(CONF_WEATHER_ENTITY)
_cover_entities = entry.options.get(CONF_ENTITIES, [])
_entities = ["sun.sun"]
for entity in [_temp_entity, _presence_entity, _weather_entity]:
if entity is not None:
_entities.append(entity)
_entities += _cover_entities

entry.async_on_unload(
async_track_state_change(
Expand All @@ -58,19 +59,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = coordinator

configure_blueprint(hass=hass, config_entry=entry)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS_SW)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

entry.async_on_unload(entry.add_update_listener(_async_update_listener))
return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(
entry, PLATFORMS_SW
):
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok
Expand Down
25 changes: 0 additions & 25 deletions custom_components/adaptive_cover/blueprint.py

This file was deleted.

6 changes: 4 additions & 2 deletions custom_components/adaptive_cover/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ def sunset_valid(self) -> bool:
sunset = self.sun_data.sunset().replace(tzinfo=None)
sunrise = self.sun_data.sunrise().replace(tzinfo=None)
after_sunset = datetime.utcnow() > (sunset + timedelta(minutes=self.sunset_off))
before_sunrise = datetime.utcnow() < (sunrise - timedelta(minutes=self.sunset_off))
return (after_sunset and before_sunrise)
before_sunrise = datetime.utcnow() < (
sunrise + timedelta(minutes=self.sunset_off)
)
return after_sunset or before_sunrise

@property
def default(self) -> float:
Expand Down
155 changes: 118 additions & 37 deletions custom_components/adaptive_cover/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
from .const import (
CONF_AWNING_ANGLE,
CONF_AZIMUTH,
CONF_BLUEPRINT,
CONF_CLIMATE_MODE,
CONF_DEFAULT_HEIGHT,
CONF_DELTA_POSITION,
CONF_DELTA_TIME,
CONF_DISTANCE,
CONF_ENTITIES,
CONF_FOV_LEFT,
Expand All @@ -33,6 +34,8 @@
CONF_OUTSIDETEMP_ENTITY,
CONF_PRESENCE_ENTITY,
CONF_SENSOR_TYPE,
CONF_START_ENTITY,
CONF_START_TIME,
CONF_SUNSET_OFFSET,
CONF_SUNSET_POS,
CONF_TEMP_ENTITY,
Expand All @@ -55,8 +58,7 @@
CONFIG_SCHEMA = vol.Schema(
{
vol.Required("name"): selector.TextSelector(),
vol.Optional(CONF_BLUEPRINT, default=False): bool,
vol.Optional(CONF_MODE, default="basic"): selector.SelectSelector(
vol.Optional(CONF_MODE): selector.SelectSelector(
selector.SelectSelectorConfig(
options=SENSOR_TYPE_MENU, translation_key="mode"
)
Expand All @@ -73,71 +75,107 @@
OPTIONS = vol.Schema(
{
vol.Required(CONF_AZIMUTH, default=180): selector.NumberSelector(
selector.NumberSelectorConfig(min=0, max=359, mode="slider")
selector.NumberSelectorConfig(
min=0, max=359, mode="slider", unit_of_measurement="°"
)
),
vol.Required(CONF_DEFAULT_HEIGHT, default=60): selector.NumberSelector(
selector.NumberSelectorConfig(min=1, max=100, step=1, mode="slider")
selector.NumberSelectorConfig(
min=1, max=100, step=1, mode="slider", unit_of_measurement="%"
)
),
vol.Optional(CONF_MAX_POSITION, default=100): selector.NumberSelector(
selector.NumberSelectorConfig(min=1, max=100, step=1, mode="slider")
selector.NumberSelectorConfig(
min=1, max=100, step=1, mode="slider", unit_of_measurement="%"
)
),
vol.Required(CONF_FOV_LEFT, default=90): selector.NumberSelector(
selector.NumberSelectorConfig(min=1, max=90, step=1, mode="slider")
selector.NumberSelectorConfig(
min=1, max=90, step=1, mode="slider", unit_of_measurement="°"
)
),
vol.Required(CONF_FOV_RIGHT, default=90): selector.NumberSelector(
selector.NumberSelectorConfig(min=1, max=90, step=1, mode="slider")
selector.NumberSelectorConfig(
min=1, max=90, step=1, mode="slider", unit_of_measurement="°"
)
),
vol.Required(CONF_SUNSET_POS, default=0): selector.NumberSelector(
selector.NumberSelectorConfig(min=0, max=100, step=1, mode="slider")
selector.NumberSelectorConfig(
min=0, max=100, step=1, mode="slider", unit_of_measurement="%"
)
),
vol.Required(CONF_SUNSET_OFFSET, default=0): selector.NumberSelector(
selector.NumberSelectorConfig(mode="box")
),
vol.Optional(CONF_ENTITIES, default=[]): selector.EntitySelector(
selector.EntitySelectorConfig(domain="cover", multiple=True)
selector.NumberSelectorConfig(mode="box", unit_of_measurement="minutes")
),
vol.Required(CONF_INVERSE_STATE, default=False): bool,
}
)

VERTICAL_OPTIONS = vol.Schema(
{
vol.Optional(CONF_ENTITIES, default=[]): selector.EntitySelector(
selector.EntitySelectorConfig(
multiple=True,
filter=selector.EntityFilterSelectorConfig(
domain="cover",
supported_features=["cover.CoverEntityFeature.SET_POSITION"],
),
)
),
vol.Required(CONF_HEIGHT_WIN, default=2.1): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.1, max=6, step=0.01, mode="slider")
selector.NumberSelectorConfig(
min=0.1, max=6, step=0.01, mode="slider", unit_of_measurement="m"
)
),
vol.Required(CONF_DISTANCE, default=0.5): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.1, max=2, step=0.1, mode="slider")
selector.NumberSelectorConfig(
min=0.1, max=2, step=0.1, mode="slider", unit_of_measurement="m"
)
),
}
).extend(OPTIONS.schema)

TEST_OPTIONS = vol.Schema(
{
vol.Optional(CONF_BLUEPRINT, default=True): bool,
}
)

HORIZONTAL_OPTIONS = vol.Schema(
{
vol.Required(CONF_HEIGHT_AWNING, default=2.1): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.1, max=6, step=0.01, mode="slider")
selector.NumberSelectorConfig(
min=0.1, max=6, step=0.01, mode="slider", unit_of_measurement="m"
)
),
vol.Required(CONF_LENGTH_AWNING, default=2.1): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.3, max=6, step=0.01, mode="slider")
selector.NumberSelectorConfig(
min=0.3, max=6, step=0.01, mode="slider", unit_of_measurement="m"
)
),
vol.Required(CONF_AWNING_ANGLE, default=0): selector.NumberSelector(
selector.NumberSelectorConfig(min=0, max=45, mode="slider")
selector.NumberSelectorConfig(
min=0, max=45, mode="slider", unit_of_measurement="°"
)
),
}
).extend(VERTICAL_OPTIONS.schema)

TILT_OPTIONS = vol.Schema(
{
vol.Optional(CONF_ENTITIES, default=[]): selector.EntitySelector(
selector.EntitySelectorConfig(
multiple=True,
filter=selector.EntityFilterSelectorConfig(
domain="cover",
supported_features=["cover.CoverEntityFeature.SET_TILT_POSITION"],
),
)
),
vol.Required(CONF_TILT_DEPTH, default=3): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.1, max=15, step=0.1, mode="slider")
selector.NumberSelectorConfig(
min=0.1, max=15, step=0.1, mode="slider", unit_of_measurement="cm"
)
),
vol.Required(CONF_TILT_DISTANCE, default=2): selector.NumberSelector(
selector.NumberSelectorConfig(min=0.1, max=15, step=0.1, mode="slider")
selector.NumberSelectorConfig(
min=0.1, max=15, step=0.1, mode="slider", unit_of_measurement="cm"
)
),
vol.Required(CONF_TILT_MODE, default="mode2"): selector.SelectSelector(
selector.SelectSelectorConfig(
Expand All @@ -153,10 +191,14 @@
selector.EntityFilterSelectorConfig(domain=["climate", "sensor"])
),
vol.Required(CONF_TEMP_LOW, default=21): selector.NumberSelector(
selector.NumberSelectorConfig(min=0, max=86, step=1, mode="slider")
selector.NumberSelectorConfig(
min=0, max=86, step=1, mode="slider", unit_of_measurement="°"
)
),
vol.Required(CONF_TEMP_HIGH, default=25): selector.NumberSelector(
selector.NumberSelectorConfig(min=0, max=90, step=1, mode="slider")
selector.NumberSelectorConfig(
min=0, max=90, step=1, mode="slider", unit_of_measurement="°"
)
),
vol.Optional(
CONF_OUTSIDETEMP_ENTITY, default=vol.UNDEFINED
Expand Down Expand Up @@ -210,6 +252,26 @@
)


AUTOMATION_CONFIG = vol.Schema(
{
vol.Required(CONF_DELTA_POSITION, default=1): selector.NumberSelector(
selector.NumberSelectorConfig(
min=1, max=90, step=1, mode="slider", unit_of_measurement="%"
)
),
vol.Optional(CONF_DELTA_TIME, default=2): selector.NumberSelector(
selector.NumberSelectorConfig(
min=2, mode="box", unit_of_measurement="minutes"
)
),
vol.Optional(CONF_START_TIME, default="00:00:00"): selector.TimeSelector(),
vol.Optional(CONF_START_ENTITY): selector.EntitySelector(
selector.EntitySelectorConfig(domain=["sensor", "input_datetime"])
),
}
)


class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle ConfigFlow."""

Expand Down Expand Up @@ -243,9 +305,7 @@ async def async_step_vertical(self, user_input: dict[str, Any] | None = None):
self.type_blind = SensorType.BLIND
if user_input is not None:
self.config.update(user_input)
if self.config[CONF_CLIMATE_MODE] is True:
return await self.async_step_climate()
return await self.async_step_update()
return await self.async_step_automation()
return self.async_show_form(
step_id="vertical",
data_schema=CLIMATE_MODE.extend(VERTICAL_OPTIONS.schema),
Expand All @@ -256,9 +316,7 @@ async def async_step_horizontal(self, user_input: dict[str, Any] | None = None):
self.type_blind = SensorType.AWNING
if user_input is not None:
self.config.update(user_input)
if self.config[CONF_CLIMATE_MODE] is True:
return await self.async_step_climate()
return await self.async_step_update()
return await self.async_step_automation()
return self.async_show_form(
step_id="horizontal",
data_schema=CLIMATE_MODE.extend(HORIZONTAL_OPTIONS.schema),
Expand All @@ -269,13 +327,20 @@ async def async_step_tilt(self, user_input: dict[str, Any] | None = None):
self.type_blind = SensorType.TILT
if user_input is not None:
self.config.update(user_input)
if self.config[CONF_CLIMATE_MODE] is True:
return await self.async_step_climate()
return await self.async_step_update()
return await self.async_step_automation()
return self.async_show_form(
step_id="tilt", data_schema=CLIMATE_MODE.extend(TILT_OPTIONS.schema)
)

async def async_step_automation(self, user_input: dict[str, Any] | None = None):
"""Manage automation options."""
if user_input is not None:
self.config.update(user_input)
if self.config[CONF_CLIMATE_MODE] is True:
return await self.async_step_climate()
return await self.async_step_update()
return self.async_show_form(step_id="automation", data_schema=AUTOMATION_CONFIG)

async def async_step_climate(self, user_input: dict[str, Any] | None = None):
"""Manage climate options."""
if user_input is not None:
Expand Down Expand Up @@ -303,7 +368,6 @@ async def async_step_update(self, user_input: dict[str, Any] | None = None):
title=f"{type[self.type_blind]} {self.config['name']}",
data={
"name": self.config["name"],
CONF_BLUEPRINT: self.config[CONF_BLUEPRINT],
CONF_SENSOR_TYPE: self.type_blind,
},
options={
Expand Down Expand Up @@ -332,6 +396,10 @@ async def async_step_update(self, user_input: dict[str, Any] | None = None):
CONF_OUTSIDETEMP_ENTITY: self.config.get(CONF_OUTSIDETEMP_ENTITY),
CONF_CLIMATE_MODE: self.config.get(CONF_CLIMATE_MODE),
CONF_WEATHER_STATE: self.config.get(CONF_WEATHER_STATE),
CONF_DELTA_POSITION: self.config.get(CONF_DELTA_POSITION),
CONF_DELTA_TIME: self.config.get(CONF_DELTA_TIME),
CONF_START_TIME: self.config.get(CONF_START_TIME),
CONF_START_ENTITY: self.config.get(CONF_START_ENTITY),
},
)

Expand All @@ -353,6 +421,19 @@ async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Manage the options."""
return self.async_show_menu(
step_id="init", menu_options=["automation", "blind"]
)

async def async_step_automation(self, user_input: dict[str, Any] | None = None):
"""Manage automation options."""
if user_input is not None:
self.options.update(user_input)
return await self._update_options()
return self.async_show_form(step_id="automation", data_schema=AUTOMATION_CONFIG)

async def async_step_blind(self, user_input: dict[str, Any] | None = None):
"""Adjust blind parameters."""
if self.sensor_type == SensorType.BLIND:
return await self.async_step_vertical()
if self.sensor_type == SensorType.AWNING:
Expand Down
Loading

0 comments on commit 9f9f44c

Please sign in to comment.