Display knob

How far away is this:

From running ESP Home and doing a knob controlled modal info display / control input?

It could go all kinds of ways, but for a simple concept I see the knob switching between modes, blue background displays for info, green background displays would include controls, and maybe spontaneous alerts could show with red background.

Ideally, I would want some kind of “easily” editable config file to define the modes so they could be updated / developed without breaking out the whole tool chain for each new refinement.

Now I am picturing a mode where you can rotate through “channel” selections for the TV and music player… I actually developed something like that for a http server that runs scripts on the HTPC, but hopping up to the HA level brings in a wider gamut of controls.

That display is not supported and probably won’t be for a while as it has 2 different ESP32 chips.

Get this one. It already has full support for ESPhome.

2 Likes

Quite close I guess. Not sure about the battery part:

1 Like

That is a whole rabbit-hole world of stuff over there. The Core 2 also looks nice, touchscreen only instead of dial, no RFID reader, but battery is included:

FWIW, I’ve got both the Waveshare and the M5 now (Waveshare only just arrived this evening).

The Waveshare is more of a complete product; it feels far more robust (and I’ve gone for the ones with a built-in battery). The M5Stack Dial is a much more exposed experimenter’s product. Overall, I prefer the anodised aluminium of the Waveshare - but they’re both pretty good.

Now I need to sort out my ESP dev env… I’ve been more focused on Pi Picos lately.

2 Likes

Got mine today……this was not a great first time non esphome project! I’m about 20 hours deep learning about vscode/libraries, bin files, firmware flashing, I’ve read every piece of documentation there is!
Have you had a chance to build custom “firmware” for this device? Would love to chat!

Hi,
i got it kind of working but im still not happy since a lot of things are still missing.

i also started here:

i will update in the next days the yaml there since i got a couple new things working like battery etc

There are probably other ppl there which are better than me, so feel free to post here improvements etc

3 Likes

The device(s) work fine in esphome, problem is that for unknown reasons they put audio out on the esp32 and mic + display on the esp32-s3, makes it hard to use it as i voice assistant. so i put it back in the drawer :laughing:

you can flash both esp’s from esphome, just flip the usb-c plug.

here is what i got for the esp32-s3 side before i put it back in the drawer:

substitutions:
  name: esphome-web-d1e9b4
  friendly_name: Xiaozhi Knob

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  min_version: 2025.5.0
  name_add_mac_suffix: false

esp32:
  board: esp32-s3-devkitc-1
  flash_size: 16MB
  cpu_frequency: 240MHz
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"

psram:
  mode: octal
  speed: 80MHz

api:

ota:
  - platform: esphome
    id: ota_esphome

logger:
  level: DEBUG

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Xiaozhi 3.5 Hotspot"
    password: "RZ7D3EzJdPM6"

captive_portal:

uart:
  id: audio_uart
  tx_pin: GPIO41
  rx_pin: GPIO40
  baud_rate: 115200

i2c:
  - id: bus_a
    sda: GPIO11
    scl: GPIO12
    scan: true

sensor:
  - platform: adc
    pin: 1
    name: "Battery Voltage"
    id: battery_voltage
    attenuation: 12db
    accuracy_decimals: 2
    update_interval: 1s
    unit_of_measurement: "V"
    icon: mdi:battery-medium
    filters:
      - multiply: 2.0
      - median:
          window_size: 7
          send_every: 7
          send_first_at: 7
      - throttle: 1min
    on_value:
      then:
        - component.update: battery_percentage

  - platform: rotary_encoder
    id: knob
    name: "Rotary Knob Raw"
    pin_a:
      number: GPIO8
      mode: INPUT_PULLUP
    pin_b:
      number: GPIO7
      mode: INPUT_PULLUP
    resolution: 2
    on_clockwise:
      then:
        - logger.log: "Knob turned → CLOCKWISE"
    on_anticlockwise:
      then:
        - logger.log: "Knob turned → COUNTER-CLOCKWISE"


  - platform: template
    id: battery_percentage
    name: "Battery Percentage"
    lambda: return id(battery_voltage).state;
    accuracy_decimals: 0
    unit_of_measurement: "%"
    icon: mdi:battery-medium
    filters:
      - calibrate_linear:
         method: exact
         datapoints:
          - 2.80 -> 0.0
          - 3.10 -> 10.0
          - 3.30 -> 20.0
          - 3.45 -> 30.0
          - 3.60 -> 40.0
          - 3.70 -> 50.0
          - 3.75 -> 60.0
          - 3.80 -> 70.0
          - 3.90 -> 80.0
          - 4.00 -> 90.0
          - 4.20 -> 100.0
      - lambda: |-
          if (x > 100) return 100;
          if (x < 0) return 0;
          return x;

switch:
  - platform: gpio
    name: "PA CTRL"
    pin: 48
    restore_mode: RESTORE_DEFAULT_ON

i2s_audio:
  - id: i2s_in
    i2s_lrclk_pin: GPIO45
    i2s_bclk_pin: GPIO42


microphone:
  - platform: i2s_audio
    id: i2s_microphone
    i2s_audio_id: i2s_in
    i2s_din_pin: GPIO46
    adc_type: external
    pdm: false
    channel: left
    sample_rate: 16000
    bits_per_sample: 32bit

time:
  - platform: sntp
    id: sntp_time
    timezone: "Europe/Berlin"

font:
  - file: "gfonts://Roboto"
    id: my_font
    size: 28
  - file: "gfonts://Roboto"
    id: roboto_52
    size: 52

binary_sensor:
  - platform: template
    name: "Touch Button"
    id: touch_input

# SCREEN & TOUCH

output:
  - platform: ledc
    pin: 47
    id: backlight_output

light:
  - platform: monochromatic
    id: Sled
    name: Screen
    icon: "mdi:television"
    entity_category: config
    output: backlight_output
    restore_mode: ALWAYS_ON
    default_transition_length: 250ms

external_components:
  - source: github://pr#10392
    components: [mipi_spi]
    refresh: 1d

spi:
  id: display_qspi
  type: quad
  clk_pin: 13
  data_pins: [15, 16, 17, 18]

touchscreen:
  - platform: cst816
    id: my_touchscreen
    interrupt_pin: GPIO9
    reset_pin: GPIO10
    display: main_display
    on_touch:
      then:
        - logger.log:
            format: "Touch at (%d, %d)"
            args: [touch.x, touch.y]
        - binary_sensor.template.publish:
            id: touch_input
            state: ON
    on_release:
      then:
        - binary_sensor.template.publish:
            id: touch_input
            state: OFF

display:
  - platform: mipi_spi
    id: main_display
    model: JC3636W518V2
    rotation: 180
    cs_pin: 14
    reset_pin: 21
    update_interval: 1s

    lambda: |-
      auto black = Color(0,0,0), red = Color(255,0,0), green = Color(0,255,0), blue = Color(0,0,255), yellow = Color(255,255,0), white = Color(255,255, 255), cyberlightgreen = Color(0,255,159), cyberlightblue = Color(0,184,255), cyberpink = Color(214,0,255);
      it.fill(black);
      it.strftime(180, 180, id(roboto_52), cyberlightgreen, TextAlign::CENTER, "%H:%M:%S", id(sntp_time).now());


3 Likes

Hi @RealDeco, thanks for that i changed some things on my code and it works.

i couldnt test the audio and mic stuff since i get an error that i need arduino framework for that.

the rotary encoder also doesnt work for me, probably because its not waveshare but an Guition device?
at least the custom rotary component i created seems to work: WaveShare-Knob-Esp32S3/components/rotary_encoder_custom at main · KrX3D/WaveShare-Knob-Esp32S3 · GitHub

did you get the other SD Card and Vibration motor DRV2605 working?

i stopped when i couldn’t get audo to work, and yes the guition is red, and the waveshare is blue and it looked like a promising device, but it’s a confusing device to work with in esphome :frowning:

Hi @RealDeco , I used your yaml configuration for Waveshare ESP32S3 1.8 rotary knob (blue). The touch works and the time is displayed. However when I rotate the knob it just displays the rotation direction once and does not log the direction no matter how many times the knob is rotated. Requesting your help to figure out the problem. Attaching log snapshot for your reference.

It is not directly comparable, but i use this component https://esphome.io/components/sensor/rotary_encoder/ with a M5Stack Dial.

# --- Rotary Encoder Sensor Component ---
sensor:
  # The platform name is 'rotary_encoder'
  - platform: rotary_encoder
    id: room_dial_sensor
    # The pins you provided for the ESP32-S3 Dial
    pin_a: 
      number: GPIO40
      mode:
        input: true
        pullup: true
    pin_b: 
      number: GPIO41
      mode:
        input: true
        pullup: true
    # The rotary encoder value will increase/decrease by 1 per click/detent
    name: "Dial Step Count"
    resolution: 1
    
    # NEW: Use lambdas to check boundaries before setting the next value
    on_clockwise:
      then:
        - lambda: |-
            const float MAX_TEMP = 28.0;
            const float STEP_SIZE = 0.5;
            
            float current_state = id(setpoint_number).state;
            
            // Only increment if the current state is less than the maximum value
            if (current_state < MAX_TEMP) {
              float new_value = current_state + STEP_SIZE;
              // Ensures we don't accidentally exceed MAX_TEMP due to floating point math
              if (new_value > MAX_TEMP) new_value = MAX_TEMP;
              
              id(setpoint_number).publish_state(new_value);
            }

    on_anticlockwise:
      then:
        - lambda: |-
            const float MIN_TEMP = 16.0;
            const float STEP_SIZE = 0.5;
            
            float current_state = id(setpoint_number).state;
            
            // Only decrement if the current state is greater than the minimum value
            if (current_state > MIN_TEMP) {
              float new_value = current_state - STEP_SIZE;
              // Ensures we don't accidentally drop below MIN_TEMP
              if (new_value < MIN_TEMP) new_value = MIN_TEMP;

              id(setpoint_number).publish_state(new_value);
            }

I hope it’s helpful.

1 Like

Thank you @juergenjw. I shall try this :saluting_face:

I also bought the Waveshare Knob and your work on github is very helpful. Thank you for sharing.

1 Like

Is there a consensus on waveshare vs m5stack?

I’m looking for a display for turning on my garage heater. I can see these being good for turning on, setting temp with the dial, setting a timer to turn off the heater with a dial.

Also could display current temp.

Not controlling the heater directly. Just as a UI.

M5stack is 1.8” so a little on the smaller side, but preference goes to whatever is more supported and ready to go out of the box…