diyhue / diyHue

Main diyHue software repo
https://diyhue.org/
Other
1.52k stars 276 forks source link

Yeelight Discovery Docker Container #502

Open Mushoz opened 3 years ago

Mushoz commented 3 years ago

Describe the bug When running diyHue inside a container with bridge networking, Yeelights cannot be found. Using TCPdump, it is clear that discovery happens via multicast at 239.255.255.250. However, this multicast traffic only reaches the docker host and does NOT get forwarded to the host's LAN network where the lights reside.

Steps to Reproduce

  1. Set up the docker container via the provided command for bridge networking. Be sure to include the host's MAC address and IP address as environment variables.
  2. Connect to the emulated Hue bridge via Hue essentials (this works).
  3. Start a search for lights while having Yeelights enabled and LAN control enabled.
  4. No lights are found

Expected behavior

  1. Lights are found

Logs There aren't any errors in the logs, since everything is working as expected on diyHue's side. The multicast discovery packets simply never reach the Yeelights.

Docker Info (please complete the following information):

Checklist

Additional context N/A

alexyao2015 commented 3 years ago

This is correct. Typically, we would advise using host networking mode to avoid this issue. The yeelight api documentation specifically state to use multicast to try to find the bulbs, so that is the way that has been implemented. If you have a better way to avoid this issue, please let us know

Mushoz commented 3 years ago

I have been thinking on this issue for a while. Using host networking is definitely the easiest solution, but while Docker is great for ease of deployment, it's also a great tool for increasing security over simply running all applications directly on the Host. Sharing the same network space as the host definitely decreases the security aspect.

I have also been thinking of fixing this issue with some "smart" networking, by increasing the TTL of the multicast packets and proxying or routing the multicast traffic from the docker interface to the host's physical interface, but it has some major drawbacks:

  1. You need to set this up on the host, which makes the ease of deployment much worse.
  2. There's no way to directly include this in this project itself, meaning everyone would have to duplicate this same work to get it to work.
  3. It's kinda hacky

From what I understand on how some other lights from other manufacturers are found (which also showed up in tcpdump), is by simply getting the IP from the host in the environment variable and then by simply sending 255 messages to a known port of said lights to all 255 different addresses in the current subnet. This means that this code to do so is already there, and could be reused. Yeelights are reachable by telnet on port 55443, so trying to connect on that port on all 255 address in the current subnet should do the trick. While the discovery protocol is definitely neater, as it also immediately returns current values of the light bulb, there's nothing an initial "get_prop" call won't be able to fetch.

It's definitely not as clean as the current implementation IMO, but it would allow the program to work in container mode as well. I'd understand if this is something you'd rather not implement, since it's not as clean. But in that case it might be worthwhile to include some information in the docs that Yeelights are not supported in container mode.

alexyao2015 commented 3 years ago

For many of the protocols that we currently have, diyhue uses nmap to do a scan of ip addresses within a subnet. I'll have to review the documentation again for how yeelights work, however if we can directly attempt communication with the bulb (which I assume we can), that would be a potential solution for this.

Mushoz commented 3 years ago

I am pretty sure you already have this, but if not, here's the link to the documentation where I got my information from: https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf

Thank you very much for looking into a potential solution!

alexyao2015 commented 3 years ago

A fix for this likely won't be implemented for a while since there are other pressing issues. In the meantime, I believe you can switch back to bridge mode after the lights have been discovered so if you wish to avoid using host networking, that is an option.

Mushoz commented 3 years ago

I managed to find a workout by using a macvlan. This should be possible to setup via docker itself, but I prefer to run my containers via docker-compose. Below is the docker-compose file I am using to set up this container on its own IP in the same subnet as the rest of the network, which means the container is able to find the lights just fine, while still being isolated from the docker host:

version: '2.1'
services:
  diyhue:
    image: diyhue/core:latest
    restart: always
    container_name: diyhue
    volumes:
      - ./data:/opt/hue-emulator/export/
    stdin_open: true
    tty: true
    stop_grace_period: 1m
    networks: 
      - diyhue_macvlan

networks:
  diyhue_macvlan:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      driver: default
      config:
        - subnet: 192.168.2.0/24
          gateway: 192.168.2.1

It's a bit more complicated than a regular setup, but works as a nice workaround for now :)

alexyao2015 commented 3 years ago

In that case, it's still not isolated by the docker network driver. It still has access to the entire network, just not on the hosts networking. It's pretty similar there.

OlafHaalstra commented 2 years ago

It is not a pretty solution but as a bypass you can the lightbulb as a manual configuration. If you don't want to think about how to set this up I advise to clone the repository and do the following:

sudo mkdir -p /opt/hue-emulator
sudo chown $USER /opt/hue-emulator
git clone https://github.com/diyhue/diyHue.git
cd diyHue
git checkout beta
pip install -r requirements
cd BridgeEmulator
python3
>>> from lights import discover
>>> discover.scanForLights()
>>> exit()
cat /opt/hue-emulator/config/lights.yaml 

This will create a config for you which you can subsequently copy to the docker volume (which you should bind in that case). The lights.yaml will look this (you could also immediately add such a configuration):

'1':
  id_v2: eaf1ab4d-9e64-4fff-8f4c-ab7c9fc09180
  name: Yeelight color 178
  modelid: LCT015
  uniqueid: 00:17:88:01:00:c7:fe:34-0b
  state:
    'on': false
    bri: 200
    hue: 0
    sat: 0
    xy:
    - 0.0
    - 0.0
    ct: 461
    alert: none
    mode: homeautomation
    effect: none
    colormode: ct
    reachable: true
  config:
    archetype: sultanbulb
    function: mixed
    direction: omnidirectional
    startup:
      mode: safety
      configured: true
  protocol: yeelight
  protocol_cfg:
    ip: 192.168.178.178
    id: '0x0000000007d46377'
    backlight: false
    model: color