WebThingsIO / gateway-docker

Legacy docker image for WebThings Gateway - now moved to main gateway repo at https://github.com/WebThingsIO/gateway
Mozilla Public License 2.0
72 stars 25 forks source link

Auto-discovery webthing-arduino project fail. #24

Closed matiasdelellis closed 5 years ago

matiasdelellis commented 5 years ago

Hi all, I am writing a project of webthing-arduino library, an air conditioner controller using Wemos D1 mini, IR Controller Shield, and SHT30 Shield. Then I would like to propose it as an example for that library, but first I must ensure that works correctly.

The main problem I find is the discovery of the device. Although it was documented in the library (https://github.com/mozilla-iot/webthing-arduino/search?q=discovery&type=Issues), I think the problem is in this project.

I am working with the Gateway in docker, with a apache reverse proxy. When I click the + button to add devices, It is supposed to start looking, but does not discover anything.

When viewing the log of the gateway, it seems that the this discovers the device, but cannot connect to it.

2019-08-05 22:59:06.151 INFO   : thing-url: Failed to connect to http://ac-controller.local:80: FetchError: request to http://ac-controller.local:80/ failed, reason: getaddrinfo ENOTFOUND ac-controller.local ac-controller.local:80

If I connect to this URL, download the description of the device correctly:

[matias@ideapad ~]$ curl -i -H "Accept: application/json" "http://ac-controller.local:80"
HTTP/1.1 200 OK
Content-Length: 872
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: PUT, GET, OPTIONS
Connection: close
Accept-Ranges: none

[{"id":"ac","title":"Air Conditioning Controller","@context":"https://iot.mozilla.org/schemas","securityDefinitions":{"nosec_sc":{"scheme":"nosec"}},"@type":["OnOffSwitch"],"links":[{"rel":"properties","href":"/things/ac/properties"},{"rel":"events","href":"/things/ac/events"},{"rel":"alternate","href":"ws://192.168.1.246:80/things/ac"}],"properties":{"ambientHum":{"type":"number","readOnly":true,"unit":"%","@type":"AmbientHumProperty","links":[{"href":"/things/ac/properties/ambientHum"}]},"ambientTemp":{"type":"number","readOnly":true,"unit":"°C","@type":"AmbientTempProperty","links":[{"href":"/things/ac/properties/ambientTemp"}]},"setTemp":{"type":"number","unit":"°C","@type":"TempProperty","links":[{"href":"/things/ac/properties/setTemp"}]},"on":{"type":"boolean","@type":"OnOffProperty","links":[{"href":"/things/ac/properties/on"}]}},"href":"/things/ac"}]

The code that fails is this: https://github.com/mozilla-iot/thing-url-adapter/blob/master/thing-url-adapter.js#L479-L490

Note that If I click on "Add by url" and enter the IP, it works correctly, and I can interact with the device.

So here comes my research, I hope it helps ... Thanks for all,

mrstegeman commented 5 years ago

It seems like the gateway Docker image is unable to do mDNS resolution on your network. Are you running your container in host networking mode? I'm guessing we need to add avahi-daemon libnss-mdns to the Docker image, but that seems to be... complicated.

See: https://stackoverflow.com/questions/30646943/how-to-avahi-browse-from-a-docker-container

matiasdelellis commented 5 years ago

Ohh.. It seems to be on that side.. Evidently, the gateway docker discovers it, but cannot access it..

Executing the command inside the container (I should have tried it before :sweat_smile: ) fail.

[matias@nube ~]$ sudo docker exec -it 41db43129204 curl -i -H "Accept: application/json" "http://ac-controller.local:80"
curl: (6) Could not resolve host: ac-controller.local

But if I use the ip it works.. :smiley:

[matias@nube ~]$ sudo docker exec -it 41db43129204 curl -i -H "Accept: application/json" "http://192.168.1.246:80"
HTTP/1.1 200 OK
Content-Length: 872
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: PUT, GET, OPTIONS
Connection: close
Accept-Ranges: none

[{"id":"ac","title":"Air Conditioning Controller","@context":"https://iot.mozilla.org/schemas","securityDefinitions":{"nosec_sc":{"scheme":"nosec"}},"@type":["OnOffSwitch"],"links":[{"rel":"properties","href":"/things/ac/properties"},{"rel":"events","href":"/things/ac/events"},{"rel":"alternate","href":"ws://192.168.1.246:80/things/ac"}],"properties":{"ambientHum":{"type":"number","readOnly":true,"unit":"%","@type":"AmbientHumProperty","links":[{"href":"/things/ac/properties/ambientHum"}]},"ambientTemp":{"type":"number","readOnly":true,"unit":"°C","@type":"AmbientTempProperty","links":[{"href":"/things/ac/properties/ambientTemp"}]},"setTemp":{"type":"number","unit":"°C","@type":"TempProperty","links":[{"href":"/things/ac/properties/setTemp"}]},"on":{"type":"boolean","@type":"OnOffProperty","links":[{"href":"/things/ac/properties/on"}]}},"href":"/things/ac"}

Thanks @mrstegeman , I guess you can close it, and open it in the docker repository.

matiasdelellis commented 5 years ago

Sorry..

Are you running your container in host networking mode?

You mean this?

So, yes. In these test I am using:

sudo docker run -d --rm -v /usr/share/mozilla-iot:/home/node/.mozilla-iot --net=host --name mozilla-iot-gateway mozillaiot/gateway:latest

mrstegeman commented 5 years ago

I've been playing around, and here's what I've discovered:

  1. nss-mdns (the mDNS resolution library) only works with avahi-daemon running.
  2. avahi-daemon has a hard dependency on dbus.
  3. dbus doesn't really work inside a Docker container.
  4. You can share in the dbus socket from the host, or use the running avahi-daemon instance from the host, but that's pretty terrible for users.
  5. We could get around all of this by using IP addresses, rather than <hostname>.local, in thing-url-adapter. However, that falls apart if the host is then assigned a new IP address via DHCP.
  6. Sticking with IP addresses in the config is probably the best workaround for this issue.
matiasdelellis commented 5 years ago

Hi,

Sticking with IP addresses in the config is probably the best workaround for this issue.

Well, I guess it's acceptable as an optional configuration.. Disabled by default, and documented in this repo to use when necessary.

However, that falls apart if the host is then assigned a new IP address via DHCP.

I insist on the optional for this reason, since it is a problem of this implementation, and most of the potential users will not implement the gateway using docker.

Thanks for investigating.

mrstegeman commented 5 years ago

Added some notes to the README. Thanks for bringing up the issue, I had never encountered it!

white-gecko commented 5 years ago

I have the gateway running in docker on an olimex board running armbian (https://www.armbian.com/olimex-lime-2/). I additionally had to install libnss-mdns (which also depends on avahi-daemon). So far about my environment. Can anybody explain, how to mount the avahi daemon into the docker environment? Where is the socket usually running, and where does the gateway docker expect it? Maybe this could also be added to the README as well.

white-gecko commented 5 years ago

I found the socket under /var/run/avahi-daemon/socket on the host but just mounting it to the smae path /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket did not do the trick.

mrstegeman commented 5 years ago

I don't think the avahi socket is the problem, it's the lack of dbus.

white-gecko commented 5 years ago

What about running a dbus inside the docker image: https://stackoverflow.com/a/45274624/414075

Or use it like this: https://github.com/mviereck/x11docker/wiki/How-to-connect-container-to-DBus-from-host

mrstegeman commented 5 years ago

The second one is probably preferable, if you can get it to work. I've tried running dbus inside containers in the past and have had very bad luck. Please let me know if you get a solution working, though!

white-gecko commented 5 years ago

With my pull request the libnss-mdns and avahi-daemon is included. The avahi-daemon can be started with enable-dbus=no in the configuration. When I enter the container with docker exec -it … /bin/bash I can ping my .local devices which was not possible before. But somehow the WebThings gateway does only do "Scanning for new devices... " but does not find the single-thing (https://github.com/mozilla-iot/webthing-python/blob/master/example/single-thing.py) that is running on the computer that can be pinged using its hostename.local from within the container.

mrstegeman commented 5 years ago

This is fantastic! I'm able to find and add devices just fine now.

Questions:

  1. Do you have the "Web Thing" add-on installed?
  2. Are you able to add that host by using the "Add by URL" feature?
white-gecko commented 5 years ago

Cool, yes it works. Didn't know I had to add the "Web Thing" add-on I thought this is native.

mrstegeman commented 5 years ago

Great! I'm rebuilding the Docker images and will push to Docker Hub shortly.