sampsyo / wideq Goto Github PK
View Code? Open in Web Editor NEWreverse-engineered client for the LG SmartThinQ API
Home Page: https://pypi.org/project/wideq/
License: MIT License
reverse-engineered client for the LG SmartThinQ API
Home Page: https://pypi.org/project/wideq/
License: MIT License
When I first setup the SmartThinQ app I logged in via a linked google account.
When I tried to login from the example.py
link, the "Sign in with Google" option brought me to a "Page not found error".
I'm going to try making an account without third-party login to see if it resolves it. I just wanted to document this in case anyone else runs into the same issue.
EDIT: It worked just fine without third-party login. I'll add a mention to the README.
am using oznu/docker-homebridge with homebridge UI enabled on Western Digital PR4100
the error I am getting when home bridge loads:
[8/28/2019, 10:35:23 AM] Homebridge is running on port 53998.
Traceback (most recent call last):
File "/homebridge/node_modules/homebridge-lg-airco/resources/wideq/example.py", line 1, in
import wideq
File "/homebridge/node_modules/homebridge-lg-airco/resources/wideq/wideq/init.py", line 3, in
from .core import * # noqa
File "/homebridge/node_modules/homebridge-lg-airco/resources/wideq/wideq/core.py", line 9, in
import requests
ModuleNotFoundError: No module named 'requests'
Here is python3 version:
Hello I am trying to use the wideq with this bundle but keep getting error when execute
/homebridge/node_modules/homebridge-lg-airco/resources/wideq # python3 --version
Python 3.7.3
When running command: python3 example.py -c “US” -l “en-US” -s "wideq_state.json" ls
/homebridge/node_modules/homebridge-lg-airco/resources/wideq # python3 example.py -c “US” -l “en-US” -s "wideq_state.json" ls
Traceback (most recent call last):
File "example.py", line 1, in
import wideq
File "/homebridge/node_modules/homebridge-lg-airco/resources/wideq/wideq/init.py", line 3, in
from .core import * # noqa
File "/homebridge/node_modules/homebridge-lg-airco/resources/wideq/wideq/core.py", line 9, in
import requests
ModuleNotFoundError: No module named 'requests'
I am sure I saw this discussed previously but I can't find it, so apologies in advance.
I am working on a Homebridge plugin to incorporate the wideq library. It was mentioned somewhere (?) that the authenticate() functionality might be moved into wideq directly if the "Go to this url, type in your login credentials, copy the resultant URL, and paste it here" thing could be done automatically with LG login info that's saved somewhere.
While I understand the concepts, the implementation is WAY above my experience level with GET/POST, etc.
FYI, using the ac-mon example I am already able to display the room temp from my LG AC in a HomeKit temperature sensor button icon. (Low hanging fruit :-)), but only after I have manually logged into the LG site using example.py.
So.....none of this will work automatically across a reboot unless wideq can log into the LG server automatically when it needs to. Is anyone (even considering) working on this? Help!
It seems like it’d be helpful to allow the user to change the country code - I just tested with editing the “US” and “en-US” to be “CA” and “en-CA” respectively and everything works - but for upstream implementations like hass-smartthinq
that’s trickier to do!
When I try to login and press the Sign In button nothing happens. I'm not being redirected. Is the URL correct? (https://mx.m.lgaccount.com/login/sign_in?country=MX&language=es_MX&svcCode=SVC202&aut)
It used to work a copule weeks ago. I'm not using third-party log in and I already tried on different browsers and devices.
After I've authenticated when I re-run the example the ls call only returns the langpack not the actual device list.
I'm assuming based on the documentation that the steps are:
python3 example.py -c US -l en-US
log in and get that redirect URL as asked -- paste into the output -- it closes, seeming to save my auth info.
then, I run:
python3 example.py ls
-- but nothing happens, no error, no output.
It seems from my guessing at syntax that I've got it right (if I try a different command, I properly get an error that it's an invalid command), but I'm not getting anything listed. I should be seeing a Washer and a Dryer... and maybe a TV also.
Any assistance on debugging / logging to help do so would be appreciated!
Hi,
Hoping you can help.
When running this command I get the subsequent traceback error:
root@Home-NAS:~/LGAC_SmartT# python3 example.py -c PL -l en-UK
Log in here:
https://pl.m.lgaccount.com/login/sign_in?grant_type=password&authSvr=oauth2&division=ha&client_id=LGAO221A02&language=en-EN&country=PL&svcCode=SVC202
Then paste the URL where the browser is redirected:
https://pl.m.lgaccount.com/login/iabClose?access_token=8171549c188f321d92e0197e2ac998b3c3eabb307b06cd2c7cddc460b015e67ced5a6f6bfdfb3ed6aa6e13cbbfab9a88&refresh_token=30986299b0c15d599e9b54720ce0975fe2c8236db7290456bfcda8dfb227c995b85fa6d7249c419d6d038ab3b5d11a21&oauth2_backend_url=https://gb.lgeapi.com/
Traceback (most recent call last):
File "example.py", line 214, in <module>
example(sys.argv[1:])
File "example.py", line 200, in example
example_command(client, args)
File "example.py", line 179, in example_command
func = EXAMPLE_COMMANDS[args[0]]
KeyError: '-c'
Can't see at this point where the error is as redirect URL seems correct.
I'm currently following the instructions in this GitHub article
https://github.com/olinek2/LGAC_SmartT
Although I've tried both examples, the one provide above and additionally editing the wideq.py file and making the changes in there directly (as per the other article), both produce the same results.
This is currently running on a Synology NAS, of which I followed the instructions (as per the other article) but entering the following commands and got to this point:
python3 -m pip install -U setuptools
python3 -m pip install gevent msgpack-python greenlet
git clone https://github.com/olinek2/LGAC_SmartT
cd LGAC_SmartT
python3 -m pip install -e .
export PATH="$PATH:/volume1/@appstore/py3k/usr/local/bin"
Appreciate your help in advance.
Probably same (or related) to #64 and many others.
But while others fail at start, mine returns some results right.
$ python3 example.py -c BR -l pt-BR ac-config d27f5d70-7149-11d3-80c7-7440bec36c49
2020-02-09 14:45:20 INFO [wideq.example] Session expired.
{'UseTime': '43', 'ChangePeriod': '720', 'ChangeDate': '00000000'}
{'RemainTime': '0', 'ChangePeriod': '0'}
{'Day': '0', 'Week': '0', 'Month': '0'}
413 watts
0 watts
0
True
Traceback (most recent call last):
File "example.py", line 269, in <module>
main()
File "example.py", line 265, in main
example(args.country, args.language, args.verbose, args.cmd, args.args)
File "example.py", line 206, in example
example_command(client, cmd, args)
File "example.py", line 175, in example_command
func(client, *args)
File "example.py", line 156, in ac_config
print(ac.get_zones())
File "/media/alpe/42e85415-2b13-4e65-bff6-e01945d9ea67/temp/wideq/wideq/ac.py", line 198, in get_zones
return self._get_config('DuctZone')
File "/media/alpe/42e85415-2b13-4e65-bff6-e01945d9ea67/temp/wideq/wideq/client.py", line 435, in _get_config
return json.loads(base64.b64decode(data).decode('utf8'))
File "/usr/lib/python3.6/json/__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.6/json/decoder.py", line 355, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
Does wideq need to have a constant internet connection to LG servers to control devices after initial device setup? Thanks!
% python3 example.py -c BR -l pt-BR mon d27c7740-7149-11d3-10b4-7440be9deeb2
Polling...
Polling...
Polling...
After some command in wideq my AC is locked in android/ios app for few minutes, I have warning that AC using some other user...why wideq don`t close connection to API? How to fix it?
Getting the AC device ID worked ok, but I get the following error when trying to turn the AC on/off. None of the other device commands seem to work either but I thought I'd start here:
$ python3 example.py turn off d27bdb00-7149-11d3-80b0-2c2bf923c76c
Traceback (most recent call last):
File "example.py", line 203, in
main()
File "example.py", line 199, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 163, in example
example_command(client, cmd, args)
File "example.py", line 139, in example_command
func(client, *args)
File "example.py", line 113, in turn
ac = wideq.ACDevice(client, client.get_device(device_id))
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 778, in init
self.model = client.model_info(device)
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 608, in model_info
url = device.model_info_url
AttributeError: 'NoneType' object has no attribute 'model_info_url'
$
I'm having trouble running the python script on macOS Catalina.
I am VERY inexperienced with coding and am receiving this message.
Brennans-MacBook-Pro:wideq Brennan$ python3 example.py -c US -l en-US
Traceback (most recent call last):
File "example.py", line 1, in
import wideq
File "/Users/Brennan/Desktop/custom_components/wideq/wideq/init.py", line 3, in
from .core import * # noqa
File "/Users/Brennan/Desktop/custom_components/wideq/wideq/core.py", line 9, in
import requests
ModuleNotFoundError: No module named 'requests'
Brennans-MacBook-Pro:wideq Brennan$
If anyone could help push me in the right direction that would be stellar.
Hello!
Thanks for this work!
I've bought LG fridge and using Charles debugged requests from iOS app.
For settings temperature and express freeze commands it sends next request:
('rti/rtiControl', {
'cmd': 'Control',
'cmdOpt': 'Set',
'value': 'ControlData',
'data': 'Af8BAv////////8='
'deviceId': device_id,
'workId': gen_uuid(),
'format': 'B64',
})
Pay attention to data. What kind of format is that? I can't decode it.
As far as I see from wideq_state.json, the format of message is correct:
"ControlWifi": {
"type": "BINARY(BYTE)",
"action": {
"SetControl": {
"cmd": "Control",
"cmdOpt": "Set",
"value": "ControlData",
"data": "[{{TempRefrigerator}}, 255, {{IcePlus}}, {{FreshAirFilter}}, 255, 255, 255, 255, 255, 255, 255]"
}
}
}
But I can't encode data. Maybe you saw it somewhere while reverse engineering it?
Thanks!
Quick question around the "StateCode" that is being returned by the device monitoring. I noticed the following values:
S (normal), F (data isn't being refreshed anymore, related to token refresh?), and also N, P, W and E. Does anyone knows what they mean?
Thanks!
I have 3 SmartThinQ devices (Dishwasher, Washer and Dryer).
Dishwasher and Dryer are returned in the device list but Washier is, for whatever reason, is missing.
I've debugged it as far as I could and it looks like the data returned from POST to device\deviceList just doesn't contain the Washer for some reason. The washer is on the same account and works fine in SmartThinQ app.
I've seen recent mention on HA forum of LG changing their API endpoints.
So, perhaps, there is another API endpoint that could possibly be used instead of device\deviceList to get the list of devices?
First of all - I'm so grateful you made this!
It looks like there's a bug with wideq where it expects an array of devices at wideq.py#L395. On an account with a single device, self.session.get_devices()
returns an object, not an array of objects. Because it assumes an array will be returned, it falls apart after this as it attempts to iterate over the object's keys thinking each key represents a device.
I can retrieve the device current status but no command currently works because of the following error:
Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/service.py", line 287, in _handle_service_platform_call
await getattr(entity, func)(**data)
File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/config/custom_components/climate/smartthinq.py", line 162, in set_operation_mode
self.turn_off()
File "/config/custom_components/climate/smartthinq.py", line 194, in turn_off
self._ac.set_on(False)
File "/config/deps/lib/python3.6/site-packages/wideq.py", line 923, in set_on
self._set_control('Operation', op_value)
File "/config/deps/lib/python3.6/site-packages/wideq.py", line 755, in _set_control
{key: value},
File "/config/deps/lib/python3.6/site-packages/wideq.py", line 372, in set_device_controls
'data': '',
File "/config/deps/lib/python3.6/site-packages/wideq.py", line 296, in post
return lgedm_post(url, data, self.auth.access_token, self.session_id)
File "/config/deps/lib/python3.6/site-packages/wideq.py", line 137, in lgedm_post
raise APIError(code, message)
wideq.APIError: ('0011', '등록되지 않은 모델입니다.')
Which translates to "Unregistered model"
I'm guessing is a localization issue with the model of AC I have: AC RAC_056905_MX
Any way to fix this?
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "/usr/lib/python3/dist-packages/urllib3/util/retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='eic.lgthinq.com', port=46030): Max retries exceeded with url: /api/member/login (Caused by SSLError(SSLError(1, '[SSL: DH_KEY_TOO_SMALL] dh key too small (_ssl.c:1056)')))
Terrific job finding this api, im working on a Driver for Hubitat Elevation hub base on this API thanks for the figuring this out, I only can imagine how much work you put in to this I download the the repo and try the example scrip and got an error:
Traceback (most recent call last):
File "example.py", line 1, in
import wideq
File "/home/pi/LGSmart/wideq-master/wideq/init.py", line 4, in
from .client import * # noqa
File "/home/pi/LGSmart/wideq-master/wideq/client.py", line 422
self.model: ModelInfo = client.model_info(device)
^
is because a typo on /wideq/client.py
line 422 should say "self.model.ModelInfo = client.model_info(device)"
Got the following error:
$ python3 example.py ac-mon d27bdb00-7149-11d3-80b0-2c2bf923c76c
Traceback (most recent call last):
File "example.py", line 203, in
main()
File "example.py", line 199, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 163, in example
example_command(client, cmd, args)
File "example.py", line 139, in example_command
func(client, *args)
File "example.py", line 93, in ac_mon
'on' if state.is_on else 'off'
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 1059, in mode
return ACMode(self.lookup_enum('OpMode'))
File "/usr/lib/python3.5/enum.py", line 241, in call
return cls.new(cls, value)
File "/usr/lib/python3.5/enum.py", line 476, in new
raise ValueError("%r is not a valid %s" % (value, cls.name))
ValueError: '@AC_MAIN_OPERATION_MODE_ENERGY_SAVER_W' is not a valid ACMode
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/urllib3/contrib/pyopenssl.py", line 485, in wrap_socket
cnx.do_handshake()
File "/usr/local/lib/python3.7/site-packages/OpenSSL/SSL.py", line 1934, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/usr/local/lib/python3.7/site-packages/OpenSSL/SSL.py", line 1671, in _raise_ssl_error
_raise_current_error()
File "/usr/local/lib/python3.7/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')]
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 672, in urlopen
chunked=chunked,
File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 376, in _make_request
self._validate_conn(conn)
File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 994, in validate_conn
conn.connect()
File "/usr/local/lib/python3.7/site-packages/urllib3/connection.py", line 394, in connect
ssl_context=context,
File "/usr/local/lib/python3.7/site-packages/urllib3/util/ssl.py", line 370, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "/usr/local/lib/python3.7/site-packages/urllib3/contrib/pyopenssl.py", line 491, in wrap_socket
raise ssl.SSLError("bad handshake: %r" % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])",)
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 720, 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 436, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='ruic.lgthinq.com', port=46030): Max retries exceeded with url: /api/member/login (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/setup.py", line 176, in _async_setup_component
component.setup, hass, processed_config # type: ignore
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/smartthinq/init.py", line 69, in setup
client = wideq.Client.from_token(refresh_token, region, language)
File "/config/deps/lib/python3.7/site-packages/wideq/client.py", line 220, in from_token
client.refresh()
File "/config/deps/lib/python3.7/site-packages/wideq/client.py", line 204, in refresh
self._session, self._devices = self.auth.start_session()
File "/config/deps/lib/python3.7/site-packages/wideq/core.py", line 273, in start_session
self.gateway.country, self.gateway.language)
File "/config/deps/lib/python3.7/site-packages/wideq/core.py", line 191, in login
return lgedm_post(url, data)
File "/config/deps/lib/python3.7/site-packages/wideq/core.py", line 120, in lgedm_post
res = requests.post(url, json={DATA_ROOT: data}, headers=headers)
File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 116, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='ruic.lgthinq.com', port=46030): Max retries exceeded with url: /api/member/login (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
If AC is off it cannot be turned back on. (Issue from hass-smarthinq)
Model: LG 115V Dual Inverter Technology Portable Air Conditioner
ASIN: B07NC2QM6V
Item model number: LP1419IVSM
Output from example.py:
d2806ee0-xxxx-xxxx-xxxx-7440beb80834: Office AC (AC POT_056905_WW)
[master] $ python3 example.py ac-mon d2806ee0-xxxx-xxxx-xxxx-7440beb80834
off; COOL; cur 68°F; cfg 75°F; fan speed LOW
off; COOL; cur 68°F; cfg 75°F; fan speed LOW
off; COOL; cur 68°F; cfg 75°F; fan speed LOW
off; COOL; cur 68°F; cfg 75°F; fan speed LOW
[master !] $ python3 example.py ac-config d2806ee0-xxxx-xxxx-xxxx-7440beb80834
************DEBUG DUMP DATA *********
b'{"UseTime":"0","ChangePeriod":"720","ChangeDate":"00000000"}'
************DEBUG DUMP DATA END *********
{'UseTime': '0', 'ChangePeriod': '720', 'ChangeDate': '00000000'}
************DEBUG DUMP DATA *********
b'{"RemainTime":"98","ChangePeriod":"250"}'
************DEBUG DUMP DATA END *********
{'RemainTime': '98', 'ChangePeriod': '250'}
************DEBUG DUMP DATA *********
b'{"Day":"0","Week":"0","Month":"0"}'
************DEBUG DUMP DATA END *********
{'Day': '0', 'Week': '0', 'Month': '0'}
************DEBUG DUMP DATA *********
b'{"InOutInstantPower":"50"}'
************DEBUG DUMP DATA END *********
50 watts
************DEBUG DUMP DATA *********
b'{"OutTotalInstantPower":"0"}'
************DEBUG DUMP DATA END *********
0 watts
0
True
************DEBUG DUMP DATA *********
b'{[{"No":"1","Cfg":"1","State":"0"},{"No":"2","Cfg":"0","State":"0"},{"No":"3","Cfg":"0","State":"0"},{"No":"4","Cfg":"0","State":"0"},{"No":"5","Cfg":"0","State":"0"},{"No":"6","Cfg":"0","State":"0"},{"No":"7","Cfg":"0","State":"0"},{"No":"8","Cfg":"0","State":"0"}]}'
************DEBUG DUMP DATA END *********
Traceback (most recent call last):
File "example.py", line 269, in <module>
main()
File "example.py", line 265, in main
example(args.country, args.language, args.verbose, args.cmd, args.args)
File "example.py", line 206, in example
example_command(client, cmd, args)
File "example.py", line 175, in example_command
func(client, *args)
File "example.py", line 156, in ac_config
print(ac.get_zones())
File "/mnt/e/Development/github/wideq/wideq/ac.py", line 198, in get_zones
return self._get_config('DuctZone')
File "/mnt/e/Development/github/wideq/wideq/client.py", line 440, in _get_config
return json.loads(base64.b64decode(data).decode('utf8'))
File "/usr/lib/python3.6/json/__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.6/json/decoder.py", line 355, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
[master] $ python3 example.py turn d2806ee0-xxxx-xxxx-xxxx-7440beb80834 on
Traceback (most recent call last):
File "example.py", line 269, in <module>
main()
File "example.py", line 265, in main
example(args.country, args.language, args.verbose, args.cmd, args.args)
File "example.py", line 206, in example
example_command(client, cmd, args)
File "example.py", line 175, in example_command
func(client, *args)
File "example.py", line 144, in turn
ac.set_on(on_off == 'on')
File "/mnt/e/Development/github/wideq/wideq/ac.py", line 233, in set_on
op_value = self.model.enum_value('Operation', op.value)
File "/mnt/e/Development/github/wideq/wideq/client.py", line 345, in enum_value
return options_inv[name]
KeyError: '@AC_MAIN_OPERATION_ALL_ON_W'
Hi,
I was considering adding type annotations (since they make refactoring a lot easier). Currently the tox file has Python 3.4 listed, which makes things a lot harder.
Considering home assistant is on Python 3.7 (I think?), I'd like to propose to bump the minimum Python version to 3.6 or 3.7.
Python 3.6 comes with f-strings, which in my opinion also makes things a lot easier, since it allows very readable string formatting.
Opinions appreciated :)
Hi!
I found solution https://github.com/wkd8176/wideq where @wkd8176 did great job and create pip package wideq-kr. And also I found a lot of forks where people has been changed language and country. I think we need create parameters for them.
I'd like to integrate my LG devices with HomeKit and I'd like to create package homebridge-wideq.
I'm building an automation tool in node.js for my home and wanted to integrate some LG devices into it. I was going to port this library to node.js, but wanted to see if anyone was already working on that before I started.
I use homebridge UI so i went into the UI and setup the country as CA and en-CA and put my refresh token in. I then reboot homebridge and it launches well.
Homebridge launches and this shows
[1/23/2020, 9:16:52 PM] [WideQ] Initializing WideQ platform...
[1/23/2020, 9:16:52 PM] [WideQ] **************************************************************
[1/23/2020, 9:16:52 PM] [WideQ] WideQ v0.0.5 by NorDroN
[1/23/2020, 9:16:52 PM] [WideQ] GitHub: https://github.com/NorDroN/homebridge-wideq
[1/23/2020, 9:16:52 PM] [WideQ] Email: [email protected]
[1/23/2020, 9:16:52 PM] [WideQ] **************************************************************
Apparently, the newest fork of wideQ has a new API but the home bridge node hasn't been updated. does anyone know how to update the Homebridge node? Here is a link to the home bridge git
I'm in Australia and my LG account is set to Australia.
I was trying to login with country set to AU, but no language specified. I got a token from LG successfully, but then an SSL protocol error when it tried to access the API.
Eventually I tried adding the country code en-AU, didn't even login again but used the same token URL, and then it worked. Is it possible to handle this condition better than pages of SSL errors?
$ python3 example.py -c US
Log in here:
https://us.m.lgaccount.com/login/sign_in?country=US&language=en-US&svcCode=SVC202&authSvr=oauth2&client_id=LGAO221A02&division=ha&grant_type=password
Then paste the URL where the browser is redirected:
https://us.m.lgaccount.com/member/iabClose?access_token=<>&refresh_token=<>&oauth2_backend_url=https://kr.lgeapi.com/
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py", line 453, in wrap_socket
cnx.do_handshake()
File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1915, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1647, in _raise_ssl_error
_raise_current_error()
File "/usr/lib/python3/dist-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'ssl_choose_client_version', 'unsupported protocol')]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 600, in urlopen
chunked=chunked)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 343, in _make_request
self._validate_conn(conn)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 841, in _validate_conn
conn.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 344, in connect
ssl_context=context)
File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 344, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py", line 459, in wrap_socket
raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'ssl_choose_client_version', 'unsupported protocol')])",)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "/usr/lib/python3/dist-packages/urllib3/util/retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='aic.lgthinq.com', port=46030): Max retries exceeded with url: /api/member/login (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl_choose_client_version', 'unsupported protocol')])")))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "example.py", line 225, in <module>
main()
File "example.py", line 221, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 181, in example
example_command(client, cmd, args)
File "example.py", line 157, in example_command
func(client, *args)
File "example.py", line 26, in ls
for device in client.devices:
File "/home/hamish/src/wideq/wideq/client.py", line 123, in devices
self._devices = self.session.get_devices()
File "/home/hamish/src/wideq/wideq/client.py", line 114, in session
self._session, self._devices = self.auth.start_session()
File "/home/hamish/src/wideq/wideq/core.py", line 273, in start_session
self.gateway.country, self.gateway.language)
File "/home/hamish/src/wideq/wideq/core.py", line 191, in login
return lgedm_post(url, data)
File "/home/hamish/src/wideq/wideq/core.py", line 120, in lgedm_post
res = requests.post(url, json={DATA_ROOT: data}, headers=headers)
File "/usr/lib/python3/dist-packages/requests/api.py", line 116, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/lib/python3/dist-packages/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='aic.lgthinq.com', port=46030): Max retries exceeded with url: /api/member/login (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl_choose_client_version', 'unsupported protocol')])")))
Hi. I'm not a programmer and I don't know how to write code, basically I do everything as they write it here. I need your help. I have an LG B09TS air conditioner, this air conditioner only works with the Video API 2 library.
"snapshot": {
"airState.wMode.lowHeating": 0.0,
"airState.quality.PM1": 0.0,
"airState.quality.PM2": 0.0,
"airState.reservation.sleepTime": 0.0,
"airState.filterMngStates.maxTime": 0.0,
"airState.reservation.targetTimeToStart": 0.0,
"airState.opMode": 2.0,
"airState.quality.sensorMon": 0.0,
"meta": {
"allDeviceInfoUpdate": false,
"messageId": ""
},
"airState.powerSave.basic": 0.0,
"online": true,
"airState.wDir.hStep": 3.0,
"timestamp": xxxxxxxxxxxxx.0,
"airState.energy.accumulated": 1.0,
"airState.tempState.target": 30.0,
"airState.quality.PM10": 0.0,
"airState.quality.overall": 0.0,
"airState.miscFuncState.antiBugs": 0.0,
"airState.miscFuncState.extraOp": 0.0,
"airState.wMode.airClean": 1.0,
"airState.windStrength": 2.0,
"static": {
"deviceType": "401",
"countryCode": "RU"
},
"airState.tempState.current": 22.5,
"airState.operation": 1.0,
"airState.miscFuncState.autoDry": 0.0,
"airState.filterMngStates.useTime": 0.0,
"airState.wMode.jet": 0.0,
"airState.energy.accumulatedTime": 302.0,
"airState.reservation.targetTimeToStop": 0.0,
"airState.lightingState.displayControl": 0.0,
"airState.diagCode": 0.0,
"airState.wDir.vStep": 6.0,
"airState.energy.onCurrent": 60.0
},
"online": true,
"platformType": "thinq2",
"area": xxxxxx,
"regDt": xxxxxxxxxxxxxx.0,
"blackboxYn": "Y",
"modelProtocol": "STANDARD",
"order": 1,
"drServiceYn": "N",
"fwInfoList": [
{
Traceback (most recent call last):
File "example.py", line 238, in
main()
File "example.py", line 234, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 194, in example
example_command(client, cmd, args)
File "example.py", line 170, in example_command
func(client, *args)
File "example.py", line 140, in turn
ac.set_on(on_off == 'on')
File "/home/xxxxxxxx/wideq/wideq/ac.py", line 233, in set_on
op_value = self.model.enum_value('Operation', op.value)
File "/home/xxxxxxxx/wideq/wideq/client.py", line 344, in enum_value
options = self.value(key).options
File "/home/xxxxxxxx/wideq/wideq/client.py", line 319, in value
d = self.data['Value'][name]
KeyError: 'Operation'
what am I doing wrong here?
You can schedule air conditioning control via Python, except for those specified on your home page https://github.com/sampsyo/wideq?
I use the majordomo smart home platform, this platform works with both PHP and Python. How do I output values received from the air conditioner in PHP and Python?
Hi,
When sending the on commands to the api endpoint, the ac is not turned on.
I've tried with the 3 on commands as following payload. Anything I'm missing?
data = {
'cmd': 'Control',
'cmdOpt': 'Set',
'value': {"Operation": "AC_MAIN_OPERATION_ALL_ON_W"},
'deviceId': device_id,
'workId': gen_uuid(),
'data': '',
}
--> turning it off works as expected and setting the temperature too.
KR
Alex
Hi,
I'm willing to add refrigerator support but I don't know how I can pull the actual property/command names from refrigerator.
Can you provide any advice on how you've done it with currently supported devices?
Hi,
I'm getting the following error when running example.py on my Pi4 with latest raspbian
OpenSSL.SSL.Error: [('SSL routines', 'tls_process_ske_dhe', 'dh key too small')]
Any ideas?
Thanks for your help!
Rob
https://aic.lgthinq.com:46030/api/rti/rtiControl {'cmd': 'Config', 'cmdOpt': 'Get', 'value': 'DuctZone', 'deviceId': 'd27c7740-7149-11d3-80b4-7440be9deeb2', 'workId': 'a3dcce9c-af3d-1024-a8a0-cfbb0c395bb3', 'data': ''} <Response [200]> {'returnCd': '0000', 'returnMsg': 'OK', 'deviceId': 'd27c7740-7149-11d3-80b4-7440be9deeb2', 'stateCode': 'S', 'workId': 'n-a3dcce9c-af3d-1024-a8a0-cfbb0c395b', 'returnData': 'e1t7Ik5vIjoiMSIsIkNmZyI6IjEiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiMiIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiMyIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiNCIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiNSIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiNiIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiNyIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifSx7Ik5vIjoiOCIsIkNmZyI6IjAiLCJTdGF0ZSI6IjAifV19', 'format': 'B64', 'deviceState': 'E', 'timestamp': 0}
Traceback (most recent call last):
File "example.py", line 230, in
main()
File "example.py", line 226, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 186, in example
example_command(client, cmd, args)
File "example.py", line 162, in example_command
func(client, *args)
File "example.py", line 147, in ac_config
print(ac.get_zones())
File "/Users/david/dev/unsorted/wideq/wideq/ac.py", line 196, in get_zones
return self._get_config('DuctZone')
File "/Users/david/dev/unsorted/wideq/wideq/client.py", line 440, in _get_config
return json.loads(base64.b64decode(data).decode('utf8'))
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/json/init.py", line 348, in loads
return _default_decoder.decode(s)
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
Hi,
I am trying to run example.py for the first time, I think the authentication was successful since I get a URL with tokens, however when I paste the URL back I get the following error:
Traceback (most recent call last):
File "example.py", line 225, in
main()
File "example.py", line 221, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 181, in example
example_command(client, cmd, args)
File "example.py", line 157, in example_command
func(client, *args)
File "example.py", line 26, in ls
for device in client.devices:
File "D:\Python37\apps\wideq-master\wideq\client.py", line 123, in devices
self._devices = self.session.get_devices()
File "D:\Python37\apps\wideq-master\wideq\client.py", line 114, in session
self._session, self._devices = self.auth.start_session()
File "D:\Python37\apps\wideq-master\wideq\core.py", line 275, in start_session
self.gateway.country, self.gateway.language)
File "D:\Python37\apps\wideq-master\wideq\core.py", line 193, in login
return lgedm_post(url, data)
File "D:\Python37\apps\wideq-master\wideq\core.py", line 133, in lgedm_post
raise APIError(code, message)
wideq.core.APIError: ('0010', '데이터가 존재하지 않습니다.')
any suggestions ?
thanks,
Got the following error when trying ac-config:
$ python3 example.py ac-config d27bdb00-7149-11d3-80b0-2c2bf923c76c
Session expired.
{'UseTime': '0', 'ChangePeriod': '720', 'ChangeDate': '00000000'}
{'RemainTime': '205', 'ChangePeriod': '250'}
{'Month': '0', 'Day': '0', 'Week': '0'}
Traceback (most recent call last):
File "example.py", line 203, in
main()
File "example.py", line 199, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 163, in example
example_command(client, cmd, args)
File "example.py", line 139, in example_command
func(client, *args)
File "example.py", line 122, in ac_config
print(ac.get_volume())
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 981, in get_volume
value = self._get_control('SpkVolume')
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 808, in _get_control
'Control',
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 398, in get_device_config
'data': '',
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 306, in post
return lgedm_post(url, data, self.auth.access_token, self.session_id)
File "/home/pi/Desktop/wideq-1.0.1/wideq.py", line 140, in lgedm_post
raise APIError(code, message)
wideq.APIError: ('0100', '실패')
What does "SpkVolume" have to do with an A/C? Just curious :-)
Hi I want to get device list lg thinq dryer over 14kg. but it does not.
My community says that wideq only works old devices which is 9kg dryer using LG Thinq.
Is there any way to use my 14kg dryer in HA?
Thanks
python3 example.py -c BR -l pt-BR ac-config d27c7740-7149-11d3-10b4-7440be9deeb2
{'UseTime': '74', 'ChangePeriod': '720', 'ChangeDate': '00000000'}
{'RemainTime': '0', 'ChangePeriod': '0'}
{'Day': '0', 'Week': '0', 'Month': '0'}
Traceback (most recent call last):
File "example.py", line 230, in
main()
File "example.py", line 226, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 186, in example
example_command(client, cmd, args)
File "example.py", line 162, in example_command
func(client, *args)
File "example.py", line 145, in ac_config
print(ac.get_volume())
File "/Users/david/dev/unsorted/wideq/wideq/ac.py", line 259, in get_volume
value = self._get_control('SpkVolume')
File "/Users/david/dev/unsorted/wideq/wideq/client.py", line 447, in _get_control
'Control',
File "/Users/david/dev/unsorted/wideq/wideq/core.py", line 397, in get_device_config
'data': '',
File "/Users/david/dev/unsorted/wideq/wideq/core.py", line 299, in post
return lgedm_post(url, data, self.auth.access_token, self.session_id)
File "/Users/david/dev/unsorted/wideq/wideq/core.py", line 133, in lgedm_post
raise APIError(code, message)
wideq.core.APIError: ('0100', '실패')
After installing the library and running python3 example.py, it is requested to log in the following url:
Once I log in the page I am redirected to the following url which displays "Page not found"
Had wideq working on a raspberry pi before. Removed it (messing around), then re-cloned the repository. Now when I attempt to run example.py, I get the following error:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py", line 417, in wrap_socket
cnx.do_handshake()
File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1426, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1167, in _raise_ssl_error
raise SysCallError(-1, "Unexpected EOF")
OpenSSL.SSL.SysCallError: (-1, 'Unexpected EOF')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 594, in urlopen
chunked=chunked)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 350, in _make_request
self._validate_conn(conn)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 837, in _validate_conn
conn.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 323, in connect
ssl_context=context)
File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 324, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py", line 424, in wrap_socket
raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 423, in send
timeout=timeout
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 624, in urlopen
raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "example.py", line 225, in <module>
main()
File "example.py", line 221, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 176, in example
client._auth = authenticate(client.gateway)
File "/home/pi/wideq/wideq.py", line 483, in gateway
self._gateway = Gateway.discover(self._country, self._language)
File "/home/pi/wideq/wideq.py", line 252, in discover
gw = gateway_info(country, language)
File "/home/pi/wideq/wideq.py", line 154, in gateway_info
{'countryCode': country, 'langCode': language},
File "/home/pi/wideq/wideq.py", line 127, in lgedm_post
res = requests.post(url, json={DATA_ROOT: data}, headers=headers)
File "/usr/lib/python3/dist-packages/requests/api.py", line 110, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/lib/python3/dist-packages/requests/api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 497, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
I was wondering if someone figured out if it is possible to add a redirect_uri to the authentication request? I am trying to get this to work for a Homey app and I can receive oauth2 callbacks. This would make the authentication process a lot more user friendly.
Hi,
can you tell me where to look in the code to add some rtiControl values to control airflow of the AC unit?
I have looked in charles proxy in the app requests and they are as follows:
"cmd": "Control",
"cmdOpt": "Set",
"value": (...)
left right swing:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "6", "WDirHStep": "100" },
left right blow left:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "6", "WDirHStep": "1" },
left right blow right:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "6", "WDirHStep": "5" },
up/ down swing:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "100", "WDirHStep": "5" },
up down blow up:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "1", "WDirHStep": "5" },
up down blow down:
"value": { "Jet": "0", "PowerSave": "0", "WDirVStep": "6", "WDirHStep": "5" },
energy saving:
value": { "Jet": "0", "PowerSave": "1", "WDirVStep": "1", "WDirHStep": "5" },
purification:
"value": { "AirClean": "1" },
Hi,
can I on some way check current power usage of my AC with wideq?
Thanks.
python3 example.py -c BR -l pt-BR ac-config XXXXX-XXX-XXXX...
Traceback (most recent call last):
File "example.py", line 252, in <module>
main()
File "example.py", line 248, in main
example(args.country, args.language, args.cmd, args.args)
File "example.py", line 196, in example
example_command(client, cmd, args)
File "example.py", line 172, in example_command
func(client, *args)
File "example.py", line 146, in ac_config
print(ac.get_filter_state())
File "/Users/david/dev/dacrypt/wideq/wideq/ac.py", line 239, in get_filter_state
return self._get_config('Filter')
File "/Users/david/dev/dacrypt/wideq/wideq/client.py", line 443, in _get_config
data = self.client.session.get_device_config(
File "/Users/david/dev/dacrypt/wideq/wideq/core.py", line 395, in get_device_config
res = self.post('rti/rtiControl', {
File "/Users/david/dev/dacrypt/wideq/wideq/core.py", line 303, in post
return lgedm_post(url, data, self.auth.access_token, self.session_id)
File "/Users/david/dev/dacrypt/wideq/wideq/core.py", line 144, in lgedm_post
raise APIError(code, message)
wideq.core.APIError: ('0011', '등록되지 않은 모델입니다.')
I'm guessing this error happens because LG doesn't allow 2 users to connect at the same time.
just wondering
Very nice add-on, have used it without any problems so far. So great job and thanks a lot for all your time spend on this.
I have just a small feature request, to have this add-on added to the HOME ASSISTANT COMMUNITY STORE (HACS). So that we can easily stay up-to-date with the latest version!
Do you think we can figure out a way to get it to work with this?
Thanks.
If this works my then next step would be to work on a Home Assistant Custom Component.
Good afternoon! I can not get information on my air conditioner
I am relatively new to python but would love to use your script
I did run the example.py through the python IDE by loading the file and executing the "Run" command from the IDE menu - It gave me the prompt through the python shell for the URL then it rendered what I believe is the key telling me this is a refrigerator signature...
all seems good but then I dont know what to do :)
any hint would be very appreciated -
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.