Modern Forms Smart Fans - Integration

Thanks again. I’ll report back if I make any progress.

Progress! It works if in configuration.yaml I use my loopback dynamic dns address and forward a port instead of using my local address. I’ll take it!..although I’d like to know why.

So Jim, thank you again both for sharing your integration and for assisting.

1 Like

Thanks for sharing! Worked first try on my Modern Forms Wynd 42 Fan!

1 Like

Great Integration! Worked like champ. How do you display in UI with speed control for fan? I can get the fan to display, but have to click in to set speed. Just wondering what everyone is using

each numbered button is a templated switch

Thanks @jimpastos for your integration. For anyone who wants a more compact fan card, I modified some code by another user to work with the six speeds of the modern forms fan.

1 Like

FYI, WAC Lighting, the parent company of the Modern Forms brand has started producing new fans under the “WAC Smart Fan” brand. These fans use the same API as the Modern Forms fans, except it is initially locked behind an in-app purchase.

After connecting your fan to the network and making the additional in-app purchase, @jimpastos’s custom component will work with the WAC Smart Fans.

Jim:
Thanks for the component. I am working on the interface card now. Might you share your yaml code?
Paul Earley

I had the component working for a bit and then it spit out the error below. This may have been a coincidence but around this general time, my wife tried to turn the fan on (from the wall control) and called down the stairs that my fancy new fan was not working!

Log Details (ERROR)
Logger: homeassistant.components.websocket_api.http.connection.140632753678096
Source: custom_components/modernforms/__init__.py:124
Integration: Home Assistant WebSocket API (documentation, issues)
First occurred: 8:20:08 PM (3 occurrences)
Last logged: 8:20:14 PM

HTTPConnectionPool(host='192.168.86.50', port=80): Max retries exceeded with url: /mf (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fe79d298b10>: Failed to establish a new connection: [Errno 113] Host is unreachable'))
HTTPConnectionPool(host='192.168.86.50', port=80): Max retries exceeded with url: /mf (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fe7a08c32d0>: Failed to establish a new connection: [Errno 113] Host is unreachable'))
HTTPConnectionPool(host='192.168.86.50', port=80): Max retries exceeded with url: /mf (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fe7a08bcdd0>: Failed to establish a new connection: [Errno 113] Host is unreachable'))
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/urllib3/connection.py", line 160, in _new_conn
    (self._dns_host, self.port), self.timeout, **extra_kw
  File "/usr/local/lib/python3.7/site-packages/urllib3/util/connection.py", line 84, in create_connection
    raise err
  File "/usr/local/lib/python3.7/site-packages/urllib3/util/connection.py", line 74, in create_connection
    sock.connect(sa)
OSError: [Errno 113] Host is unreachable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 677, in urlopen
    chunked=chunked,
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 392, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/lib/python3.7/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/lib/python3.7/http/client.py", line 1298, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/local/lib/python3.7/http/client.py", line 1247, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/local/lib/python3.7/http/client.py", line 1026, in _send_output
    self.send(msg)
  File "/usr/local/lib/python3.7/http/client.py", line 966, in send
    self.connect()
  File "/usr/local/lib/python3.7/site-packages/urllib3/connection.py", line 187, in connect
    conn = self._new_conn()
  File "/usr/local/lib/python3.7/site-packages/urllib3/connection.py", line 172, in _new_conn
    self, "Failed to establish a new connection: %s" % e
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7fe79d298b10>: Failed to establish a new connection: [Errno 113] Host is unreachable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 725, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "/usr/local/lib/python3.7/site-packages/urllib3/util/retry.py", line 439, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='192.168.86.50', port=80): Max retries exceeded with url: /mf (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fe79d298b10>: Failed to establish a new connection: [Errno 113] Host is unreachable'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 130, in handle_call_service
    connection.context(msg),
  File "/usr/src/homeassistant/homeassistant/core.py", line 1260, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1295, in _execute_service
    await handler.func(service_call)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 209, in handle_service
    self._platforms.values(), func, call, required_features
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 454, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 595, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 485, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/fan/__init__.py", line 113, in async_set_speed
    await self.hass.async_add_job(self.set_speed, speed)
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/modernforms/fan.py", line 29, in set_speed
    self.device.set_fan_speed(int(speed))
  File "/config/custom_components/modernforms/__init__.py", line 102, in set_fan_speed
    self._send_request({"fanOn": 1, "fanSpeed": speed})
  File "/config/custom_components/modernforms/__init__.py", line 124, in _send_request
    r = requests.post(self.url, json=data)
  File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 119, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='192.168.86.50', port=80): Max retries exceeded with url: /mf (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fe79d298b10>: Failed to establish a new connection: [Errno 113] Host is unreachable'))

Did you manage to fix this?
You Fan’s IP probably changed (not 192.168.86.50 anymore). You should mark is as static on your router

My router assigns a fixed IP.

I was able to get things to work, but the CAUSE is the question. It looks like my wall control for the fan just goes off line from time to time. While I was working with your custom component (I was using tscibilia’s lovelace control) it seemed to fall off every day. I would pull the airgap on the wall control or toggle the circuit breaker for the fan for 30 seconds and it would reconnect immediately. Several searches of the log would show messages stating too many queries of the fan IP (sorry I did not save those!).

I will keep you informed. And thanks again.

It has been running for a whole day without having to reboot the wall control.

And thanks for the component!

2 Likes

Any plans to add HACS support for this integration ?

1 Like

Jim:
I have your modern forms component running on 4 fans at home. All have IPs assigned by my Google mesh router. All fans have local and `Net access (WiFi and cloud access icons appear on the app). One or more fans continue to report the below error. When I ping the fan from the command line (especially when traffic has been quiescent for a while) the first response is slow (lengths up to 580ms). See below:

Reply from 192.168.86.50: bytes=32 time=586ms TTL=255
Reply from 192.168.86.50: bytes=32 time=354ms TTL=255
Reply from 192.168.86.50: bytes=32 time=172ms TTL=255
Reply from 192.168.86.50: bytes=32 time=80ms TTL=255

I wonder of the error comes from the component being impatient asking for the response.

Here is the error again, it appears randomly with multiple fans:

2020-08-25 04:32:54 ERROR (MainThread) [homeassistant] Error doing job: Future exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 159, in _new_conn
    conn = connection.create_connection(
  File "/usr/local/lib/python3.8/site-packages/urllib3/util/connection.py", line 84, in create_connection
    raise err
  File "/usr/local/lib/python3.8/site-packages/urllib3/util/connection.py", line 74, in create_connection
    sock.connect(sa)
OSError: [Errno 113] Host is unreachable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen
    httplib_response = self._make_request(
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 392, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/lib/python3.8/http/client.py", line 1240, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1286, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1235, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1006, in _send_output
    self.send(msg)
  File "/usr/local/lib/python3.8/http/client.py", line 946, in send
    self.connect()
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 187, in connect
    conn = self._new_conn()
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 171, in _new_conn
    raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7fa83f28e6a0>: Failed to establish a new connection: [Errno 113] Host is unreachable

Any thoughts where I should go to further debug this?
Paul

Hmm, how is the Wifi connection to the fan? Maybe its struggling?
Another option is to limit the refresh interval. I believe the setting is per fan and defaults to 10s.
try something like

modernforms:
  - host: ...
    name: ...
    light: ...
    scan_interval: 20

Will try to increase scan interval and report back. Two of the fans are < 15 feet and line of sight from one of the Google Mesh units so signal strength should not be an issue.
Thanks!

Setting scan_interval produced this error:

Logger: homeassistant.setup
Source: helpers/event.py:459
First occurred: 12:21:20 PM (1 occurrences)
Last logged: 12:21:20 PM

Error during setup of component modernforms
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 191, in _async_setup_component
    result = await task
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/modernforms/__init__.py", line 28, in setup
    hass.data[DOMAIN][DEVICES].append(ModernFormsDevice(hass, name, host, has_light, scan_interval))
  File "/config/custom_components/modernforms/__init__.py", line 64, in __init__
    self.poll = async_track_time_interval(hass, update_action, interval)
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 468, in async_track_time_interval
    remove = async_track_point_in_utc_time(hass, interval_listener, next_interval())
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 459, in next_interval
    return dt_util.utcnow() + interval
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'int'

I will look at the code too to see if I can correct the incompatability b/t datetime and int variable types.
Paul

Edited modernforms component, file __init__.py as follows:
Added:

import datetime 

to line 3

Changed line ~66 from:

self.poll = async_track_time_interval(hass, update_action, interval)

to:

    self.poll = async_track_time_interval(hass, update_action, datetime.timedelta(0,interval))

This seemed to remove the type casting error with the interval variable. Will follow up with whether the increasing the interval helped.
Paul

1 Like

Thank you for this. Since there’s already a correct import at the top, what seems to have done the trick for me is just changing line 64:

    self.poll = async_track_time_interval(hass, update_action, timedelta(0, interval))

Since I’m relatively new to Home Assistant, I wonder what would be the best way to confirm this change had a desired effect (i.e. actually changed the polling interval).

Context: I have two Modern Forms Roboto fans, and they have been rather wonky since I started using this integration. After about a day or so, their TCP/IP stack appears to freeze solid, and they stop responding. I have a strong suspicion it’s the “intense” polling from Home Assistant integration that is triggering a memory leak of some sort on the fans. I want to see if slower polling delays the reintroduction of the issue, or it’s simply time-based.

@tscibilia

Thank you for the code. Please forgive me as I am really new to all this, I have my fan working with the standard cards but I really like the one you put together. Can you tell me where I need to actually put this code? I have my home assistant running on a Pi 3B. Thanks in advance for any assistance.

It is good to see I am not the only one with this problem.

And yup, did not look carefully and timedelta from datetime was already imported. Changing the singular line at ~64 was all that was needed.

I agree that a probable memory leak in the fan’s firmware seems like the most likely culprit. Slowing the polling will only eliminate this if the firmware has a garbage collection scheme. I wonder if we could command the fan to reboot in the dead of the night?

My fans have been more stable after decreasing the polling rate.