QuentinCG / Milight-Wifi-Bridge-3.0-Python-Library

[Done] Milight 3.0 python library (LimitlessLED Wifi Bridge v6.0): Control milight wireless lights with wifi (Python and shell library, multi-platform)
MIT License
16 stars 7 forks source link

Color index ? #3

Closed thevinz62 closed 5 years ago

thevinz62 commented 5 years ago

I have just a new question, how is the color calculated ? I used to use the old library with the 3 components R G and B to have a color. Now i see that in your script it's only one number beteween 0 and 255 ! Is that a way to convert 0-255 R, 0,255 G and 0-255 B to that number between 0 and 255 ? Thank you for help !

QuentinCG commented 5 years ago

I don't know exactly how it is calculated. Here are some examples of colors (it is the protocols that requires this, this is kind of ugly, I fully agree with you on this but I can't do anything about it): 0xFF = Red, 0xD9 = Lavender, 0xBA = Blue, 0x85 = Aqua, 0x7A = Green, 0x54 = Lime, 0x3B = Yellow, 0x1E = Orange https://github.com/QuentinCG/Milight-Wifi-Bridge-3.0-Python-Library/blob/master/MilightWifiBridge/MilightWifiBridge.py#L574

It seems to be the same logic in other scripts using the protocol: https://git.zotha.de/gsgh/gsgh-plugin-milight/blob/bb9c012b0b3913e651b4174fa7f1cc321bd3ee09/milight/milight.go#L14

thevinz62 commented 5 years ago

I have a function written in php that take in entry the hex value of a color (like html) and return the milight color ! Please feel free to use and convert in python to integrate on the script ;-)


function rgbHexToMiLight($hexColor)
    {
        $hexColor = ltrim($hexColor, '#');
        $hexColorLenghth = strlen($hexColor);
        if ($hexColorLenghth != 8 && $hexColorLenghth != 6) {
            throw new \Exception('Color hex code must match 8 or 6 characters');
        }
        if ($hexColorLenghth == 8) {
            $r = hexdec(substr($hexColor, 2, 2));
            $g = hexdec(substr($hexColor, 4, 2));
            $b = hexdec(substr($hexColor, 6, 2));
            if (($r == 0 && $g == 0 && $b == 0) || ($r == 255 && $g == 255 && $b == 255)) {
                throw new \Exception('Color cannot be black or white');
            }
            return array($r, $g, $b);
        }
        $r = hexdec(substr($hexColor, 0, 2));
        $g = hexdec(substr($hexColor, 2, 2));
        $b = hexdec(substr($hexColor, 4, 2));
        if (($r == 0 && $g == 0 && $b == 0) || ($r == 255 && $g == 255 && $b == 255)) {
            throw new \Exception('Color cannot be black or white');
        }
        $r = $r / 255;
        $g = $g / 255;
        $b = $b / 255;
        $max = max($r, $g, $b);
        $min = min($r, $g, $b);
        $l = ($max + $min) / 2;
        $d = $max - $min;
        $h = '';
        if ($d == 0) {
            $h = $s = 0;
        } else {
            $s = $d / (1 - abs(2 * $l - 1));
            switch ($max) {
                case $r:
                    $h = 60 * fmod((($g - $b) / $d), 6);
                    if ($b > $g) {
                        $h += 360;
                    }
                    break;
                case $g:
                    $h = 60 * (($b - $r) / $d + 2);
                    break;
                case $b:
                    $h = 60 * (($r - $g) / $d + 4);
                    break;
            }
        }
        $color = ((int)($h / 360.0 * 255.0)) % 256;
        return $color;
    }```
QuentinCG commented 5 years ago

Nice, thank you, I'll add this when I'll have some time.

QuentinCG commented 5 years ago

Hi @thevinz62

I tried your function (in php) but it doesn't work properly whatever rgb value I use. My other problem is that, $s is used nowhere in your algorithm...

Are you sure you gave the entire algorithm?

QuentinCG commented 5 years ago

To not lose my work while waiting an answer, here is the php -> python edit:


import re
import math

def rgbToMilightColor(rgbColor):
"""Convert RGB color into Milight color format

Keyword arguments:
   milightColor -- (string) RGB color ('#000000' -> '#FFFFFF')

  return: (int) Milight color (between 0 and 255)
 """
    trimmedRgbColor = re.sub('#', '', rgbColor)
    if len(trimmedRgbColor) != 6:
      logging.error("Invalid '{}' RGB color (must be between '#000000' and '#FFFFFF')".format(str(rgbColor)))
      return 0

    red = int(trimmedRgbColor[0:2], 16)
    green = int(trimmedRgbColor[2:4], 16)
    blue = int(trimmedRgbColor[4:6], 16)

    # Absolute black or white are not possible with RGB to Milight algorithm
    if (red == 0 and green == 0 and blue == 0):
      red = 1

    if (red == 255 and green == 255 and blue == 255):
      red = 254

    red = float(red) / 255.0
    green = float(green) / 255.0
    blue = float(blue) / 255.0

    max_value = (max(red, green, blue))
    min_value = (min(red, green, blue))

    mid_range_value = (max_value + min_value) / 2
    range_value = (max_value) - (min_value)

    # No idea what 'h' and 's' mean... (if you know, tell me so I can put better name)
    # Maybe it is hsv values? but not using s and v?????
    h = 0
    if range_value != 0:
      #s = range_value / (1 - abs(2 * mid_range_value - 1))
      if max_value == red:
        h = 60.0 * math.fmod((green - blue) / range_value, 6)
        if blue > green:
          h += 360.0
      elif max_value == green:
        h = 60.0 * ((blue - red) / (range_value + 2))
      elif max_value == blue:
        h = 60.0 * ((red - green) / (range_value + 4))

    return ((int)(h / 360.0 * 255.0)) % 256`
QuentinCG commented 5 years ago

Since there is no information anywhere (even from milight documentation) on how to convert correctly from rgb to milight color format, I will close this issue.

Feel free to do reverse engineering on milight and update this issue (or open a new issue).