diff --git a/README.md b/README.md index dc43b60..5acb8c3 100644 --- a/README.md +++ b/README.md @@ -125,22 +125,24 @@ If you have any further questions, I will be happy to help. You can use it for Push Notifications. ``` -alias: Pixoo Notification -description: "" +alias: YOUR TITEL trigger: - - platform: state - entity_id: - - event.ANY-EVENT -condition: [] + - platform: YOUR PLATFORM + e.g. entity_id: YOUR ENTITY action: - service: divoom_pixoo.show_message data: entity_id: sensor.divoom_pixoo - message: HELLO WORLD - position: [0,0] - color: [255, 0, 255] - font: FONT_GICKO -mode: single + #If you want draw more than 1 Message u have to need more positions, colors and fonts too + messages: ["Message 1", "Message 2"] + positions: [[1, 1], [1, 20]] + colors: [[255, 0, 0], [0, 255, 0]] + fonts: ["FONT_GICKO", "FONT_PICO_8"] + #same as Messages at images u need for each image an image_positions + images : ["/config/custom_components/divoom_pixoo/img/sunpower.png", + "/config/custom_components/divoom_pixoo/img/haus.png"] + image_positions : [[1, 30], + [20, 30]] ``` ## Font diff --git a/custom_components/divoom_pixoo/__init__.py b/custom_components/divoom_pixoo/__init__.py index b7b5d63..6170198 100644 --- a/custom_components/divoom_pixoo/__init__.py +++ b/custom_components/divoom_pixoo/__init__.py @@ -7,6 +7,7 @@ from homeassistant.helpers import config_validation as cv DOMAIN = "divoom_pixoo" +VERSION = "1.2.0" async def async_setup(hass: HomeAssistant, config: dict): @@ -37,16 +38,16 @@ async def async_setup(hass: HomeAssistant, config: dict): async def async_show_message(service: ServiceCall): """Handle the service call to show a message on the Pixoo device.""" entity_id = service.data.get('entity_id') - message = service.data.get('message') - position = service.data.get('position') - color = service.data.get('color') - font = service.data.get('font') - image = service.data.get('image') - image_position = service.data.get('image_position') - + messages = service.data.get('messages') + positions = service.data.get('positions') + colors = service.data.get('colors') + fonts = service.data.get('fonts') + images = service.data.get('images', []) + image_positions = service.data.get('image_positions', []) + ... for entity in hass.data[DOMAIN].get('entities', []): if entity.entity_id == entity_id: - await entity.async_show_message(message, position, color, font, image, image_position) + await entity.async_show_message(messages, positions, colors, fonts, images, image_positions) break # Service registrieren diff --git a/custom_components/divoom_pixoo/img/weather/cloudy.png b/custom_components/divoom_pixoo/img/weather/cloudy.png new file mode 100644 index 0000000..ced4a36 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/cloudy.png differ diff --git a/custom_components/divoom_pixoo/img/weather/exceptional.png b/custom_components/divoom_pixoo/img/weather/exceptional.png new file mode 100644 index 0000000..d23c6eb Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/exceptional.png differ diff --git a/custom_components/divoom_pixoo/img/weather/fog.png b/custom_components/divoom_pixoo/img/weather/fog.png new file mode 100644 index 0000000..87d9b19 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/fog.png differ diff --git a/custom_components/divoom_pixoo/img/weather/frost.png b/custom_components/divoom_pixoo/img/weather/frost.png new file mode 100644 index 0000000..eef7c61 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/frost.png differ diff --git a/custom_components/divoom_pixoo/img/weather/humidity.png b/custom_components/divoom_pixoo/img/weather/humidity.png new file mode 100644 index 0000000..25becf4 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/humidity.png differ diff --git a/custom_components/divoom_pixoo/img/weather/lightning.png b/custom_components/divoom_pixoo/img/weather/lightning.png new file mode 100644 index 0000000..562e420 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/lightning.png differ diff --git a/custom_components/divoom_pixoo/img/weather/partlycloudy.png b/custom_components/divoom_pixoo/img/weather/partlycloudy.png new file mode 100644 index 0000000..1a9dc11 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/partlycloudy.png differ diff --git a/custom_components/divoom_pixoo/img/weather/rainy.png b/custom_components/divoom_pixoo/img/weather/rainy.png new file mode 100644 index 0000000..5ebfbe7 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/rainy.png differ diff --git a/custom_components/divoom_pixoo/img/weather/snowy.png b/custom_components/divoom_pixoo/img/weather/snowy.png new file mode 100644 index 0000000..61b70dd Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/snowy.png differ diff --git a/custom_components/divoom_pixoo/img/weather/sunny.png b/custom_components/divoom_pixoo/img/weather/sunny.png new file mode 100644 index 0000000..5cdc14a Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/sunny.png differ diff --git a/custom_components/divoom_pixoo/img/weather/windy.png b/custom_components/divoom_pixoo/img/weather/windy.png new file mode 100644 index 0000000..d210e28 Binary files /dev/null and b/custom_components/divoom_pixoo/img/weather/windy.png differ diff --git a/custom_components/divoom_pixoo/light.py b/custom_components/divoom_pixoo/light.py index 58cb105..a540961 100644 --- a/custom_components/divoom_pixoo/light.py +++ b/custom_components/divoom_pixoo/light.py @@ -3,9 +3,10 @@ from homeassistant.components.light import (ATTR_BRIGHTNESS, PLATFORM_SCHEMA, LightEntity) from homeassistant.const import CONF_IP_ADDRESS from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN +from . import DOMAIN, VERSION from .pixoo64._pixoo import Pixoo import logging @@ -38,7 +39,7 @@ def setup_platform( class DivoomLight(LightEntity): def __init__(self, ip_address): self._ip_address = ip_address - self._name = "divoom_pixoo" + self._name = "Divoom Pixoo 64 Light" self._state = None self._brightness = None self._pixoo = Pixoo(self._ip_address) @@ -69,3 +70,21 @@ def turn_off(self, **kwargs): def update(self) -> None: self._state = self._pixoo.get_state() + + @property + def name(self): + return self._name + + @property + def unique_id(self): + return f"divoom_pixoo_light" + + @property + def device_info(self) -> DeviceInfo: + return DeviceInfo( + identifiers={(DOMAIN, self.unique_id)}, + name=self.name, + manufacturer="Divoom", + model="Pixoo", + sw_version=VERSION, + ) diff --git a/custom_components/divoom_pixoo/schemas/channel_schema.py b/custom_components/divoom_pixoo/schemas/channel_schema.py new file mode 100644 index 0000000..40cdd8d --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/channel_schema.py @@ -0,0 +1,6 @@ +import voluptuous as vol +from homeassistant.helpers import config_validation as cv + +CHANNEL_SCHEMA = vol.Schema({ + vol.Required('number'): cv.positive_int, +}) diff --git a/custom_components/divoom_pixoo/schemas/clockid_schema.py b/custom_components/divoom_pixoo/schemas/clockid_schema.py new file mode 100644 index 0000000..3365202 --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/clockid_schema.py @@ -0,0 +1,6 @@ +import voluptuous as vol +from homeassistant.helpers import config_validation as cv + +CLOCKID_SCHEMA = vol.Schema({ + vol.Required('number'): cv.positive_int, +}) diff --git a/custom_components/divoom_pixoo/schemas/image_schema.py b/custom_components/divoom_pixoo/schemas/image_schema.py new file mode 100644 index 0000000..75b700f --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/image_schema.py @@ -0,0 +1,7 @@ +import voluptuous as vol +from homeassistant.helpers import config_validation as cv + +IMAGE_SCHEMA = vol.Schema({ + vol.Required('image'): cv.string, + vol.Required('position'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=2, max=2)), +}) diff --git a/custom_components/divoom_pixoo/schemas/page_schema.py b/custom_components/divoom_pixoo/schemas/page_schema.py new file mode 100644 index 0000000..f3b7bda --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/page_schema.py @@ -0,0 +1,17 @@ +import voluptuous as vol +from homeassistant.helpers import config_validation as cv +from .text_schema import TEXT_SCHEMA +from .image_schema import IMAGE_SCHEMA +from .pv_schema import PV_SCHEMA +from .channel_schema import CHANNEL_SCHEMA +from .clockid_schema import CLOCKID_SCHEMA + +PAGE_SCHEMA = vol.Schema({ + vol.Required('page'): cv.positive_int, + vol.Optional('condition'): cv.template, + vol.Optional('texts'): vol.All(cv.ensure_list, [TEXT_SCHEMA]), + vol.Optional('images'): vol.All(cv.ensure_list, [IMAGE_SCHEMA]), + vol.Optional('PV'): PV_SCHEMA, + vol.Optional('channel'): vol.All(cv.ensure_list, [CHANNEL_SCHEMA]), + vol.Optional('clockId'): vol.All(cv.ensure_list, [CLOCKID_SCHEMA]), +}) diff --git a/custom_components/divoom_pixoo/schemas/pv_schema.py b/custom_components/divoom_pixoo/schemas/pv_schema.py new file mode 100644 index 0000000..b9aedb3 --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/pv_schema.py @@ -0,0 +1,12 @@ +# pv_schema.py +import voluptuous as vol +from homeassistant.helpers import config_validation as cv + +PV_SCHEMA = vol.Schema({ + vol.Required('power'): cv.string, + vol.Required('storage'): cv.string, + vol.Required('discharge'): cv.string, + vol.Required('powerhousetotal'): cv.string, + vol.Required('vomNetz'): cv.string, + vol.Required('time'): cv.string, +}) diff --git a/custom_components/divoom_pixoo/schemas/text_schema.py b/custom_components/divoom_pixoo/schemas/text_schema.py new file mode 100644 index 0000000..4d6d16d --- /dev/null +++ b/custom_components/divoom_pixoo/schemas/text_schema.py @@ -0,0 +1,9 @@ +import voluptuous as vol +from homeassistant.helpers import config_validation as cv + +TEXT_SCHEMA = vol.Schema({ + vol.Required('text'): cv.string, + vol.Required('position'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=2, max=2)), + vol.Required('font'): cv.string, + vol.Required('font_color'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=3, max=3)), +}) diff --git a/custom_components/divoom_pixoo/sensor.py b/custom_components/divoom_pixoo/sensor.py index cec0d1b..7cf9fb7 100644 --- a/custom_components/divoom_pixoo/sensor.py +++ b/custom_components/divoom_pixoo/sensor.py @@ -6,63 +6,28 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.helpers.entity import Entity from homeassistant.const import CONF_IP_ADDRESS -from homeassistant.helpers.template import Template +from homeassistant.helpers.template import Template, TemplateError +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_platform from . import DOMAIN +from .schemas.page_schema import PAGE_SCHEMA + from .pages.solar import solar from .pixoo64._pixoo import Pixoo from .pixoo64._font import FONT_PICO_8, FONT_GICKO - import logging _LOGGER = logging.getLogger(__name__) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_IP_ADDRESS): cv.string, vol.Optional('scan_interval'): cv.time_period, - vol.Required('pages'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('page'): cv.positive_int, - vol.Optional('texts'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('text'): cv.string, - vol.Required('position'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=2, max=2)), - vol.Required('font'): cv.string, - vol.Required('font_color'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=3, max=3)), - }) - ]), - vol.Optional('images'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('image'): cv.string, - vol.Required('position'): vol.All(cv.ensure_list, [cv.positive_int], vol.Length(min=2, max=2)), - }) - ]), - vol.Optional('PV'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('power'): cv.string, - vol.Required('storage'): cv.string, - vol.Required('discharge'): cv.string, - vol.Required('powerhousetotal'): cv.string, - vol.Required('vomNetz'): cv.string, - vol.Required('time'): cv.string, - }) - ]), - vol.Optional('channel'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('number'): cv.positive_int, - }) - ]), - vol.Optional('clockId'): vol.All(cv.ensure_list, [ - vol.Schema({ - vol.Required('number'): cv.positive_int, - }) - ]), - }) - ]), + vol.Required('pages'): vol.All(cv.ensure_list, [PAGE_SCHEMA]), }) + async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): if discovery_info is None: discovery_info = config.get(DOMAIN) @@ -70,6 +35,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= return ip_address = discovery_info[CONF_IP_ADDRESS] pages = discovery_info.get('pages', []) + for page in pages: + condition_template = page.get('condition') + if condition_template is not None: + try: + page['condition_template'] = Template(condition_template, hass) + except (TemplateError, ValueError) as e: + _LOGGER.error("Error in condition template: %s", e) + page['condition_template'] = None scan_interval_config = discovery_info.get('scan_interval') _LOGGER.debug("Scan interval config: %s", scan_interval_config) @@ -86,6 +59,19 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= entity = Pixoo64(ip_address, pages, scan_interval) async_add_entities([entity], True) + platform = entity_platform.current_platform.get() + platform.async_register_entity_service( + 'show_message', + { + vol.Required('messages'): [cv.string], + vol.Required('positions'): [[cv.positive_int]], + vol.Required('colors'): [[cv.positive_int]], + vol.Required('fonts'): [cv.string], + vol.Optional('images', default=[]): [cv.string], + vol.Optional('image_positions', default=[]): [[cv.positive_int]], + }, + 'async_show_message', + ) class Pixoo64(Entity): @@ -114,7 +100,7 @@ async def async_added_to_hass(self): async def async_will_remove_from_hass(self): """When entity is being removed from hass.""" if self._update_interval is not None: - self._update_interval() # Dies stoppt das Zeitintervall + self._update_interval() self._update_interval = None async def _async_update(self, now=None): @@ -125,11 +111,24 @@ async def _async_update_data(self): if self.showing_notification: return + self._current_page = self._pages[self._current_page_index] current_page_data = self._pages[self._current_page_index] _LOGGER.debug(f"current page: {current_page_data}") - self._current_page = self._pages[self._current_page_index] - self._attr_extra_state_attributes['page'] = self._current_page['page'] - self._current_page_index = (self._current_page_index + 1) % len(self._pages) + self._attr_extra_state_attributes['page'] = current_page_data['page'] + + + if 'condition_template' in current_page_data: + condition = current_page_data['condition_template'] + condition.hass = self.hass + try: + if not condition.async_render(): + self._current_page_index = (self._current_page_index + 1) % len(self._pages) + return + except TemplateError as e: + _LOGGER.error("Error rendering condition template: %s", e) + self._current_page_index = (self._current_page_index + 1) % len(self._pages) + return + def update(): pixoo = Pixoo(self._ip_address) @@ -168,9 +167,13 @@ def update(): pixoo.push() await self.hass.async_add_executor_job(update) + self._current_page_index = (self._current_page_index + 1) % len(self._pages) - async def async_show_message(self, message, position, color, font, image=None, image_position=None): - if self.hass is None: + + + async def async_show_message(self, messages, positions, colors, fonts, images=None, image_positions=None): + if not all([messages, positions, colors, fonts]) or len(messages) != len(positions) != len(colors) != len(fonts): + _LOGGER.error("Lists for messages, positions, colors, and fonts must all be present and have the same length.") return self.showing_notification = True @@ -179,17 +182,23 @@ def draw(): pixoo = Pixoo(self._ip_address) pixoo.clear() - if image and image_position: - pixoo.draw_image(image, tuple(image_position)) + for img, img_pos in zip(images, image_positions): + pixoo.draw_image(img, tuple(img_pos)) + + for message, position, color, font in zip(messages, positions, colors, fonts): + selected_font = FONT_PICO_8 if font == 'FONT_PICO_8' else FONT_GICKO + if font == 'FONT_PICO_8': + pixoo.draw_text(message, tuple(position), tuple(color), selected_font) + else: + pixoo.draw_text(message.upper(), tuple(position), tuple(color), selected_font) - selected_font = FONT_PICO_8 if font == 'FONT_PICO_8' else FONT_GICKO - pixoo.draw_text(message, tuple(position), tuple(color), selected_font) pixoo.push() await self.hass.async_add_executor_job(draw) await asyncio.sleep(self._scan_interval.total_seconds()) self.showing_notification = False + @property def state(self): return self._current_page['page']