Ankündigung

Einklappen
Keine Ankündigung bisher.

HSV relatives Dimmen in absoluten RGB-Wert umrechnen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    [Codebeispiel] HSV relatives Dimmen in absoluten RGB-Wert umrechnen

    Moin,
    da ich zu meinem Vorhaben nicht wirklich viel gefunden habe, dachte ich mir, ich stelle meine aktuelle Sonntagsbastelei hier kurz vor. Natürlich mit dem Hintergedanken, dass sie unter Euren kritischen Augen nur besser werden kann und dass der eine oder andere vielleicht auch etwas damit anfangen kann.

    Zuerst mal kurz zum Problem:
    RGB LEDs werden via DALI vom MDT Dali Gateway gesteuert. Die Ansteuerung erfolgt über 3Byte RGB. Das Gateway kann alternativ auch HSV, aber nicht beides gleichzeitig.
    Ein BJE Comfort Panel und MDT Glastaster 2 sollen jeweils die Steuerung übernehmen. Hier liegt das Problem: BJE spricht nur RGB, die Glastaster nur HSV.

    Also erstmal die Items konfigurieren:
    Code:
    # wz_voute.yaml
    %YAML 1.1
    ---
    wohnzimmer:
        voute:
            schalten:
                name: Voute schalten
                type: bool
                knx_dpt: 1.001
                knx_send: 2/0/18
                knx_listen: 2/0/20
            dimmen:
                name: Voute dimmen
                type: foo
                knx_dpt: 3.007
                knx_send: 2/0/19
            absolut:
                name: Voute absolut dimmen
                type: num
                knx_dpt: 5.001
                knx_send: 2/0/23
                knx_listen: 2/0/24
            rgb:
                name: Voute RGB-Wert
                type: num
                knx_dpt: 232.600
                knx_send: 2/0/21
                knx_listen: 2/0/22
            hue_wert:
                name: Voute Farbton
                type: num
                knx_dpt: 5.003
                knx_send: 2/0/30
            hue_dimmen:
                name: Voute Farbton relativ
                type: foo
                knx_dpt: 3.007
                knx_listen: 2/0/31
            sat_wert:
                name: Voute Sättigung
                type: num
                knx_dpt: 5.001
                knx_send: 2/0/32
            sat_dimmen:
                name: Voute Sättigung relativ
                type: foo
                knx_dpt: 3.007
                knx_listen: 2/0/33
            val_wert:
                name: Voute Helligkeit
                type: num
                knx_dpt: 5.001
                knx_send: 2/0/34
            val_dimmen:
                name: Voute Helligkeit relativ
                type: foo
                knx_dpt: 3.007
                knx_listen: 2/0/35
    Schritt 1:
    Der Glastaster verändert die Werte für Hue, Saturation und Value nicht als Wertedimmer, sondern über normale 4 Bit Diagramme. Also habe ich erstmal drei virtuelle Dimmer als Logiken gebaut. Ich zeige hier nur Hue und Saturation, Value ist ja dasselbe Vorgehen wie Saturation.

    Code:
    #!/usr/bin/env python3
    #
    # This file contains a logic for use with SmartHomeNG
    #
    # Name of the logic: wz_dimmer_h.py
    #
    
    # This logic performs the following function(s):
    #
    #   Aktualisiert den DPT 5.003 Hue Wert über ein 3.007 Telegramm
    #   von Gentlemanunlike und ChatGPT
    
    # The following triggers should be defined in ../etc/logic.yaml:
    #   watch_item ist das jeweilige Dimmtelegramm
    #    watch_item = wohnzimmer.voute.hue_dimmen
    #
    
    # Variablenkonfiguration
    Wert = sh.wohnzimmer.voute.hue_wert()   #Wert der gedimmt werden soll
    Schritt = sh.wohnzimmer.voute.hue_dimmen() #Dimmtelegramm
    Schrittweite = 3 #Dimmgeschwindigkeit
    
    # Dimmfunktion
    def rel_dimmen(Wert, Schritt, Schrittweite):
        
        # Berechnen des Dimmwerts basierend auf dem Schritt
        if Schritt == 0:
            return Wert  # Keine Änderung
        
        # Dimmwert verringern
        if Schritt < 8:
            neuer_wert = Wert - Schrittweite
            return neuer_wert % 256  # Zyklisch durchlaufen
        
        # Dimmwert erhöhen
        elif Schritt < 15:
            neuer_wert = Wert + Schrittweite
            return neuer_wert % 256  # Zyklisch durchlaufen
        
        # Maximale Helligkeit
        else:
            return Wert # Keine Änderung
    
    neuer_wert = rel_dimmen(Wert, Schritt, Schrittweite)
    sh.wohnzimmer.voute.hue_wert(neuer_wert)​
    Code:
    #!/usr/bin/env python3
    #
    # This file contains a logic for use with SmartHomeNG
    #
    # Name of the logic: wz_dimmer_s.py
    #
    
    # This logic performs the following function(s):
    #
    #   Aktualisiert den DPT 5.001 Sat Wert über ein 3.007 Telegramm
    #   von Gentlemanunlike und ChatGPT
    
    # The following triggers should be defined in ../etc/logic.yaml:
    #   watch_item ist das jeweilige Dimmtelegramm
    #    watch_item = wohnzimmer.voute.sat_dimmen
    #
    
    # Variablenkonfiguration
    Wert = sh.wohnzimmer.voute.sat_wert()   #Wert der gedimmt werden soll
    Schritt = sh.wohnzimmer.voute.sat_dimmen() #Dimmtelegramm
    Schrittweite = 3 #Dimmgeschwindigkeit
    
    # Dimmfunktion
    def rel_dimmen(Wert, Schritt, Schrittweite):
        
        # Berechnen des Dimmwerts basierend auf dem Schritt
        if Schritt == 0:
            return Wert  # Keine Änderung
        
        # Dimmwert verringern
        if Schritt < 8:
            return Wert - Schrittweite if Wert >= Schrittweite else 0
        
        # Dimmwert erhöhen
        elif Schritt < 15:
            return Wert + Schrittweite if Wert + Schrittweite <= 100 else 100
        
        # Maximale Helligkeit
        else:
            return Wert # Keine Änderung
    
    neuer_wert = rel_dimmen(Wert, Schritt, Schrittweite)
    sh.wohnzimmer.voute.sat_wert(neuer_wert)
    Wie ihr seht, habe ich mir künstliche Hilfe geholt. Für einen Wenig-Programmierer wie mich ein echter Segen.

    Ich mache mich jetzt an die Umrechnung, ihr könnt bis hier ja gerne schonmal Feedback geben

    Beste Grüße

    Unknown User
    Zuletzt geändert von unknownuser; 21.04.2024, 11:47. Grund: kleinere Korrekturen

    #2
    Und nun die Umrechnung von HSV zu RGB:
    Code:
    #!/usr/bin/env python3
    #
    # This file contains a logic for use with SmartHomeNG
    #
    # Name of the logic: wz_voute_hsv_to_rgb.py
    #
    
    # This logic performs the following function(s):
    #
    #   Konvertiert Hue Sat und Val in ein 3Byte RGB Telegramm
    #   Erstellt von UnknownUser und ChatGPT
    
    # The following triggers should be defined in ../etc/logic.yaml:
    #
    #    watch_item = <leuchte>.hue_wert | <leuchte>.sat_wert | <leuchte>.val_wert
    #
    
    def knx_to_float(knx_value):
        """
        Convert KNX 8-bit value (0-255) to float (0-1).
        
        Args:
        knx_value (int): KNX 8-bit value
        
        Returns:
        float: Float value between 0 and 1
        """
        return knx_value / 255.0
    
    def knx_to_hue(knx_value):
        """
        Convert KNX 8-bit value (0-255) to hue value (0-360).
        
        Args:
        knx_value (int): KNX 8-bit value
        
        Returns:
        float: Hue value between 0 and 360
        """
        return knx_value * 360.0 / 255.0
    
    def hsv_to_rgb(h, s, v):
        """
        Convert HSV (Hue, Saturation, Value) to RGB (Red, Green, Blue).
        
        Args:
        h (float): Hue value (0-360)
        s (float): Saturation value (0-1)
        v (float): Value value (0-1)
        
        Returns:
        int: 24-bit RGB value
        """
        
        # Umrechnung der Winkel von Grad in einen Faktor zwischen 0 und 1
        h /= 360.0
        
        # Berechnung der Werte C, X und m
        c = v * s
        x = c * (1 - abs((h * 6) % 2 - 1))
        m = v - c
        
        # Initialisierung der RGB-Werte
        r, g, b = 0, 0, 0
        
        # Umrechnung je nach Hue-Bereich
        if 0 <= h < 1/6:
            r, g, b = c, x, 0
        elif 1/6 <= h < 2/6:
            r, g, b = x, c, 0
        elif 2/6 <= h < 3/6:
            r, g, b = 0, c, x
        elif 3/6 <= h < 4/6:
            r, g, b = 0, x, c
        elif 4/6 <= h < 5/6:
            r, g, b = x, 0, c
        elif 5/6 <= h < 1:
            r, g, b = c, 0, x
        
        # Umrechnung von 0-1 in 0-255
        r = int((r + m) * 255)
        g = int((g + m) * 255)
        b = int((b + m) * 255)
        
        # Zusammensetzung des 24-Bit RGB-Werts
        rgb_wert = (r << 16) + (g << 8) + b
        
        return rgb_wert
    
    # Hauptprogramm
    h_knx = sh.wohnzimmer.voute.hue_wert()
    s_knx = sh.wohnzimmer.voute.sat_wert()
    v_knx = sh.wohnzimmer.voute.val_wert()
        
    h = knx_to_hue(h_knx)
    s = knx_to_float(s_knx)
    v = knx_to_float(v_knx)
        
    rgb_wert = hsv_to_rgb(h, s, v)
    sh.wohnzimmer.voute.rgb(rgb_wert)
    ​
    Damit die Anzeige auf den Glastastern stimmt, muss natürlich auch ein geänderter RGB Wert in HSV Werte konvertiert werden:
    Code:
    #!/usr/bin/env python3
    #
    # This file contains a logic for use with SmartHomeNG
    #
    # Name of the logic: wz_voute_rgb_to_hsv.py
    #
    
    # This logic performs the following function(s):
    #
    #    Konvertiert einen 232.600 RGB Wert in Werte für Hue (5.003) Saturation und Value (je 5.001)
    #
    
    # The following triggers should be defined in ../etc/logic.yaml:
    #
    #    watch_item = <leuchte>.rgb_wert
    #
    
    def rgb_to_hsv(rgb_wert):
        """
        Convert 24-bit RGB value to HSV (Hue, Saturation, Value).
        
        Args:
        rgb_wert (int): 24-bit RGB value (KNX 232.600)
        
        Returns:
        tuple: HSV values as floats (Hue between 0-360, Saturation and Value between 0-1)
        """
        
        # Extraktion der RGB-Komponenten aus dem 24-Bit RGB-Wert
        r = (rgb_wert >> 16) & 0xFF
        g = (rgb_wert >> 8) & 0xFF
        b = rgb_wert & 0xFF
        
        # Umrechnung von 0-255 in 0-1
        r /= 255.0
        g /= 255.0
        b /= 255.0
        
        cmax = max(r, g, b)
        cmin = min(r, g, b)
        delta = cmax - cmin
        
        # Berechnung des Hue-Wertes
        if delta == 0:
            h = 0
        elif cmax == r:
            h = 60 * (((g - b) / delta) % 6)
        elif cmax == g:
            h = 60 * (((b - r) / delta) + 2)
        else:
            h = 60 * (((r - g) / delta) + 4)
        
        # Berechnung des Saturation-Wertes
        if cmax == 0:
            s = 0
        else:
            s = delta / cmax
        
        # Berechnung des Value-Wertes
        v = cmax
        
        # Umrechnung des Hue-Wertes von 0-360 in 0-255
        h_knx = int(h * 255 / 360)
        
        return h_knx, int(s * 255), int(v * 255)
    
    # Hauptprogramm
    rgb_wert = sh.wohnzimmer.voute.rgb()
        
    h_knx, s_knx, v_knx = rgb_to_hsv(rgb_wert)
        
    sh.wohnzimmer.voute.hue_wert(h_knx)
    sh.wohnzimmer.voute.sat_wert(s_knx)
    sh.wohnzimmer.voute.val_wert(v_knx)
    ​
    Zuletzt geändert von unknownuser; 21.04.2024, 11:48. Grund: kleinere Korrekturen

    Kommentar


      #3
      So langsam gehen die Probleme los 😅

      Plan: Logiken so anpassen, dass ich nicht für jede LED Leuchte einen eigenen Satz Logiken brauche
      Problem: Naja, irgendwie bekomme ich die Syntax nicht auf die Kette...

      Logfile
      Code:
      2024-04-21  15:30:19 ERROR    logics.wz_voute_hsv_to_rgb In der Logik ist ein Fehler aufgetreten:
         Logik 'wz_voute_hsv_to_rgb', Datei '/usr/local/smarthome/logics/wz_voute_hsv_to_rgb.py', Zeile 91
         Hauptroutine der Logik, Exception: 'str' object has no attribute 'return_parent'​
      Code (die Funktion klappt, deshalb nur das Hauptprogramm)
      Code:
      # Hauptprogramm
      Item = trigger['by'].return_parent() #Dies ist besagte Zeile 91
      h_knx = Item.hue_wert()
      s_knx = Item.sat_wert()
      v_knx = Item.val_wert()
      logger.debug("Ausgabe der erstellten Variablen")
      logger.debug(Item)
      logger.debug(h_knx)
      logger.debug(s_knx)
      logger.debug(v_knx)
          
      h = knx_to_hue(h_knx)
      s = knx_to_float(s_knx)
      v = knx_to_float(v_knx)
          
      rgb_wert = hsv_to_rgb(h, s, v)
      Item.rgb(rgb_wert)
      logger.debug(Item.rgb())
      ​
      Ich habe schon einige Varianten durch, aber keine hat funktioniert. Irgendwie habe ich das mit den Properties noch nicht so ganz verstanden 😅

      Kommentar


        #4
        Das trigger dict enthält nur Strings. trigger['by'] enthält also den path des Items, welches getriggert hat, nicht das Item-Objekt.

        Um das Itemobjekt zu bekommen, musst Du noch return_item(path) verwenden.

        Die zeile muss also
        Code:
        Item = sh.items.return_item(trigger['by']).return_parent()
        heissen.
        Zuletzt geändert von Msinn; 21.04.2024, 15:31.
        Viele Grüße
        Martin

        There is no cloud. It's only someone else's computer.

        Kommentar


          #5
          Du kannst Dir mal spasseshalber folgende Codezeilen in den Kopf Deiner Logik kopieren:
          Code:
          if sh.shng_status['code'] != 20:
              logic.logger.warning('Logik ignoriert, SmartHomeNG läuft noch nicht')
              raise LeaveLogic()
          
          by = trigger.get('by', '')
          source = trigger.get('source', '')
          dest = trigger.get('dest', '')
          value = trigger.get('value', '')
          logger.debug(f'Triggered by {by}, source {source}, value {value}, dest {dest}')
          dann wirst Du (Logging korrekt eingestellt für Deine Logik) sowas im Log finden:

          Code:
          2024-04-21 15:50:37 DEBUG logics.EG_Kueche_Bewegungsmelder Getriggert durch: {'by': 'Item', 'source': 'Kueche.Praesenzmelder', 'source_details': 'knx:1.1.107:ga=8/1/100', 'dest': None, 'value': False}
          ​
          Daraus folgt für Deinen Code entsprechend das Du 'Item' zurückgeliefert bekommst, was ein string aber kein Item ist.

          Du kannst dann ein Item bekommen mit der Funktion sh.items.return_item(trigger['source'])). Allerdings solltest Du Fehlerbehandlung in der Logik nutzen, falls trigger['by'] z.B. nicht 'Item' ist, dann kommt bei source nicht das erwartete heraus.
          Zuletzt geändert von bmx; 21.04.2024, 15:35.

          Kommentar


            #6
            Zitat von bmx Beitrag anzeigen
            Daraus folgt für Deinen Code entsprechend das Du 'Item' zurückgeliefert bekommst, was ein string aber kein Item ist.

            Du kannst dann ein Item bekommen mit der Funktion sh.items.return_item(trigger['source'])). Allerdings solltest Du Fehlerbehandlung in der Logik nutzen, falls trigger['by'] z.B. nicht 'Item' ist, dann kommt bei source nicht das erwartete heraus.
            Erstmal: Danke! Ich stand gerade nämlich vor dem String-Problem.
            Zu deinem Vorschlag: Ich habe jetzt das Hauptprogramm in eine if-Schleife gepackt. Das sollte ja eigentlich ausreichen, oder was meinst du?

            Code:
            # Hauptprogramm
            if trigger['by'] == "Item":
                Item =  sh.items.return_item(trigger['source']).return_parent()
                h_knx = Item.hue_wert()
                s_knx = Item.sat_wert()
                v_knx = Item.val_wert()
                
                h = knx_to_hue(h_knx)
                s = knx_to_float(s_knx)
                v = knx_to_float(v_knx)
                
                rgb_wert = hsv_to_rgb(h, s, v)
                Item.rgb(rgb_wert)​
            So funktioniert es bisweilen auch. Deinen Header finde ich gut, den werde ich gleich einfügen!

            Kommentar

            Lädt...
            X