]> www.infradead.org Git - users/dwmw2/esp32-pool.git/commitdiff
First mostly working version of blind control
authorDavid Woodhouse <dwmw@amazon.co.uk>
Tue, 11 Feb 2025 18:31:13 +0000 (18:31 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Tue, 11 Feb 2025 18:31:13 +0000 (18:31 +0000)
blind.yaml [new file with mode: 0644]
landing-blind-3.yaml [new file with mode: 0644]

diff --git a/blind.yaml b/blind.yaml
new file mode 100644 (file)
index 0000000..3d22b14
--- /dev/null
@@ -0,0 +1,316 @@
+# Based on https://github.com/joshr120/PD-Stepper/blob/main/Software/ESPHome/PD-Stepper-Blinds-Advanced.yaml
+# (GPLv3)
+
+
+esp32:
+  board: esp32-s3-devkitc-1
+  framework:
+    type: esp-idf
+
+esphome:
+  name: ${name}
+  platformio_options:
+    board_build.flash_mode: dio
+    upload_speed: 921600
+  on_boot:
+    - tmc2209.configure:
+        microsteps: 2 # ${microsteps}
+        interpolation: true
+        tcool_threshold: 400
+    - tmc2209.stallguard:
+        threshold: 45   #set lower if stall gaurd triggering too often
+    - tmc2209.currents:
+        ihold: 0
+        tpowerdown: 0
+        iholddelay: 0
+        # irun: 16
+        run_current: 800m #Set your desired current here (800m = 800mA, 1 = 1A etc.)
+        standstill_mode: freewheeling
+
+     # set PD voltage    # 5V  9V  12V  15V  20V
+     #  CFG1             # 1   0    0    0    0
+     #  CFG2             # -   0    0    1    1
+     #  CFG3             # -   0    1    1    0
+    - lambda: |-
+         int voltage = 15; // 5, 9, 12, 15 or 20.
+         bool cfg1 = false, cfg2 = false, cfg3 = false;
+         if (voltage == 5) {
+            cfg1 = true;
+         } else if (voltage == 9) {
+            // all off;
+         } else if (voltage == 12) {
+            cfg3 = true;
+         } else if (voltage == 15) {
+            cfg2 = cfg3 = true;
+         } else if (voltage == 20) {
+            cfg2 = true;
+         } else ESP_LOGE("USB-PD", "Invalid voltage %dV selected", voltage);
+         id(CFG1_pin).set_state(cfg1);
+         id(CFG2_pin).set_state(cfg2);
+         id(CFG3_pin).set_state(cfg3);
+
+
+    - delay: 0.5s
+    - lambda: id(sensored_home_pos) = id(encoder)->get_state();  # Set the home position to power on position
+    # - button.press: home
+
+packages:
+  base: !include base.yaml
+
+wifi:
+  power_save_mode: none
+  networks:
+    - ssid: !secret wifi_ssid
+      password: !secret wifi_pw
+      bssid: !secret lantiq_bssid
+      priority: 1
+
+logger:
+  level: INFO
+
+sun:
+  latitude: !secret latitude
+  longitude: !secret longitude
+
+  on_sunrise:
+    - then:
+      - cover.open: pd_blinds
+  on_sunset:
+    - then:
+      - cover.close: pd_blinds
+
+external_components:
+  - source: github://slimcdk/esphome-custom-components
+    components: [tmc2209_hub, tmc2209, stepper]
+
+mqtt:
+  on_connect:
+    then:
+      - light.turn_on: led2
+  on_disconnect:
+    then:
+      - light.turn_off: led2
+
+i2c:
+  sda: 8
+  scl: 9
+  scan: true
+
+uart:
+  tx_pin: 17
+  rx_pin: 18
+  baud_rate: 712000
+
+output:
+  - platform: ledc
+    pin: 12
+    id: led1_output
+
+  - platform: ledc
+    pin: 10
+    id: led2_output
+
+  - platform: gpio
+    pin: GPIO38
+    id: CFG1_pin
+  - platform: gpio
+    pin: GPIO48
+    id: CFG2_pin
+  - platform: gpio
+    pin: GPIO47
+    id: CFG3_pin
+
+light:
+  - platform: monochromatic
+    output: led1_output
+    id: led1
+    name: LED 1
+  - platform: status_led
+    output: led2_output
+    id: led2
+    name: Status LED
+
+globals:
+  - id: encoder_tracking_
+    type: int32_t[2]
+    restore_value: no
+
+  - id: encoder_offset_
+    type: int32_t
+    restore_value: no
+
+  - id: sensored_home_pos
+    type: int32_t
+    restore_value: no
+    initial_value: "0"
+
+stepper:
+  - platform: tmc2209
+    id: motor
+    max_speed: 600 steps/s
+    acceleration: 400 steps/s^2
+    deceleration: 400 steps/s^2
+    rsense: 100 mOhm
+    vsense: False
+    enn_pin: 21
+    diag_pin: 16
+    index_pin: 11
+    # step_pin: 5
+    # dir_pin: 6
+    on_stall:
+      - logger.log:
+         format: "Motor stalled!"
+         level: INFO
+      - stepper.stop: motor #un-comment this to disable on stall
+      - lambda: id(sensored_home_pos) = id(encoder)->get_state();  #un-comment this to not reset home on stall
+      - cover.template.publish:
+          id: pd_blinds
+          state: OPEN
+      - light.turn_on:
+          id: led1
+          transition_length: 0s
+      - delay: 250ms
+      - light.turn_off:
+          id: led1
+          transition_length: 1s
+
+button:
+  - platform: restart
+    name: Restart
+
+  - platform: template
+    name: Stop
+    on_press:
+      - stepper.stop: motor
+
+binary_sensor:
+ - platform: gpio
+   name: Power Good
+   pin:
+     number: 15
+     mode: INPUT
+     inverted: true
+   device_class: power
+   filters:
+     - delayed_on: 10ms
+
+ - platform: gpio
+   name: Button 1
+   pin:
+     number: 35
+     mode: INPUT
+     inverted: true
+   id: btn1
+   filters:
+     - delayed_on: 10ms
+   on_press:
+     - cover.close: pd_blinds
+
+ - platform: gpio
+   name: Button 2
+   id: btn2
+   pin:
+     number: 36
+     mode: INPUT
+     inverted: true
+   filters:
+     - delayed_on: 10ms
+   on_press:
+     - tmc2209.disable: motor
+
+ - platform: gpio
+   name: Button 3
+   id: btn3
+   pin:
+     number: 37
+     mode: INPUT
+     inverted: true
+   filters:
+     - delayed_on: 10ms
+   on_press:
+     - cover.open: pd_blinds
+
+as5600:
+  slow_filter: 16x
+
+sensor:
+  - platform: as5600
+    id: encoder_status
+    update_interval: 60s
+    status:
+      name: Encoder status
+
+  - platform: as5600
+    name: Encoder
+    id: encoder
+    internal: true
+    update_interval: 0ms
+    filters:
+      - delta: 2 # throttle the high polling rate to only act on value changes
+      # compute absolute position from angle value
+      - lambda: |
+          const uint16_t curr = x;
+          int16_t delta = curr - id(encoder_tracking_)[0];
+          if (delta > 2048)
+            delta -= 4096;
+          else if (delta < -2047)
+            delta += 4096;
+          ESP_LOGD("angle", "Old %d new %d delta %d now %d home %d", id(encoder_tracking_)[0], curr, delta,
+            id(encoder_tracking_)[1] + delta, id(sensored_home_pos)          );
+          id(encoder_tracking_)[0] = curr;
+          id(encoder_tracking_)[1] -= delta;
+          if (id(encoder_tracking_)[1] < id(sensored_home_pos)) {
+             ESP_LOGI("home", "Adjusted to %d", id(encoder_tracking_)[1]);
+             id(sensored_home_pos) = id(encoder_tracking_)[1];
+          }
+          return id(encoder_tracking_)[1];
+    accuracy_decimals: 0
+    state_class: measurement
+
+  - platform: adc
+    pin: 4
+    name: VBUS Voltage
+    update_interval: 10s
+    attenuation: 12dB
+    filters:
+      - multiply: 8.47742
+
+cover:
+  - platform: template
+    id: pd_blinds
+    name: PD Stepper Blinds
+    has_position: true
+    assumed_state: false
+    # internal: true
+    lambda: |-
+      int percent = 100.0 * (id(encoder)->get_state()-id(sensored_home_pos)) / ${encoder_closed_pos};
+      return (100.0 - percent) / 100.0;
+    stop_action:
+      - tmc2209.disable: motor
+    open_action:
+      - lambda: |-
+          int32_t wantpos = id(sensored_home_pos);
+          int32_t posdelta = wantpos - id(encoder)->get_state();
+          int32_t stepdelta = ((posdelta * 200 * ${microsteps}) + 2048) / 4096;
+          ESP_LOGI("cover", "From %f to open (%f to %d) is delta %d, %d steps. Step %d -> %d",
+                            id(pd_blinds)->position, id(encoder)->get_state(), wantpos, posdelta, stepdelta,
+                            id(motor)->current_position, id(motor)->current_position + stepdelta);
+          id(motor).set_target(id(motor)->current_position + stepdelta);
+    close_action:
+      - lambda: |-
+          int32_t wantpos = id(sensored_home_pos) + ${encoder_closed_pos};
+          int32_t posdelta = wantpos - id(encoder)->get_state();
+          int32_t stepdelta = ((posdelta * 200 * ${microsteps}) + 2048) / 4096;
+          ESP_LOGI("cover", "From %f to closed (%f to %d) is delta %d, %d steps. Step %d -> %d",
+                            id(pd_blinds)->position,  id(encoder)->get_state(), wantpos, posdelta, stepdelta,
+                            id(motor)->current_position, id(motor)->current_position + stepdelta);
+          id(motor).set_target(id(motor)->current_position + stepdelta);
+    position_action:
+      - lambda: |-
+          int32_t wantpos = id(sensored_home_pos) + (1.0 - pos) * ${encoder_closed_pos};
+          int32_t posdelta = wantpos - id(encoder)->get_state();
+          int32_t stepdelta = ((posdelta * 200 * ${microsteps}) + 2048) / 4096;
+          ESP_LOGI("cover", "From %f to %f (%f to %d) is delta %d, %d steps. Step %d -> %d",
+                            id(pd_blinds)->position, pos, id(encoder)->get_state(), wantpos, posdelta, stepdelta,
+                            id(motor)->current_position, id(motor)->current_position + stepdelta);
+          id(motor).set_target(id(motor)->current_position + stepdelta);
diff --git a/landing-blind-3.yaml b/landing-blind-3.yaml
new file mode 100644 (file)
index 0000000..ce7ebfc
--- /dev/null
@@ -0,0 +1,7 @@
+substitutions:
+  name: "landing-blind-3"
+  encoder_closed_pos: "230000" # full blinds length (in encoder counts) !! CHANGE TO SUIT YOUR SETUP !!
+  microsteps: "2"
+
+packages:
+  blind: !include blind.yaml