ewelink-api-python
ewelink-api-python copied to clipboard
This is great - could maybe have more in the readme.md ...
Not an issue - just some kudos!
I had used https://github.com/skydiver/ewelink-api successfully in node/javascript, but needed a Python version.
Initially I found https://github.com/lucien2k/sonoff-python and spent a day failing to make it work.
But this port just worked!
It could maybe do with a few more instructions in the readme, to indicate how very easy this is to make work, e.g.
import ewelink
import json
email = 'your_email'
password = 'your_password'
region = 'eu' # or 'us' or 'cn'
connection = ewelink.Ewelink(email, password, region)
devices = connection.getDevices()
for device in devices['devicelist']:
print(f'{device["deviceid"]}, {device["name"]}')
resp = connection.getDevice(devices['devicelist'][0]["deviceid"])
print(f'{json.dumps(resp)}')
Boom! Excellent!
This deserves to be better known.
Using this simple script I have got this errors, at least Im logged in :)
[root@testowy ewelink-api-python]# python3 test.py
{'log': 'ok', 'status': 'success'}
Traceback (most recent call last):
File "test.py", line 7, in <module>
devices = connection.getDevices()
File "/root/ewelink-api-python/ewelink/ewelink.py", line 28, in getDevices
return Object(res.json())
File "/root/ewelink-api-python/ewelink/models/object.py", line 7, in __init__
self.__recurse_to_self()
File "/root/ewelink-api-python/ewelink/models/object.py", line 44, in __recurse_to_self
l = list(map(Object, value.copy()))
File "/root/ewelink-api-python/ewelink/models/object.py", line 7, in __init__
self.__recurse_to_self()
File "/root/ewelink-api-python/ewelink/models/object.py", line 44, in __recurse_to_self
l = list(map(Object, value.copy()))
File "/root/ewelink-api-python/ewelink/models/object.py", line 5, in __init__
super().__init__(data)
ValueError: dictionary update sequence element #0 has length 1; 2 is required
@PJanisio and @ajfhodgson well i have a lot of work, that's why im not able to focus on it. Janisio you might have not got that error if u would have used the repo before the latest commit which broke stuff unknowingly cause i left somethings incomplete. 😔 Well im planning an asynchronous re-write of this. That will make it stable and accurate.
Dont let it die :)
I have done an asynchronous re write of this. Its under development still, check out the new examples.
And, this isn't a port anymore, its a independent wrapper around the API. Independent of what ewelink-api does. It will have its own features. I cannot assure anything about its future
I appreciate the time these things soak up!
Well, the version I downloaded continues to successfully poll two humidity sensors under my house every 30 minutes, and has since January, 2022, so I have no reason to upgrade until that stops working! :-)
To encourage you, here's what you've enabled for me:
Red is humidity outside the house (from openweather.org), purple and green are under my house. Blue is amount of rain (London, UK) - it's been a VERY dry spring!
Thanks for udpates, but damn im newbie at python, so maybe you can take a look at this syntax error I got:
[root@testowy ewelink-api-python]# python3 test.py
Traceback (most recent call last):
File "test.py", line 14, in <module>
import ewelink
File "/root/ewelink-api-python/ewelink/__init__.py", line 1, in <module>
from .client import Client, login
File "/root/ewelink-api-python/ewelink/client.py", line 14, in <module>
from .models import ClientUser, Device, Devices, Region
File "/root/ewelink-api-python/ewelink/models/__init__.py", line 2, in <module>
from .user import AppInfo, ClientInfo, ClientUser
File "/root/ewelink-api-python/ewelink/models/user.py", line 47
if extra := data.get('extra', None):
^
SyntaxError: invalid syntax
@PJanisio make sure your Python version is 3.9+
@PJanisio make sure your Python version is 3.9+
Damn, mine is 3.6.8 and unfortunatelly I can not update it to 3.9 so far completely. I think i need to run it in its own 3.9 environment.
Hmmm... Python assignment is simply
extra = data.get('extra', None)
no colon!!!
Well okay, Python 3.9.6 installed, credentials are ok -sorry to bother :)
[root@testowy ewelink-api-python]# python3 test.py
Traceback (most recent call last):
File "/www/python/ewelink-api-python/test.py", line 1, in <module>
import ewelink
File "/www/python/ewelink-api-python/ewelink/__init__.py", line 1, in <module>
from .client import Client, login
File "/www/python/ewelink-api-python/ewelink/client.py", line 14, in <module>
from .models import ClientUser, Device, Devices, Region
File "/www/python/ewelink-api-python/ewelink/models/__init__.py", line 2, in <module>
from .user import AppInfo, ClientInfo, ClientUser
File "/www/python/ewelink-api-python/ewelink/models/user.py", line 6, in <module>
from ..http import HttpClient
File "/www/python/ewelink-api-python/ewelink/http.py", line 27, in <module>
'email': str | None,
TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
[root@testowy ewelink-api-python]# python3 --version
Python 3.9.6
Hmmm... Python assignment is simply
extra = data.get('extra', None)
no colon!!!
Sorry, but :=
is the walrus operator added in Python 3.8. You may check about them in the docs.
@PJanisio i m not sure why that error occurs. Im not able to reproduce it
@PJanisio oh damn, sorry im really sorry, this totally forgot. Its not python 3.9+ you need python 3.10+ for this library. Really very sorry for your troubles
@PJanisio oh damn, sorry im really sorry, this totally forgot. Its not python 3.9+ you need python 3.10+ for this library. Really very sorry for your troubles
Don`t worry its not a priority :) There is a step forward - im using compiled python 3.10.4.
[root@testowy ewelink-api-python]# python3.10 test.py
Traceback (most recent call last):
File "/www/python/ewelink-api-python/test.py", line 4, in <module>
@ewelink.login('xxxxxxxxxx', 'xxxxxxxxx')
File "/www/python/ewelink-api-python/ewelink/client.py", line 67, in login
asyncio.get_event_loop().run_until_complete(client.login())
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/www/python/ewelink-api-python/ewelink/client.py", line 43, in login
self.devices = Devices(
File "/www/python/ewelink-api-python/ewelink/models/device.py", line 83, in __init__
super().__init__(devices)
File "/www/python/ewelink-api-python/ewelink/client.py", line 44, in <genexpr>
Device(data = device, http = self.http, ws=self.ws) for device in (await self.http.get_devices()).get('devicelist', [])
File "/www/python/ewelink-api-python/ewelink/models/device.py", line 49, in __init__
self.state: PowerState = PowerState[data['params']['switch']]
KeyError: 'switch'
Maybe its a specific device issue. Below my devices list (model):
- 4CH Pro
- POWR2
- BASICR2
- Touch EU
@PJanisio hmm true. I just have sonoff and i thought 'switch' should probably be common to all devices, didnt know it wasnt i will probably make a change such that this state becomes Optional
I'd like to thank you for this great tool. I'm currently facing the same issue as "switch" key is not found. In my case it is called "switches". Here is the details I received for "param":
"params":{
"bindInfos":{
"gaction":[
"HERE IS SOME KIND OF A KEY"
]
},
"version":8,
"switches":[
{
"switch":"off",
"outlet":0
},
{
"switch":"off",
"outlet":1
},
{
"switch":"off",
"outlet":2
},
{
"switch":"off",
"outlet":3
}
],
I only have Sonoff Micro installed in my account.
So after playing around for a bit. I've fixed the issue by replacing the code found in ewelink\models\device.py:50 From:
self.state: Power = Power[data['params']['switch']]
To:
self.state: Power = Power[data['params']['switches'][0]['switch']]
Oh man .. I'd love to contribute to this, seems like the code is written in an advance way that I never tried to type with. I'll try to learn something or two about asyncio maybe I can help :)
All the thanks to you 👍
One thing I'm currently facing .. I always get asyncio.exceptions.TimeoutError when trying to change the status of a device ..
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 456, in wait_for
return fut.result()
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\Users\USER\ewelink-api-python\sonoffy.py", line 6, in <module>
async def main(client: Client):
File "c:\Users\USER\ewelink-api-python\ewelink\client.py", line 69, in decorator
result = asyncio.get_event_loop().run_until_complete(f(client))
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 646, in run_until_complete
return future.result()
File "c:\Users\USER\ewelink-api-python\sonoffy.py", line 19, in main
await device.edit(Power.on)
File "c:\Users\USER\ewelink-api-python\ewelink\models\device.py", line 68, in edit
await self.ws.update_device_status(self.id,
File "c:\Users\USER\ewelink-api-python\ewelink\ws.py", line 87, in update_device_status
result = await asyncio.wait_for(fut, timeout = 30)
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 458, in wait_for
raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError
getting this error, any idea how to resolve this?
File "test.py", line 30, in
@Shisir99 make sure you on Python 3.10+
@PJanisio @Cainor the "switch" KeyError is fixed in the latest commit. Please update your libraries to the latest master branch of the repository.
@Cainor you can access the switches using:
switches = device.params.switches
print(switches[0].switch, switches[1].switch)
@PJanisio @Cainor the "switch" KeyError is fixed in the latest commit. Please update your libraries to the latest master branch of the repository.
@Cainor you can access the switches using:
switches = device.params.switches print(switches[0].switch, switches[1].switch)
Works like a charm ! :) So using example script from readme I can see devices data, but at the end of script I got this error message. Dunno what is NoneType device/object.
Traceback (most recent call last):
File "/www/python/ewelink-api-python/test.py", line 5, in <module>
async def main(client: Client):
File "/www/python/ewelink-api-python/ewelink/client.py", line 94, in decorator
result = asyncio.get_event_loop().run_until_complete(f(client))
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/www/python/ewelink-api-python/test.py", line 12, in main
print(device.params)
AttributeError: 'NoneType' object has no attribute 'params'
@Shisir99 make sure you on Python 3.10+
@sputh-the-pigeon yes , I am on python 3.10+ although getting the error.
@PJanisio the device is None
. Means the device ID you provided is invalid and no such device with that ID exists.
@Shisir99 I do not get that error. Check if you have multiple python installations or probably any older version of python is running the code.
you can access the switches using:
switches = device.params.switches print(switches[0].switch, switches[1].switch)
Sure, this will work for accessing the state on/off as str, but switches can be turned off and on and current implementation seems to support only per device
ON/OFF, not per switch
- like for example 4 channel relays?
@PJanisio the device is
None
. Means the device ID you provided is invalid and no such device with that ID exists.
Exactly, I have done mistype in device id. My bad :)
@JabLuszko I'm aware. I haven't implemented those because of my exams. Until those are done, you may use:
await client.ws.update_device_status(deviceid, switches = ...)
This is raw websocket method, all per channel, per device on off methods are built on top of this only, here's the source: https://github.com/AceExpert/ewelink-api-python/blob/2c6305f5abf4874284a6fe48a327fe60020d5326/ewelink/ws.py#L71