jabesq-org / pyatmo Goto Github PK
View Code? Open in Web Editor NEWSimple API to access Netatmo weather station data from any python script (for Netatmo information, see www.netatmo.com)
License: MIT License
Simple API to access Netatmo weather station data from any python script (for Netatmo information, see www.netatmo.com)
License: MIT License
Hi. I did a little probing today to see if it may be possible to add a workaround for the 169.254 IP Address issue referenced in #347. I lodged an issue with them earlier today about this too as I strongly believe this is a Netatmo device firmware to cloud API integration bug. However, I have experienced first hand the delays from Netatmo in the past.
I understand that the process today is now roughly:
My suggestion is instead of 4, let's:
We can now match the mDNS mac_address attribute to the /homestatus MAC address and substitute in the IP address from mDNS over the top of the http://169.254.x.x address. This will preserve the security key in the path of the URL and allow us to continue to connect to the device locally.
The Netatmo support library (pyatmo) logs errors every 5 minutes:
2021-05-21 07:49:21 ERROR (SyncWorker_2) [pyatmo.thermostat] Errors in response: {'status': 'ok', 'time_server': 1621576162}
This is not an issue or bug, but a request for some instructions (sorry).
Maybe add some simple, basic example for connecting to netatmo on the home network inside firewall.
Something that I don't understand is the significance of "client_id" and "client_secret" and also the "redirect URL". Can you maybe shed some light on this?:
import pyatmo
USERNAME = "netatmo username"
PASSWORD = "netatmo password"
REDIRECT_URL = What is this?
authorization = pyatmo.ClientAuth(
client_id=None,
client_secret=None,
username=USERNAME,
password=PASSWORD,
redirect_uri=REDIRECT_URL,
scope="read_station",
)
r = pyatmo.HomeData(authorization)
r.update()
r.process()
print(r.homes)
for home_id in r.homes.keys():
r = pyatmo.HomeStatus(authorization, home_id)
r.update()
r.process()
print(r.rooms)
Missing devicetype when requesting devices through Home Assistant Netatmo integration. Logs below. Also reported on the integration as Issue #93609
Happy to take a look myself, but would need some guidance on where to start since I don't even know what the device represents exactly.
Error setting up entry Home Assistant Cloud for netatmo
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/pyatmo/home.py", line 72, in get_module
return getattr(modules, module["type"])(
AttributeError: module 'pyatmo.modules' has no attribute 'BNCS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 387, in async_setup
result = await component.async_setup_entry(hass, self)
File "/usr/src/homeassistant/homeassistant/components/netatmo/__init__.py", line 164, in async_setup_entry
await data_handler.async_setup()
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 153, in async_setup
await self.subscribe(ACCOUNT, ACCOUNT, None)
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 244, in subscribe
await self.async_fetch_data(signal_name)
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 200, in async_fetch_data
await getattr(self.account, self.publisher[signal_name].method)(
File "/usr/local/lib/python3.10/site-packages/pyatmo/account.py", line 69, in async_update_topology
self.process_topology()
File "/usr/local/lib/python3.10/site-packages/pyatmo/account.py", line 58, in process_topology
self.homes[home_id] = Home(self.auth, raw_data=home)
File "/usr/local/lib/python3.10/site-packages/pyatmo/home.py", line 49, in __init__
self.modules = {
File "/usr/local/lib/python3.10/site-packages/pyatmo/home.py", line 50, in <dictcomp>
module["id"]: self.get_module(module)
File "/usr/local/lib/python3.10/site-packages/pyatmo/home.py", line 78, in get_module
return getattr(modules, "NLunknown")(
File "/usr/local/lib/python3.10/site-packages/pyatmo/modules/module.py", line 520, in __init__
self.device_type = DeviceType(module["type"])
File "/usr/local/lib/python3.10/enum.py", line 385, in __call__
return cls.__new__(cls, value)
File "/usr/local/lib/python3.10/enum.py", line 710, in __new__
raise ve_exc
ValueError: 'BNCS' is not a valid **DeviceType**
Muller-Intuitiv provides equipments that are label as 'by Netatmo'.
I'm reverse engineering their propiretary API, which is mostly compatbile with Netatmo, so I was thinking to use and modify pyatmo. My ultimate goal is to add support to home-assistant which uses this module
I think it might be good to add this support in your library as it might not be a lot of effort. To do so, I will need need some guidance to do it the right way (hint : I'm not a python developper)
Some hardcoded values have to be customized to work properly:
I have done a very ugly "patch" to test this approach:
helpers.py
_BASE_URL: str = "https://app.muller-intuitiv.net/"
oauth2_session.py : OAuth2Session::request
data['user_prefix'] = 'muller'
log.debug("Requesting url %s using method %s.", url, method)
log.debug("Supplying headers %s and data %s", headers, data)
log.debug("Passing through key word arguments %s.", kwargs)
return super(OAuth2Session, self).request(
method, url, headers=headers, data=data, **kwargs
)
Currently the followin llittle script works fine: I'm able to retreive all informations needed. I will then need to adapt / add some custom class for parsing their JSON, but I think this part can be easier for me.
authorization = pyatmo.ClientAuth(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
username=USERNAME,
password=PASSWORD,
scope="read_muller write_muller",
)
r = pyatmo.HomeData(authorization)
r.update()
r.process()
print(r.homes)
for home_id in r.homes.keys():
r = pyatmo.HomeStatus(authorization, home_id)
r.update()
r.process()
print(r.rooms)
The Dimmable Light BNLD is missing.
{
"id": "<id>",
"type": "BNLD",
"name": "<NAME>",
"setup_date": 0000000000,
"room_id": "<RoomId>",
"bridge": "<BridgeId>"
}
{
"id": "<id>",
"type": "BNLD",
"on": false,
"brightness": 0,
"firmware_revision": 1,
"reachable": true,
"bridge": "<BridgeId>"
}
Hello,
I don't know if this problem is linked to pyatmo or my raspberry pi configuration. But when I try to access my weather station data, if I'm running the script without sudo, I get them. If I use sudo, I get an empty table. I installed pyatmo with and without sudo: (sudo) pip3 install pyatmo
.
When I call this line print("\tWS-OBJ**** STATIONS " + str(self.weatherData.stations))
(weatherData
is a pyatmo.WeatherStationData
object), I get the result below:
# without sudo
pi@raspberrypi:~/GitHub/project $ python3 linkWeatherStation.py
WS-OBJ**** STATIONS {'ADDR': {'_id': 'ADDR', 'station_name': 'name', ...}}
# with sudo
pi@raspberrypi:~/GitHub/project $ sudo python3 linkWeatherStation.py
WS-OBJ**** STATIONS defaultdict(<class 'dict'>, {})
Is there a reason the station is not responding in sudo mode?
Thanks in advance
I'd like to edit the schedule data, but I'm missing the SyncSchedule method in the library. Do you plan to implement it?
From my point of view, just JSON/YAML in the format the netatmo API accepts is flexible enough.
Hello,
This not really an issue but more an enhancement. I would like to know if it should be possible to have information from smart door and window sensors. Indeed I manage to obtain some informations from webhook but it should be great if we could obtain also status of these sensors.
This information is present from the api but I do not know if you could had this in pyatmo in order to obtain information in Home Assistant also. What I understand is that we can obtain many information via API, including the open/close state via a call to /homestatus method. JSON will look like the following :
{
"id": "70:ee:XXXXXX",
"type": "NACamDoorTag",
"name": "Door",
"battery_percent": 98,
"rf": 31,
"status": "open", <= this is the open/close state
"category": "door"
}
but is it possible to have informations from pyatmo and then integrate in Home Assistant ?
I have a Smarther thermostat (Smarther2 in Italy).
the following code works properly
homeData = pyatmo.HomeData(authorization)
homeData.update()
print(homeData.raw_data)
only differently from the website doesn't show all the info about the house but it stop at rooms details.
when i run the following code, with home_id set accordingly to previous response
homeStatus = pyatmo.HomeStatus(authorization, home_id="xxxxxxxxxxx")
homeStatus.update()
print(homeStatus.raw_data)
I get :
Traceback (most recent call last):
File "C:\Users\Francesco\Desktop\Temp\test.py", line 21, in
homeStatus.update()
File "C:\Users\Francesco\anaconda3\lib\site-packages\pyatmo\thermostat.py", line 264, in update
self.raw_data = extract_raw_data(resp.json(), "home")
File "C:\Users\Francesco\anaconda3\lib\site-packages\pyatmo\helpers.py", line 57, in extract_raw_data
raise NoDevice("No device found, errors in response")
pyatmo.exceptions.NoDevice: No device found, errors in response
while on netatmo API tryout all the information including the thermostat are properly shown.
Any hint ?
Hi,
Thanks for your work, i don't know if it's already implelented but, it's possible to add more scopes (https://dev.netatmo.com/apidocumentation/control#scopes) from Home + Control ?
Thanks in advance
please add support for open_window field, which is provided by api /homestatus and in room section
rooms:[
0:{
id:"1412979261"
reachable:true
anticipating:false
heating_power_request:0
open_window:false
therm_measured_temperature:22.5
therm_setpoint_temperature:12
therm_setpoint_start_time:1679635022
therm_setpoint_end_time:1679640422
therm_setpoint_mode:"manual"
}]
Hello,
I succeed to used Pyatmo to connect to my weather station using Client credentials grant type (with username and password). But now, I would like to connect using the Authorization code grant type, for more safety; and also because I'll need to connect to a station that is on another account.
I couldn't find any info in the usage.md
file, so I tried myself, but it doesn't seem to work. I have no error when I'm connecting, but when I'm trying to get data, I get an empty answer.
Here's what I did :
token = {
"scope":"read_station",
"access_token":"token"
}
auth2 = pyatmo.NetatmoOAuth2(
client_id=clientId,
client_secret=clientSecret,
token=token,
scope="read_station"
)
weatherData = pyatmo.WeatherStationData(auth2)
# then the access functions I'm using are the same in both method
Is it possible to use Pyatmo with the Authorization code grant type, if yes, what I'm missing?
PS: I'm getting the access token by calling the "https://api.netatmo.com/oauth2/authorize"
URL.
Thanks in advance,
Siméon
Hello!
Bticino and Legrand are discontinuing API support for Bticino MyHome Server 1 API and management of such modules has been migrated to the Netatmo API.
In order to get MyHome Server 1 modules from Netatmo, the following scopes should be added to the authentication request:
Except for those scopes, I think MyHome Server 1 modules should work exactly like all the other Netatmo modules!
Thanks!
Hey
do we somewhere have a "working" piece of code for this repository - so what are the 5 lines of code that we need to use the library?
e.g. how to I use async_update_weather_stations?
In my current code I had been using
authorization = pyatmo.NetatmoOAuth2(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
# scope="read_station",
)
authorization.extra["refresh_token"]="xxx"
authorization.refresh_tokens()
# 2 : Get devices list
weatherData = pyatmo.WeatherStationData(authorization)
but somehow pyatmo.WeatherStationData
does not show any stations anymore...
What's the adviced implementation way right now? Do I need to switch to async_update_weather_stations
?
Hi! I was trying to debug why my BTicino Smart Load Shedder wasn't showing up as an entity in Home Assistant and I think it's because of a missing mapping for that device (NLPS) in DEVICE_CATEGORY_MAP here:
https://github.com/jabesq/pyatmo/blob/75c1ef7a6ad170f203ab16a0c23eb639fb5e1408/src/pyatmo/modules/device_types.py#L122
I presume the missing entry should look something like:
DeviceType.NLPS: DeviceCategory.meter
but I'm not 100% sure whether it was just forgotten or if there were explicit reasons for not including that device in that map at the time, so it would be cool if someone could confirm if it's fine to just add the entry.
I'm not a Python developer so I wouldn't be very comfortable opening a PR myself (I would probably get stuck setting up the dev environment for running tests), but I can try if someone is willing to give me some direction.
Thanks!
The problem
Just received this email:
Home + Control API on Works with Legrand will be deprecated in the next 2 years and replaced by Home + Control API on Netatmo Connect.
The goal is to provide a unified API including more solutions and to support new devices like modules for Electrical Panel "... with Netatmo"
We advise you to migrate as soon as possible on this new API to still benefit from a continuity of service
@jabesq , are you plan for this?
Can we get a release of this package so we get the latest aiohttp pinning into Home Assistant?
Currently, this package (on the latest release) conflict with the aiohttp version used by Home Assistant. Releasing a newer version would solve that.
It is not a problem, but would it be possible to read the current temperature from the history of netatmo instead of the state of the room?
the idea is to get a precision of 0.1 instead of 0.5.
The docker file for the dev container includes copying Pipfile.lock, but this is excluded from the gitignore with a comment.
I tried removing it from the copy command but building the container is still failing.
9.768 Traceback (most recent call last):
9.768 File "/usr/local/py-utils/bin/pipenv", line 8, in <module>
9.768 sys.exit(cli())
9.768 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 1130, in __call__
9.769 return self.main(*args, **kwargs)
9.769 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/cli/options.py", line 58, in main
9.769 return super().main(*args, **kwargs, windows_expand_args=False)
9.769 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 1055, in main
9.770 rv = self.invoke(ctx)
9.770 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 1657, in invoke
9.770 return _process_result(sub_ctx.command.invoke(sub_ctx))
9.770 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 1404, in invoke
9.771 return ctx.invoke(self.callback, **ctx.params)
9.771 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 760, in invoke
9.771 return __callback(*args, **kwargs)
9.771 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/decorators.py", line 84, in new_func
9.778 return ctx.invoke(f, obj, *args, **kwargs)
9.778 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/vendor/click/core.py", line 760, in invoke
9.778 return __callback(*args, **kwargs)
9.778 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/cli/command.py", line 783, in requirements
9.778 lockfile = state.project.load_lockfile(expand_env_vars=False)
9.778 File "/usr/local/py-utils/venvs/pipenv/lib/python3.10/site-packages/pipe
nv/project.py", line 1044, in load_lockfile
9.782 with io.open(self.lockfile_location, encoding="utf-8") as lock:
9.782 FileNotFoundError: [Errno 2] No such file or directory: '/workspaces/Pipfi
le.lock'
------
Dockerfile-with-features:14
--------------------
13 | # Create Python requirements files from pipenv (lockfile)
14 | >>> RUN pip3 install -U pip \
15 | >>> && pip3 install pipenv \
16 | >>> && pipenv requirements > /tmp/requirements.txt \
17 | >>> && pipenv requirements --dev > /tmp/requirements_dev.txt
18 |
--------------------
ERROR: failed to solve: process "/bin/bash -o pipefail -c pip3 install -U pip
&& pip3 install pipenv && pipenv requirements > /tmp/requirements.txt
&& pipenv requirements --dev > /tmp/requirements_dev.txt" did not complete succe
ssfully: exit code: 1
When "therm_setpoint_mode": "manual"
or max
, there is usually an end time specified (3 hours by default). Can this be exposed by the Room
class?
If the devcontainer is fixed (#466), I would be happy to try add this feature myself.
Hello,
it's the first time that I use this plugin.
And I thinks that Device Type.NIS: Device Category.siren is missing in DEVICE_CATEGORY_MAP
Please, could you confirm ?
Thanks
I find my NLD - Double Gangs On-Off Remote Switch module in the JSON file loaded by pyatmo. However, it does not appear in the list of devices for the Netatmo integration in Home Assistant.
{
"id": "00:04:74:00:00:8a:b2:75",
"type": "NLD",
"name": "**REDACTED**",
"setup_date": 1684916606,
"room_id": "521888878",
"bridge": "00:04:74:22:29:ca"
},
{
"id": "00:04:74:00:00:8a:b2:75#1",
"type": "NLD",
"setup_date": 1684916606,
"bridge": "00:04:74:22:29:ca"
},
{
"id": "00:04:74:00:00:8a:b2:75#2",
"type": "NLD",
"setup_date": 1684916606,
"bridge": "00:04:74:22:29:ca"
}
What must be done to see it appear?
Regards
Hey
It looks like the /oauth2/token API was finally deprecated...and because of that the things described in usage.md dont work anymore
see marker here:
https://dev.netatmo.com/apidocumentation/oauth#client-credential
error message:
DEBUG:requests_oauthlib.oauth2_session:Encoding `client_id` "5ef5c45497729b1a4d7fe0c3" with `client_secret` as Basic auth credentials.
DEBUG:requests_oauthlib.oauth2_session:Requesting url https://api.netatmo.com/oauth2/token using method POST.
DEBUG:requests_oauthlib.oauth2_session:Supplying headers {'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'} and data {'grant_type': 'password', 'username': 'user, 'password': 'password', 'scope': 'read_station'}
DEBUG:requests_oauthlib.oauth2_session:Passing through key word arguments {'timeout': None, 'auth': <requests.auth.HTTPBasicAuth object at 0xb59efa50>, 'verify': True, 'proxies': None}.
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.netatmo.com:443
DEBUG:urllib3.connectionpool:https://api.netatmo.com:443 "POST /oauth2/token HTTP/1.1" 400 None
DEBUG:requests_oauthlib.oauth2_session:Request to fetch token completed with status 400.
DEBUG:requests_oauthlib.oauth2_session:Request url was https://api.netatmo.com/oauth2/token
DEBUG:requests_oauthlib.oauth2_session:Request headers were {'User-Agent': 'python-requests/2.21.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Content-Length': '96', 'Authorization': 'Basic NWVmNWM0NTQ5NzcyOWIxYTRkN2ZlMGMzOjJIb2ZDdEx5RGtSQ1VXTG52eGxCYWVod2ZtdVJGWXgwR29VQ1A2aDdVQg=='}
DEBUG:requests_oauthlib.oauth2_session:Request body was grant_type=password&username=user&password=password&scope=read_station
DEBUG:requests_oauthlib.oauth2_session:Response headers were {'Server': 'nginx', 'Date': 'Thu, 13 Jul 2023 08:34:44 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Expires': '0', 'Cache-Control': 'no-cache, must-revalidate', 'X-XSS-Protection': '1; mode=block', 'Access-Control-Allow-Origin': '*', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'X-Powered-By': 'Netatmo'} and content {"error":"unauthorized_client"}.
DEBUG:requests_oauthlib.oauth2_session:Invoking 0 token response hooks.
Traceback (most recent call last):
File "lockatmo6.py", line 38, in <module>
scope="read_station",
File "/home/pi/.local/lib/python3.7/site-packages/pyatmo/auth.py", line 266, in __init__
scope=scope,
File "/home/pi/.local/lib/python3.7/site-packages/requests_oauthlib/oauth2_session.py", line 360, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 421, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 431, in parse_token_response
validate_token_parameters(params)
File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 438, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/home/pi/.local/lib/python3.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 405, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.UnauthorizedClientError: (unauthorized_client) ```
It seems that my Wireless 4 scenes switch (bought as Legrand 756368) is reported as "NLDP" which seems to break the Netatmo Home Assistant integration. I've opened a relevant bug here: home-assistant/core#91755
The issue actually comes from this library, which doesn't include NLDP as a DeviceType.
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/pyatmo/home.py", line 72, in get_module
return getattr(modules, module["type"])(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pyatmo.modules' has no attribute 'NLDP'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 387, in async_setup
result = await component.async_setup_entry(hass, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/netatmo/__init__.py", line 185, in async_setup_entry
await data_handler.async_setup()
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 153, in async_setup
await self.subscribe(ACCOUNT, ACCOUNT, None)
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 244, in subscribe
await self.async_fetch_data(signal_name)
File "/usr/src/homeassistant/homeassistant/components/netatmo/data_handler.py", line 200, in async_fetch_data
await getattr(self.account, self.publisher[signal_name].method)(
File "/usr/local/lib/python3.11/site-packages/pyatmo/account.py", line 69, in async_update_topology
self.process_topology()
File "/usr/local/lib/python3.11/site-packages/pyatmo/account.py", line 58, in process_topology
self.homes[home_id] = Home(self.auth, raw_data=home)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyatmo/home.py", line 49, in __init__
self.modules = {
^
File "/usr/local/lib/python3.11/site-packages/pyatmo/home.py", line 50, in <dictcomp>
module["id"]: self.get_module(module)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyatmo/home.py", line 78, in get_module
return getattr(modules, "NLunknown")(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyatmo/modules/module.py", line 520, in __init__
self.device_type = DeviceType(module["type"])
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/enum.py", line 712, in __call__
return cls.__new__(cls, value)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/enum.py", line 1128, in __new__
raise ve_exc
ValueError: 'NLDP' is not a valid DeviceType
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.