diff --git a/README.md b/README.md
index 8ba9df2..5297c1f 100755
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Wiser Home Assistant Integration v3.4.1
+# Wiser Home Assistant Integration v3.4.2
[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/hacs/integration)
[![downloads](https://shields.io/github/downloads/asantaga/wiserHomeAssistantPlatform/latest/total?style=for-the-badge)](https://github.com/asantaga/wiserHomeAssistantPlatform)
@@ -10,6 +10,8 @@ It also supports some European versions of the Wiser Hub under the Schneider Ele
For the latest version of the Wiser Home Assistant Platform please install via HACS. If you want bleeding edge then checkout the dev branch, or look out for beta releases via HACS. Depending on what you choose you may need to use the Manual Code Installation as described in the Wiki.
+**This integration requires a minimum HA version of 2023.12.**
+
Detailed information about this integration has now been moved to our [Wiki pages](https://github.com/asantaga/wiserHomeAssistantPlatform/wiki)
For more information checkout the AMAZING community thread available on
@@ -22,6 +24,15 @@ For more information checkout the AMAZING community thread available on
## Change log
+- v3.4.2
+ - Reverted to using aiohttp for communication and resolved issues caused by HA2023.12
+ - Bumped api to v1.5.5
+ - Fixed issue where hub communication would error due to command characters in payload (issue [#418](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/418))
+ - Updated schedule card to allow hiding of hot water schedule (issue [#415](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/415))
+ - Included version in card resources to improve updating of new versions
+ - Added more v2 hub features and attributes
+ - Improved error handling/logging when hub offline and command is issued
+
- v3.4.1
- Corrected error deleting schedule
- Handle space at end of secret key and prevent error (issue [#409](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/409))
diff --git a/custom_components/wiser/__init__.py b/custom_components/wiser/__init__.py
index bddd562..11758d9 100755
--- a/custom_components/wiser/__init__.py
+++ b/custom_components/wiser/__init__.py
@@ -67,7 +67,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry):
# Register custom cards
cards = WiserCardRegistration(hass)
await cards.async_register()
- await cards.async_remove_gzip_files()
_LOGGER.info(
f"Wiser Component Setup Completed ({coordinator.wiserhub.system.name})"
diff --git a/custom_components/wiser/button.py b/custom_components/wiser/button.py
index 6f6099e..08ea467 100644
--- a/custom_components/wiser/button.py
+++ b/custom_components/wiser/button.py
@@ -6,7 +6,7 @@
from homeassistant.util import dt as dt_util
from homeassistant.helpers.update_coordinator import CoordinatorEntity
-from .helpers import get_device_name, get_unique_id, get_identifier
+from .helpers import get_device_name, get_unique_id, get_identifier, hub_error_handler
from .const import (
DATA,
@@ -90,6 +90,7 @@ class WiserBoostAllHeatingButton(WiserButton):
def __init__(self, data) -> None:
super().__init__(data, "Boost All Heating")
+ @hub_error_handler
async def async_press(self):
boost_time = self._data.boost_time
boost_temp = self._data.boost_temp
@@ -105,6 +106,7 @@ class WiserCancelHeatingOverridesButton(WiserButton):
def __init__(self, data) -> None:
super().__init__(data, "Cancel All Heating Overrides")
+ @hub_error_handler
async def async_press(self):
await self._data.wiserhub.system.cancel_all_overrides()
await self.async_force_update()
@@ -118,6 +120,7 @@ class WiserBoostHotWaterButton(WiserButton):
def __init__(self, data) -> None:
super().__init__(data, "Boost Hot Water")
+ @hub_error_handler
async def async_press(self):
boost_time = self._data.hw_boost_time
await self._data.wiserhub.hotwater.boost(boost_time)
@@ -132,6 +135,7 @@ class WiserCancelHotWaterOverridesButton(WiserButton):
def __init__(self, data) -> None:
super().__init__(data, "Cancel Hot Water Overrides")
+ @hub_error_handler
async def async_press(self):
await self._data.wiserhub.hotwater.cancel_overrides()
await self.async_force_update()
@@ -145,6 +149,7 @@ class WiserOverrideHotWaterButton(WiserButton):
def __init__(self, data) -> None:
super().__init__(data, "Toggle Hot Water")
+ @hub_error_handler
async def async_press(self):
await self._data.wiserhub.hotwater.override_state(
"Off" if self._data.wiserhub.hotwater.current_state == "On" else "On"
@@ -163,6 +168,7 @@ def __init__(self, data, moment_id) -> None:
data, f"Moments {data.wiserhub.moments.get_by_id(moment_id).name}"
)
+ @hub_error_handler
async def async_press(self):
await self._data.wiserhub.moments.get_by_id(self._moment_id).activate()
await self.async_force_update()
diff --git a/custom_components/wiser/climate.py b/custom_components/wiser/climate.py
index fa197c8..67b8e76 100755
--- a/custom_components/wiser/climate.py
+++ b/custom_components/wiser/climate.py
@@ -32,6 +32,7 @@
from .helpers import (
get_device_name,
get_identifier,
+ hub_error_handler,
)
from .schedules import WiserScheduleEntity
@@ -207,6 +208,7 @@ def name(self):
"""Return Name of device."""
return f"{get_device_name(self._data, self._actuator_id)} Floor Temp"
+ @hub_error_handler
async def async_set_temperature(self, **kwargs) -> None:
"""Set new target temperature."""
if (
@@ -353,6 +355,7 @@ def hvac_modes(self):
"""Return the list of available operation modes."""
return self._hvac_modes_list
+ @hub_error_handler
async def async_set_hvac_mode(self, hvac_mode):
"""Set new operation mode."""
_LOGGER.debug(f"Setting HVAC mode to {hvac_mode} for {self._room.name}")
@@ -399,6 +402,7 @@ def preset_modes(self):
"""Return the list of available preset modes."""
return self._room.available_presets
+ @hub_error_handler
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Async call to set preset mode ."""
_LOGGER.debug(f"Setting Preset Mode {preset_mode} for {self._room.name}")
@@ -452,6 +456,51 @@ def extra_state_attributes(self):
attrs["control_direction"] = self._room.control_direction
attrs["displayed_setpoint"] = self._room.displayed_setpoint
+ # Added by LGO
+ # Climate capabilities only with Hub Vé
+ if self._room.capabilities:
+ attrs["heating_supported"] = self._room.capabilities.heating_supported
+ attrs["cooling_supported"] = self._room.capabilities.cooling_supported
+ attrs[
+ "minimum_heat_set_point"
+ ] = self._room.capabilities.minimum_heat_set_point
+ attrs[
+ "maximum_heat_set_point"
+ ] = self._room.capabilities.maximum_heat_set_point
+ attrs[
+ "minimum_cool_set_point"
+ ] = self._room.capabilities.minimum_cool_set_point
+ attrs[
+ "maximum_cool_set_point"
+ ] = self._room.capabilities.maximum_cool_set_point
+ attrs["setpoint_step"] = self._room.capabilities.setpoint_step
+ attrs["ambient_temperature"] = self._room.capabilities.ambient_temperature
+ attrs["temperature_control"] = self._room.capabilities.temperature_control
+ attrs[
+ "open_window_detection"
+ ] = self._room.capabilities.open_window_detection
+ attrs[
+ "hydronic_channel_selection"
+ ] = self._room.capabilities.hydronic_channel_selection
+ attrs["on_off_supported"] = self._room.capabilities.on_off_supported
+
+ # Summer comfort
+
+ attrs["include_in_summer_comfort"] = self._room.include_in_summer_comfort
+ attrs["floor_sensor_state"] = self._room.floor_sensor_state
+
+ # occupancy
+
+ attrs["occupancy_capable"] = self._room.occupancy_capable
+ if self._room.occupancy_capable:
+ attrs["occupancy"] = self._room.occupancy
+ attrs["occupied_heating_set_point"] = self._room.occupied_heating_set_point
+ attrs[
+ "unoccupied_heating_set_point"
+ ] = self._room.unoccupied_heating_set_point
+
+ # End Added by LGO
+
# Room can have no schedule
if self._room.schedule:
attrs["schedule_id"] = self._room.schedule.id
@@ -507,6 +556,7 @@ def target_temperature_low(self) -> float | None:
"""
return self._room.passive_mode_lower_temp
+ @hub_error_handler
async def async_set_temperature(self, **kwargs):
"""Set new target temperatures."""
if self._room.is_passive_mode and not self._room.is_boosted:
@@ -553,6 +603,7 @@ def unique_id(self):
f"{self._data.wiserhub.system.name}-WiserRoom-{self._room_id}-{self.name}"
)
+ @hub_error_handler
@callback
async def async_boost_heating(
self, time_period: int, temperature_delta=0, temperature=0
diff --git a/custom_components/wiser/const.py b/custom_components/wiser/const.py
index f3c5c05..9722143 100755
--- a/custom_components/wiser/const.py
+++ b/custom_components/wiser/const.py
@@ -5,12 +5,24 @@
Angelosantagata@gmail.com
"""
+VERSION = "3.4.1"
DOMAIN = "wiser"
DATA_WISER_CONFIG = "wiser_config"
URL_BASE = "/wiser"
-WISER_CARD_FILENAMES = ["wiser-schedule-card.js", "wiser-zigbee-card.js"]
-VERSION = "3.4.1"
+WISER_CARDS = [
+ {
+ "name": "Wiser Schedule Card",
+ "filename": "wiser-schedule-card.js",
+ "version": "1.3.3",
+ },
+ {
+ "name": "Wiser Zigbee Card",
+ "filename": "wiser-zigbee-card.js",
+ "version": "2.1.1",
+ },
+]
+
WISER_PLATFORMS = [
"climate",
"sensor",
diff --git a/custom_components/wiser/coordinator.py b/custom_components/wiser/coordinator.py
index f9f54d8..fd877f0 100644
--- a/custom_components/wiser/coordinator.py
+++ b/custom_components/wiser/coordinator.py
@@ -1,43 +1,36 @@
+from dataclasses import dataclass
from datetime import datetime, timedelta
import logging
-from dataclasses import dataclass
-
-from homeassistant.config_entries import ConfigEntry
-
-from homeassistant.core import HomeAssistant
-from homeassistant.helpers.dispatcher import async_dispatcher_send
-from homeassistant.helpers.aiohttp_client import async_get_clientsession
-from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
-
-from homeassistant.const import (
- CONF_HOST,
- CONF_PASSWORD,
- CONF_SCAN_INTERVAL,
-)
from aioWiserHeatAPI.wiserhub import (
- TEMP_MINIMUM,
TEMP_MAXIMUM,
+ TEMP_MINIMUM,
WiserAPI,
- WiserHubConnectionError,
WiserHubAuthenticationError,
+ WiserHubConnectionError,
WiserHubRESTError,
)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.dispatcher import async_dispatcher_send
+from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
+
from .const import (
CONF_AUTOMATIONS_PASSIVE,
CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT,
- CONF_RESTORE_MANUAL_TEMP_OPTION,
- CONF_SETPOINT_MODE,
- CUSTOM_DATA_STORE,
- DEFAULT_PASSIVE_TEMP_INCREMENT,
- DEFAULT_SETPOINT_MODE,
CONF_HEATING_BOOST_TEMP,
CONF_HEATING_BOOST_TIME,
CONF_HW_BOOST_TIME,
+ CONF_RESTORE_MANUAL_TEMP_OPTION,
+ CONF_SETPOINT_MODE,
+ CUSTOM_DATA_STORE,
DEFAULT_BOOST_TEMP,
DEFAULT_BOOST_TEMP_TIME,
+ DEFAULT_PASSIVE_TEMP_INCREMENT,
DEFAULT_SCAN_INTERVAL,
+ DEFAULT_SETPOINT_MODE,
DOMAIN,
MIN_SCAN_INTERVAL,
)
@@ -119,7 +112,6 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
self.wiserhub = WiserAPI(
host=config_entry.data[CONF_HOST],
secret=str(config_entry.data[CONF_PASSWORD]).strip(),
- session=async_get_clientsession(hass),
extra_config_file=hass.config.config_dir + CUSTOM_DATA_STORE,
enable_automations=self.enable_automations_passive_mode,
)
diff --git a/custom_components/wiser/cover.py b/custom_components/wiser/cover.py
index 1d31d1c..caf43f8 100644
--- a/custom_components/wiser/cover.py
+++ b/custom_components/wiser/cover.py
@@ -15,19 +15,13 @@
CoverEntity,
CoverEntityFeature,
)
-
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
+from .const import DATA, DOMAIN, MANUFACTURER_SCHNEIDER
+from .helpers import get_device_name, get_identifier, hub_error_handler
from .schedules import WiserScheduleEntity
-from .const import (
- DATA,
- DOMAIN,
- MANUFACTURER_SCHNEIDER,
-)
-from .helpers import get_device_name, get_identifier
-
MANUFACTURER = MANUFACTURER_SCHNEIDER
_LOGGER = logging.getLogger(__name__)
@@ -39,7 +33,12 @@
| CoverEntityFeature.STOP
)
-TILT_SUPPORT_FLAGS = (CoverEntityFeature.OPEN_TILT | CoverEntityFeature.CLOSE_TILT | CoverEntityFeature.SET_TILT_POSITION | CoverEntityFeature.STOP_TILT)
+TILT_SUPPORT_FLAGS = (
+ CoverEntityFeature.OPEN_TILT
+ | CoverEntityFeature.CLOSE_TILT
+ | CoverEntityFeature.SET_TILT_POSITION
+ | CoverEntityFeature.STOP_TILT
+)
async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities):
@@ -83,7 +82,7 @@ def _handle_coordinator_update(self) -> None:
@property
def supported_features(self):
"""Flag supported features."""
- if self._device.is_tilt_supported:
+ if self._device.drive_config.tilt_enabled:
return SUPPORT_FLAGS + TILT_SUPPORT_FLAGS
return SUPPORT_FLAGS
@@ -94,7 +93,9 @@ def device_info(self):
"name": get_device_name(self._data, self._device_id),
"identifiers": {(DOMAIN, get_identifier(self._data, self._device_id))},
"manufacturer": MANUFACTURER,
- "model": self._data.wiserhub.devices.get_by_id(self._device_id).product_type,
+ "model": self._data.wiserhub.devices.get_by_id(
+ self._device_id
+ ).product_type,
"via_device": (DOMAIN, self._data.wiserhub.system.name),
}
@@ -116,7 +117,9 @@ def current_cover_position(self):
@property
def current_cover_tilt_position(self) -> int | None:
"""Return current position of cover tilt."""
- return self._device.current_tilt
+ """ If tilt feauture is enabled"""
+ if self._device.drive_config.tilt_enabled:
+ return self._device.current_tilt
@property
def is_closed(self):
@@ -159,6 +162,10 @@ def extra_state_attributes(self):
# Settings
attrs["shutter_id"] = self._device_id
+ # features supported
+ attrs["is_lift_position_supported"] = self._device.is_lift_position_supported
+ attrs["is_tilt_supported"] = self._device.is_tilt_supported
+
attrs["away_mode_action"] = self._device.away_mode_action
attrs["mode"] = self._device.mode
attrs["lift_open_time"] = self._device.drive_config.open_time
@@ -184,7 +191,7 @@ def extra_state_attributes(self):
attrs["target_lift"] = self._device.target_lift
attrs["scheduled_lift"] = self._device.scheduled_lift
- if self._device.is_tilt_supported:
+ if self._device.drive_config.tilt_enabled:
# Tilt settings
attrs["current_tilt"] = self._device.current_tilt
attrs["manual_tilt"] = self._device.manual_tilt
@@ -194,6 +201,11 @@ def extra_state_attributes(self):
attrs["tilt_angle_open"] = self._device.drive_config.tilt_angle_open
attrs["tilt_movement"] = self._device.tilt_movement
+ # Summer comfort Added LGO
+ attrs["respect_summer_comfort"] = self._device.respect_summer_comfort
+ attrs["summer_comfort_lift"] = self._device.summer_comfort_lift
+ attrs["summer_comfort_tilt"] = self._device.summer_comfort_tilt
+
# Schedule
attrs["schedule_id"] = self._device.schedule_id
if self._device.schedule:
@@ -205,6 +217,7 @@ def extra_state_attributes(self):
return attrs
+ @hub_error_handler
async def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position."""
position = kwargs[ATTR_POSITION]
@@ -212,24 +225,28 @@ async def async_set_cover_position(self, **kwargs):
await self._device.open(position)
await self.async_force_update()
+ @hub_error_handler
async def async_close_cover(self, **kwargs):
- """Close shutter"""
+ """Close shutter."""
_LOGGER.debug(f"Closing {self.name}")
await self._device.close()
await self.async_force_update()
+ @hub_error_handler
async def async_open_cover(self, **kwargs):
- """Close shutter"""
+ """Open shutter."""
_LOGGER.debug(f"Opening {self.name}")
await self._device.open()
await self.async_force_update()
+ @hub_error_handler
async def async_stop_cover(self, **kwargs):
- """Stop shutter"""
+ """Stop shutter."""
_LOGGER.debug(f"Stopping {self.name}")
await self._device.stop()
await self.async_force_update()
+ @hub_error_handler
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
"""Move the cover tilt to a specific position."""
position = kwargs[ATTR_TILT_POSITION]
@@ -237,19 +254,22 @@ async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
await self._device.open_tilt(position)
await self.async_force_update()
+ @hub_error_handler
async def async_close_cover_tilt(self, **kwargs):
- """Close shutter"""
+ """Close shutter tilt."""
_LOGGER.debug(f"Closing tilt {self.name}")
await self._device.close_tilt()
await self.async_force_update()
+ @hub_error_handler
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
- """Open the cover tilt."""
+ """Open shutter tilt."""
await self._device.open_tilt()
await self.async_force_update()
+ @hub_error_handler
async def async_stop_cover_tilt(self, **kwargs):
- """Stop shutter"""
+ """Stop shutter tilt."""
_LOGGER.debug(f"Stopping tilt {self.name}")
await self._device.stop_tilt()
await self.async_force_update()
diff --git a/custom_components/wiser/frontend/__init__.py b/custom_components/wiser/frontend/__init__.py
index 651994b..3f0fb2c 100644
--- a/custom_components/wiser/frontend/__init__.py
+++ b/custom_components/wiser/frontend/__init__.py
@@ -4,7 +4,7 @@
from homeassistant.helpers.event import async_call_later
-from ..const import URL_BASE, WISER_CARD_FILENAMES
+from ..const import URL_BASE, WISER_CARDS
_LOGGER = logging.getLogger(__name__)
@@ -20,7 +20,7 @@ async def async_register(self):
# install card resources
async def async_register_wiser_path(self):
- # Register custom cards path
+ # Register custom cards path if not already registered
self.hass.http.register_static_path(
URL_BASE,
self.hass.config.path("custom_components/wiser/frontend"),
@@ -41,29 +41,76 @@ async def check_lovelace_resources_loaded(now):
async def async_register_wiser_cards(self):
_LOGGER.debug("Installing Lovelace resources for Wiser cards")
- for card_filename in WISER_CARD_FILENAMES:
- url = f"{URL_BASE}/{card_filename}"
- resource_loaded = [
- res["url"]
- for res in self.hass.data["lovelace"]["resources"].async_items()
- if res["url"] == url
- ]
- if not resource_loaded:
- resource_id = await self.hass.data["lovelace"][
- "resources"
- ].async_create_item({"res_type": "module", "url": url})
+
+ # Get resources already registered
+ wiser_resources = [
+ resource
+ for resource in self.hass.data["lovelace"]["resources"].async_items()
+ if resource["url"].startswith(URL_BASE)
+ ]
+
+ for card in WISER_CARDS:
+ url = f"{URL_BASE}/{card.get('filename')}"
+
+ card_registered = False
+
+ for res in wiser_resources:
+ if self.get_resource_path(res["url"]) == url:
+ card_registered = True
+ # check version
+ if self.get_resource_version(res["url"]) != card.get("version"):
+ # Update card version
+ _LOGGER.debug(
+ "Updating %s to version %s",
+ card.get("name"),
+ card.get("version"),
+ )
+ await self.hass.data["lovelace"]["resources"].async_update_item(
+ res.get("id"),
+ {
+ "res_type": "module",
+ "url": url + "?v=" + card.get("version"),
+ },
+ )
+ # Remove old gzipped files
+ await self.async_remove_gzip_files()
+ else:
+ _LOGGER.debug(
+ "%s already registered as version %s",
+ card.get("name"),
+ card.get("version"),
+ )
+
+ if not card_registered:
+ _LOGGER.debug(
+ "Registering %s as version %s",
+ card.get("name"),
+ card.get("version"),
+ )
+ await self.hass.data["lovelace"]["resources"].async_create_item(
+ {"res_type": "module", "url": url + "?v=" + card.get("version")}
+ )
+
+ def get_resource_path(self, url: str):
+ return url.split("?")[0]
+
+ def get_resource_version(self, url: str):
+ try:
+ return url.split("?")[1].replace("v=", "")
+ except Exception:
+ return 0
async def async_unregister(self):
# Unload lovelace module resource
if self.hass.data["lovelace"]["mode"] == "storage":
- for card_filename in WISER_CARD_FILENAMES:
- url = f"{URL_BASE}/{card_filename}"
+ for card in WISER_CARDS:
+ url = f"{URL_BASE}/{card.get('filename')}"
wiser_resources = [
resource
for resource in self.hass.data["lovelace"][
"resources"
].async_items()
- if resource["url"] == url
+ if str(resource["url"]).startswith(url)
]
for resource in wiser_resources:
await self.hass.data["lovelace"]["resources"].async_delete_item(
@@ -83,5 +130,5 @@ async def async_remove_gzip_files(self):
):
_LOGGER.debug(f"Removing older gzip file - {file}")
os.remove(f"{path}/{file}")
- except:
+ except Exception:
pass
diff --git a/custom_components/wiser/frontend/wiser-schedule-card.js b/custom_components/wiser/frontend/wiser-schedule-card.js
index cf5c44c..dce875f 100644
--- a/custom_components/wiser/frontend/wiser-schedule-card.js
+++ b/custom_components/wiser/frontend/wiser-schedule-card.js
@@ -81,7 +81,7 @@ const he=e=>t=>"function"==typeof t?((e,t)=>(customElements.define(e,t),t))(e,t)
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
-function ye(e,t,i){let o,n=e;return"object"==typeof e?(n=e.slot,o=e):o={flatten:t},i?function(e){const{slot:t,selector:i}=null!=e?e:{};return fe({descriptor:o=>({get(){var o;const n="slot"+(t?`[name=${t}]`:":not([name])"),r=null===(o=this.renderRoot)||void 0===o?void 0:o.querySelector(n),d=null!=r?xe(r,e):[];return i?d.filter((e=>e.matches(i))):d},enumerable:!0,configurable:!0})})}({slot:n,flatten:t,selector:i}):fe({descriptor:e=>({get(){var e,t;const i="slot"+(n?`[name=${n}]`:":not([name])"),r=null===(e=this.renderRoot)||void 0===e?void 0:e.querySelector(i);return null!==(t=null==r?void 0:r.assignedNodes(o))&&void 0!==t?t:[]},enumerable:!0,configurable:!0})})}var we,Ee;!function(e){e.language="language",e.system="system",e.comma_decimal="comma_decimal",e.decimal_comma="decimal_comma",e.space_comma="space_comma",e.none="none"}(we||(we={})),function(e){e.language="language",e.system="system",e.am_pm="12",e.twenty_four="24"}(Ee||(Ee={}));var Se=function(e,t,i,o){o=o||{},i=null==i?{}:i;var n=new Event(t,{bubbles:void 0===o.bubbles||o.bubbles,cancelable:Boolean(o.cancelable),composed:void 0===o.composed||o.composed});return n.detail=i,e.dispatchEvent(n),n};function Ce(e,t,i){if(t.has("config")||i)return!0;if(e.config.entity){var o=t.get("hass");return!o||o.states[e.config.entity]!==e.hass.states[e.config.entity]}return!1}const Ae="1.3.2",Ie=86400;var Te,Oe,$e,ke;!function(e){e.Heating="mdi:radiator",e.OnOff="mdi:power-socket-uk",e.Shutters="mdi:blinds",e.Lighting="mdi:lightbulb-outline"}(Te||(Te={})),function(e){e.Overview="OVERVIEW",e.ScheduleEdit="SCHEDULE_EDIT",e.ScheduleCopy="SCHEDULE_COPY",e.ScheduleAdd="SCHEDULE_ADD",e.ScheduleRename="SCHEDULE_RENAME"}(Oe||(Oe={})),function(e){e.Heating="19",e.OnOff="Off",e.Lighting="0",e.Shutters="100"}($e||($e={})),function(e){e.Heating="°C",e.OnOff="",e.Lighting="%",e.Shutters="%"}(ke||(ke={}));const Re=["Heating","OnOff","Lighting","Shutters"],Le=["Lighting","Shutters"],De=["Weekdays","Weekend"],Fe=["Monday","Tuesday","Wednesday","Thursday","Friday"],Me=["Saturday","Sunday"],Ne=Fe.concat(Me),ze=["Sunrise","Sunset"];var Pe;!function(e){e.Sunrise="3000",e.Sunset="4000"}(Pe||(Pe={}));var He={version:"Version",invalid_configuration:"Invalid configuration",no_schedules:"No Schedules Found",name_required:"Name is required"},Be={actions:{copy:"Copy",files:"Files",rename:"Rename",add:"Add",view:"View",add_schedule:"Add Schedule"},labels:{setting:"Setting",name:"Name",assigns:"Assigns",start:"Start",end:"End",to:"to"},days:{monday:"Monday",tuesday:"Tuesday",wednesday:"Wednesday",thursday:"Thursday",friday:"Friday",saturday:"Saturday",sunday:"Sunday",weekdays:"Weekdays",weekend:"Weekend",all:"All",short:{monday:"Mon",tuesday:"Tue",wednesday:"Wed",thursday:"Thu",friday:"Fri",saturday:"Sat",sunday:"Sun"}},headings:{schedule_actions:"Schedule Actions",schedule_type:"Schedule Type",schedule_id:"Schedule Id",schedule_name:"Schedule Name",schedule_assignment:"Schedule Assignment",not_assigned:"(Not Assigned)",rename_schedule:"Rename Schedule",copy_schedule:"Copy Schedule",delete_schedule:"Delete Schedule"},helpers:{enter_new_name:"Enter the new name for the Schedule",select_copy_schedule:"Select the schedule below to copy to",delete_schedule_confirm:"Are you sure you wish to delete the schedule",select_a_schedule:"Select a schedule to view",add_schedule:"Select the schedule type and enter a name for the schedule to create"}},Ve={common:He,wiser:Be},Ue={version:"Déclinaison",invalid_configuration:"Configuration Invalide",no_schedules:"Aucun Programme Trouvé",name_required:"Nom est obligatoire"},je={actions:{copy:"Copie",files:"Fichier",rename:"Renommer",add:"Ajouter",view:"Voir",add_schedule:"Ajouter un Programme"},labels:{setting:"Paramètre",name:"Nom",assigns:"Attribuers",start:"Début",end:"Fin",to:"à"},days:{monday:"Lundi",tuesday:"Mardi",wednesday:"Mercredi",thursday:"Jeudi",friday:"Vendredi",saturday:"Samedi",sunday:"Dimanche",weekdays:"Lun à Ven",weekend:"Sam et Dim",all:"Toute",short:{monday:"Lun",tuesday:"Mar",wednesday:"Mer",thursday:"Jeu",friday:"Ven",saturday:"Sam",sunday:"Dim"}},headings:{schedule_actions:"Programmer des Actions",schedule_type:"Type de Programme",schedule_id:"Numéro de Programme",schedule_name:"Nom de Programme",schedule_assignment:"Attribuer de Programme",not_assigned:"(Non Attribué)",rename_schedule:"Renommer le Programme",copy_schedule:"Copier le Programme",delete_schedule:"Supprimer le Programme"},helpers:{enter_new_name:"Entrez un nom pour le Programme",select_copy_schedule:"Sélectionnez le calendrier ci-dessous pour le copier",delete_schedule_confirm:"Êtes-vous sûr de vouloir effacer ce programme",select_a_schedule:"Sélectionner un programme à afficher",add_schedule:"Sélectionnez le type de programme et entrez un nom pour la programme à créer"}},We={common:Ue,wiser:je};const Ye={en:Object.freeze({__proto__:null,common:He,wiser:Be,default:Ve}),fr:Object.freeze({__proto__:null,common:Ue,wiser:je,default:We})};function Ge(e,t="",i=""){const o=(localStorage.getItem("selectedLanguage")||"en").replace(/['"]+/g,"").replace("-","_");let n;try{n=e.split(".").reduce(((e,t)=>e[t]),Ye[o]),n||(n=e.split(".").reduce(((e,t)=>e[t]),Ye.en))}catch(t){try{n=e.split(".").reduce(((e,t)=>e[t]),Ye.en)}catch(e){n=""}}return void 0===n&&(n=e.split(".").reduce(((e,t)=>e[t]),Ye.en)),""!==t&&""!==i&&(n=n.replace(t,i)),n}const Xe=h`
+function ye(e,t,i){let o,n=e;return"object"==typeof e?(n=e.slot,o=e):o={flatten:t},i?function(e){const{slot:t,selector:i}=null!=e?e:{};return fe({descriptor:o=>({get(){var o;const n="slot"+(t?`[name=${t}]`:":not([name])"),r=null===(o=this.renderRoot)||void 0===o?void 0:o.querySelector(n),d=null!=r?xe(r,e):[];return i?d.filter((e=>e.matches(i))):d},enumerable:!0,configurable:!0})})}({slot:n,flatten:t,selector:i}):fe({descriptor:e=>({get(){var e,t;const i="slot"+(n?`[name=${n}]`:":not([name])"),r=null===(e=this.renderRoot)||void 0===e?void 0:e.querySelector(i);return null!==(t=null==r?void 0:r.assignedNodes(o))&&void 0!==t?t:[]},enumerable:!0,configurable:!0})})}var we,Ee;!function(e){e.language="language",e.system="system",e.comma_decimal="comma_decimal",e.decimal_comma="decimal_comma",e.space_comma="space_comma",e.none="none"}(we||(we={})),function(e){e.language="language",e.system="system",e.am_pm="12",e.twenty_four="24"}(Ee||(Ee={}));var Se=function(e,t,i,o){o=o||{},i=null==i?{}:i;var n=new Event(t,{bubbles:void 0===o.bubbles||o.bubbles,cancelable:Boolean(o.cancelable),composed:void 0===o.composed||o.composed});return n.detail=i,e.dispatchEvent(n),n};function Ce(e,t,i){if(t.has("config")||i)return!0;if(e.config.entity){var o=t.get("hass");return!o||o.states[e.config.entity]!==e.hass.states[e.config.entity]}return!1}const Ae="1.3.3",Ie=86400;var Te,Oe,$e,ke;!function(e){e.Heating="mdi:radiator",e.OnOff="mdi:power-socket-uk",e.Shutters="mdi:blinds",e.Lighting="mdi:lightbulb-outline"}(Te||(Te={})),function(e){e.Overview="OVERVIEW",e.ScheduleEdit="SCHEDULE_EDIT",e.ScheduleCopy="SCHEDULE_COPY",e.ScheduleAdd="SCHEDULE_ADD",e.ScheduleRename="SCHEDULE_RENAME"}(Oe||(Oe={})),function(e){e.Heating="19",e.OnOff="Off",e.Lighting="0",e.Shutters="100"}($e||($e={})),function(e){e.Heating="°C",e.OnOff="",e.Lighting="%",e.Shutters="%"}(ke||(ke={}));const Re=["Heating","OnOff","Lighting","Shutters"],Le=["Lighting","Shutters"],De=["Weekdays","Weekend"],Fe=["Monday","Tuesday","Wednesday","Thursday","Friday"],Me=["Saturday","Sunday"],Ne=Fe.concat(Me),ze=["Sunrise","Sunset"];var Pe;!function(e){e.Sunrise="3000",e.Sunset="4000"}(Pe||(Pe={}));var He={version:"Version",invalid_configuration:"Invalid configuration",no_schedules:"No Schedules Found",name_required:"Name is required"},Be={actions:{copy:"Copy",files:"Files",rename:"Rename",add:"Add",view:"View",add_schedule:"Add Schedule"},labels:{setting:"Setting",name:"Name",assigns:"Assigns",start:"Start",end:"End",to:"to"},days:{monday:"Monday",tuesday:"Tuesday",wednesday:"Wednesday",thursday:"Thursday",friday:"Friday",saturday:"Saturday",sunday:"Sunday",weekdays:"Weekdays",weekend:"Weekend",all:"All",short:{monday:"Mon",tuesday:"Tue",wednesday:"Wed",thursday:"Thu",friday:"Fri",saturday:"Sat",sunday:"Sun"}},headings:{schedule_actions:"Schedule Actions",schedule_type:"Schedule Type",schedule_id:"Schedule Id",schedule_name:"Schedule Name",schedule_assignment:"Schedule Assignment",not_assigned:"(Not Assigned)",rename_schedule:"Rename Schedule",copy_schedule:"Copy Schedule",delete_schedule:"Delete Schedule"},helpers:{enter_new_name:"Enter the new name for the Schedule",select_copy_schedule:"Select the schedule below to copy to",delete_schedule_confirm:"Are you sure you wish to delete the schedule",select_a_schedule:"Select a schedule to view",add_schedule:"Select the schedule type and enter a name for the schedule to create"}},Ve={common:He,wiser:Be},Ue={version:"Déclinaison",invalid_configuration:"Configuration Invalide",no_schedules:"Aucun Programme Trouvé",name_required:"Nom est obligatoire"},je={actions:{copy:"Copie",files:"Fichier",rename:"Renommer",add:"Ajouter",view:"Voir",add_schedule:"Ajouter un Programme"},labels:{setting:"Paramètre",name:"Nom",assigns:"Attribuers",start:"Début",end:"Fin",to:"à"},days:{monday:"Lundi",tuesday:"Mardi",wednesday:"Mercredi",thursday:"Jeudi",friday:"Vendredi",saturday:"Samedi",sunday:"Dimanche",weekdays:"Lun à Ven",weekend:"Sam et Dim",all:"Toute",short:{monday:"Lun",tuesday:"Mar",wednesday:"Mer",thursday:"Jeu",friday:"Ven",saturday:"Sam",sunday:"Dim"}},headings:{schedule_actions:"Programmer des Actions",schedule_type:"Type de Programme",schedule_id:"Numéro de Programme",schedule_name:"Nom de Programme",schedule_assignment:"Attribuer de Programme",not_assigned:"(Non Attribué)",rename_schedule:"Renommer le Programme",copy_schedule:"Copier le Programme",delete_schedule:"Supprimer le Programme"},helpers:{enter_new_name:"Entrez un nom pour le Programme",select_copy_schedule:"Sélectionnez le calendrier ci-dessous pour le copier",delete_schedule_confirm:"Êtes-vous sûr de vouloir effacer ce programme",select_a_schedule:"Sélectionner un programme à afficher",add_schedule:"Sélectionnez le type de programme et entrez un nom pour la programme à créer"}},We={common:Ue,wiser:je};const Ye={en:Object.freeze({__proto__:null,common:He,wiser:Be,default:Ve}),fr:Object.freeze({__proto__:null,common:Ue,wiser:je,default:We})};function Ge(e,t="",i=""){const o=(localStorage.getItem("selectedLanguage")||"en").replace(/['"]+/g,"").replace("-","_");let n;try{n=e.split(".").reduce(((e,t)=>e[t]),Ye[o]),n||(n=e.split(".").reduce(((e,t)=>e[t]),Ye.en))}catch(t){try{n=e.split(".").reduce(((e,t)=>e[t]),Ye.en)}catch(e){n=""}}return void 0===n&&(n=e.split(".").reduce(((e,t)=>e[t]),Ye.en)),""!==t&&""!==i&&(n=n.replace(t,i)),n}const Xe=h`
.card-header {
display: flex;
justify-content: space-between;
@@ -188,12 +188,12 @@ function ye(e,t,i){let o,n=e;return"object"==typeof e?(n=e.slot,o=e):o={flatten:
${this.supported_schedule_types.map((e=>this.renderScheduleItemsByType(e)))}
${this.renderAddScheduleButton()}
- `:U` ${this._showWarning(Ge("wiser.common.no_schedules"))} `:U``}_showWarning(e){return U`
Default View Options