diff --git a/README.md b/README.md index 75b6eda9..5d0af9cd 100644 --- a/README.md +++ b/README.md @@ -260,7 +260,7 @@ nspanel-1: config: panelRecvTopic: "tele/tasmota_your_mqtt_topic/RESULT" panelSendTopic: "cmnd/tasmota_your_mqtt_topic/CustomSend" - #model: us-p # uncomment this if you have the us version, see table below for more information + updateMode: "auto-notify" timeoutScreensaver: 20 #brightnessScreensaver: 10 brightnessScreensaver: @@ -268,49 +268,28 @@ nspanel-1: value: 10 - time: "23:00:00" value: 0 - locale: "de_DE" - dateFormatBabel: "full" - timeFormat: "%H:%M" - dateFormat: "%A, %d. %B %Y" # ignored if babel python package is installed - weather: weather.example - pages: + locale: "de_DE" # used for translations in translations.py and for localized date if babel python package is installed + screensaver: + weather: weather.k3ll3r + cards: - type: cardEntities - heading: Example Page 1 - items: - - cover.example_cover - - switch.example_switch - - input_boolean.example_input_boolean - - sensor.example_sensor - - type: cardEntities - heading: Example Page 2 - items: - - button.example_button - - input_button.example_input_button - - light.light_example - - delete # (read this as 'empty') - - type: cardEntities - heading: Example Page 3 - items: - - scene.example_scene - - delete - - delete - - delete + entities: + - entity: light.example_item + name: NameOverride + - entity: light.example_item + title: Example Entities - type: cardGrid - heading: Example Page 4 - items: - - light.light_example - - button.example_button - - cover.example_cover - - scene.example_scene - - switch.example_switch - - delete + entities: + - entity: select.example_item + - entity: select.example_item + - entity: light.example_item + title: Exmaple Gird - type: cardThermo - heading: Exmaple Thermostat - item: climate.example_climate + entity: climate.example_item - type: cardMedia - item: media_player.spotify_user + entity: media_player.example_item - type: cardAlarm - item: alarm_control_panel.alarmo + entity: alarm_control_panel.alarmo ``` key | optional | type | default | description @@ -327,13 +306,21 @@ key | optional | type | default | description `panelSendTopic` | False | string | `cmnd/tasmota_your_mqtt_topic/CustomSend` | The mqtt topic used to send messages. `updateMode` | True | string | `auto-notify` | Update Mode; Possible values: "auto", "auto-notify", "manual" `model` | True | string | `eu` | Model; Possible values: "eu", "us-l" and "us-p" -`timeoutScreensaver` | True | integer | `20` | Timeout for the screen to enter screensaver, to disable screensaver use 0 -`brightnessScreensaver` | True | integer/complex | `20` | Brightness for the screen to enter screensaver, see example below for complex/scheduled config. -`brightnessScreensaverTracking` | True | string | None | Forces screensaver brightness to 0 in case entity state is not_home, can be a group, person or device_tracker entity. +`sleepTimeout` | True | integer | `20` | Timeout for the screen to enter screensaver, to disable screensaver use 0 +`sleepBrightness` | True | integer/complex | `20` | Brightness for the screen to enter screensaver, see example below for complex/scheduled config. +`sleepTracking` | True | string | None | Forces screensaver brightness to 0 in case entity state is not_home, can be a group, person or device_tracker entity. `locale` | True | string | `en_US` | Used by babel to determinante Date format on screensaver, also used for localization. `dateFormatBabel` | True | string | `full` | formatting options on https://babel.pocoo.org/en/latest/dates.html?highlight=name%20of%20day#date-fields `timeFormat` | True | string | `%H:%M` | Time Format on screensaver. Substring after `?` is displayed in a seperate smaller textbox. Useful for 12h time format with AM/PM `"%I:%M ?%p"` `dateFormat` | True | string | `%A, %d. %B %Y` | date format used if babel is not installed +`cards` | False | complex | | configuration for pages that are displayed on panel +`screensaver` | True | complex | | configuration for screensaver +`hiddenCards` | True | complex | | configuration for pages that can be accessed though navigate items + +Possible configuration values for screensaver config: + +key | optional | type | default | description +-- | -- | -- | -- | -- `weather` | True | string | `weather.example` | weather entity from homeassistant `weatherUnit` | True | string | `celsius` | unit for temperature, valid values are `celsius` or `fahrenheit` `weatherOverrideForecast1` | True | string | `None` | sensor entity from home assistant here to override the first weather forecast item on the screensaver @@ -341,14 +328,13 @@ key | optional | type | default | description `weatherOverrideForecast3` | True | string | `None` | sensor entity from home assistant here to override the third weather forecast item on the screensaver `weatherOverrideForecast4` | True | string | `None` | sensor entity from home assistant here to override the forth weather forecast item on the screensaver `doubleTapToUnlock` | True | boolean | `False` | requires to tap screensaver two times -`pages` | False | complex | | configuration for pages on panel -#### Schedule screensaver brightness +#### Schedule sleep brightness It is possible to schedule a brightness change for the screen at specific times. ```yaml - brightnessScreensaver: + sleepBrightness: - time: "7:00:00" value: 10 - time: "23:00:00" @@ -361,17 +347,13 @@ To override Icons or Names of entities you can configure an icon and/or name in Only the icons listed in the [Icon Table](HMI#icons-ids) are useable. ```yaml - - type: cardGrid - heading: Lights - items: - - light.wled - - light.schreibtischlampe - - switch.deckenbeleuchtung_hinten: - icon: lightbulb - name: Lampe - - delete - - delete - - type: cardMedia + 'entities': [{ + 'entity': 'switch.test_item', + 'name': 'Test Item' + 'icon': 'lightbulb' + }, { + 'entity': 'switch.test_item' + }], ``` ## How to update diff --git a/appdaemon/apps.yaml b/appdaemon/apps.yaml index 2d1cf3a8..5dbec26f 100644 --- a/appdaemon/apps.yaml +++ b/appdaemon/apps.yaml @@ -13,30 +13,25 @@ nspanel-1: value: 10 - time: "23:00:00" value: 0 - locale: "de_DE" # only used if babel python package is installed - dateFormatBabel: "full" # only used if babel python package is installed - # formatting options on https://babel.pocoo.org/en/latest/dates.html?highlight=name%20of%20day#date-fields - timeFormat: "%H:%M" - dateFormat: "%A, %d. %B %Y" # ignored if babel python package is installed - weather: weather.example - weatherOverrideForecast3: sensor.nas_cpu_perc - weatherOverrideForecast4: - sensor.solar_power_current: # use this for overriding name and icon - name: Sonne - icon: solar-power + locale: "de_DE" # used for translations in translations.py and for localized date if babel python package is installed + screensaver: + weather: weather.k3ll3r cards: - - type: entities + - type: cardEntities entities: - entity: light.example_item name: NameOverride - entity: light.example_item title: Example Entities - - type: gird + - type: cardGrid entities: - entity: select.example_item - entity: select.example_item - entity: light.example_item title: Exmaple Gird - - type: climate - entity: light.example_item - title: Exmaple Climate \ No newline at end of file + - type: cardThermo + entity: climate.example_item + - type: cardMedia + entity: media_player.example_item + - type: cardAlarm + entity: alarm_control_panel.alarmo \ No newline at end of file diff --git a/apps/nspanel-lovelace-ui/luibackend/config.py b/apps/nspanel-lovelace-ui/luibackend/config.py index ada71214..f65dd48a 100644 --- a/apps/nspanel-lovelace-ui/luibackend/config.py +++ b/apps/nspanel-lovelace-ui/luibackend/config.py @@ -11,17 +11,31 @@ class Entity(object): self.iconOverride = entity_input_config.get("icon") class Card(object): - def __init__(self, card_input_config): + def __init__(self, card_input_config, pos=None): + self.pos = pos + self.raw_config = card_input_config self.cardType = card_input_config.get("type", "unknown") self.title = card_input_config.get("title", "unknown") + self.key = card_input_config.get("key", "unknown") # for single entity card like climate or media self.entity = None if card_input_config.get("entity") is not None: - self.entity = Entity(card_input_config.get("entity")) + self.entity = Entity(card_input_config) # for pages like grid or entities self.entities = [] for e in card_input_config.get("entities", []): self.entities.append(Entity(e)) + self.id = f"{self.cardType}_{self.key}".replace(".","_").replace("~","_").replace(" ","_") + LOGGER.info(f"Created Card {self.cardType} with pos {pos} and id {self.id}") + + def get_entity_list(self): + entityIds = [] + if self.entity is not None: + entityIds.append(self.entity.entityId) + else: + for e in self.entities: + entityIds.append(e.entityId) + return entityIds class LuiBackendConfig(object): @@ -30,22 +44,15 @@ class LuiBackendConfig(object): 'panelSendTopic': "cmnd/tasmota_your_mqtt_topic/CustomSend", 'updateMode': "auto-notify", 'model': "eu", - 'timeoutScreensaver': 20, - 'brightnessScreensaver': 20, - 'brightnessScreensaverTracking': None, + 'sleepTimeout': 20, + 'sleepBrightness': 20, + 'sleepTracking': None, 'locale': "en_US", 'timeFormat': "%H:%M", 'dateFormatBabel': "full", 'dateFormat': "%A, %d. %B %Y", - 'weather': 'weather.example', - 'weatherUnit': 'celsius', - 'weatherOverrideForecast1': None, - 'weatherOverrideForecast2': None, - 'weatherOverrideForecast3': None, - 'weatherOverrideForecast4': None, - 'doubleTapToUnlock': False, 'cards': [{ - 'type': 'entities', + 'type': 'cardEntities', 'entities': [{ 'entity': 'switch.test_item', 'name': 'Test Item' @@ -54,7 +61,7 @@ class LuiBackendConfig(object): }], 'title': 'Example Entities Page' }, { - 'type': 'grid', + 'type': 'cardGrid', 'entities': [{ 'entity': 'switch.test_item' }, { @@ -66,9 +73,19 @@ class LuiBackendConfig(object): 'title': 'Example Grid Page' }, { 'type': 'climate', - 'entity': 'climate.test_item' - 'title': 'Example Climate Page' - }] + 'entity': 'climate.test_item', + }], + 'screensaver': { + 'type': 'screensaver', + 'weather': 'weather.example', + 'weatherUnit': 'celsius', + 'weatherOverrideForecast1': None, + 'weatherOverrideForecast2': None, + 'weatherOverrideForecast3': None, + 'weatherOverrideForecast4': None, + 'doubleTapToUnlock': False + }, + 'hiddenCards': [] } def __init__(self, ha_api, config_in): @@ -76,7 +93,7 @@ class LuiBackendConfig(object): HA_API = ha_api self._config = {} self._config_cards = [] - self._current_card = None + self._config_screensaver = None self.load(config_in) @@ -85,16 +102,51 @@ class LuiBackendConfig(object): if k in self._DEFAULT_CONFIG: self._config[k] = v LOGGER.info(f"Loaded config: {self._config}") - + + # parse cards displayed on panel + pos = 0 for card in self.get("cards"): - self._config_cards.append(Card(card)) - # set current card to first card - self._current_card = self._config_cards[0] + self._config_cards.append(Card(card, pos)) + pos = pos + 1 + # parse screensaver + screensaver = Card(self.get("screensaver")) + # parsed hidden pages that can be accessed through navigate + for card in self.get("hiddenCards"): + self._config_hidden_cards.append(Card(card)) def get(self, name): - value = self._config.get(name) - if value is None: - value = self._DEFAULT_CONFIG.get(name) + path = name.split(".") + value = self._config + for p in path: + if value is not None: + value = value.get(p, None) + if value is not None: + return value + # try to get a value from default config + value = self._DEFAULT_CONFIG + for p in path: + if value is not None: + value = value.get(p, None) return value + + def get_all_entity_names(self): + entities = [] + for card in self._config_cards: + entities.extend(card.get_entity_list()) + return entities + def getCard(self, pos): + card = self._config_cards[pos%len(self._config_cards)] + return card + + def searchCard(self, id): + id = id.replace("navigate.", "") + for card in self._config_cards: + if card.id == id: + return card + if self._config_screensaver.id == id: + return screensaver + for card in self._config_hidden_cards: + if card.id == id: + return card \ No newline at end of file diff --git a/apps/nspanel-lovelace-ui/luibackend/controller.py b/apps/nspanel-lovelace-ui/luibackend/controller.py index df4cb0d3..f5a7c65d 100644 --- a/apps/nspanel-lovelace-ui/luibackend/controller.py +++ b/apps/nspanel-lovelace-ui/luibackend/controller.py @@ -13,8 +13,8 @@ class LuiController(object): self._config = config self._send_mqtt_msg = send_mqtt_msg - # first child of root page (default, after startup) - self._current_page = self._config._page_config.childs[0] + # first card (default, after startup) + self._current_card = self._config.getCard(0) self._pages_gen = LuiPagesGen(ha_api, config, send_mqtt_msg) @@ -42,7 +42,6 @@ class LuiController(object): # calculate current brightness self.current_screensaver_brightness = self.calc_current_screensaver_brightness() - # call update_screensaver_brightness on changes of entity configured in brightnessScreensaverTracking bst = self._config.get("brightnessScreensaverTracking") if bst is not None and self._ha_api.entity_exists(bst): @@ -103,7 +102,7 @@ class LuiController(object): return current_screensaver_brightness def register_callbacks(self): - items = self._config.get_root_page().get_all_item_names() + items = self._config.get_all_entity_names() LOGGER.debug(f"Registering callbacks for the following items: {items}") for item in items: if self._ha_api.entity_exists(item): @@ -111,12 +110,12 @@ class LuiController(object): def state_change_callback(self, entity, attribute, old, new, kwargs): LOGGER.debug(f"Got callback for: {entity}") - LOGGER.debug(f"Current page has the following items: {self._current_page.get_items()}") - if entity in self._current_page.get_all_item_names(recursive=False): + LOGGER.debug(f"Current page has the following items: {self._current_card.get_entity_list()}") + if entity in self._current_card.get_entity_list(): LOGGER.debug(f"Callback Entity is on current page: {entity}") - self._pages_gen.render_page(self._current_page, send_page_type=False) + self._pages_gen.render_card(self._current_card, send_page_type=False) # send detail page update, just in case - if self._current_page.data.get("type", "unknown") in ["cardGrid", "cardEntities"]: + if self._current_card.cardType in ["cardGrid", "cardEntities"]: if entity.startswith("light"): self._pages_gen.generate_light_detail_page(entity) if entity.startswith("cover"): @@ -134,9 +133,9 @@ class LuiController(object): # internal buttons if entity_id == "screensaver" and button_type == "bExit": if self._config.get("doubleTapToUnlock") and int(value) >= 2: - self._pages_gen.render_page(self._current_page) + self._pages_gen.render_card(self._current_card) elif not self._config.get("doubleTapToUnlock"): - self._pages_gen.render_page(self._current_page) + self._pages_gen.render_card(self._current_card) return if button_type == "sleepReached": @@ -144,17 +143,19 @@ class LuiController(object): return if button_type == "bExit": - self._pages_gen.render_page(self._current_page) + self._pages_gen.render_card(self._current_card) if button_type == "bNext": - self._current_page = self._current_page.next() - self._pages_gen.render_page(self._current_page) + card = self._config.getCard(self._current_card.pos+1) + self._current_card = card + self._pages_gen.render_card(card) if button_type == "bPrev": - self._current_page = self._current_page.prev() - self._pages_gen.render_page(self._current_page) + card = self._config.getCard(self._current_card.pos-1) + self._current_card = card + self._pages_gen.render_card(card) elif entity_id == "updateDisplayNoYes" and value == "no": - self._pages_gen.render_page(self._current_page) + self._pages_gen.render_card(self._current_card) # buttons with actions on HA if button_type == "OnOff": @@ -180,8 +181,8 @@ class LuiController(object): if button_type == "button": if entity_id.startswith('navigate'): # internal for navigation to nested pages - self._current_page = self._config.get_root_page().search_page_by_name(entity_id)[0] - self._pages_gen.render_page(self._current_page) + self._current_card = self._config.searchCard(entity_id) + self._pages_gen.render_card(self._current_card) elif entity_id.startswith('scene'): self._ha_api.get_entity(entity_id).call_service("turn_on") elif entity_id.startswith('script'): diff --git a/apps/nspanel-lovelace-ui/luibackend/pages.py b/apps/nspanel-lovelace-ui/luibackend/pages.py index 1692d546..31da3b53 100644 --- a/apps/nspanel-lovelace-ui/luibackend/pages.py +++ b/apps/nspanel-lovelace-ui/luibackend/pages.py @@ -55,19 +55,19 @@ class LuiPagesGen(object): def page_type(self, target_page): self._send_mqtt_msg(f"pageType~{target_page}") - def generate_screensaver_page(self): + def generate_screensaver_page(self, card): self.page_type("screensaver") self.update_screensaver_weather() def update_screensaver_weather(self): global babel_spec - we_name = self._config.get("weather") - unit = self._config.get("weatherUnit") + we_name = self._config.get("screensaver.weather") + unit = self._config.get("screensaver.weatherUnit") if self._ha_api.entity_exists(we_name): we = self._ha_api.get_entity(we_name) else: - LOGGER.error("Skipping Weather Update, entity not found") + LOGGER.error("Skipping Weather Update, entity {we_name} not found") return icon_cur = get_icon_id_ha("weather", state=we.state) @@ -75,7 +75,7 @@ class LuiPagesGen(object): weather_res = "" for i in range(1,5): - wOF = self._config.get(f"weatherOverrideForecast{i}") + wOF = self._config.get(f"screensaver.weatherOverrideForecast{i}") if wOF is None: up = we.attributes.forecast[i-1]['datetime'] up = datetime.datetime.fromisoformat(up) @@ -87,13 +87,9 @@ class LuiPagesGen(object): down = convert_temperature(we.attributes.forecast[i-1]['temperature'], unit) else: LOGGER.info(f"Forecast {i} is overriden with {wOF}") - icon = None - name = None - if type(wOF) is dict: - icon = next(iter(wOF.items()))[1].get('icon') - name = next(iter(wOF.items()))[1].get('name') - wOF = next(iter(wOF.items()))[0] - entity = self._ha_api.get_entity(wOF) + icon = wOF.iconOverride + name = wOF.nameOverride + entity = self._ha_api.get_entity(wOF.entityId) up = name if name is not None else entity.attributes.friendly_name icon = get_icon_id_ha("sensor", state=entity.state, device_class=entity.attributes.get("device_class", ""), overwrite=icon) unit_of_measurement = entity.attributes.get("unit_of_measurement", "") @@ -102,73 +98,69 @@ class LuiPagesGen(object): self._send_mqtt_msg(f"weatherUpdate~{icon_cur}~{text_cur}{weather_res}") - def generate_entities_item(self, item): - icon = None - name = None - if type(item) is dict: - icon = next(iter(item.items()))[1].get('icon') - name = next(iter(item.items()))[1].get('name') - item = next(iter(item.items()))[0] - # type of the item is the string before the "." in the item name - item_type = item.split(".")[0] - LOGGER.debug(f"Generating item command for {item} with type {item_type}",) - # Internal Entities - if item_type == "delete": - return f"~{item_type}~~~~~" - if item_type == "navigate": - page_search = self._config.get_root_page().search_page_by_name(item) - if len(page_search) > 0: - page_data = page_search[0].data - if name is None: - name = page_data.get("heading") + def generate_entities_item(self, entity): + entityId = entity.entityId + icon = entity.iconOverride + name = entity.nameOverride + # type of the item is the string before the "." in the entityId + entityType = entityId.split(".")[0] + + LOGGER.debug(f"Generating item for {entityId} with type {entityType}",) + # Internal types + if entityType == "delete": + return f"~{entityType}~~~~~" + if entityType == "navigate": + page_search_res = self._config.searchPage(entityId) + if page_search_res is not None: + name = page_search_res.title text = get_translation(self._locale,"PRESS") icon_id = get_icon_id(icon) if icon is not None else get_icon_id(page_data.get("icon", "gesture-tap-button")) - return f"~button~{item}~{icon_id}~17299~{name}~{text}" + return f"~button~{entityId}~{icon_id}~17299~{name}~{text}" else: - return f"~text~{item}~{get_icon_id('alert-circle-outline')}~17299~page not found~" - if not self._ha_api.entity_exists(item): - return f"~text~{item}~{get_icon_id('alert-circle-outline')}~17299~Not found check~ apps.yaml" + return f"~text~{entityId}~{get_icon_id('alert-circle-outline')}~17299~page not found~" + if not self._ha_api.entity_exists(entityId): + return f"~text~{entityId}~{get_icon_id('alert-circle-outline')}~17299~Not found check~ apps.yaml" # HA Entities - entity = self._ha_api.get_entity(item) + entity = self._ha_api.get_entity(entityId) name = name if name is not None else entity.attributes.friendly_name - if item_type == "cover": + if entityType == "cover": icon_id = get_icon_id_ha("cover", state=entity.state, overwrite=icon) - return f"~shutter~{item}~{icon_id}~17299~{name}~" - if item_type in "light": + return f"~shutter~{entityId}~{icon_id}~17299~{name}~" + if entityType in "light": switch_val = 1 if entity.state == "on" else 0 icon_color = self.get_entity_color(entity) icon_id = get_icon_id_ha("light", overwrite=icon) - return f"~{item_type}~{item}~{icon_id}~{icon_color}~{name}~{switch_val}" - if item_type in ["switch", "input_boolean"]: + return f"~{entityType}~{entityId}~{icon_id}~{icon_color}~{name}~{switch_val}" + if entityType in ["switch", "input_boolean"]: switch_val = 1 if entity.state == "on" else 0 icon_color = self.get_entity_color(entity) - icon_id = get_icon_id_ha(item_type, state=entity.state, overwrite=icon) - return f"~switch~{item}~{icon_id}~{icon_color}~{name}~{switch_val}" - if item_type in ["sensor", "binary_sensor"]: + icon_id = get_icon_id_ha(entityType, state=entity.state, overwrite=icon) + return f"~switch~{entityId}~{icon_id}~{icon_color}~{name}~{switch_val}" + if entityType in ["sensor", "binary_sensor"]: device_class = entity.attributes.get("device_class", "") icon_id = get_icon_id_ha("sensor", state=entity.state, device_class=device_class, overwrite=icon) unit_of_measurement = entity.attributes.get("unit_of_measurement", "") value = entity.state + " " + unit_of_measurement icon_color = self.get_entity_color(entity) - return f"~text~{item}~{icon_id}~{icon_color}~{name}~{value}" - if item_type in ["button", "input_button"]: + return f"~text~{entityId}~{icon_id}~{icon_color}~{name}~{value}" + if entityType in ["button", "input_button"]: icon_id = get_icon_id_ha("button", overwrite=icon) text = get_translation(self._locale,"PRESS") - return f"~button~{item}~{icon_id}~17299~{name}~{text}" - if item_type == "scene": + return f"~button~{entityId}~{icon_id}~17299~{name}~{text}" + if entityType == "scene": icon_id = get_icon_id_ha("scene", overwrite=icon) text = get_translation(self._locale,"ACTIVATE") - return f"~button~{item}~{icon_id}~17299~{name}~{text}" - if item_type == "script": + return f"~button~{entityId}~{icon_id}~17299~{name}~{text}" + if entityType == "script": icon_id = get_icon_id_ha("script", overwrite=icon) text = get_translation(self._locale,"run") - return f"~button~{item}~{icon_id}~17299~{name}~{text}" - if item_type == "number": + return f"~button~{entityId}~{icon_id}~17299~{name}~{text}" + if entityType == "number": icon_id = get_icon_id_ha("number", overwrite=icon) min_v = entity.attributes.get("min", 0) max_v = entity.attributes.get("max", 100) - return f"~number~{item}~{icon_id}~17299~{name}~{entity.state}|{min_v}|{max_v}" + return f"~number~{entityId}~{icon_id}~17299~{name}~{entity.state}|{min_v}|{max_v}" def generate_entities_page(self, heading, items): navigation = "" @@ -180,7 +172,8 @@ class LuiPagesGen(object): - def generate_thermo_page(self, item): + def generate_thermo_page(self, entity): + item = entity.entityId if not self._ha_api.entity_exists(item): command = f"entityUpd~{item}~Not found~220~220~Not found~150~300~5" else: @@ -237,7 +230,8 @@ class LuiPagesGen(object): command = f"entityUpd~{heading}~~{item}~{current_temp}~{dest_temp}~{status}~{min_temp}~{max_temp}~{step_temp}{icon_res}" self._send_mqtt_msg(command) - def generate_media_page(self, item): + def generate_media_page(self, entity): + item = entity.entityId if not self._ha_api.entity_exists(item): command = f"entityUpd~|{item}|Not found|{get_icon_id('alert-circle-outline')}|Please check your|apps.yaml in AppDaemon|50|{get_icon_id('alert-circle-outline')}" else: @@ -270,7 +264,8 @@ class LuiPagesGen(object): command = f"entityUpd~|{heading}||{item}|{icon}|{title}|{author}|{volume}|{iconplaypause}|{source}|{speakerlist[:200]}|{onoffbutton}" self._send_mqtt_msg(command) - def generate_alarm_page(self, item): + def generate_alarm_page(self, entity): + item = entity.entityId if not self._ha_api.entity_exists(item): command = f"entityUpd~{item}~Not found~Not found~Check your~Check your~apps.~apps.~yaml~yaml~0~~0" else: @@ -330,23 +325,23 @@ class LuiPagesGen(object): command = f"entityUpd~{item}~{navigation}{arm_buttons}~{icon}~{color}~{numpad}~{flashing}" self._send_mqtt_msg(command) - def render_page(self, page, send_page_type=True): - config = page.data - page_type = config["type"] - LOGGER.info(f"Started rendering of page {page.pos} with type {page_type}") + def render_card(self, card, send_page_type=True): + LOGGER.info(f"Started rendering of page {card.pos} with type {card.cardType}") # Switch to page if send_page_type: - self.page_type(page_type) - if page_type in ["cardEntities", "cardGrid"]: - heading = config.get("heading", "unknown") - self.generate_entities_page(heading, page.get_items()) + self.page_type(card.cardType) + if card.cardType in ["cardEntities", "cardGrid"]: + self.generate_entities_page(card.title, card.entities) return - if page_type == "cardThermo": - self.generate_thermo_page(page.data.get("item")) - if page_type == "cardMedia": - self.generate_media_page(page.data.get("item")) - if page_type == "cardAlarm": - self.generate_alarm_page(page.data.get("item")) + if card.cardType == "cardThermo": + self.generate_thermo_page(card.entity) + if card.cardType == "cardMedia": + self.generate_media_page(card.entity) + if card.cardType == "cardAlarm": + self.generate_alarm_page(card.entity) + + if card.cardType == "screensaver": + self.generate_screensaver_page(card) def generate_light_detail_page(self, entity): @@ -380,7 +375,7 @@ class LuiPagesGen(object): def generate_shutter_detail_page(self, entity): entity = self._ha_api.get_entity(entity) pos = 100-int(entity.attributes.get("current_position", 50)) - self._send_mqtt_msg(f"entityUpdateDetail,{pos}") + self._send_mqtt_msg(f"entityUpdateDetail~{pos}") def send_message_page(self, id, heading, msg, b1, b2): self._send_mqtt_msg(f"pageType~popupNotify") diff --git a/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py b/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py index ea44bbc4..ba2e3ae0 100644 --- a/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py +++ b/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py @@ -51,42 +51,40 @@ class NsPanelLovelaceUIManager(hass.Hass): mqtt_api = self._mqtt_api = self.get_plugin_api("MQTT") cfg = self._cfg = LuiBackendConfig(self, self.args["config"]) - #topic_send = cfg.get("panelSendTopic") - #def send_mqtt_msg(msg, topic=None): - # if topic is None: - # topic = topic_send - # LOGGER.info(f"Sending MQTT Message: {msg}") - # mqtt_api.mqtt_publish(topic, msg) -# - ## Request Tasmota Driver Version - #mqtt_api.mqtt_publish(topic_send.replace("CustomSend", "GetDriverVersion"), "x") -# - #controller = LuiController(self, cfg, send_mqtt_msg) -# - #desired_display_firmware_version = 26 - #version = "v2.4.0" - # - #model = cfg.get("model") - #if model == "us-l": - # # us landscape version - # desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-l-{version}.tft" - #elif model == "us-p": - # # us portrait version - # desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-p-{version}.tft" - #else: - # # eu version - # desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-{version}.tft" -# - # - #desired_tasmota_driver_version = 3 - #desired_tasmota_driver_url = "https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be" - # - #mode = cfg.get("updateMode") - #topic_send = cfg.get("panelSendTopic") - #updater = Updater(send_mqtt_msg, topic_send, mode, desired_display_firmware_version, model, desired_display_firmware_url, desired_tasmota_driver_version, desired_tasmota_driver_url) -# - #topic_recv = cfg.get("panelRecvTopic") - #LuiMqttListener(mqtt_api, topic_recv, controller, updater) -# - #LOGGER.info('Started') -# \ No newline at end of file + topic_send = cfg.get("panelSendTopic") + def send_mqtt_msg(msg, topic=None): + if topic is None: + topic = topic_send + LOGGER.info(f"Sending MQTT Message: {msg}") + mqtt_api.mqtt_publish(topic, msg) + + # Request Tasmota Driver Version + mqtt_api.mqtt_publish(topic_send.replace("CustomSend", "GetDriverVersion"), "x") + + controller = LuiController(self, cfg, send_mqtt_msg) + + desired_display_firmware_version = 26 + version = "v2.4.0" + + model = cfg.get("model") + if model == "us-l": + # us landscape version + desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-l-{version}.tft" + elif model == "us-p": + # us portrait version + desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-p-{version}.tft" + else: + # eu version + desired_display_firmware_url = f"http://nspanel.pky.eu/lovelace-ui/github/nspanel-{version}.tft" + + desired_tasmota_driver_version = 3 + desired_tasmota_driver_url = "https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be" + + mode = cfg.get("updateMode") + topic_send = cfg.get("panelSendTopic") + updater = Updater(send_mqtt_msg, topic_send, mode, desired_display_firmware_version, model, desired_display_firmware_url, desired_tasmota_driver_version, desired_tasmota_driver_url) + + topic_recv = cfg.get("panelRecvTopic") + LuiMqttListener(mqtt_api, topic_recv, controller, updater) + + LOGGER.info('Started')