Hi all, I’ve gotten this 95% complete so thought I’d share with the community in case it’s helpful for others. Use it if is, no need to credit me. I’m a new user, I can’t put too many links in the post, apologies for the lack of hyperlinks.
We were gifted one of these star/nebula projectors after my daughter was born to help with sleep (it didn’t help, but nothing did, however she really likes the light now). I recently decided to see if I could flash it with something open source.
Initially I flashed with OpenBeken, following this guide from joelstevens1101 and p.kaczmarek2: elektroda.com. This worked just fine, however I wasn’t happy with the config interface in OBK (I’m a tech enthusiast, not an expert, and OBK is not intuitive or user-friendly - not intended as a criticism, for most open source projects user-friendliness can’t and shouldn’t be put above functionality). So, I instead flashed the device with ESPHome. Thanks to one very helpful redditor, I did this without needing to break out the soldering iron again, instead taking advantage of the OBK API and curl (link to reddit comment: reddit.com)
Using OBK first did give me the advantage of learning the GPIO pin config, as the BK7231 GUI flash tool (on GitHub) can export the Tuya configuration and extract GPIO. Between that and the joelstevens1101 guide I had the info I needed to configure ESPHome.
Some important notes:
- The laser light and lens motor seem to be powered in series, so that if the motor is off, the laser will light but very dimly. However if the motor is set to about 10% or 20%, the projected lights won’t spin at a noticeable rate while the laser can be powered at full brightness. So with this in mind, I’ve configured ESPHome to drive the motor at minimum speed whenever the laser is enabled. Disabling both the laser and RGB (nebula) light will also disable the motor, as you can hear it spinning and it uses a small amount of power to run. Similarly the motor can’t be enabled while both lights are disabled. Feel free to change this behaviour if you want to.
- The side button is currently configured to toggle the device on and off. In the future I’d like a long press to toggle the lights and motor, with a short press cycling through some preset scenes. I’ll probably do this in ESPHome even though it’s probably easier in Home Assistant, since I’d prefer the device be functional without a wifi connection. But my daughter wanted her “stars” back, so this will have to wait.
- By default the RGB, laser, and motor will be active when the device boots. I did this for family/wife approval so the device will “just work” if it was unplugged for some reason. Again, change it if you want.
- I’m not a software developer or engineer, just an enthusiast. This is probably not bug-free. I welcome feedback and suggestions for improvements.
The .yaml code, not including any of the main config:
### Device Configuration ###
## Substitutions ##
# Define GPIO pins for PWM controls and the button LED ring here.
# Default configuration is based on pinout for W3BS/BK7231T from a Mirabella
# Genio Wi-Fi Nebula and Star Projector (purchased 2021). Pinout for your
# device may be different.
substitutions:
PinPWM_R: 'GPIO9'
PinPWM_G: "GPIO24"
PinPWM_B: "GPIO26"
PinPWM_LASER: "GPIO8"
PinPWM_MOTOR: "GPIO6"
PinGPIO_BTN_LED: "GPIO7"
## WiFi & network connection diagnostic information ##
# Generally useful, not always desired. Delete if not.
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
ssid:
name: "SSID"
mac_address:
name: "MAC Address"
sensor:
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: "diagnostic"
## Light components ##
# Note: the motor and laser light are connected in series. If the motor
# is disabled, the laser light will be very dim. Enabling the motor
# (even at very low power so that the rotation of the projected lights
# is too slow to notice) will allow the laser to light at full brightness.
# The device is configured to ensure the motor is enabled whenever the
# laser is enabled, and to disabled the motor when both the RGB light and
# laser are disabled.
light:
## Case button - blue LED ring ##
# Enabled only when RGB/laser/motor are enabled, this behaviour is controlled
# below. By default this light is not exposed to Home Assistant.
- platform: binary
output: LED_BTN
id: BTN_LED
name: "Button LED"
internal: True # Delete to allow control in Home Assistant
## Galaxy projector - main RGB light ##
- platform: rgb
id: RGB_GALAXY
name: "Galaxy Projector"
red: PWM_RED
green: PWM_GREEN
blue: PWM_BLUE
# When disabling the RGB light, IF laser is disabled, then disable the motor
on_turn_off:
then:
- if:
condition:
light.is_off: LIGHT_LASER
then:
- light.turn_off: MOTOR
- light.turn_off: BTN_LED
else:
- light.turn_off: RGB_GALAXY
# Enable the button LED when light is enabled
on_turn_on:
then:
- light.turn_on: BTN_LED
## Galaxy projector - laser light ##
- platform: monochromatic
id: LIGHT_LASER
name: "Galaxy Projector Laser"
output: PWM_LASER
# When disabling the laser, if RGB is also disabled, then disable the motor
on_turn_off:
then:
- if:
condition:
light.is_off: RGB_GALAXY
then:
- light.turn_off: MOTOR
- light.turn_off: BTN_LED
else:
- light.turn_off: LIGHT_LASER
# When enabling the laser, enable the motor if it is disabled
on_turn_on:
then:
- if:
condition:
- light.is_off: MOTOR
then:
- light.control:
id: MOTOR
state: True
brightness: 40%
else:
- light.turn_on: LIGHT_LASER
- light.turn_on: BTN_LED
## Galaxy projector - motor control
# Monochromatic light component is used for ease of control in Home Assistant.
# I tested Servo Component but found it to be inconsistent and not intuitive
# with how the motor is intended to be used. Additionally the motor cannot run
# in reverse, so that functionality isn't required.
- platform: monochromatic
id: MOTOR
output: PWM_MOTOR
name: "Galaxy Projector Motor"
# When disabling the motor, if the laser is disabled, then disable the motor.
# Else, set the motor PWM output power to 0.1.
# Laser and motor are powered in series. If the motor is disabled, laser output is very dim.
on_turn_off:
then:
- if:
condition:
light.is_off: LIGHT_LASER
then:
light.turn_off: MOTOR
else:
- light.control:
id: MOTOR
state: True
brightness: 40%
# When enabling, if both RGB and laser are currently disabled, do not enable the motor.
# The motor makes an audible noise when running and consumes power, I prefer this doesn't
# happen. Feel free to disable if you like.
on_turn_on:
then:
- if:
condition:
and:
- light.is_off: RGB_GALAXY
- light.is_off: LIGHT_LASER
then:
- light.turn_off: MOTOR
else:
- light.turn_on: MOTOR
## Case Button Configuration ##
# The button is currently configured to toggle all lights and the motor when pressed. If
# Home Assistant is used, the lights will resume their previous state when toggled back
# on.
# To Do:
# - Change power toggle to long press
# - Enable preset scenes when button is short pressed
binary_sensor:
- platform: gpio
pin:
number: GPIO14
mode:
input: True
#pullup: True
inverted: True
id: BTN_SIDE
internal: True
on_click:
then:
- if:
condition:
or:
- light.is_on: LIGHT_LASER
- light.is_on: RGB_GALAXY
then:
- light.turn_off: LIGHT_LASER
- light.turn_off: RGB_GALAXY
- light.turn_off: MOTOR
- light.turn_off: BTN_LED
else:
Null
- if:
condition:
and:
- light.is_off: LIGHT_LASER
- light.is_off: RGB_GALAXY
then:
- light.turn_on: MOTOR
- light.turn_on: RGB_GALAXY
- light.turn_on: LIGHT_LASER
- light.turn_on: BTN_LED
else:
Null
## PWM/GPIO configuration ##
# Change pin values in Substitutions, above (not here unless you really want to).
output:
- platform: libretiny_pwm
pin: $PinPWM_R
id: PWM_RED
inverted: True
- platform: libretiny_pwm
pin: $PinPWM_G
id: PWM_GREEN
inverted: True
- platform: libretiny_pwm
pin: $PinPWM_B
id: PWM_BLUE
inverted: True
- platform: libretiny_pwm
pin: $PinPWM_MOTOR
id: PWM_MOTOR
min_power: 0.2 # Tuned to ensure Laser gets 100% power, motor should not turn.
zero_means_zero: True # So that motor can be disabled
- platform: libretiny_pwm
pin: $PinPWM_LASER
id: PWM_LASER
inverted: True
min_power: 0.3 # Some flickering below this level
zero_means_zero: True # So that laser can be disabled
- platform: gpio
pin: $PinGPIO_BTN_LED
id: LED_BTN
inverted: True