SmartHome-yourself / sonoff-tx-ultimate-for-esphome

ESPHome Custom Component for Sonoff TX Ultimate
https://smarthomeyourself.de/sonoff-tx-ultimate-mit-esphome-custom-component/
MIT License
87 stars 36 forks source link

4 Relays version #26

Open umbex opened 7 months ago

umbex commented 7 months ago

Hello, thanks for the great work!

I'm tinkering with the 120-4 Relays EU version, and I figured out to enable the 4th channel touch on the yaml.

FYI, touch positions are mapped as follows: Touch 1: pos 1,2 Touch 2: pos 3,4,5 Touch 3: pos 6,7,8 Touch 4: pos 9,10

LEDS are 32. Top side: from 31 to 8 Right side: from 9 to 14 Bottom side: from 15 to 24 Left side: from 25 to 30

Having four buttons, the mapping of scripts with button_left, middle, right will need a renaming maybe. It will be great if you will like to support this device version. All the best

Jetro97 commented 7 months ago

Same here,

I'm available to help supporting this version

iUnstable0 commented 7 months ago

same. also @umbex thanks for providing the positions n the led ill try maybe editing and if it works might create a PR

iUnstable0 commented 6 months ago

@umbex for the leds the orientation u mean when mounting it portrait? or landscape? if you get what i mean 😅

iUnstable0 commented 6 months ago

@umbex this is useful https://github.com/SmartHome-yourself/sonoff-tx-ultimate-for-esphome/issues/15#issuecomment-1826440436

I edited it and added support for 4 relays also changed a couple of things to match my needs this is the yaml variant.c4.yaml

script:
  - id: do_nighttime_mode_active
    then:
      - lambda: |-
          ESP_LOGD("script.do_nighttime_mode_active", "Nighttime mode activated...");

          float red = ${nt_exp_red};
          float green = ${nt_exp_green};
          float blue = ${nt_exp_blue};
          float bright = ${nt_exp_bright};

          float s_red = ${nt_exp_s_red};
          float s_green = ${nt_exp_s_green};
          float s_blue = ${nt_exp_s_blue};
          float s_bright = ${nt_exp_s_bright};

          ESP_LOGD("script.do_nighttime_mode_active", "Setting TEMPLATE(s) => R: %f G: %f B: %f BR: %f", red, green, blue, bright);

          id(leds_sw_left).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_bright).set_transition_length(0).perform();
          id(leds_sw_right).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_bright).set_transition_length(0).perform();

          id(figure_out_which_partition_to_light).execute(1);
          id(figure_out_which_partition_to_light).execute(2);
          id(figure_out_which_partition_to_light).execute(3);
          id(figure_out_which_partition_to_light).execute(4);

  - id: do_daytime_mode_active
    then:
      - lambda: |-
          ESP_LOGD("script.do_daytime_mode_active", "Daytime mode activated...");

          float red = ${dt_exp_red};
          float green = ${dt_exp_green};
          float blue = ${dt_exp_blue};
          float bright = ${dt_exp_bright};

          float s_red = ${nt_exp_s_red};
          float s_green = ${nt_exp_s_green};
          float s_blue = ${nt_exp_s_blue};
          float s_bright = ${nt_exp_s_bright};

          ESP_LOGD("script.do_daytime_mode_active", "Setting TEMPLATE(s) => R: %f G: %f B: %f BR: %f", red, green, blue, bright);

          id(leds_sw_left).turn_off().set_rgb( s_red, s_green, s_blue ).set_brightness(s_bright).set_transition_length(0).perform();
          id(leds_sw_right).turn_off().set_rgb( s_red, s_green, s_blue ).set_brightness(s_bright).set_transition_length(0).perform();

          id(figure_out_which_partition_to_light).execute(1);
          id(figure_out_which_partition_to_light).execute(2);
          id(figure_out_which_partition_to_light).execute(3);
          id(figure_out_which_partition_to_light).execute(4);

  - id: figure_out_which_partition_to_light
    mode: single
    parameters:
      output_num: int
    then:
      - lambda: |-
          auto TAG = "script.figure_out_which_partition_to_light";
          // We don't know WHICH partition light to pull RGB/BR from, but regardless we do need place to store....
          float red, green, blue, br;

          float s_red = ${nt_exp_s_red};
          float s_green = ${nt_exp_s_green};
          float s_blue = ${nt_exp_s_blue};
          float s_br = ${nt_exp_s_bright};

          ESP_LOGD(TAG, "Trigger was output %d", output_num);

          switch (output_num) {
            case 1:
                // Output 1 is left button, so we want to light the top partition
                id(template_light_1).current_values_as_rgb(&red, &green, &blue);
                id(template_light_1).current_values_as_brightness(&br);
                ESP_LOGD(TAG, "Light State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);

                // Will be either just .state for entities that have bool on/off properties or something like
                //  .current_values.is_on() for entities that don't.
                if(id(out_1).${out_1_state_exp}) {
                  ESP_LOGD(TAG, "out_1: ON, setting left side ON");

                  ESP_LOGD(TAG, "glbl_normal_regime_mode_is_nighttime: %d", id(glbl_normal_regime_mode_is_nighttime));

                  // If night mode is active, we dont turn off but instead change the color to match the exp_s values (left and right side of the switches for night light)
                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_1_bottom).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_1_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }

                  id(leds_button_1_top).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                } else {
                  ESP_LOGD(TAG, "out_1: OFF, setting right side ON");

                  id(leds_button_1_bottom).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();

                  ESP_LOGD(TAG, "glbl_normal_regime_mode_is_nighttime: %d", id(glbl_normal_regime_mode_is_nighttime));

                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_1_top).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_1_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }
                }
                break;
            case 2:
                id(template_light_2).current_values_as_rgb(&red, &green, &blue);
                id(template_light_2).current_values_as_brightness(&br);

                ESP_LOGD(TAG, "Light State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);

                // The C++ code we call changes based on which type of output out_2 is
                if(id(out_2).${out_2_state_exp}) {
                  ESP_LOGD(TAG, "out_2: ON, setting left side ON");

                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_2_bottom).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_2_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }

                  id(leds_button_2_top).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                } else {
                  ESP_LOGD(TAG, "out_2: OFF, setting right side ON");

                  id(leds_button_2_bottom).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();

                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_2_top).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_2_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }
                }
                break;
            case 3:
                id(template_light_3).current_values_as_rgb(&red, &green, &blue);
                id(template_light_3).current_values_as_brightness(&br);

                ESP_LOGD(TAG, "Light State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);

                if(id(out_3).${out_3_state_exp}) {
                  ESP_LOGD(TAG, "out_3: ON, setting left side ON");

                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_3_bottom).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_3_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }

                  id(leds_button_3_top).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                } else {
                  ESP_LOGD(TAG, "out_3: OFF, setting right side ON");

                  id(leds_button_3_bottom).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();

                  if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                    id(leds_button_3_top).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                  } else {
                    id(leds_button_3_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  }
                }
                break;
              case 4:
                  id(template_light_4).current_values_as_rgb(&red, &green, &blue);
                  id(template_light_4).current_values_as_brightness(&br);

                  ESP_LOGD(TAG, "Light State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);

                  if(id(out_4).${out_4_state_exp}) {
                    ESP_LOGD(TAG, "out_4: ON, setting left side ON");

                    if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                      id(leds_button_4_bottom).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                    } else {
                      id(leds_button_4_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                    }

                    id(leds_button_4_top).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                  } else {
                    ESP_LOGD(TAG, "out_4: OFF, setting right side ON");

                    id(leds_button_4_bottom).turn_on().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();

                    if ( id(glbl_normal_regime_mode_is_nighttime) ) {
                      id(leds_button_4_top).turn_on().set_rgb( s_red, s_green, s_blue ).set_brightness(s_br).set_transition_length(0).perform();
                    } else {
                      id(leds_button_4_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
                    }
                  }
                  break;
              default:
                ESP_LOGE(TAG, "Unknown output number: %d", output_num);
                return;
            }

  # Called on boot or any time we're transitioning from mood-light to a "normal" mode
  - id: resume_normal_regime_for_leds
    mode: single
    # When resuming normal regime, figure out which color scheme we should be using and then run the "figure out which partition to light" script for each output
    then:
      # TODO: SUN HORIZON
      # - script.execute:
      #     id: figure_out_normal_regime_mode
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 1
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 2
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 3
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 4

##
# See the LEDs section of readme.md
# There are 10 LEDs on each side, we have 3 groups which means we'll need 4 "buffers"
# 10 - 4 = 6 and 6/3 is 2 so we'll use 2 leds per partition
##
light:
  - name: "Left"
    platform: partition
    id: leds_sw_left
    segments:
      - id: leds_all
        from: 25
        to: 30
      - id: leds_all
        from: 0
        to: 1
      - id: leds_all
        from: 3
        to: 4
      - id: leds_all
        from: 6
        to: 7

    effects:
      - addressable_scan:
          name: "Scan"
      - addressable_rainbow:
          name: "Rainbow"
          speed: 10
          width: 20

  - name: "Right"
    platform: partition
    id: leds_sw_right
    segments:
      - id: leds_all
        from: 9
        to: 14
      - id: leds_all
        from: 16
        to: 17
      - id: leds_all
        from: 19
        to: 20
      - id: leds_all
        from: 22
        to: 23

    effects:
      - addressable_scan:
          name: "Scan"
      - addressable_rainbow:
          name: "Rainbow"
          speed: 10
          width: 20

  - name: "Button Left Top (internal)"
    platform: partition
    id: leds_button_1_top
    internal: true
    segments:
      - id: leds_all
        from: 31
        to: 31

  - name: "Button Left Bottom (internal)"
    platform: partition
    id: leds_button_1_bottom
    internal: true
    segments:
      - id: leds_all
        from: 24
        to: 24

  - name: "Button Middle Left Top (internal)"
    platform: partition
    id: leds_button_2_top
    internal: true
    # segments: [3]
    segments:
      - id: leds_all
        from: 2
        to: 2

  - name: "Button Middle Left Bottom (internal)"
    platform: partition
    id: leds_button_2_bottom
    internal: true
    # segments: [22]
    segments:
      - id: leds_all
        from: 21
        to: 21

  - name: "Button Middle Right Top (internal)"
    platform: partition
    id: leds_button_3_top
    internal: true
    # segments: [6]
    segments:
      - id: leds_all
        from: 5
        to: 5

  - name: "Button Middle Right Bottom (internal)"
    platform: partition
    id: leds_button_3_bottom
    internal: true
    # segments: [19]
    segments:
      - id: leds_all
        from: 18
        to: 18

  - name: "Button Right Top (internal)"
    platform: partition
    id: leds_button_4_top
    internal: true
    # segments: [9]
    segments:
      - id: leds_all
        from: 8
        to: 8

  - name: "Button Right Bottom (internal)"
    platform: partition
    id: leds_button_4_bottom
    internal: true
    # segments: [16]
    segments:
      - id: leds_all
        from: 15
        to: 15

  # Expose a "template" light entity to HA.
  # Use this to "wrap" the partition lights and pass through values to them.
  # See readme.md for more info
  - platform: custom
    lambda: |-
      // Sign of life
      ESP_LOGD("light.template_light", "Alive!");

      auto template_light_1 = new TemplateLight();
      App.register_component(template_light_1);

      auto template_light_2 = new TemplateLight();
      App.register_component(template_light_2);

      auto template_light_3 = new TemplateLight();
      App.register_component(template_light_3);

      auto template_light_4 = new TemplateLight();
      App.register_component(template_light_4);

      return {template_light_1, template_light_2, template_light_3, template_light_4};

    lights:
      - name: "Indicator 1"
        id: template_light_1
        # Expose to HA, under config section
        internal: false
        entity_category: config

        # Template light should restore to last state / ON at boot
        restore_mode: RESTORE_AND_ON
        # We do not bother with gamma correction here, we want to keep the values as unadulterated as possible as this is JUST a pass through
        # The actual light(s) that we pass values to will handle gamma correction (if configured)
        gamma_correct: 0.0
        # Likewise, we do not want to do any smoothing here, we want to pass the values through as quickly as possible
        default_transition_length: 0s

        # In testing, I can't get the (gamma corrected...) partition light(s) to turn on at all below ~20%.
        # Not clear _why_ this is (too dim to see?) but it's a problem because there's nothing preventing you from setting a brightness of < 20% in HA.
        # HA thinks that the light is on, but it's not actually on.
        # Ideally i'd be able to set min_brightness here like I can with other types of light in ESPHome, but I can't.
        # More than likely i'll need to implement this myself in the template_light.h file.
        ##
        # We need to link our state to the actual partition lights... which is not as straightforward as expected.
        # After a lot of trial/error, this is the least janky method I could come up with.
        ##
        # Because we have a transition length of 0, the on_state hook really shouldn't be called more than 2x
        # Once as soon as any command is received; it'll print the state we're about to move away from
        # Once as soon as we've reached the  commanded state that was just received; it'll print the state we're at / should match what HA commanded.
        # However, the on_state call is STILL needed because a light that is on full red and then given a command to go to full purple will not pass through
        #   on/off state.
        ##
        on_turn_on:
          - lambda: |-
              // Get user requested RGB values and pass them through to the partition lights
              float red, green, blue, br;
              id(template_light_1).current_values_as_rgb(&red, &green, &blue);
              id(template_light_1).current_values_as_brightness(&br);

              // Pass through should happen ONLY in the on_state and on_turn_off hooks so just log here
              // Since we have ZERO gamma correction, the values here should _match_ the ones set in HA
              // They'll just be normalized though. So HA sends red: 255, here, we get 1.0
              ESP_LOGD("template_light_1.on_turn_on", "ON_TURN_ON => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

        on_turn_off:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_1).current_values_as_rgb(&red, &green, &blue);
              id(template_light_1).current_values_as_brightness(&br);
              // OFF means OFF so both partitions should be off
              ESP_LOGD("template_light_1.on_turn_off", "TURN OFF");
              id(leds_button_1_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
              id(leds_button_1_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();              

        on_state:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_1).current_values_as_rgb(&red, &green, &blue);
              id(template_light_1).current_values_as_brightness(&br);
              ESP_LOGD("template_light_1.on_state", "State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

          # Figure out which partition light to light up now that we have an updated state
          - script.execute:
              id: figure_out_which_partition_to_light
              # Output 1 = top
              output_num: 1

      - name: "Indicator 2"
        id: template_light_2
        internal: false
        entity_category: config
        restore_mode: RESTORE_AND_ON
        gamma_correct: 0.0
        default_transition_length: 0s

        on_turn_on:
          - lambda: |-
              // Get user requested RGB values and pass them through to the partition lights
              float red, green, blue, br;
              id(template_light_2).current_values_as_rgb(&red, &green, &blue);
              id(template_light_2).current_values_as_brightness(&br);

              // Pass through should happen ONLY in the on_state and on_turn_off hooks so just log here
              // Since we have ZERO gamma correction, the values here should _match_ the ones set in HA
              // They'll just be normalized though. So HA sends red: 255, here, we get 1.0
              ESP_LOGD("template_light_2.on_turn_on", "ON_TURN_ON => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

        on_turn_off:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_2).current_values_as_rgb(&red, &green, &blue);
              id(template_light_2).current_values_as_brightness(&br);
              // OFF means OFF so both partitions should be off
              ESP_LOGD("template_light_2.on_turn_off", "TURN OFF");
              id(leds_button_2_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
              id(leds_button_2_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();              

        on_state:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_2).current_values_as_rgb(&red, &green, &blue);
              id(template_light_2).current_values_as_brightness(&br);
              ESP_LOGD("template_light_2.on_state", "State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

          - script.execute:
              id: figure_out_which_partition_to_light
              # Output 2 = middle on 3c version
              output_num: 2

      - name: "Indicator 3"
        id: template_light_3
        internal: false
        entity_category: config
        restore_mode: RESTORE_AND_ON
        gamma_correct: 0.0
        default_transition_length: 0s

        on_turn_on:
          - lambda: |-
              // Get user requested RGB values and pass them through to the partition lights
              float red, green, blue, br;
              id(template_light_3).current_values_as_rgb(&red, &green, &blue);
              id(template_light_3).current_values_as_brightness(&br);

              // Pass through should happen ONLY in the on_state and on_turn_off hooks so just log here
              // Since we have ZERO gamma correction, the values here should _match_ the ones set in HA
              // They'll just be normalized though. So HA sends red: 255, here, we get 1.0
              ESP_LOGD("template_light_3.on_turn_on", "ON_TURN_ON => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

        on_turn_off:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_3).current_values_as_rgb(&red, &green, &blue);
              id(template_light_3).current_values_as_brightness(&br);
              // OFF means OFF so both partitions should be off
              ESP_LOGD("template_light_3.on_turn_off", "TURN OFF");
              id(leds_button_3_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
              id(leds_button_3_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();              

        on_state:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_3).current_values_as_rgb(&red, &green, &blue);
              id(template_light_3).current_values_as_brightness(&br);
              ESP_LOGD("template_light_3.on_state", "State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

          - script.execute:
              id: figure_out_which_partition_to_light
              output_num: 3

      - name: "Indicator 4"
        id: template_light_4
        internal: false
        entity_category: config
        restore_mode: RESTORE_AND_ON
        gamma_correct: 0.0
        default_transition_length: 0s

        on_turn_on:
          - lambda: |-
              // Get user requested RGB values and pass them through to the partition lights
              float red, green, blue, br;
              id(template_light_4).current_values_as_rgb(&red, &green, &blue);
              id(template_light_4).current_values_as_brightness(&br);

              // Pass through should happen ONLY in the on_state and on_turn_off hooks so just log here
              // Since we have ZERO gamma correction, the values here should _match_ the ones set in HA
              // They'll just be normalized though. So HA sends red: 255, here, we get 1.0
              ESP_LOGD("template_light_4.on_turn_on", "ON_TURN_ON => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);              

        on_turn_off:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_4).current_values_as_rgb(&red, &green, &blue);
              id(template_light_4).current_values_as_brightness(&br);
              // OFF means OFF so both partitions should be off
              ESP_LOGD("template_light_4.on_turn_off", "TURN OFF");
              id(leds_button_4_top).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();
              id(leds_button_4_bottom).turn_off().set_rgb( red, green, blue ).set_brightness(br).set_transition_length(0).perform();              

        on_state:
          - lambda: |-
              // Get template RGB values
              float red, green, blue, br;
              id(template_light_4).current_values_as_rgb(&red, &green, &blue);
              id(template_light_4).current_values_as_brightness(&br);
              ESP_LOGD("template_light_4.on_state", "State => R: %f, G: %f, B: %f BR: %f", red, green, blue, br);

# Set up the gpio outputs for the relays
output:
  - id: relay_1
    platform: gpio
    pin: GPIO18

  - id: relay_2
    platform: gpio
    pin: GPIO17

  - id: relay_3
    platform: gpio
    pin: GPIO27

  - id: relay_4
    platform: gpio
    pin: GPIO23

testswitch.yaml (snippet)


packages:
  common: !include packages/base.yaml

  # 3 relay version
  output: !include
    file: packages/variant.c4.yaml
    vars:
      # Relay 1,3 are wired up to lights
      # out_1_state_exp: "state"
      out_1_state_exp: "current_values.is_on()"
      # out_2_state_exp: "state"
      out_2_state_exp: "current_values.is_on()"
      # out_3_state_exp: "state"
      out_3_state_exp: "current_values.is_on()"
      # out_4_state_exp: "state"
      out_4_state_exp: "current_values.is_on()"

# Customize what each of the three relays do
light:
  # Relay 1 and 2 are the fan/light combo
  - name: Left Light
    id: out_1
    platform: binary
    output: relay_1
    restore_mode: RESTORE_DEFAULT_OFF

    # When changing between states, we need to update the partition light(s)
    on_turn_on:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 1

    on_turn_off:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 1

  # Main overhead light
  - name: Middle Left Light
    id: out_2
    platform: binary
    output: relay_2
    restore_mode: RESTORE_DEFAULT_OFF

    on_turn_on:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 2

    on_turn_off:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 2

  # Main overhead light
  - name: Middle Right Light
    id: out_3
    platform: binary
    output: relay_3
    restore_mode: RESTORE_DEFAULT_OFF

    on_turn_on:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 3

    on_turn_off:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 3

  - name: Right Light
    id: out_4
    platform: binary
    output: relay_4
    restore_mode: RESTORE_DEFAULT_OFF

    on_turn_on:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 4

    on_turn_off:
      - script.execute:
          id: figure_out_which_partition_to_light
          output_num: 4

tx_ultimate_touch:
  id: tx_touch
  uart: uart_touch

  on_press:
    # Let the user know we've registered the touch
    - script.execute: buzz_default
    # Like "traditional" switches, we act as soon as pressed and do not wait for "release"
    # Unless user has disabled touch input processing
    - lambda: >
        ESP_LOGD("tx_ultimate_touch.on_press", "Touch Position: %d / State: %d", touch.x, touch.state);

        if (!id(glbl_sw_touch_enable)) {
          ESP_LOGD("tx_ultimate_touch.on_press", "Touch is disabled, ignoring");
          return;
        }

        // 4 ch version means we split the touch surface into 4 equal size zones
        // 0-2, 3-5, 6-8, 9-11
        // There's nothing stopping you from creating unequal sized zones if desired!
        /////////////////////////////////
        // The if/else pattern is extended or shortened depending on the number of relays
        // In addition to modifying the if/else pattern, you'll need to update the code that
        //    checks the state of each output.
        // I wish ESPHome would have a more homogenous API for this since there IS a homogenous
        //  API for calling the turn_on/turn_off methods!
        /////////////////////////////////

        if (touch.x <= 2) {
          ESP_LOGD("tx_ultimate_touch.on_press", "Toggle 1");
          if(id(out_1).current_values.is_on() ) {
            id(out_1).turn_off().perform();
          } else {
            id(out_1).turn_on().perform();
          }
        } else if (touch.x <= 5) {
          ESP_LOGD("tx_ultimate_touch.on_press", "Toggle 2");
          if(id(out_2).current_values.is_on() ) {
            id(out_2).turn_off().perform();
          } else {
            id(out_2).turn_on().perform();
          }
        } else if (touch.x <= 8) {
          ESP_LOGD("tx_ultimate_touch.on_press", "Toggle 3");
          if(id(out_3).current_values.is_on() ) {
            id(out_3).turn_off().perform();
          } else {
            id(out_3).turn_on().perform();
          }
        } else {
          ESP_LOGD("tx_ultimate_touch.on_press", "Toggle 4");
          if(id(out_4).current_values.is_on() ) {
            id(out_4).turn_off().perform();
          } else {
            id(out_4).turn_on().perform();
          }
        }     

(thanks to @kquinsland)

m4dm4xi commented 5 months ago

Hello, thanks for the great work!

I'm tinkering with the 120-4 Relays EU version, and I figured out to enable the 4th channel touch on the yaml.

FYI, touch positions are mapped as follows: Touch 1: pos 1,2 Touch 2: pos 3,4,5 Touch 3: pos 6,7,8 Touch 4: pos 9,10

LEDS are 32. Top side: from 31 to 8 Right side: from 9 to 14 Bottom side: from 15 to 24 Left side: from 25 to 30

Having four buttons, the mapping of scripts with button_left, middle, right will need a renaming maybe. It will be great if you will like to support this device version. All the best

Have you found a properly working solution?

SebTM commented 4 months ago

Hey, I'm looking forward to get one of the 4-gang version, is there any chance this component will add support for the 4-gang version as well? ✌🏻