Code Monkey home page Code Monkey logo

pywizlight's People

Contributors

akx avatar alex3d avatar allcontributors[bot] avatar angadsingh avatar bdraco avatar bigjohnson avatar daanzu avatar durnezj avatar eibanez avatar emichael avatar fabaff avatar github-actions[bot] avatar mots avatar nollium avatar pablopiriz avatar sbidy avatar scriptsrc avatar skitterrusty avatar snickell avatar svbz3r0 avatar teraskull avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pywizlight's Issues

Error while installing

Hi,
I'm getting this error while installing this...
cmd_vUriSjKdtc
.
How do I get around this?

Thanks

discovery failed on multihomed windows machine

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.

Fix memory leak in discovery

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

Setup.py is broken

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

PilotBuilder's _set_rgb overrides the 'c' and 'w' values I pass into the PilotBuilder's constructor.

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

Event Loop throws runtime error

When using loop = asyncio.get_event_loop() as per the example and then in my coroutine assigning loop = loop I get a runtime error. However if I omit creating/getting the event thread all together this code works just fine and I am able to control my wiz lights just fine. Explanation?

image

Question: How to run tests?

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?

Support motion sensor enable / disable

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. :)

asyncio.create_task() breaks the UDP packet transmission

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())

Additional or alternative scenes?

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):

image

And this is what the file for christmas_tw looks like (scene_christmas_tw_big.png):
image

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.

cc: @vodovozovge @angadsingh

Kelvin range too limiting

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

Installation Problem

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.

pip install fails on current RaspberryPi OS

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/

Implement backoff when bulb is offline

We try really hard to reach the bulb when it is offline.

Screen Shot 2022-02-07 at 16 17 22

Retry should use a progressive backoff as its using a bit of cpu time if there are many offline bulbs

Energy data

Investigate if its possible to get energy data from the device to show in Home Assistant

AssertionError in pywizlight.discovery

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:

transport, BaseTransport

Maybe @akx can help me here? Is this a cast issue?

Implement support for Wiz Plug

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

Async issue with in discovery class

Exception if discover class is called.
Workaround in 0.3.4 but not finally fixed.

"""Fix for async problems if boardcast_registration is called twice! See #13."""

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'

Auto-discovery

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!

Issue with DNS lookup in sendUDPMessage

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)

How to migrate from wiz_light custom repo to built-in integration

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?

Ignore test messages

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?

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?

Question: Example usage of get/setWifiConfig

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!

Question: Use Wiz offline?

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?

Comment: Determining Bulb Kind

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?

Throw exceptions while creating the instance

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.

If a request is retried, the response may arrive after the next message is sent

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?

Auto discovery not working with Philips Wiz Wifi Bulb

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:

  1. No response when I use the pywizlight discover option with broadcast IP 255.255.255.255.
  2. No response when I use 'nc' Linux command to send UDP packets with the above IP.
  3. Able to get a response when I directly use Bulb IP (both 'nc' and 'discover' option).
  4. Able to talk to the device (using bulb IP) such as toggle, get device info, etc.

How to auto-discover this Wiz device on the network?

Three channel RGB not displaying correctly

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)))

`Exception ignored` when trying to get state of a bulb.

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

"Task exception was never retrieved" with turn_off()

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!

bulb synchronisation (popcorn effect)

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 :)

Send retry timeout of 5 sec is not enough (WIZ lamp drops WiFi connection exactly every 4 minutes for about 5 seconds)

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

Fix race condition during unload of integration when bulb is offline

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

CentOS/RHEL 8 installation fails with missing dependency

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

WizLightTimeOutError

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.

Simplify public API

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

Add Support for remotes

Buttons

ON: "src":"wfa1"
OFF: "src":"wfa2"
NIGHT: "wfa3"
1: "wfa16"
2: "wfa17"
3: "src":"wfa18"
4: "wfa19"
BRIGHT - "src":"wfa8"
BRIGHT + "src":"wfa9"

Question: simple script

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.