Getting started with AppDaemon scripting

@tjntomas my current progress is below. However, this image below will still be mostly white; I assumed the “dominant” color here to be green, not white (even though white is altogether using up more space of the image). So while my script works, I am not 100% happy with it.

# Interaktion zwischen Home Assistant und AppDaemon
import appdaemon.plugins.hass.hassapi as hass
# Farben auslesen
from colorthief import ColorThief
# HTTP Kram
import urllib.request
# Zufallsauswahl
import random
# Farben rgb <==> hex
from colour import Color
# Farben intensivieren (saturation)
from colormap import rgb2hex, hex2rgb

# VARIABELN FESTLEGEN
IMG_NAME = "img.jpg"

# Klasse zum Auslesen der Farbe
class ColorMedia(hass.Hass):
    def initialize(self):

        # erfrage die Config Parameters aus apps.yaml
        self.sensor = self.args['sensor']
        self.media_player = self.args['media_player']
        self.light = self.args['light']
        self.mein_effect = self.args['effect']
        self.url = self.args.get("ha_url", None)
        # self.helligkeit = self.args['brightness']

        # Beobachte, wann der media_player die Grafik ändert
        self.listen_state(self.set_color, self.media_player, attribute="entity_picture")

    def set_color(self, entity, attribute, old, new, kwargs):
        # erhalte URL der Grafik vom media_player attribute "entity_picture"
        img_url = self.get_state(entity, attribute="entity_picture")
        new_url = self.url + img_url

        # Speichere die Grafik lokal ab
        urllib.request.urlretrieve(new_url, IMG_NAME)

        # Farben auslesen, festlegen, etc.
        color_thief = ColorThief(IMG_NAME)
        rgb_color = color_thief.get_color()
        rgb_list = [rgb_color[0], rgb_color[1], rgb_color[2]]
        self.log(rgb_list)
        # In Hex umwandeln
        chex = Color(rgb2hex(rgb_color[0], rgb_color[1], rgb_color[2]))
        self.log("Saturation: %s" % chex.saturation)
        if chex.saturation < 0.55:
            chex.saturation = 0.6
        else:
            pass
        rgb_list = hex2rgb("%s" % chex)
        self.log(rgb_list)

        # # Update den Sensor in Home Assistant mit der neuen Farbe
        self.set_state(self.sensor, state=rgb_list)


        # # Zufälligen Effekt beim Wechsel
        optionen = self.mein_effect
        zufall = random.choice(optionen)

        # # Stelle das Licht entsprechend ein
        self.turn_on(self.light, rgb_color=rgb_list)
        # # Verändere den Effekt und die Helligkeit
        # self.call_service("light/turn_on", entity_id=self.light, effect=self.mein_effect, brightness=self.helligkeit)
        self.call_service("light/turn_on", entity_id=self.light, effect=zufall)

        # # Ab hier rumgeteste
        # teststate = self.get_state(self.light, attribute="effect")
        # # self.log("Hier steht was")
        # self.log(teststate)

I should really switch to writing comments in English as well…

Hi there,

I am testing this integration for some hours but I am getting this error:

File "/usr/lib/python3.8/site-packages/appdaemon/app_management.py", line 788, in check_app_updates
    await utils.run_in_executor(self, self.read_app, mod["name"], mod["reload"])
  File "/usr/lib/python3.8/site-packages/appdaemon/utils.py", line 276, in run_in_executor
    response = future.result()
  File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/lib/python3.8/site-packages/appdaemon/app_management.py", line 580, in read_app
    self.modules[module_name] = importlib.import_module(module_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/config/appdaemon/apps/ben_colorthief.py", line 4, in <module>
    from colorthief import ColorThief
ModuleNotFoundError: No module named 'colorthief'

I think its nothing big but I am not getting it.

Greets
Daniel

EDIT: Got it!

I’ll say this in case anybody else encounters the same issue: you need to install Color Thief manually, either by running the pip command in the docker container, or (if I understand the docs correctly) via a requirements.txt in the root directory og AppDaemon.

I did a manual installation and now I get another error:

File "/config/appdaemon/apps/colorthief/colorthief.py", line 4, in <module>
    from colorthief import ColorThief
ImportError: cannot import name 'ColorThief' from partially initialized module 'colorthief' (most likely due to a circular import) (/config/appdaemon/apps/colorthief/colorthief.py)

How do you have your system setup? Appdaemon in Docker, as an add-on to Home Assistant, or in a docker container? The library install procedures are slightly different depending on the above.

As add-on in Home Assistant

Ok, have a look here: https://appdaemon.readthedocs.io/en/latest/DOCKER_TUTORIAL.html?highlight=requirements.txt#adding-dependencies

You need to create a requirements.txt in the appdaemon config folder file and add the required dependencies there.

In this case, just add the line
colorthief==0.2.1
to the text file and restart Appdaemon.

And remove the manually installed library.

@tjntomas are you still working on this?

While the solution I last posted here works okay, I am not happy with some colors; usually, if the associated cover image is mostly, let’s say blue, the lights will turn blue. However, in rare occasions, it will be a totally different color that is not even on the cover (or so little that you wouldn’t realize when looking at the cover), so you’d expect blue lights and they’ll turn purple… I have not been able to find the cause for this, as it only happens very seldomly.

Another issue is the saturation. When a cover is mostly white, my saturation attempt will work and set the lights to some color instead of white, as (if I understand correctly) most covers aren’t 100% white, but have some tint of color in them that just gets saturated through the appdaemon script. But I guess our eyes/minds “expect” different colors from the images we see than the script calculates. Just now a song started with a cover that looks to me like it is a very de-saturated shade of green - yet the lights turn to blue after being saturated to the declared value; I don’t see why what looks to be green turns blue when saturated more.

Since WLED allows a secondary color to be set (so some effects can be constructed from two different, manually defined colors), I’ll work on building a palette (works via ColorThief, then trying to use the two most dominant colors. I tried this a bit, but didn’t get it to work (while the palette will actually be built, it will have some colors I don’t see in the image at all, then again miss some essential colors that are definitely there).