Integration of a kitchen fan (Fjäråskupan) into HomeAssistant

Just wanted to share how I managed to control my kitchen fan/light from HA and with that Google Assistant.

The fan is mounted in the ceiling and has a remote that operates at 433 MHz, but it’s some strange bidirectional protocol so I didn’t succeed in controlling the fan with that. But the fan also have bluetooth and an app. So what I did was spying on the communication between my Andriod phone and the fan by following a guide similar to this one:
https://support.honeywellaidc.com/s/article/How-to-capture-Bluetooth-traffic-from-and-to-an-Android-Device

So the solution is based on a Raspberry Pi that is placed in the vicinity of the fan, communication over bluetooth with the fan. In HA I have used a light template and a fan template that uses scripts/ssh to communicate with the Raspberry Pi. HA is running on a NUC in the livingroom.

ha

The result can be found in here:

2 Likes

@leifmariposa - Exactly what I have been looking for!
I’m running Hassio on a rpi 3 model b that is located in the vicinity of th fan (Fjäråskupan Athena 120). I just need to figure out if this solution can work out of the box with utilizing the BLE onboard the same rpi I am running Hassio on.
I am a little bit of a noob on more advanced parts of Hassio, could you point me in any direction?

Would this work?

  1. Copy the .sh files (with correct mac-adress) to a folder in Hass.io
  2. Add the .yaml inline configuration.yaml
  3. Adjust the paths to the script files (set_kitchen_fan.sh and set_kitchen_fan_light.sh) in configuration.yaml
  4. Adjust the Mac-adress

Thanks in advance for any guidance!

Can confirm I got it working by setting it up as per my previous!
After making sure the bluetooth onboard the rpi was tracking devices I could capture the fan MAC and pair it.

For the .yaml’s I use packages setup, hence the kitchen_fan.yaml and kitchen_fan_light was added to the “config/packages” directory and include in configuration.yaml:

homeassistant:
  packages: !include_dir_named packages

After adjusting paths to the scripts in the .yaml’s above and added the controls to lovelace I fired away and voila.

One thing I remain to figure out though… It seems as the light setting command does not work entirely as hoped for in my case (the Athena 120 from 2020);

  • When I set the level 1-11%, nothing happens.
  • I need to set the value to 12% or above for the light to turn on.
  • 12% - 100% the light seems to be controlled in 10% steps rather than in steps of 1%.

I want to get the light to respond to each percent (1-100%).

@leifmariposa - Are you able to set the absolute percent-setting? How did you sniff out the hexadecimal command for your fan?

Thanks again for your contribution, it has really helped improved our HA-setup!

/Magnus

Phenomenal. Although I have no idea where to begin. I run a PI 4 and boot into the Hassio OS. How to I get this to work? (I do have an additional PI3 to play with too).

I hate this fan light with such fury. It needs to be integrated with everything else.

// Update

So. In 24 hours into this I realised that some kind of coding knowledge is required.

As this is my first ever coding or interaction with Linux I did the following.

Setup:

  • Homeassistant OS on Raspberry PI4 running Home Assistant OS
  • Second RPI3 with a bluetooth dongle

My idiots guide to this:

  • Clean raspian image installed on the PI with all of the updates
  • RPI does >not< need bluetooth special setup to run BLE - the new raspian versions takes care of that
  • Installed VNC to remote desktop into the thing (yeah, terminals are scary for me as of now).
  • I then scanned for BLE-signals with the PI essentially kissing the fan - and then picked out the MAC-address at the top of the list.
  • Yaml-file in the folder /packages/ and then the a reference to that folder written in the main configuration.yaml-file
  • Configure permissions and users (first time I saw “sudo”… so this took a while) - root access was my chosen path for SSH account. Also - I don’t have a clue if this makes any sense. The config had PI
  • Setup the SSH (did for both devices, not sure if that is needed). Regardless - this was done with ssh_keygen followed by ssh_copy_id and voila!
  • Now I can run all the commands from terminal without calling a specific key-file…

and yeah, that’s where I am right now. I can get and set from terminal in hassio - but the graphical interface does not yet work. I guess this has to do with the SSH-stuff. Since both units are best buddies now I will dig into the code and see if I can adjust something. Only problem is that I only have 24 hours of coding knowledge. Wish me luck.

This is the last thing in our home that cannot be shut down with voice command. But I will succeed with this and I will forever be grateful Leif. Nu jäklar.

Update2: I did it! Had to refer to the keyfile I manually copied into config/ssh/ (just as in the code provided). Now it works. I feel like god. Programming is fun. I am victorious. The fan is no longer a lone ranger but in my realm of power. God bless you Leif. We did it.

Soonish… Comparing home-assistant:dev...elupus:fjaraskupan · home-assistant/core · GitHub if it works out well i’ll put on hacs or in core.

1 Like

Has anybody else tried the builtin integration yet? I know @TheGizzle has issues, but would be nice to know if anybody else tried it.

I do. But had a lot of issues to get it up and to understand what was happening. I’m using HA blue with TP-Link UB400 Nano USB on 1m usb extension cord.

Initial setup scan and

docker exec -it homeassistant /bin/bash
cd /usr/local/lib/python3.9/site-packages/fjaraskupan
python -m fjaraskupan scan

will always fail unless I run below first

python -m fjaraskupan state 04:91:62:8C:8E:8E

I sometimes need to do it after reboots to. RSSI will never update and stay at 0.

However this below picks up RSSI and then it will update in HA, this also works before initial setup in HA:

import asyncio
from bleak import BleakScanner
 
 def detection_callback(device, advertisement_data):
     print(device.address, "RSSI:", device.rssi, advertisement_data)

 async def main():
     scanner = BleakScanner()
     scanner.register_detection_callback(detection_callback)
     await scanner.start()
     await asyncio.sleep(5.0)
     await scanner.stop() 
    for d in scanner.discovered_devices:
         print(d)

asyncio.run(main())

Prints:

04:91:62:8C:8E:8E RSSI: -59 AdvertisementData(local_name='COOKERHOOD_FJAR', manufacturer_data={20296: b'ODFJAR\x00\x02\x00\x01\x00\x00\x00'}, service_uuids=['00001800-0000-1000-8000-00805f9b34fb', '00001801-0000-1000-8000-00805f9b34fb', '77a2bd49-1e5a-4961-bba1-21f34fa4bc7b'])

Sometimes connection is lost after 30min but then suddenly 5 hours without issues. Seems very random. Distance is only 1m with a wall in between.

HAOS 7.1 did break bluetooth, I suspect some issue with BlueZ and kernel 5.10.88 but only guessing. I reverted too HAOS 7.0 to get it running again.

Good to know there is at least some success. Strange that you need the manual scan on start. We do have scan active constantly. Do you have any other Bluetooth things active? I wonder if something ends up disabling the scan.

It’s the only integration with bluetooth in HA. Current debug output don’t catch anything. Let me know if I can help to run any custom debug code of your choosing?

+1 on yada75’s experiences

I have set up a RPI3 under the kitchen worktop to talk to the cookerhood and more or less have the exact same issues. Integration wouldn’t even install until I broke into the docker image and issued the state check.

A year-ago-something I tried to hack a MQTT-to-BLE bridge for the cookerhood, but couldn’t get the BLE stack to behave reliably and eventually gave up due to lack of time. It seems to me the problems here are the same. The entities becomes unavailable frequently and the response on state changes can take minutes.

Following up with log output of a failure where the entities become unavailable (and then recover):

2022-01-09 13:25:26 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 10.917 seconds (success: True)
2022-01-09 13:25:56 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 10.882 seconds (success: True)
2022-01-09 13:26:26 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 10.905 seconds (success: True)
2022-01-09 13:26:56 ERROR (MainThread) [homeassistant.components.fjaraskupan] Unexpected error fetching Fjaraskupan Updater data: Timeout on connect
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/dbus_next/aio/message_bus.py", line 305, in call
    await future
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/asyncio/tasks.py", line 492, in wait_for
    fut.result()
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 156, in __aenter__
    await self._client.__aenter__()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/client.py", line 61, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/bluezdbus/client.py", line 267, in connect
    reply = await asyncio.wait_for(
  File "/usr/local/lib/python3.9/asyncio/tasks.py", line 494, in wait_for
    raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/usr/src/homeassistant/homeassistant/components/fjaraskupan/__init__.py", line 80, in async_update_data
    await device.update()
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 210, in update
    async with self:
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 159, in __aenter__
    raise FjaraskupanTimeout("Timeout on connect") from exc
fjaraskupan.FjaraskupanTimeout: Timeout on connect
2022-01-09 13:26:56 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 10.090 seconds (success: False)
2022-01-09 13:27:26 ERROR (MainThread) [homeassistant.components.fjaraskupan] Unexpected error fetching Fjaraskupan Updater data: Timeout on connect
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/dbus_next/aio/message_bus.py", line 305, in call
    await future
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/asyncio/tasks.py", line 492, in wait_for
    fut.result()
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 156, in __aenter__
    await self._client.__aenter__()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/client.py", line 61, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/bluezdbus/client.py", line 267, in connect
    reply = await asyncio.wait_for(
  File "/usr/local/lib/python3.9/asyncio/tasks.py", line 494, in wait_for
    raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/usr/src/homeassistant/homeassistant/components/fjaraskupan/__init__.py", line 80, in async_update_data
    await device.update()
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 210, in update
    async with self:
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 159, in __aenter__
    raise FjaraskupanTimeout("Timeout on connect") from exc
fjaraskupan.FjaraskupanTimeout: Timeout on connect
2022-01-09 13:27:26 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 10.067 seconds (success: False)
2022-01-09 13:27:49 INFO (MainThread) [homeassistant.components.fjaraskupan] Fetching Fjaraskupan Updater data recovered
2022-01-09 13:27:49 DEBUG (MainThread) [homeassistant.components.fjaraskupan] Finished fetching Fjaraskupan Updater data in 3.879 seconds (success: True)

Note that I have changed update interval to 20 seconds between updates to speed things up. I also see these types of failures:

2022-01-09 14:26:52 ERROR (MainThread) [homeassistant.components.fjaraskupan] Unexpected error fetching Fjaraskupan Updater data: Error on connect
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 156, in __aenter__
    await self._client.__aenter__()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/client.py", line 61, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/bluezdbus/client.py", line 278, in connect
    assert_reply(reply)
  File "/usr/local/lib/python3.9/site-packages/bleak/backends/bluezdbus/utils.py", line 23, in assert_reply
    raise BleakDBusError(reply.error_name, reply.body)
bleak.exc.BleakDBusError: [org.bluez.Error.Failed] Software caused connection abort

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/usr/src/homeassistant/homeassistant/components/fjaraskupan/__init__.py", line 80, in async_update_data
    await device.update()
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 210, in update
    async with self:
  File "/usr/local/lib/python3.9/site-packages/fjaraskupan/__init__.py", line 162, in __aenter__
    raise FjaraskupanBleakError("Error on connect") from exc
fjaraskupan.FjaraskupanBleakError: Error on connect

I regularly see update times > 20 seconds, so I have increased the timeout for the bleak client to 60 sec. Will post updates if I get any more insights.

Great that you had some success. I actually got initial install working better when I applied this https://github.com/hbldh/bleak/pull/715 but it don’t help for random connection errors, now it installs at second attempt. No idea why, but @elupus maybe knows?

Now it seems that Bleak 0.14 with some other fixes is ready soon and If we are lucky everything will improve.

Seem like version 0.14 solved the discovery issues, but not the random connection errors. One step forward at least.

Yes, some progress in the right direction. I don’t know if it’s possible to upgrade Bluez myself with HA-OS, probably not. With ha-blue Odroid-N2+ I’m still at Bluez 5.58 and latest is 6.63 and will probably change something. Is it the same with Rasberry Pi?

bash-5.1# bluetoothctl -v
bluetoothctl: 5.58

Have you tried debug log? (scanner is really chatty)

logger:
  default: warning
  logs:
    homeassistant.components.fjaraskupan: debug
    fjaraskupan: debug
    bleak.backends.bluezdbus.scanner: debug
    bleak.backends.bluezdbus.client: debug

Generally the integration should be passively listen to announces. However if this is not seen within 120 seconds, it will try to connect. The devices themself seem a bit crash prone when you connect to them ä.

So if you have discovery issues, then maybe the integration keeps connecting to the device every 120 second instead,.causing it to crash.

Could very well be that the device itself is flaky. And yes, there are reconnections at the configured intervals (every time). Have you gotten this to work reliably in your installation?

I’ll take a look at your code and see if I can get notifications out of the cooker hood. I never managed to do that in my previous attempt to integrate it, and just concluded that it probably didn’t support notifications.

Yes, exact same version in the RPI3 docker image. I could add some further debug on bleak, and see what that gives.

Or to invest the time into trying hack something to work with esphome and the ble client component instead! Would have been a cleaner solution for me as the RPI is there for the sole purpose of communicating with the cookerhood.

Really appreciering all involverad here - i at the end of the line with my pi4. I need to invest myself to the lush and magical stable land of Nuc’s I keep hearing about. The RP4 seems to have issues with the Bluetooth protocol in some way. Cant get that name to show up.

Old hacky solution was having a rasperry pi3 as a bridge which worked remarkably well. May have to revert to that.

Or just go full nuc.

I had big problems with HA OS 7.1-7.6 with Odroid N2+ and bluetooth. HA OS dev220404 seems to fix many issues so connectivity is at par or better than OS 7.0. https://github.com/home-assistant/operating-system/issues/1746#issuecomment-1094219430

Updated HA to 2022.6.0 and then unable to connect. Tried to remove and add Fjäråskupan but won’t find any devices. Manually reverted last commit #72569 then add Fjäråskupan worked again, seems DEVICE_NAME don’t work with HAOS Bluez 5.63, HA Blues 5.58 and bleak 14.3.

The earlier commit #71969 don’t play well with UUID here and results in unavailable after some minutes.

Then I tried to add my mac adress instead of DEVICE_NAME with filter and changed __init__.py row_93 to:

scanner = BleakScanner(filters={“Pattern”: “04:91:62:8C:8E:8E”, “DuplicateData”: True})

And success , running better then ever for last 24h with no disconnect at all!

@elupus can you use mac adress?