sbidy / pywizlight Goto Github PK
View Code? Open in Web Editor NEWA python connector for WiZ devices
License: MIT License
A python connector for WiZ devices
License: MIT License
Thanks, Johan
Discovery failed on a multihomed windows 10 box, is seemed to broadcast on the wrong networkinterface. After changing the broadcast address 255.255.255.255 in broadcast_registration to the local network broadcast address 192.168.0.255 it worked.
There is a risk of leaking since self.loop.call_later(1, self.broadcast_registration)
keeps calling and if self.transport
is never cleared it will run as long as the object exists
Running sudo python3 setup.py
does not work because after this commit: de28d14#diff-41caa14b44b8bb1cc66b4ee093105957R3, the get_version()
function cannot find the version because the single quotes were replaced with double quotes in _version.py
. Also, would be nice for installation instructions for someone looking to download this and get started right away
I'm creating a PilotBuilder with the RGB values (255, 173, 0), 0 cold white, and 0 warm white. Then I'm passing the PilotBuilder instance into the turn_on method of the light.
It turns out the PilotBuilder constructor passes my RGB value to _set_rgb, which in turn calls rgb2rgbcw and uses the returned values to set cold white and warm white to non-zero values.
This appears to be very much intentional and so I'm assuming this isn't a bug and you're covering a use case I'm unaware of. Perhaps I'm using the PilotBuilder incorrectly to set the RGB values of my bulb. However, it seemingly would be very nice for the PilotBuilder to maintain the values I passed into the constructor.
This isn't a huge deal because I can work around this by doing this after I create the PilotBuilder:
pilot_builder.pilot_params["w"] = 0
pilot_builder.pilot_params["c"] = 0
I already asked this on the Home Assistant integration repository but maybe this is better asked here. Does this work with the WiZMote? If so how do we integrate that?
Hey all,
pip install pytest pytest-asyncio
$ pip freeze | grep pytest
pytest==6.2.3
pytest-asyncio==0.15.1
$ pytest pywizlight/tests
platform darwin -- Python 3.9.2, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: /Users/patrickk/github/pywizlight
plugins: asyncio-0.15.1
collected 18 items
pywizlight/tests/test_bulb.py F.................
All seem to pass except for test_Bulb_Discovery
FAILED pywizlight/tests/test_bulb.py::TestBulb::test_Bulb_Discovery - OSError: [Errno 48] Address already in use
I don't see any documentation on setting up the tests nor are there any github actions configured to run the tests. Any idea what I'm doing wrong?
I was curious if this API might expose the Enable / Disable setting for the WiZ Motion Sensor in the room settings? I wish WiZ made this setting schedulable but, alas, no. :( If I could program it, that would be cool. :)
@sbidy Is there a way to use effects like breath/pulsate or spectrum?
Using asyncio.create_task(bulb.turn_on())
makes the library raise a WizLightConnectionError
. Expected behavior is that the UDP packet would be relayed anyways and I could make a similar call to turn on an indefinite amount of lightbulbs, with the help of a for loop, for example.
Note that tcpdump
shows that no packet is sent
Example code to reproduce the error:
import asyncio
from pywizlight import wizlight
async def test():
bulb = wizlight("192.168.0.10")
asyncio.create_task(bulb.turn_on())
if __name__ == '__main__':
asyncio.run(test())
Last night I downloaded the Android APK of the app and poking around I found the images that represent each scene. I did find all the images for the scenes listed in pywizlight/scenes.py
I did find a few additional images, which correspond to alternative versions of scenes listed in the repo. It seems to me that they are animated scenes that only use the white LEDs. The scene names have _tw
appended to them (maybe for True White?).
For instance, this is what the file for christmas
looks like (scene_christmas_big.png
):
And this is what the file for christmas_tw
looks like (scene_christmas_tw_big.png
):
There are five scenes that have this alternative version:
bedtime_tw
christmas_tw
relax_tw
tv_time_tw
wakeup_tw
I don't have an android device, but these scenes are not listed in the iOS app at all. I wonder if there is an additional parameter that needs to be implemented to activate them.
The WiZ G95 and WiZ C35 lights colour temperature ranges from 2000 to 4500.
I've successfully tested both with echo '{"method":"setPilot","params":{"temp":2000}}' | nc -u -w 1 192.168.30.10 38899
.
Can you adjust the _set_colortemp
method in bulb.py to be less restrictive?
From my testing with these lights, anything less than 1000 kelvin, or more than 12000 kelvin results in an "Invalid params" response. Thankfully the light seems to have its own check - if you command 1000 kelvin, it will default to 2000 (and 12000 defaults to 4500).
Hopefully the above is true for all other WiZ lights.
Perhaps use:
def _set_colortemp(self, kelvin: int):
"""Set the color temperature for the white led in the bulb."""
if kelvin < 1000:
kelvin = 1000
elif kelvin > 12000:
kelvin = 12000
self.pilot_params["temp"] = kelvin
When installing using pip install pywizlight
I get the following error:
Collecting pywizlight
Downloading pywizlight-0.3.4.tar.gz (11 kB)
ERROR: Command errored out with exit status 1:
command: /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/tmp/pip-install-i4iV2H/pywizlight/setup.py'"'"'; __file__='"'"'/private/tmp/pip-install-i4iV2H/pywizlight/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /private/tmp/pip-install-i4iV2H/pywizlight/pip-egg-info
cwd: /private/tmp/pip-install-i4iV2H/pywizlight/
Complete output (6 lines):
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/private/tmp/pip-install-i4iV2H/pywizlight/setup.py", line 11
def get_version() -> str:
^
SyntaxError: invalid syntax
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
owen@raspberrypi:~ $ uname -a
Linux raspberrypi 5.10.17+ #1403 Mon Feb 22 11:26:13 GMT 2021 armv6l GNU/Linux
owen@raspberrypi:~ $ python -v
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
# /usr/lib/python2.7/site.pyc matches /usr/lib/python2.7/site.py
import site # precompiled from /usr/lib/python2.7/site.pyc
# /usr/lib/python2.7/os.pyc matches /usr/lib/python2.7/os.py
import os # precompiled from /usr/lib/python2.7/os.pyc
import errno # builtin
import posix # builtin
# /usr/lib/python2.7/posixpath.pyc matches /usr/lib/python2.7/posixpath.py
import posixpath # precompiled from /usr/lib/python2.7/posixpath.pyc
# /usr/lib/python2.7/stat.pyc matches /usr/lib/python2.7/stat.py
import stat # precompiled from /usr/lib/python2.7/stat.pyc
# /usr/lib/python2.7/genericpath.pyc matches /usr/lib/python2.7/genericpath.py
import genericpath # precompiled from /usr/lib/python2.7/genericpath.pyc
# /usr/lib/python2.7/warnings.pyc matches /usr/lib/python2.7/warnings.py
import warnings # precompiled from /usr/lib/python2.7/warnings.pyc
# /usr/lib/python2.7/linecache.pyc matches /usr/lib/python2.7/linecache.py
import linecache # precompiled from /usr/lib/python2.7/linecache.pyc
# /usr/lib/python2.7/types.pyc matches /usr/lib/python2.7/types.py
import types # precompiled from /usr/lib/python2.7/types.pyc
# /usr/lib/python2.7/UserDict.pyc matches /usr/lib/python2.7/UserDict.py
import UserDict # precompiled from /usr/lib/python2.7/UserDict.pyc
# /usr/lib/python2.7/_abcoll.pyc matches /usr/lib/python2.7/_abcoll.py
import _abcoll # precompiled from /usr/lib/python2.7/_abcoll.pyc
# /usr/lib/python2.7/abc.pyc matches /usr/lib/python2.7/abc.py
import abc # precompiled from /usr/lib/python2.7/abc.pyc
# /usr/lib/python2.7/_weakrefset.pyc matches /usr/lib/python2.7/_weakrefset.py
import _weakrefset # precompiled from /usr/lib/python2.7/_weakrefset.pyc
import _weakref # builtin
# /usr/lib/python2.7/copy_reg.pyc matches /usr/lib/python2.7/copy_reg.py
import copy_reg # precompiled from /usr/lib/python2.7/copy_reg.pyc
# /usr/lib/python2.7/traceback.pyc matches /usr/lib/python2.7/traceback.py
import traceback # precompiled from /usr/lib/python2.7/traceback.pyc
# /usr/lib/python2.7/sysconfig.pyc matches /usr/lib/python2.7/sysconfig.py
import sysconfig # precompiled from /usr/lib/python2.7/sysconfig.pyc
# /usr/lib/python2.7/re.pyc matches /usr/lib/python2.7/re.py
import re # precompiled from /usr/lib/python2.7/re.pyc
# /usr/lib/python2.7/sre_compile.pyc matches /usr/lib/python2.7/sre_compile.py
import sre_compile # precompiled from /usr/lib/python2.7/sre_compile.pyc
import _sre # builtin
# /usr/lib/python2.7/sre_parse.pyc matches /usr/lib/python2.7/sre_parse.py
import sre_parse # precompiled from /usr/lib/python2.7/sre_parse.pyc
# /usr/lib/python2.7/sre_constants.pyc matches /usr/lib/python2.7/sre_constants.py
import sre_constants # precompiled from /usr/lib/python2.7/sre_constants.pyc
import _locale # builtin
# /usr/lib/python2.7/_sysconfigdata.pyc matches /usr/lib/python2.7/_sysconfigdata.py
import _sysconfigdata # precompiled from /usr/lib/python2.7/_sysconfigdata.pyc
# /usr/lib/python2.7/plat-arm-linux-gnueabihf/_sysconfigdata_nd.pyc matches /usr/lib/python2.7/plat-arm-linux-gnueabihf/_sysconfigdata_nd.py
import _sysconfigdata_nd # precompiled from /usr/lib/python2.7/plat-arm-linux-gnueabihf/_sysconfigdata_nd.pyc
# /usr/lib/python2.7/sitecustomize.pyc matches /usr/lib/python2.7/sitecustomize.py
import sitecustomize # precompiled from /usr/lib/python2.7/sitecustomize.pyc
import encodings # directory /usr/lib/python2.7/encodings
# /usr/lib/python2.7/encodings/__init__.pyc matches /usr/lib/python2.7/encodings/__init__.py
import encodings # precompiled from /usr/lib/python2.7/encodings/__init__.pyc
# /usr/lib/python2.7/codecs.pyc matches /usr/lib/python2.7/codecs.py
import codecs # precompiled from /usr/lib/python2.7/codecs.pyc
import _codecs # builtin
# /usr/lib/python2.7/encodings/aliases.pyc matches /usr/lib/python2.7/encodings/aliases.py
import encodings.aliases # precompiled from /usr/lib/python2.7/encodings/aliases.pyc
# /usr/lib/python2.7/encodings/latin_1.pyc matches /usr/lib/python2.7/encodings/latin_1.py
import encodings.latin_1 # precompiled from /usr/lib/python2.7/encodings/latin_1.pyc
Python 2.7.16 (default, Oct 10 2019, 22:02:15)
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
dlopen("/usr/lib/python2.7/lib-dynload/readline.arm-linux-gnueabihf.so", 2);
import readline # dynamically loaded from /usr/lib/python2.7/lib-dynload/readline.arm-linux-gnueabihf.so
When I run pip install pywizlight, I get the following:
owen@raspberrypi:~ $ pip install pywizlight
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pywizlight
Downloading https://files.pythonhosted.org/packages/61/e5/a74356870c0a9f1f4506f1e694aba9325bf9b9dea679509665ae5c41eb32/pywizlight-0.3.4.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/tmp/pip-install-2vUNZq/pywizlight/setup.py", line 11
def get_version() -> str:
^
SyntaxError: invalid syntax
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-2vUNZq/pywizlight/
The bulbs themselves support fade-in and out: https://taolight.helpshift.com/a/wiz/?s=using-wiz-fine-tuning&f=fade-in-fade-out-changing-how-long-it-takes-for-lights-to-turn-on-off-when-used-with-the-app-or-the-wizmote&l=en
It would be nice if we added support for this and exposed it in the Home Assistant integration!
Line 317 in 341dc04
Investigate if its possible to get energy data from the device to show in Home Assistant
Issue if try to send broadcast for discovery.
MyPy Error:
Incompatible types in assignment (expression has type "BaseTransport", variable has type "Optional[DatagramTransport]")
Exception:
Exception in callback BroadcastProtocol.connection_made(<_SelectorDat...e, bufsize=0>>)
handle: <Handle BroadcastProtocol.connection_made(<_SelectorDat...e, bufsize=0>>)>
Traceback (most recent call last):
File "C:\Program Files\Python\lib\asyncio\events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "C:\Users\Stephan\AppData\Roaming\Python\Python37\site-packages\pywizlight\discovery.py", line 66, in connection_made
transport, DatagramTransport
AssertionError
Workaround with:
pywizlight/pywizlight/discovery.py
Line 66 in 21c8263
Maybe @akx can help me here? Is this a cast issue?
The following works against a Wiz plug.
# cat test_plug.py
import asyncio
import time
import json
from pywizlight.bulb import wizlight, PilotBuilder
async def main():
light = wizlight("1.2.3.4")
print(light.__dict__)
plug_config = await light.getBulbConfig()
print(json.dumps(plug_config, indent=2))
# Turns the plug on
print("Turning plug on")
await light.turn_on(PilotBuilder())
state = await light.updateState()
print(f"Current plug state is {state.get_state()}")
time.sleep(2)
# Turns the plug off
print("Turning plug off")
await light.turn_off()
state = await light.updateState()
print(f"Current plug state is {state.get_state()}")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
# python3 test_plug.py
{'ip': '1.2.3.4', 'port': 38899, 'state': None, 'mac': None}
{
"method": "getSystemConfig",
"env": "pro",
"result": {
"mac": "a mac address",
"homeId": 1234567,
"roomId": 1234567,
"moduleName": "ESP10_SOCKET_06",
"fwVersion": "1.20.0",
"groupId": 0,
"drvConf": [
20,
2
],
"ewf": [
255,
0,
255,
255,
0,
0,
0
],
"ewfHex": "ff00ffff000000"
}
}
Turning plug on
Current plug state is True
Turning plug off
Current plug state is False
Exception if discover class is called.
Workaround in 0.3.4 but not finally fixed.
Line 359 in 0f5a321
Exception in callback discovery.BroadcastProtocol.broadcast_registration()
handle: <TimerHandle when=166638.781 discovery.BroadcastProtocol.broadcast_registration()>
Traceback (most recent call last):
self._sock.sendto(data, addr)
AttributeError: 'NoneType' object has no attribute 'sendto'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Stephan\AppData\Local\Programs\Python\Python37-32\lib\asyncio\events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "C:\Users\Stephan\Documents\GitHub\pywizlight\pywizlight\bulb.py", line 363, in broadcast_registration
register_method.encode(), ("255.255.255.255", 38899)
File "C:\Users\Stephan\AppData\Local\Programs\Python\Python37-32\lib\asyncio\selector_events.py", line 1007, in sendto
exc, 'Fatal write error on datagram transport')
File "C:\Users\Stephan\AppData\Local\Programs\Python\Python37-32\lib\asyncio\selector_events.py", line 675, in _fatal_error
self._loop.call_exception_handler({
AttributeError: 'NoneType' object has no attribute 'call_exception_handler'
It'd be great if we would have auto-discovery of bulbs instead of having to type in their IPs - this would also help the home assistant integration by adding a simple config flow.
Good news is, I have a local branch that adds this functionality - expect a PR soon!
Entered DNS name in Config Flow: wiz-22af76
Issue: the class DatagramTransport(BaseTransport)
does not accept dns names as addr parameter def sendto(self, data, addr=None)
Exception:
2022-02-08 17:43:30 ERROR (MainThread) [homeassistant.components.wiz.config_flow] Unexpected exception
Traceback (most recent call last):
File "/workspaces/core/homeassistant/components/wiz/config_flow.py", line 144, in async_step_user
mac = await bulb.getMac()
File "/usr/local/lib/python3.9/site-packages/pywizlight/bulb.py", line 518, in getMac
await self.getBulbConfig()
File "/usr/local/lib/python3.9/site-packages/pywizlight/bulb.py", line 524, in getBulbConfig
resp = await self.sendUDPMessage(message)
File "/usr/local/lib/python3.9/site-packages/pywizlight/bulb.py", line 569, in sendUDPMessage
self.transport.sendto(data, (self.ip, self.port))
File "/usr/local/lib/python3.9/asyncio/selector_events.py", line 1040, in sendto
raise ValueError(
ValueError: Invalid address: must be None or ('192.168.178.53', 38899)
It looks like the devices report a speed of 20-200 instead of 1-100
Can I control my wiz lights that are on my home network while connected to another network?
Hey Stephan,
Congrats on the release of the official Wiz integration in Home Assistant!
I was wondering how to migrate from the wiz_light custom integration to the official integration. After upgrading to the latest home assistant release, I tried simply removing the wiz_light integration and restarting, but after this I was not able to control the lights.
Is there a recommended way to upgrade, or do I need to re-configure all the lights from scratch?
2022-02-10 15:05:43 DEBUG (MainThread) [pywizlight.push_manager] ('192.168.213.57', 38900): PUSH << b'test'
2022-02-10 15:05:43 ERROR (MainThread) [pywizlight.push_manager] ('192.168.213.57', 38900): Sent invalid push message: b'test'
2022-02-10 15:05:43 DEBUG (MainThread) [pywizlight.push_manager] ('192.168.213.57', 38900): PUSH << b'test'
2022-02-10 15:05:43 ERROR (MainThread) [pywizlight.push_manager] ('192.168.213.57', 38900): Sent invalid push message: b'test'
When configuring a new device, the app sends a single string test
to check if it can be delivered.
We should not error on this and instead ignore it
Is it possible to change the lamp's minimum brightness level?
I have Gauss downlight IoT 1600lm with a minimum brightness level of 10, and it is pretty bright for wakeup sequence.
I've seen pwmRange
in UserConfig but it can't be changed from local control or from cloud Wiz Connect.
SystemConfig and UserConfig:
{'method': 'getSystemConfig', 'env': 'pro', 'result': {'mac': '', 'homeId': '', 'roomId': '', 'moduleName': 'ESP12_SHTW1C_01W', 'fwVersion': '1.21.2', 'groupId': 0, 'drvConf': [20, 1], 'ewf': [255, 0, 0, 255, 0, 0, 30], 'ewfHex': 'ff0000ff00001e', 'ping': 0}}
{'method': 'getUserConfig', 'env': 'pro', 'result': {'fadeIn': 500, 'fadeOut': 2000, 'fadeNight': False, 'dftDim': 100, 'pwmRange': [5, 100], 'whiteRange': [2700, 4000], 'extRange': [2700, 4000], 'po': False}}
@sbidy, sorry for hijacking this issue, but it seems the most relevant place to ask @vodovozovge one more question: What is the status of https://gitlab.com/wizlighting/wiz-local-control? Is it the official Wiz library other projects like pywizlight could take ideas from?
Hey team,
Thanks a ton for this library and for your efforts to get it merged into HomeAssistant.
I have ~70 wiz bulbs and I'm starting to move them to a new vlan/ssid on my network. This is quite painful to do manually. I'm hoping to use the get/setWifiConfig UDP methods from your readme.
Is there an example piece of python on how to do this? (I've read the readme but I'm not quite sure how to use it just yet)
BTW - I love how you wrote this library to be async.
Thanks for any help. I'm now a sponsor too!
Hey, I have one question, is it possible to use the Wiz bulbs (with your library) without any internet connection, so only on a local network?
In the previous versions of the firmware, there used to be an integer array returned with getSystemConfig called 'drvConf'.
Using those two numbers I figured out that it was possible to get the 'type' of the bulb pretty consistently with some experimentation.
In the latest version they took drvConf away, bot those two numbers are instead now found in getModelConfig, the values 'wcr' and 'nowc' are actually the two numbers from drvConf.
So, I've come up with a list so far, and I'd appreciate any feedback you have on this matter.
{ (wcr, nowc) or drvConf: [1,2], "Bulb Kind" }
{ (37, 1), "Philips Color & Tunable-White BR30" },
{ (50, 1), "Philips Color & Tunable-White BR30" },
{ (33, 1), "Philips Color & Tunable-White A19" },
{ (60, 1), "Philips Color & Tunable-White A19" },
{ (20, 2), "Philips Color & Tunable-White A21" },
{ (40, 1), "Philips Color & Tunable-White E14 Candelabra" }
I have about 20 different bulbs in my house. But I would love to know if these match up with what you have?
Hey,
I would love to have an connection exception to be thrown right after creating the instance.
def api_factory(ip : str) -> Any:
api = None
try:
from pywizlight import wizlight
from pywizlight.exceptions import WizLightError
try:
api = wizlight(ip)
# hack start
loop = get_loop() # instance of the loop
builder = get_builder() # instace of pilot builder
loop.run_until_complete(api.turn_on(builder()))
# hack end
except WizLightError:
exit(wording.get('connection_no').format('WIZ LIGHT') + wording.get('exclamation_mark'))
return api
except ImportError:
exit(wording.get('package_no').format('WIZ LIGHT') + wording.get('exclamation_mark'))
At the moment I need to turn the bulb on just to test the connection. See the hack start
and hack end
flags - that would be nice to be removable.
I integrated pywizlight
to Chroma Feedback that let's you use your bulbs as a traffic light for CI builds. Still working on it but release of version 8.0.0 is planned this week.
2022-02-20 14:19:14 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: >> b'{"method":"getModelConfig","params":{}}' (1/6) backoff=0.0
2022-02-20 14:19:15 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: >> b'{"method":"getModelConfig","params":{}}' (2/6) backoff=0.75
2022-02-20 14:19:16 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: << b'{"method":"getModelConfig","env":"pro","error":{"code":-32601,"message":"Method not found"}}'
2022-02-20 14:19:16 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: >> b'{"method":"getUserConfig","params":{}}' (1/6) backoff=0.0
2022-02-20 14:19:16 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: << b'{"method":"getModelConfig","env":"pro","error":{"code":-32601,"message":"Method not found"}}'
2022-02-20 14:19:16 DEBUG (MainThread) [pywizlight.bulb] 192.168.107.98: << b'{"method":"getUserConfig","env":"pro","result":{"fadeIn":500,"fadeOut":500,"dftDim":100,"pwmRange":[0,100],"whiteRange":[2700,6500],"extRange":[2200,6500],"opMode":0,"po":true}}'
2022-02-20 14:19:16 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/aiohttp/web_protocol.py", line 435, in _handle_request
resp = await request_handler(request)
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/aiohttp/web_app.py", line 504, in _handle
resp = await handler(request)
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/aiohttp/web_middlewares.py", line 117, in impl
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/security_filter.py", line 60, in security_filter_middleware
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/forwarded.py", line 100, in forwarded_middleware
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/request_context.py", line 28, in request_context_middleware
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/ban.py", line 79, in ban_middleware
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/auth.py", line 219, in auth_middleware
return await handler(request)
File "/Users/bdraco/home-assistant/homeassistant/components/http/view.py", line 137, in handle
result = await result
File "/Users/bdraco/home-assistant/homeassistant/components/config/config_entries.py", line 164, in post
return await super().post(request, flow_id)
File "/Users/bdraco/home-assistant/homeassistant/components/http/data_validator.py", line 62, in wrapper
result = await method(view, request, *args, **kwargs)
File "/Users/bdraco/home-assistant/homeassistant/helpers/data_entry_flow.py", line 111, in post
result = await self._flow_mgr.async_configure(flow_id, data)
File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 252, in async_configure
result = await self._async_handle_step(flow, cur_step["step_id"], user_input)
File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 325, in _async_handle_step
result: FlowResult = await getattr(flow, method)(user_input)
File "/Users/bdraco/home-assistant/homeassistant/components/wiz/config_flow.py", line 94, in async_step_discovery_confirm
await self._async_connect_discovered_or_abort()
File "/Users/bdraco/home-assistant/homeassistant/components/wiz/config_flow.py", line 72, in _async_connect_discovered_or_abort
bulbtype = await bulb.get_bulbtype()
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/pywizlight/bulb.py", line 545, in get_bulbtype
white_range = await self.getExtendedWhiteRange()
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/pywizlight/bulb.py", line 587, in getExtendedWhiteRange
resp = await self.getUserConfig()
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/pywizlight/bulb.py", line 691, in getUserConfig
return await self.send({"method": "getUserConfig", "params": {}})
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/pywizlight/bulb.py", line 709, in send
return await self.sendUDPMessage(to_wiz_json(message))
File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/pywizlight/bulb.py", line 746, in sendUDPMessage
raise WizLightMethodNotFound("Method not found; maybe older bulb FW?")
pywizlight.exceptions.WizLightMethodNotFound: Method not found; maybe older bulb FW?
I am trying to discover the Philips Wiz Wifi Bulb using wizlight cli but the discover option doesn't detect the device.
I tried the following:
How to auto-discover this Wiz device on the network?
Using an RGB with three distinct non-zero values does not show up correctly on the bulb.
For example using the command light.turn_on(PilotBuilder(rgb = (128, 128, 255)))
D:\TEMP>python -m pywizlight.cli --version
python -m pywizlight.cli, version 0.5.10
D:\TEMP>python -m pywizlight.cli state --ip 192.168.---.71
Get the state from 192.168.---.71
{'mac': 'd8----------', 'rssi': -42, 'src': '', 'state': True, 'sceneId': 11, 'temp': 2700, 'dimming': 20}
Exception ignored in: <function wizlight.del at 0x00000236711F4550>
Traceback (most recent call last):
File "C:\Python310\lib\site-packages\pywizlight\bulb.py", line 743, in del
self.loop.call_soon_threadsafe(self._async_close)
File "C:\Python310\lib\asyncio\base_events.py", line 790, in call_soon_threadsafe
self._check_closed()
File "C:\Python310\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.del at 0x00000236710E2CB0>
Traceback (most recent call last):
File "C:\Python310\lib\asyncio\proactor_events.py", line 116, in del
self.close()
File "C:\Python310\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Python310\lib\asyncio\base_events.py", line 745, in call_soon
self._check_closed()
File "C:\Python310\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
First of all, fantastic library! I'm only beginning to work with asyncio
so forgive me if I'm missing something obvious here.
I am trying to use asyncio.wait_for
to control the timeout of turning controlling some lights. I have created the following minimal example that tries to control a light bulb that is momentarily inaccessible (you can enter an invalid IP in the code below):
import asyncio
from pywizlight import wizlight, PilotBuilder
async def main():
# Set up a standard light
light = wizlight("192.168.0.170")
# Set bulb brightness (with async timeout)
timeout = 10
try:
#await asyncio.wait_for(light.turn_off(), timeout)
await asyncio.wait_for(light.turn_on(PilotBuilder()), timeout)
except asyncio.TimeoutError:
print('Timeout ---------------')
print('Sleep...')
await asyncio.sleep(60)
print('Done.')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
When I use the light.turn_on
method, there are no issues. The try ... except
block works as expected and the output is as follows:
>python single.py
Timeout ---------------
Sleep...
Done.
However, when I use the light.turn_off
method, asyncio complains:
>python single.py
Timeout ---------------
Sleep...
Task exception was never retrieved
future: <Task finished name='Task-4' coro=<wizlight.receiveUDPwithTimeout() done, defined at ...\Python38-32\lib\site
-packages\pywizlight\bulb.py:312> exception=TimeoutError()>
Traceback (most recent call last):
File "...\Python38-32\lib\site-packages\pywizlight\bulb.py", line 314, in receiveUDPwithTimeout
data, remote_addr = await asyncio.wait_for(stream.recv(), timeout)
File "...\Python38-32\lib\asyncio\tasks.py", line 490, in wait_for
raise exceptions.TimeoutError()
asyncio.exceptions.TimeoutError
Done.
I see there are some internal wait_for
calls in the library, but I have not been able to spot why turn_on
works fine and turn_off
does not.
Thanks for you help!
I am planning to put 10 bulbs in one room and 20 into another room and I would like them to turn on/off at the same time without popcorn effect. The Wiz Connected app mentions groups, but I see nothing about groups in pywizlight. Are scenes the same as groups ? I see a pre-defined list in scenes.py which makes me think they are not the same.
Is there support for groups or broadcast/multicast ?
Is the protocol documentation available ? For example, if sendUDPMessage() could include a delay that would help. The first packet could say "turn on in 100ms", the re-transmits could include a smaller delay like "90ms, 80ms....". As long as the bulb gets at least one and assuming jitter is small they would all come on together. Although "jitter is small" is probably a bad assumption on wifi. Really, these bulbs should just have an NTP client. Is that too much to ask :)
ESP01_SHTW_03 is one of the first Wiz bulbs. (https://www.conrad.com/p/wiz-led-light-bulb-wz0126071-eec-a-a-e-e-27-115-w-1516972)
Supports dimming, color temperature change and effects. Kelvin range is 2700 to 6500. Could you add it to the Bulblibrary?
It worked in older versions of pywizlight.
My WIZ lamp (Gauss downlight IoT) drops WiFi connection exactly every 4 minutes for about 5 seconds.
I'm not sure whether the problem with the lamp or wifi router, but you should probably extend send retries to a full receive timeout of 10 seconds.
See #66
For the record WiFi disconnection logs:
Feb 19 17:27:24 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: disassociated
Feb 19 17:27:25 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: deauthenticated due to inactivity (timer DEAUTH/REMOVE)
Feb 19 17:27:29 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: authenticated
Feb 19 17:27:29 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: associated (aid 1)
Feb 19 17:27:29 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC WPA: pairwise key handshake completed (RSN)
Feb 19 17:31:22 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC WPA: group key handshake completed (RSN)
Feb 19 17:31:23 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: disassociated
Feb 19 17:31:24 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: deauthenticated due to inactivity (timer DEAUTH/REMOVE)
Feb 19 17:31:28 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: authenticated
Feb 19 17:31:28 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC IEEE 802.11: associated (aid 1)
Feb 19 17:31:28 OpenWrt daemon.info hostapd: wlan0: STA WIZ:MAC WPA: pairwise key handshake completed (RSN)
// Yes, I have option disassoc_low_ack '0'
in OpenWRT's /etc/config/wireless
This doesn't cause a user visible user but does generate log spam
2022-02-07 22:21:46 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/pywizlight/bulb.py", line 353, in _async_send_register
await self.sendUDPMessage(message)
File "/usr/local/lib/python3.9/site-packages/pywizlight/bulb.py", line 568, in sendUDPMessage
self.transport.sendto(data, (self.ip, self.port))
AttributeError: 'NoneType' object has no attribute 'sendto'
If the integration is unloaded right in the middle of a send retry when a device is offline, the transport can be deleted out from under it. We need to guard here to make sure self.transport
is not None
While the pywizlight package is available in EPEL 8, the asyncio-dgram on which it depends has been removed for lack of a maintainer. However, the pywizlight package in EPEL 8 is fairly old and updating it might result in removing the dependency. I'm investigating that. The latest pywizlight installed with pip3.9 as a normal user does work using the python39 package. (I suspect this would also work with python38.)
For now, the RHEL 8 installation instructions in the README don't work. I'll try to create an updated RPM that does.
The dependency that lost its maintainer: https://src.fedoraproject.org/rpms/python-asyncio-dgram
Fedora package page for pywizlight: https://src.fedoraproject.org/rpms/python-pywizlight
Hello, I have been using this library to control my light. I tried to use it today and I am getting a time out error. Here is the full text: raise WizLightTimeOutError("The request to the bulb timed out")
pywizlight.exceptions.WizLightTimeOutError: The request to the bulb timed out
I updated the package and checked that I could still discover the light. I can still see it in my network, but I cannot control it.
In my personal opinion, the public API should be much more simpler. Developers who jump on board should not have to deal with PilotBuilder
and asyncio
as this are internals and should not be part of implementations. Once you switch one of these, the upgrade paths are going to be a nightmare.
I have helpers like that in my code - it is too complex just to get the name of a light:
def get_light_name(light : Any) -> str:
return light.loop.run_until_complete(light.get_bulbtype()).name
Why not just:
light.name
# Or just a collection that contains all the things
light.info()['name']
This is an suggestion of a potential future API - we can still have await but also handy _sync
methods:
await light.turn_on()
# Set bulb brightness
await light.turn_on(brightness = 255)
# Provide sync calls aswell using run_until_complete internal
light.turn_on_sync(brightness = 255)
# Set bulb brightness (with async timeout)
timeout = 10
await light.turn_on(brightness = 255), timeout)
# Set bulb to warm white
await light.turn_on(warm_white = 255)
# Set RGB values
# red to 0 = 0%, green to 128 = 50%, blue to 255 = 100%
await light.turn_on(rgb = (0, 128, 255))
As you can see this looks easier and both dependencies are hidden. I don't want to offend someone, this is just honest feedback to make everyone's life easier. Thanks
Buttons
ON: "src":"wfa1"
OFF: "src":"wfa2"
NIGHT: "wfa3"
1: "wfa16"
2: "wfa17"
3: "src":"wfa18"
4: "wfa19"
BRIGHT - "src":"wfa8"
BRIGHT + "src":"wfa9"
Im new to linux and not very versed in coding im able to use the cli to turn on and off the light but is there a simple way to run like a light.sh script and toggle the light each time its run ?
thanks kindly
If you pass 0
as a Scene ID, it gives the following error:
ValueError: Scene is not available. Only 0 to 32 are supported
The README also says you "can" input 0
:
sceneId - calls one of thr predefined scenes (int from 0 to 32)
Running the example code on Python 3.9:
await asyncio.gather(bulb1.turn_on(PilotBuilder(warm_white=255)), bulb2.turn_on(PilotBuilder(warm_white=255)), loop=loop)
Shows a DeprecationWarning:
DeprecationWarning: The loop argument is deprecated since Python 3.8, and scheduled for removal in Python 3.10
Remove loop=loop
for Python 3.10 compatibility.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.