esphome_nebula_light icon indicating copy to clipboard operation
esphome_nebula_light copied to clipboard

Any chance you can update the config for a cloud-cutter'd device

Open Deep-Six opened this issue 6 months ago • 13 comments

Heya,

I managed to get one of these things running esphome-kickstart but haven't been successful in getting a more robust config installed. Any chance you have some guidance on how to make this work?

Deep-Six avatar Dec 29 '23 06:12 Deep-Six

Could you explain what you mean with esphome-kickstart device (link to the website) and robust config?

kireque avatar Dec 30 '23 10:12 kireque

Sorry , I didn't see this until now! Esp-home kickstart is here: https://github.com/libretiny-eu/esphome-kickstart and was installed via this system:

https://github.com/tuya-cloudcutter/tuya-cloudcutter

Which allows you to flash the esphome kickstart binary instead of having to desolder and resolder. There's some relationship to libchiptool as well which I've used successfully before, but this link shows there's no profile.

https://upk.libretiny.eu/?profile=tuya-generic-sk20-smart-star-projector

Essentially I was able to use cloud cutter, to replace the factory software, and now effectively have a device that's got the factory chipset, but running a base level of esp-home which I need to be able to update with a more advanced configuration. The configuration that's here, is based on the esp8266, but I need it to be based on the beken firmware. I've just not had the time to research how to convert. Was hoping you might have an idea.

Deep-Six avatar Jan 03 '24 00:01 Deep-Six

@Deep-Six this fork by @fonix232 seems to include a WB3S esphome config (at the bottom of the readme), which should be what you are looking for? https://github.com/fonix232/esphome_nebula_light

Do you mind sharing the steps to flash it using cloudcutter? I got one of these (model: SK20) for christmas and was reading the cloudcutter docs the other day, but failed putting it into AP mode. What power/button press sequence did you use?

M4GNV5 avatar Jan 08 '24 08:01 M4GNV5

@M4GNV5 the cloudcutter docs aren't the best for this light. It took me a while to get it working properly. You need to LONG PRESS the power button until the light starts flashing fast - that's when it enters into AP mode. Just keep holding the button, first it will flash slowly (BT pairing mode), then after about 10 seconds it begins flashing fast. You'll need to repeat this process twice during the CloudCutter steps.

The configuration in my fork is also incomplete, however I did create a working ESPHome Package:

---
light:
  - platform: rgb
    name: Light
    id: rgb_light
    red: red
    green: green
    blue: blue
    restore_mode: ALWAYS_OFF
    effects:
      - random:
          name: Random Slow
          transition_length: 10s
          update_interval: 5s
      - pulse:
      - pulse:
          name: Pulse Slow
          update_interval: 2s
      - pulse:
          name: Pulse Fast
          transition_length: 0.5s
          update_interval: 0.5s
          min_brightness: 0%
          max_brightness: 100%
      - pulse:
          name: "Pulse Asymmetrical"
          transition_length:
            on_length: 1s
            off_length: 500ms
          update_interval: 1.5s
  - platform: monochromatic
    name: Laser
    id: laser
    output: laser_pwm
    restore_mode: ALWAYS_OFF
  - platform: binary
    name: bled
    id: bled
    output: bled_pwm
    restore_mode: ALWAYS_OFF
    internal: true
  - platform: monochromatic
    name: rled
    id: rled
    output: rled_pwm
    restore_mode: ALWAYS_OFF
    internal: true

fan:
  platform: speed
  name: "Motor"
  id: motor
  output: motor_pwm
  restore_mode: ALWAYS_OFF

output:
  - platform: libretiny_pwm
    id: red
    pin: PWM3
    inverted: true
  - platform: libretiny_pwm
    id: green
    pin: PWM4
    inverted: true
  - platform: libretiny_pwm
    id: blue
    pin: PWM5
    inverted: true

  - platform: libretiny_pwm
    id: laser_pwm
    pin: PWM2
    inverted: true
    max_power: 50%
  - platform: libretiny_pwm
    id: motor_pwm
    pin: PWM0
    min_power: 15%
    max_power: 50%

  - platform: gpio
    id: bled_pwm
    pin: P1
    inverted: true
  - platform: libretiny_pwm
    id: rled_pwm
    pin: PWM1
    inverted: true

binary_sensor:
  - platform: gpio
    pin: 
      number: P14
      mode: INPUT_PULLDOWN_16
      inverted: true
    name: Button
    # on_press:
    #   then:
    #     - light.turn_on: 
    #         id: rgb_light
    #         brightness: 30%
    #     - light.turn_on: 
    #         id: laser
    #         brightness: 65%
    #     - delay : 1h
    #     - light.turn_off: 
    #         id: rgb_light
    #     - light.turn_off: 
    #         id: laser

wifi:
  on_connect:
    light.turn_on: bled
  on_disconnect:
    light.turn_off: bled

api:
  on_client_connected:
    if:
      condition:
        api.connected:
      then:
        - light.turn_on: rled
      else:
        - light.turn_off: rled
  on_client_disconnected:
    if:
      condition:
        api.connected:
      then:
        - light.turn_on: rled
      else:
        - light.turn_off: rled

Just copy the above into a separate YAML and include it in your config as a package.

Some noteworthy changes I made:

  • Set a maximum power for the motor, as above 50% my unit started making a loud clicking noise - even with a maximum of 50%, around 25-30% the clicking can be audible in a silent room. I'm actually open to hardware modifications to reduce this noise.
  • Replaced the button LEDs behaviour. My SK20 has two pairs of blue LEDs, but I stuck with the bled and rled naming scheme here. One pair being on means the device connected to WiFi, two pairs (all four) means it is connected to WiFi AND the ESPHome controller (or Home Assistant, whichever you use). As long as there's a client connected to the API, all four LEDs will stay on.
  • Had to change bled_pwm from PWM to regular GPIO - unlike an ESP32 module, the WB3S module does not support PWM on that pin, and because of this, that LED wasn't working properly.
  • Disabled the button behaviour for now - I'm still working on getting a custom lambda that works like the default behaviour of the device, i.e. "turn on if off, cycle through the effects of the RGB light if on, turn off if light was on last effect"
  • Laser becomes blindingly bright above 50% brightness, and the transformer inside will also emit a loud buzzing sound, so I set that as a maximum

Also a few small notes:

  • Unfortunately LibreTiny does not yet support a few requirements for WLED, so I couldn't add that as an effect. Other remote effect controllers also won't compile
  • Due to how things are set up, it is not possible to have both the light and the motor controls on a single control in HA.
  • The aforementioned noise from the motor and laser when using too much power. IMO the motor noise is more annoying.
  • As many of the pins are inverted, and LibreTiny within ESPHome does not handle that scenario well, expect the lights to turn on during flashing/reboot/firmware update. This I haven't found a fix for.

fonix232 avatar Jan 08 '24 14:01 fonix232

Hey wow, thanks for the very long description. Especially the last part is very helpful. I did not notice any sounds, but it's not very quiet in my lab anyways. Over the last 7 hours I put some more work into it using (and fixing) the config file from your fork. I do not use homeassistant, but rather just MQTT+node-red+zigbee2mqtt at home, which is why i have a (disabled) MQTT config in my yaml.

Anyways, I created a new repository, since I assume this repo is based more on a hardware modification rather than reflashing the original: https://github.com/M4GNV5/esphome-SK20-Nebula-Light

M4GNV5 avatar Jan 08 '24 15:01 M4GNV5

That config is okay, however:

  • I'd add the aforementioned limits to it, to avoid user error causing noise (or possibly even damage - I'm pretty sure the stock firmware uses limits too, because for me on stock, the motor needed to be around 80% to start making noise)
  • Replace the whole interval block on the bottom - the Beken chips are NOT powerful enough for that check to run reliably. My approach of triggering it on wifi and api events instead will work much better.
  • You can sort the specifics of the galaxy projector into a package, as I mentioned before (just like my shared code), that way you can have a much cleaner YAML :)

fonix232 avatar Jan 08 '24 16:01 fonix232

@Deep-Six this fork by @fonix232 seems to include a WB3S esphome config (at the bottom of the readme), which should be what you are looking for? https://github.com/fonix232/esphome_nebula_light

Do you mind sharing the steps to flash it using cloudcutter? I got one of these (model: SK20) for christmas and was reading the cloudcutter docs the other day, but failed putting it into AP mode. What power/button press sequence did you use?

As @fonix232 mentioned,I believe it was a long press, but I think I did a whole bunch of other things, before figuring that out. including holding the button before plugging it in etc.

Deep-Six avatar Jan 10 '24 03:01 Deep-Six

Hello everyone, First of all, I would like to express my gratitude to all of you for your ideas and references shared above. They are very helpful, leading me to discover the tuya-cloudcutter and libretiny initially

Now, I have a question: Does the device somehow support the red (or RGB) button LED? I distinctly remember seeing the red button color in the past, whereas currently, both button LEDs are blue

I have successfully flashed my nebula with ESPHome firmware and I would like to share my enhanced configuration with you. You can find it here:

  • https://github.com/seberm/esphome-SK20-Nebula-Light/blob/master/wb3s_nebula_light.yaml

My modifications / hints

  1. Consider utilizing a Status LED Light component instead of relying on interval, wifi.{on_connect,on_disconnect}, or api.on_client_{connected,disconnected}. I have employed the button LED0 (pin P1) as a status LED because this pin does not support PWM. It's just sufficient to display the device status.
  2. I've introduced the switch template switch_main, which consolidates the states of the motor, laser, and RGB light. Essentially, it informs you whether the device is currently in use or not. If any of these components are turned on, this switch is also activated. Conversely, if all of these components are switched off, the main switch is turned off as well.
  3. I'm utilizing the LED1 (pin P7) to indicate whether the device is currently in use (i.e., if the light, laser, or motor is activated).

The switch switch_main is equipped with turn_on_action and turn_off_action, defining the default settings for lights/motor when turned on and turning all of them off when turned off, respectively

Thanks to the switch_main template, you can effortlessly toggle all these components using a button's binary sensor action. Personally, I prefer using switch.toggle: switch_main in the on_press sensor's action

f you wish to incorporate an automatic "turn off" functionality, I recommend utilizing a script - for more information, refer to the script_switch_main_timer script definition

I would appreciate if you could share additional hints or suggestions for improvement. Thank you!

seberm avatar Feb 12 '24 22:02 seberm

@seberm I'd really recommend you look into the ESPHome Package format, as it would make it much easier to share only the relevant part of the config (and also importing it could be done in essentially two lines: one to define the github import and one importing the package).

status_led is a good option, but don't forget that it is meant for error/warning reporting, which is not always optimal for an actual status display. In my case, I'd like to know quickly if the device is 1, connected to WiFi 2, connected to HA, to make debugging issues easier, hence the setup. If you only want warnings, status_led is a good option, but I personally wouldn't rely on it solely.

Similarly, the switch_main approach might work for you, but not for others - I for one do not want the laser turned on at any time, and want just the RGB projection, for which I specifically made some changes in my script that isn't in the above snippet.

Another thing I'd attempt if my C-fu wasn't abysmal, is scripting the default behaviour of the button, namely transitioning from OFF to the first effect, then through all the effects on each press, then finally again to OFF when on the last effect and the button is pressed.

As for the red LED - I think you saw it, like myself, on other people's photos. The SK20 has a few variations, not just in case but internals used too. I've seen pictures off it with a red status LED, but mine is definitely blue only - the PCB responsible for the button and LED status has 5 pins, of which 4 are used: Ground, Button GPIO, and two pins for two pairs of LEDs. There's definitely no colour variation going on. In fact the PCB is incredibly barebones, it has the connector, 2 resistors, 4 LEDs and the push button.

Also, have you guys noticed an increase in noise from the motor/gear assembly? My unit, which is usually on 24/7, has been making a quite loud rattle when the motor is over 50% for a longer period. Turning it off, or running it on 100% for an hour or two helps for a while, but the noise keeps returning and ends up being loud enough that I can't fall asleep next to it even at 20%. If you did notice this, have you managed to (physically) fix it?

fonix232 avatar Feb 13 '24 14:02 fonix232

Hello @fonix232, thanks for your insights.

Regarding the esphome package: Yes, I am aware of it. I may consider modifying the code to incorporate the esphome package in the future. The code I've shared differs slightly from the one I am currently using. My intention was simply to share my observations and suggestions. I understand that we may not necessarily have the same default settings and behaviors.

Regarding the status_led: I agree. I wanted to also inform other users about the possibility of using the status LED.

Regarding the effect transition: That is indeed a very good idea! I will implement modifications to the configuration so that users can iterate over different light/motor/laser pre-configurations (which I refer to as scenes) by clicking the button. Additionally, I would prefer to allow users to turn off all components by long-pressing a button instead of relying on a special "OFF" scene.

Regarding noise: Fortunately, I do not encounter any issues with noise (it is barely audible to me). However, in my case, the device is typically operational for a maximum of 1-2 hours per day.

seberm avatar Feb 13 '24 22:02 seberm

Here I've added support for pre-defined scenes:

  • You can find the changes in this commit: https://github.com/seberm/esphome-SK20-Nebula-Light/commit/163062a30ed1d83542069ce5f1b996769a7ad048

Now, users can turn off the device components either by toggling the switch_main or by holding down the button for one second. Additionally, I've implemented functionality for the device to remember the last scene used. To achieve this, I've utilized a global variable named global_scene_id to store the last state. Although the code has become more complex due to the inclusion of various lambdas, everything appears to be functioning smoothly.

seberm avatar Feb 13 '24 23:02 seberm

@seberm your changes look very cool. Currently for my nebula light the button simply does nothing. I would love to integrate your scene, button & status led changes into my repo. Feel free to open a pull request!

We should however find a way to allow users to select wether they want to use the webinterface, the API, homeassitant or MQTT for controlling their nebula light (apart from the button). I have not looked at esphome modules yet, but they might be the missing ingredient for separating nebula light specifics from control mechanisms

M4GNV5 avatar Feb 14 '24 20:02 M4GNV5

@M4GNV5 yes, ESPHome packages are the way to go - they allow you to compartmentalise definitions and merge them in a final config.

For example my ESPHome configs are split into a number of packages in a hierarchy:

  • The main device configs (found in /esphome) just include a few substitutions (name and friendly_name), and a handful of function imports: board and extensions
  • I have a set of packages that define boards: e.g. I have a bunch of LilyGo T-Dongle S3's, which have their own board config, made up of a base ESP32-S3 ESP-IDF config, a bluetooth proxy config (specific to ESP-IDF), and a display config for setting up the ST7735 on this board
  • The base ESP32-S3 config defines the esp32: block, and includes a few default packages: the base package, and the wifi package.
  • base defines a handful of things:
    • substitutions for network connectivity from secrets
    • esphome main block definition
    • A number of further sub-packages that define:
      • OTA capability
      • API component
      • Logging (either generic or debug)
      • A time sensor
      • A set of default sensors, switches, buttons (e.g. factory reset, safe mode and restart buttons, uptime sensors, etc.)
      • Captive portal/webserver

This is incredibly useful because this way you can break up your configs into reusable pieces - the base config for example is shared by ALL my devices, regardless if they're ESP8266/32/-S2/-S3, or Beken based. Then I have chip-specific configs that define the baseline for the MCU alone, and import the base. On top of that, I have the board-specific configs, which import the chip-specific config, and expand on it by adding board-specific details (e.g. an ESP32-S3 devkit board would combine the ESP32-S3 chip config + config for the onboard LED). Finally, I have the device-specific configs, which take the base board-specific config, and expand upon it with details specific to that device (e.g. I have a SEN55 hooked up to an ESP32-S3 devkit, which I call aqm-1 - and aqm-1 combines the esp32-s3-devkit_espidf.yaml config, and the sen55.yaml config with params specific to the device, i.e. which pins are in use)

Or, in case of my Nebula light without replacing the MCU, my setup is:

  • galaxy_lamp.yaml
    • import package: modules/devices/galaxy_projector.yaml (defines the outputs, fan, light, and adds the api/wifi on_connect/on_disconnect event handlers)
    • import package: modules/boards/tuya_wb3s.yml
      • import package: modules/common_wb3s.yml (defines bk72xx: block)
        • import package: common/wifi.yaml (defines wifi connectivity via wifi: block)
        • import package: common/base.yaml (defines esphome: block)
          • import packages: all the base shared config is handled here

This makes it incredibly easy to bring up a new device. Just create the root device_name.yaml, add the basic substitutions, then import the board package, stack on your own additions, and bam, done.

Also, if I need to change ALL my devices' configuration, it's a single file change before updating each manually.

fonix232 avatar Feb 15 '24 14:02 fonix232