diff --git a/HMI/code_gen/icons/icons.py b/HMI/code_gen/icons/icons.py index 36799533..66b58967 100644 --- a/HMI/code_gen/icons/icons.py +++ b/HMI/code_gen/icons/icons.py @@ -39,7 +39,8 @@ icons = [ "battery-medium", "shield-home", "door-open", - "door-closed" + "door-closed", + "window-closed" ] @@ -65,7 +66,7 @@ for icon_name in icons: icon_name_list.append(icon_name) # write mapping lib for python -with open(os.path.join(__location__, "../../../apps/nspanel-lovelace-ui", "icon_mapper.py"), 'w') as f: +with open(os.path.join(__location__, "../../../apps/nspanel-lovelace-ui", "icon_mapping.py"), 'w') as f: f.write("icons = {\n") for idx, val in enumerate(icon_name_list): f.write(f" '{val}': {idx},\n") diff --git a/HMI/icons.md b/HMI/icons.md index cf100a2d..6fd39e90 100644 --- a/HMI/icons.md +++ b/HMI/icons.md @@ -42,3 +42,4 @@ ID | MD Icon Name | Icon 35 | shield-home | ![shield-home](https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/0aeb4d612644d80d9d1fe242f705f362985de5dc/svg/shield-home.svg) 36 | door-open | ![door-open](https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/0aeb4d612644d80d9d1fe242f705f362985de5dc/svg/door-open.svg) 37 | door-closed | ![door-closed](https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/0aeb4d612644d80d9d1fe242f705f362985de5dc/svg/door-closed.svg) +38 | window-closed | ![window-closed](https://raw.githubusercontent.com/Templarian/MaterialDesign-SVG/0aeb4d612644d80d9d1fe242f705f362985de5dc/svg/window-closed.svg) diff --git a/HMI/nspanel.HMI b/HMI/nspanel.HMI index f02d81a7..509f630d 100644 Binary files a/HMI/nspanel.HMI and b/HMI/nspanel.HMI differ diff --git a/HMI/nspanel.tft b/HMI/nspanel.tft index 8b559f71..3f336402 100644 Binary files a/HMI/nspanel.tft and b/HMI/nspanel.tft differ diff --git a/apps/nspanel-lovelace-ui/icon_mapper.py b/apps/nspanel-lovelace-ui/icon_mapping.py similarity index 97% rename from apps/nspanel-lovelace-ui/icon_mapper.py rename to apps/nspanel-lovelace-ui/icon_mapping.py index 49cfa8cc..808ea06e 100644 --- a/apps/nspanel-lovelace-ui/icon_mapper.py +++ b/apps/nspanel-lovelace-ui/icon_mapping.py @@ -37,6 +37,7 @@ icons = { 'shield-home': 35, 'door-open': 36, 'door-closed': 37, + 'window-closed': 38, } def get_icon_id(ma_name): diff --git a/apps/nspanel-lovelace-ui/icons.py b/apps/nspanel-lovelace-ui/icons.py new file mode 100644 index 00000000..d7734d96 --- /dev/null +++ b/apps/nspanel-lovelace-ui/icons.py @@ -0,0 +1,64 @@ +from icon_mapping import get_icon_id + +weather_mapping = { + 'clear-night': 'weather-night', + 'cloudy': 'weather-cloudy', + 'exceptional': 'alert-circle-outline', + 'fog': 'weather-fog', + 'hail': 'weather-hail', + 'lightning': 'weather-lightning', + 'lightning-rainy': 'weather-lightning-rainy', + 'partlycloudy': 'weather-partly-cloudy', + 'pouring': 'weather-pouring', + 'rainy': 'weather-rainy', + 'snowy': 'weather-snowy', + 'snowy-rainy': 'weather-snowy-rainy', + 'sunny': 'weather-sunny', + 'windy': 'weather-windy', + 'windy-variant': 'weather-windy-variant' +} + +sensor_mapping_on = { + "door": "door-open", +} + +sensor_mapping_off = { + "door": "door-closed", +} + +sensor_mapping = { + "temperature": "thermometer", + "power": "flash" +} + + +def map_to_mdi_name(ha_type, state=None, device_class=None): + if ha_type == "weather": + return weather_mapping[state] if state in weather_mapping else "alert-circle-outline" + if ha_type == "button": + return "gesture-tap-button" + if ha_type == "scene": + return "palette" + if ha_type == "switch": + return "flash" + if ha_type == "light": + return "lightbulb" + if ha_type == "input_boolean": + return "check-circle-outline" if entity.state == "on" else "close-circle-outline" + if ha_type == "cover": + return "window-open" if entity.state == "open" else "window-closed" + + elif ha_type == "sensor": + if state == "on": + return sensor_mapping_on[device_class] if device_class in sensor_mapping_on else "alert-circle-outline" + elif state == "off": + return sensor_mapping_off[device_class] if device_class in sensor_mapping_off else "alert-circle-outline" + else: + return sensor_mapping[device_class] if device_class in sensor_mapping else "alert-circle-outline" + + return "alert-circle-outline" + +def get_icon_id_ha(ha_name, state=None, device_class=None, overwrite=None): + if overwrite is not None: + return get_icon_id(overwrite) + return get_icon_id(map_to_mdi_name(ha_name, state, device_class)) diff --git a/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py b/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py index 9d05e121..d8dae95d 100644 --- a/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py +++ b/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py @@ -2,8 +2,8 @@ import json import datetime import hassapi as hass from helper import scale, pos_to_color, rgb_dec565, rgb_brightness -from icon_mapper import get_icon_id - +from icon_mapping import get_icon_id +from icons import get_icon_id_ha # check Babel import importlib babel_spec = importlib.util.find_spec("babel") @@ -320,43 +320,30 @@ class LovelaceUIPanel: we = self.api.get_entity(self.config["weatherEntity"]) unit = "°C" - # this maps possible states from ha to material design icon names - weathericons = { - 'clear-night': 'weather-night', - 'cloudy': 'weather-cloudy', - 'exceptional': 'alert-circle-outline', - 'fog': 'weather-fog', - 'hail': 'weather-hail', - 'lightning': 'weather-lightning', - 'lightning-rainy': 'weather-lightning-rainy', - 'partlycloudy': 'weather-partly-cloudy', - 'pouring': 'weather-pouring', - 'rainy': 'weather-rainy', - 'snowy': 'weather-snowy', - 'snowy-rainy': 'weather-snowy-rainy', - 'sunny': 'weather-sunny', - 'windy': 'weather-windy', - 'windy-variant': 'weather-windy-variant' - } + icon_cur = get_icon_id_ha("weather", state=we.state) + text_cur = f"{we.attributes.temperature}{unit}" + icon_cur_detail = get_icon_id("water-percent") + text_cur_detail = f"{we.attributes.humidity} %" - i1 = get_icon_id(weathericons[we.attributes.forecast[0]['condition']]) - u1 = we.attributes.forecast[0]['temperature'] - i2 = get_icon_id(weathericons[we.attributes.forecast[1]['condition']]) - u2 = we.attributes.forecast[1]['temperature'] + up1 = we.attributes.forecast[0]['datetime'] + up1 = datetime.datetime.fromisoformat(up1) + icon1 = get_icon_id_ha("weather", state=we.attributes.forecast[0]['condition']) + down1 = we.attributes.forecast[0]['temperature'] + + up2 = we.attributes.forecast[1]['datetime'] + up2 = datetime.datetime.fromisoformat(up2) + icon2 = get_icon_id_ha("weather", state=we.attributes.forecast[1]['condition']) + down2 = we.attributes.forecast[1]['temperature'] - o1 = we.attributes.forecast[0]['datetime'] - o1 = datetime.datetime.fromisoformat(o1) - o2 = we.attributes.forecast[1]['datetime'] - o2 = datetime.datetime.fromisoformat(o2) global babel_spec if babel_spec is not None: - o1 = babel.dates.format_date(o1, "E", locale=self.config["locale"]) - o2 = babel.dates.format_date(o2, "E", locale=self.config["locale"]) + up1 = babel.dates.format_date(up1, "E", locale=self.config["locale"]) + up2 = babel.dates.format_date(up2, "E", locale=self.config["locale"]) else: - o1 = o1.strftime("%a") - o2 = o2.strftime("%a") + up1 = up1.strftime("%a") + up2 = up2.strftime("%a") - self.send_mqtt_msg(f"weatherUpdate,?{get_icon_id(weathericons[we.state])}?{we.attributes.temperature}{unit}?{26}?{we.attributes.humidity} %?{o1}?{i1}?{u1}?{o2}?{i2}?{u2}") + self.send_mqtt_msg(f"weatherUpdate,?{icon_cur}?{text_cur}?{icon_cur_detail}?{text_cur_detail}?{up1}?{icon1}?{down1}?{up2}?{icon2}?{down2}") def handle_button_press(self, entity_id, btype, optVal=None): @@ -474,48 +461,34 @@ class LovelaceUIPanel: name = entity.attributes.friendly_name if item_type == "cover": - icon_id = get_icon_id('window-open') if icon is None else get_icon_id(icon) + icon_id = get_icon_id_ha("cover", state=entity.state overwrite=icon) return f",shutter,{item},{icon_id},17299,{name}," if item_type == "light": switch_val = 1 if entity.state == "on" else 0 icon_color = self.getEntityColor(entity) - icon_id = get_icon_id('lightbulb') if icon is None else get_icon_id(icon) + icon_id = get_icon_id_ha("light", overwrite=icon) return f",{item_type},{item},{icon_id},{icon_color},{name},{switch_val}" if item_type == "switch" or item_type == "input_boolean": + icon_id = get_icon_id_ha(item_type, overwrite=icon) switch_val = 1 if entity.state == "on" else 0 - icon_id = get_icon_id('flash') if icon is None else get_icon_id(icon) icon_color = self.getEntityColor(entity) - if item_type == "input_boolean": - icon_id = get_icon_id("check-circle-outline") if switch_val == 1 else get_icon_id("close-circle-outline") return f",switch,{item},{icon_id},{icon_color},{name},{switch_val}" if item_type in ["sensor", "binary_sensor"]: - # maps ha device classes to material design icons - icon_mapping = { - "temperature": "thermometer", - "power": "flash" - } - if "device_class" in entity.attributes: - if entity.attributes.device_class in icon_mapping: - icon_id = icon_mapping[entity.attributes.device_class] - else: - self.api.log("No Icon found for device_class: %s. Please open a issue on github to report the missing mapping.", entity.attributes.device_class) - icon_id = get_icon_id('alert-circle-outline') - else: - icon_id = get_icon_id('alert-circle-outline') - + device_class = self.get_safe_ha_attribute(entity.attributes, "device_class", "") + icon_id = get_icon_id_ha("sensor", state=entity.state, device_class=device_class, overwrite=icon) unit_of_measurement = self.get_safe_ha_attribute(entity.attributes, "unit_of_measurement", "") value = entity.state + " " + unit_of_measurement return f",text,{item},{icon_id},17299,{name},{value}" if item_type in ["button", "input_button"]: - icon_id = get_icon_id('gesture-tap-button') if icon is None else get_icon_id(icon) + icon_id = get_icon_id_ha("button", overwrite=icon) return f",button,{item},{icon_id},17299,{name},PRESS" if item_type == "scene": - icon_id = get_icon_id('palette') if icon is None else get_icon_id(icon) + icon_id = get_icon_id_ha("scene", overwrite=icon) return f",button,{item},{icon_id},17299,{name},ACTIVATE" def generate_entities_page(self, items):