Fluval Aquasky BLE RGB-Light

Wow awesome to see great progress. I’ve wanted at least the ability to on/off monitor from away from the house for a while. A few times I’ve set the light to full on while cleaning and then forget to turn it to auto for my adjustments and it stays full brightness all day and even after it should turn off.

I definetly want to set up a temp sensor as well to keep an eye on that in summer/winter as the fish tank is “mine” my wife doesn’t really touch it or want to adjust stuff on it.

Another status update:

  1. Yes, I’m still working on that. “Daytime job” comes first though, but weekend is in sight.

  2. I can read the current status + now also the channel values.

  3. I can set the time on the LED (required for auto/pro mode, no RTC on the LED, so resets on power loss - that’s why the app sets the time every time on connect)

Todo:

  1. Set channel values - all those colors!

2. Get the handshake right:

  • App first writes 0x0F to service 1000 / characteristic 1005 to select register
  • App then reads from 1000 / 1004 and gets some magic bytes back. This would be the password. The password is only compared in the app, so no need to authenticate against the LED :wink:
  • The App writes 0x47 to 1000 / 1005 to select another register
  • The App reads from 1000 / 1004 again and gets a couple more bytes back. The app calls it “mfr register” - essentially it contains the LED software version.
  • The App writes a syncDeviceTime with the current year, month, day, day of week, hour, minute, second to 1000 / 1001
  • The App gets a notify on 1000 / 1002 witth the current device settings. Thats where I am currently at, so I can have the current device status without sending something to change that status.

Edit:
I finally got the handshake done. Upon connection, the values are now populated. yay!

Best regards
mrzottel

2 Likes

So, weekend came and went, and some more progress happened:

I finally found out what the middle byte in the encryption header is for: Packet length, but “encrypted”. I don’t know how the packet length is “encrypted”, but it is always the same value for the same packet length - so with packet length only ranging between 4 and 16, I am quite content with sniffing those values with my bluetooth sniffer and creating a list. :wink:

So the protocol to the Fluval lights is (almost) completely reverse engineered.

I am now creating a “real” integration from the mess of code I created to get this to work, i.e separating out sensors and switches and outputs. This might take a while, because I have to learn the ESPHome coding ecosystem with guidelines, coding standards and so on. But I will have a testable integration soon, with some yaml for you to test this.

Also I am quite confident that it won’t break any LEDs. I “crashed” my LEDs quite a lot, expecially with the 2nd byte of the encoding not correctly set, but nothing a power cycle of the LED could not fix. Even automated that with a remote power plug integrated into HA :wink:

So, have a little bit more patience, instructions on how to test this will most likely be my next posting here :wink:

Integration roadmap:

  • [x] Switch component for turning on/off led
  • [x] Channel sensors for channel 1-5 (outputs value from 0-1000)
  • [x] Text sensor for current mode (manual, auto, pro)
    – [x] Allow for configuration of own language mappings
  • [x] Button components for changing mode
  • [x] Output Number component for setting channels
  • [ ] Reconnect handling
  • [ ] Better error handling
  • [ ] Lint

Update 03.02.2023:

I managed to “break” the final part of encryption. Byte 2 of the encryption header is (packet_length + 1) xor 0x54 → This allows me to send arbitrary sized packets, so I finally was able to implement number entities which can update the LED channels. I could do this for my 4 channel LED before, but I want this to work on a 5 channel LED as well, even though I have none to sniff packets :wink:

Next weekend I will write instructions on how to test this integration.

best regards
mrzottel

3 Likes

So, about testing:

Please, if possible, use a dedicated ESP32 for testing. Things might crash, so be warned :wink:

At first, import the fluval_ble_led component with this code:

external_components:
  - source: github://mrzottel/esphome@fluval_ble_led
    components: [ fluval_ble_led ]

And we also need a time source, as the Fluval LEDs require a set time for their auto/pro stuff to work correctly. I use the easiest option - get time from the HA itself. But others will work too:

time:
  - platform: homeassistant
    id: ha_time

It is important that this time source has an ID, so we can reference it later.

Next is the esp32_ble_tracker, which allows us to find and treck Bluetooth Low Energy devices:

esp32_ble_tracker:

No special configuration needed here.

Then we need the ble_client to handle the basic connection to the Fluval LED as well as sending and receiving packets:

ble_client:
   - mac_address: 44:A6:E5:69:7E:8D
     id: my_ble_client

The mac address is the mac of the Fluval LED. To figure this one out I used an app called nRF Connect on my smartphone, which listed all broadcasting BLE devices in the vicinity. My Fluval LEDs showed up with their name, so it was easy to find their mac addresses. They all started with 44:46:E5 in my case. Also please make sure that you are not connected with the Fluval App to the light. It won’t advertise when connected, and you will not be able to find it in nRF Connect!

Once the ble_client is configured, we can start using the fluval_ble_led component like this:

fluval_ble_led:
  ble_client_id: my_ble_client
  time_id: ha_time
  number_of_channels: 4
  id: my_fluval_led

The Fluval component needs the ID of the previously created ble client as well as the ID of the time source. Number_of_channels is set to 4 in my case, as I only own a couple of AquaSky 2.0 lights, which are RGBW. The Marine, Plant and some other lights will have 5 channels, so either enter 4 or 5 here, depending on the light you are connecting. If you by chance have a light with less than 4 or more than 5 channels please contact me :wink:
Lastly, the fluval_ble_led needs an ID of its own, so we can use it in sensors / buttons / switches.

All the following switches/buttons/sensors only work in manual mode, as “auto” and “pro” modes do not publish any channel information and won’t accept color changes. They are automatic programs after all :wink:

There is currently one switch defined for the Fluval component: LED on/off.

switch:
- platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    name: "LED Switch"

Pretty forward: This lets you switch on/off your LED in manual mode. It also gets feedback from the LED, so it should reflect the current state.

There are 3 buttons to switch between the modes:

button:  
  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    mode: "MANUAL"
    name: "Switch to manual"

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    mode: "AUTO"
    name: "Switch to auto"

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    mode: "PRO"
    name: "Switch to pro"

These allow you to switch between the 3 modes of the LED - manual, auto, pro. If you have a device which does not support one of the modes, please contact me :slight_smile:

To see in which mode the Fluval LED is currently in, there is a text sensor:

text_sensor:
  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    mapping_manual: "Manuell"
    mapping_auto: "Automatisch"
    mapping_pro: "Professionell"
    name: "Mode"

As you can see, it supports mapping of the modes to your own language, in this case german. This is optional though (Does not make much sense here, but I used it for demonstration purposes :wink: )

Similar to the modes, there are also sensors which can display the channel values for the different channels:

sensor:    
  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    channel: 1      
    zero_if_off: true
    name: "Channel Red"

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    channel: 2      
    zero_if_off: true
    name: "Channel Green"  

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    channel: 3      
    zero_if_off: true
    name: "Channel Blue"  

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    channel: 4      
    zero_if_off: true
    name: "Channel White"

In my case, I only have 5 channels, RGB and W, so I use 4 channels here. With other lamps you can use the fifth channel as well. “Zero_if_off” means, that the channel value will display as 0 instead as “unknown” if the Fluval LED is not in manual mode. This is an optional setting.
The channel values will range from 0 to 1000 - this is the way the Fluval LED works, sorry for that. I am pretty sure it does not have 1000 distinct levels per channel anyway :wink:

Instead - or in addition to - the read only sensors, we can also use number entities to modify those channels in manual mode:

number:
  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    name: "Channel Red"
    channel: 1
    zero_if_off: true

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    name: "Channel Green"
    channel: 2
    zero_if_off: true

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    name: "Channel Blue"
    channel: 3
    zero_if_off: true

  - platform: fluval_ble_led
    fluval_ble_led_id: my_fluval_led
    name: "Channel White"
    channel: 4
    max_value: 500
    min_value: 100
    step: 10
    zero_if_off: true

They are configured almost identical to sensors, including the zero_if_off optional setting. But they display as nice sliders in HA, which in default settings allow to set the value between 0 and 1000 in 100 steps. For demonstration, I configured the white channel to have a maximum value of 500 and a minimum value of 100, in steps of 10. This is possible to do, let’s see if it has a use case :wink: You can not exceed a max of 1000 and a minimum of 0 though.

Well, thats it so far - I learned a lot about Bluetooth LE, C++, Python and Home Assist and it was really awesome to work with that - what a beautiful and elegant system. Of course I will stick around and wait for your test results, fix bugs if they come up, implement ideas - the usual stuff. Next will be a more robust reconnect logic, then linting, so the code passes ESPHome tests and meets their standards and maybe I can get the component accepted into their base :wink:

But for now, lets test please :smiling_face_with_three_hearts:

Best regards
mrzottel

3 Likes

Do you have a recommendation on what ESP32 module to use?

I successfully tested with both a wemos lolin32 lite (or the az-delivery version of this one) as well as the ESP-32 Dev Kit C V4 from az-delivery. But it should work with just about any ESP32 module that has bluetooth.

I changed from the Lolin32 lite to the Dev Kit C, because the later one has the pcb antenna a bit more “exposed” and as such hopefully a better range. The Lolin32 lite also lacks a 5V pin, but I want to create a pcb which can power the whole setup with a 12v to 5v regulator, which is then fed into the 5V pin. (12V, because most “dumb” aquarium lights have 12V power supply, and my pcb would be powered from that and include 12V relais to switch the light with the ESP32) But thats a separate project after all :wink:

So just for testing and/or controlling the Fluval LED without any further projects in mind, just about any ESP32 with bluetooth will do, that is capable of reaching the Fluval LED as well as the wifi at the same time. If range is an issue, go with one with an external antenna connection or solder on your own antenna.

Best regards
mrzottel

1 Like

I got it to sort of work on one of my Fluval plant lights. The on/off seemed to work fine, but none of the other functions worked (it is a 5 channel light, but with pink, blue, cold white, pure white, warm white).

I couldnt get my aquasky 2.0 to connect to the ESP at all - but that could be something I was doing.

EDIT: The mode was because I haddnt connected my phone to the light to set the time. When I put it in auto mode it just turned off.
After connecting the device to my phone once, the auto mode moves between manual (full brightness) and the correct auto mode settings.

The sliders dont work to change anything in manual mode though

So AquaSky 2.0 connects now and works as expected? That’s the same light I have and test against. :wink:

I will have a look at the 5 channel light not working. Maybe it is something obvious in the code. Can you send me the logs if possible?

Best regards
mrzottel

Nope - The aquasky is the one I had trouble with interestingly. Just testing it out again now.

Ill grab the logs for you shortly :slight_smile:

There seems to be a regression due to me trying to get closer to ESPHome coding style requirements. I’ll fix that =)

Should be fixed with the latest commit. I will take more care with testing before commiting, now that people are using it. Sorry!

Best regards
mrzottel

The error with the aquasky? Or the error with the colour sliders.

Just tried again - the plant light will connect fine. When I try connecting to the aqua sky the logs dont seem to even start to search for the device. But if I change only the MAC address it connects fine to another light.

[C][logger:293]: Logger:
[C][logger:294]: Level: DEBUG
[C][logger:295]: Log Baud Rate: 115200
[C][logger:296]: Hardware UART: UART0
[C][homeassistant.time:010]: Home Assistant Time:
[C][homeassistant.time:011]: Timezone: ‘AEST-10AEDT,M10.1.0,M4.1.0/3’
[C][fluval_ble_led_switch:076]: Fluval BLE LED Switch ‘LED Switch’
[C][fluval_ble_led_switch:078]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_switch:099]: Restore Mode: restore defaults to OFF
[C][fluval_ble_led_select_mode_button:021]: Fluval BLE LED Select Mode Button ‘Switch to manual’
[C][fluval_ble_led_select_mode_button:021]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_select_mode_button:021]: Fluval BLE LED Select Mode Button ‘Switch to auto’
[C][fluval_ble_led_select_mode_button:021]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_select_mode_button:021]: Fluval BLE LED Select Mode Button ‘Switch to pro’
[C][fluval_ble_led_select_mode_button:021]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_switch:036]: Fluval BLE Mode Sensor ‘Mode’
[C][fluval_ble_led_channel_sensor:045]: Fluval BLE Channel Sensor ‘Channel Red’
[C][fluval_ble_led_channel_sensor:045]: State Class: ‘’
[C][fluval_ble_led_channel_sensor:045]: Unit of Measurement: ‘’
[C][fluval_ble_led_channel_sensor:045]: Accuracy Decimals: 0
[C][fluval_ble_led_channel_sensor:045]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_channel_sensor:045]: Fluval BLE Channel Sensor ‘Channel Green’
[C][fluval_ble_led_channel_sensor:045]: State Class: ‘’
[C][fluval_ble_led_channel_sensor:045]: Unit of Measurement: ‘’
[C][fluval_ble_led_channel_sensor:045]: Accuracy Decimals: 0
[C][fluval_ble_led_channel_sensor:045]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_channel_sensor:045]: Fluval BLE Channel Sensor ‘Channel Blue’
[C][fluval_ble_led_channel_sensor:045]: State Class: ‘’
[C][fluval_ble_led_channel_sensor:045]: Unit of Measurement: ‘’
[C][fluval_ble_led_channel_sensor:045]: Accuracy Decimals: 0
[C][fluval_ble_led_channel_sensor:045]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_channel_sensor:045]: Fluval BLE Channel Sensor ‘Channel White’
[C][fluval_ble_led_channel_sensor:045]: State Class: ‘’
[C][fluval_ble_led_channel_sensor:045]: Unit of Measurement: ‘’
[C][fluval_ble_led_channel_sensor:045]: Accuracy Decimals: 0
[C][fluval_ble_led_channel_sensor:045]: Icon: ‘mdi:lightbulb’
[C][fluval_ble_led_channel_number:070]: Fluval BLE Channel Number ‘Channel Red’
[C][fluval_ble_led_channel_number:070]: Fluval BLE Channel Number ‘Channel Green’
[C][fluval_ble_led_channel_number:070]: Fluval BLE Channel Number ‘Channel Blue’
[C][fluval_ble_led_channel_number:070]: Fluval BLE Channel Number ‘Channel White’
[C][esp32_ble_tracker:870]: BLE Tracker:
[C][esp32_ble_tracker:871]: Scan Duration: 300 s
[C][esp32_ble_tracker:872]: Scan Interval: 320.0 ms
[C][esp32_ble_tracker:873]: Scan Window: 30.0 ms
[C][esp32_ble_tracker:874]: Scan Type: ACTIVE
[C][esp32_ble_tracker:875]: Continuous Scanning: True
[C][ble_client:027]: BLE Client:
[C][ble_client:028]: Address: B8:80:4F:3F:0A:E6
[C][captive_portal:088]: Captive Portal:
[C][mdns:103]: mDNS:
[C][mdns:104]: Hostname: spark
[C][ota:093]: Over-The-Air Updates:
[C][ota:094]: Address: spark.local:3232
[C][ota:097]: Using Password.
[C][api:138]: API Server:
[C][api:139]: Address: spark.local:6053
[C][api:141]: Using noise encryption: YES
[C][fluval_ble_led:013]: Fluval LED
[C][fluval_ble_led:014]: Number of channels: 4
[D][api:102]: Accepted ::FFFF:192.168.68.200
[D][api.connection:918]: Home Assistant 2023.1.4 (::FFFF:192.168.68.200): Connected successfully
[D][time:045]: Synchronized time: 2023-02-05 19:52:39

I hope I fixed the sliders not working.

Are you sure about the mac address starting with B8:80:4F? All my lights start with 44:A6:E5. I think the first 3 bytes are vendor specific, so it could be your lights should start with that too.

Best regards
mrzottel

Yeah, I questioned that also - but the app that I used to find the mac showed the correct one for the two plant lights.
I will leave it turned off overnight and try it again tomorrow afternoon to see if that helps. Ill check out your improvements and let you know also.

Is there any way to tell it to connect to three lights at once from the one ESP? I added in the three in the BLE_CLIENT section with its own ID, but I couldnt figure out how to add them into the fluval_Ble_led component section with its own ID (although I didnt try adding the Fluval_ble_led secton three times

So maybe the light with the odd mac has a different controller on board. Should still work though, as it is all controlled with the same App I guess.

Adding multiple lights to one ESP32 is something that I am about to figure out myself, like how to best proceed with that, as I have one fish tank with two AquaSky next to each other. Im not sure yet how to do that, but it is definitively on my roadmap :wink:

My best guess on how to start on this would be to have multiple BLE_CLIENT though, with their own ID, and each one controlling a single mac. But more on that later =)

That was easier than expected. I just commited a change which allows up to 3 fluval_ble_led devices to be configured. 3 is the maximum number of BLE devices an ESP32 can handle.

My configuration looks like this now:

ble_client:
  - mac_address: 44:A6:E5:69:7E:8D
    id: ble_krebse1

  - mac_address: 44:A6:E5:63:E8:7F
    id: ble_freki1

  - mac_address: 44:A6:E5:72:CE:A1
    id: ble_freki2

and the fluval_ble_led config:

fluval_ble_led:
  - ble_client_id: ble_krebse1
    time_id: ha_time
    number_of_channels: 4
    id: fluval_krebse1

  - ble_client_id: ble_freki1
    time_id: ha_time
    number_of_channels: 4
    id: fluval_freki1

  - ble_client_id: ble_freki2
    time_id: ha_time
    number_of_channels: 4
    id: fluval_freki2

From there, you can reference those ids in the sensors etc, like I did for example for the text sensors:

text_sensor:
  - platform: fluval_ble_led
    fluval_ble_led_id: fluval_krebse1
    mapping_manual: "Manuell"
    mapping_auto: "Automatisch"
    mapping_pro: "Professionell"
    name: "Krebse: Mode"

  - platform: fluval_ble_led
    fluval_ble_led_id: fluval_freki1
    mapping_manual: "Manuell"
    mapping_auto: "Automatisch"
    mapping_pro: "Professionell"
    name: "Freki1: Mode" 

  - platform: fluval_ble_led
    fluval_ble_led_id: fluval_freki2
    mapping_manual: "Manuell"
    mapping_auto: "Automatisch"
    mapping_pro: "Professionell"
    name: "Freki2: Mode"

Best regards
mrzottel

Typos should not prevent building though, but should be made visible in the configuration stage, so what was it? Maybe I need to place more input checks into the configuration stuff. :wink:

In my attempt to make testing a single thing faster I neglected to add the sensors into the build - After adding them back in for one of the lights the build went through fine.

Good find though, it should work without sensors I think - for example if all you care about is the on/off led switch. I will fix that, thanks!

1 Like

After leaving the aquasky unplugged overnight the integration works perfectly setting the mode and turning it on and off. Just need to set up the colour selectors - but so far it works great!

1 Like

Great to hear! Does it still has this strange mac address? Just curious because I have to start writing up some documentation soon :wink:

I also got the an error when removing a sensor. Cleaning up the build files fixed it for me though at the cost of a longer build. No idea if this is something with my code or a general issue of the build system - I will check discord for answers to that :wink:

Also, which device are you using for the test?

Yep - The mac address was correct.

Im using a spark x thing plus ESP - probably overkill, but I broke some of the pins on it - so this is the perfect thing for it!