ardevd / jlrpy Goto Github PK
View Code? Open in Web Editor NEWPython library for interacting with the JLR Remote Car API
License: MIT License
Python library for interacting with the JLR Remote Car API
License: MIT License
Traceback (most recent call last):
File "./test.py", line 3, in
import jlrpy
File "/Users/macmini/Library/Python/2.7/lib/python/site-packages/jlrpy.py", line 5, in
from urllib.request import Request, build_opener
ImportError: No module named request
First of all, thank you for this great library!
I'm struggling understanding the concept of refresh tokens.
Could you shed some light on the subject, please?
I am using jlrpy indirectly via the homeassistant-jlrincontrol
HomeAssistant integration. Has been working fine since I installed it, however, after rebooting HomeAssistant, I now get the following error raised from within jlrpy.
Any ideas what could be causing it? I have tried connecting using jlrpy directly with the exact same call signature to jlrpy.Connection() and I cannot reproduce the issue.
homeassistant-jlrincontrol
calls it like this:
partial(jlrpy.Connection, self.email, self.password, '' , '', self.use_china_servers)
Also, are there any plans to add in exception handling for failures in auth, device registration and user log in?
Logger: custom_components.jlrincontrol
Source: custom_components/jlrincontrol/__init__.py:396
integration: Jaguar Landrover InControl ([documentation](https://github.com/msp1974/homeassistant-jlrincontrol/blob/master/README.md))
First occurred: 20:50:03 (1 occurrences)
Last logged: 20:50:03
'NoneType' object is not subscriptable
Traceback (most recent call last):
File "/config/custom_components/jlrincontrol/__init__.py", line 396, in async_connect
self.connection = await self.hass.async_add_executor_job(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/jlrpy.py", line 80, in __init__
self.connect()
File "/usr/local/lib/python3.12/site-packages/jlrpy.py", line 125, in connect
self._register_device_and_log_in()
File "/usr/local/lib/python3.12/site-packages/jlrpy.py", line 130, in _register_device_and_log_in
self._login_user(self.head)
File "/usr/local/lib/python3.12/site-packages/jlrpy.py", line 188, in _login_user
self.user_id = user_data['userId']
~~~~~~~~~^^^^^^^^^^
TypeError: 'NoneType' object is not subscriptable
Just for information, the refresh token can be used to get a new token, without needing username/password after the initial login. You just need to keep it refreshed before you reach the expiry time.
`def refresh_token():
device_id = "alongdeviceid"
url = "https://jlp-ifas.wirelesscar.net/ifas/jlr/tokens"
payload = {
"grant_type": "refresh_token",
"refresh_token": "arefreshtoken",
}
headers = {
"Authorization": "Basic YXM6YXNwYXNz",
"Content-Type": "application/json",
"X-Device-Id": device_id,
}
res = requests.post(url, headers=headers, json=payload)
json_response = res.json()
print(json_response)`
When calling honk_blink()
on a Vehicle
object, a 401 error is returned.
The issue is that the API expects an auth token for the aptly named HBLF service to be passed along with the POST request associated with the honkblink command. Currently, we pass along the VHS auth token which is incorrect.
Hi Ardevd,
When you updated the get_status function in the jlrpy.py module recently for the change made by jag , it appears that change also managed to break the check_soc facility in the charge_offpeak.py file in the sample code library....
line 89: status = { d['key'] : d['value'] for d in v.get_status()['vehicleStatus'] }
now generates an error:
File "/home/pi/ipace/charge_offpeak.py", line 134, in
check_soc()
File "/home/pi/ipace/charge_offpeak.py", line 89, in check_soc
status = { d['key'] : d['value'] for d in v.get_status()['vehicleStatus'] }
File "/home/pi/ipace/charge_offpeak.py", line 89, in
status = { d['key'] : d['value'] for d in v.get_status()['vehicleStatus'] }
TypeError: string indices must be integers
If I replace line 227 (return result) with the following code :
coreStatusList = result['vehicleStatus']['coreStatus']
evStatusList = result['vehicleStatus']['evStatus']
result['vehicleStatus'] = coreStatusList + evStatusList
return result
<<
The original sample code now works.
You have written a nice method:
__open(self, url, headers=None, data=None)
which should be used inside the methods:
__authenticate(self, data=None)
__register_device(self, headers=None):
__login_user(self, headers=None):
get_vehicles(self, headers):
instead of duplicating the code.
When setting or deleting wakeup timers the server response is not returned to the caller.
Jaguar has changed the base URLs for the InControl Remote API. It now operates with https://if9.prod-row.jlrmotor.com
Have had to update some other parts of my scripts but generally everything has been working fine. Now login is throwing an error after authentication:
File "C:\Users\Study\AppData\Local\Programs\Python\Python312\Lib\site-packages\jlrpy.py", line 188, in _login_user
self.user_id = user_data['userId']
TypeError: 'NoneType' object is not subscriptable
Am I doing something wrong? Checked I had latest installed
\Users\Study>pip3 install jlrpy
Requirement already satisfied: jlrpy in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (1.6.0)
Requirement already satisfied: requests>=2.26.0 in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (from jlrpy) (2.31.0)
Requirement already satisfied: charset-normalizer<4,>=2 in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (from requests>=2.26.0->jlrpy) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (from requests>=2.26.0->jlrpy) (3.6)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (from requests>=2.26.0->jlrpy) (2.2.0)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\study\appdata\local\programs\python\python312\lib\site-packages (from requests>=2.26.0->jlrpy) (2024.2.2)
So... ....heeeeelp?
Hi There,
First great job on this API. It is super useful to be able to get this info from my car into openHab. Super useful and great work.
On trying it though, I notice that /geocode/reverse/ returns 400.
inControl obviously still has this feature as the app shows it, but I wonder has the API changed or is there an error in the documentation ?
Any pointers appreciated and thanks again.
Alan
Love the work you've done, any chance you would be able to add the ability to start an non I vehicle? for example f-pace?
Applications typically configure Python's logging to meet their own requirements, e.g. pushing logs to a log daemon, using a JSON format, etc. It's not useful that jlrpy reconfigures its logger on import, as that can undo application logging.
Hello. I am Angel from Seville Spain and I have a JAG E-PACE
I have not been able to test starting the engine because my car is manual and I think it would not work.
Until now I have used the library to entertain myself and make some easy applications (I am not an expert programmer).
But I have an application that connects my car with a Google Sheet where I keep all the data that I can get from the car.
A few days ago they stopped working but I updated to 1.6 and then to 1.7
Almost everything now works except the function user=c.get_user_info()
that provided me with information about the owner of the vehicle such as middleName lastName or emailAddress
Now it offers me a list with little data and errors.
Have you reported that error? it can be fixed?
Thank you so much.
Thnx for providing this lib, keep up the good work.
I'm trying to fetch all vehicles using the documenter, but running in to some errors. This is my request:
> GET /if9/jlr/users/<<My userID>>/vehicles?primaryOnly=true HTTP/1.1
> Host: if9.prod-row.jlrmotor.com
> User-Agent: insomnia/2021.2.2
> Content-Type: application/json
> X-Device-Id : <<My deviceID>>
> Authorization: Bearer <<My Bearer token>>
> Accept: */*
and this is the response:
< HTTP/1.1 400 Bad Request
< Date: Sat, 15 May 2021 14:57:57 GMT
< Content-Type: text/html;charset=utf-8
< Content-Length: 987
< Connection: keep-alive
< Age: 0
// body:
<html><head><title>JBoss Web/2.1.13.GA-patch-02 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 400 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect ().</u></p><HR size="1" noshade="noshade"><h3>JBoss Web/2.1.13.GA-patch-02</h3></body></html>
// body without html
< type: Status report
< message:
< description: The request sent by the client was syntactically incorrect ().
You have any advice?
Could you make a homebridge plugin with this, as i tried a plugin but it dosent remote start the car.
Hi, sorry to contact you directly, but I'm trying to use the JLR API which you posted at postman to get a connection via php in a smarthome tool (called Edomi).
First: as soon as it's working, is it ok for you to spread it in our KNX forum (https://knx-user-forum.de/) for free (I will mention the basis from postman there).
.... deleted because it works now. Didn't know the registering the device will lead to a failure of curl_exec on php -> I don't now where to search for 204, but it doesn't matter, works fine now.
Eivind gave me the hint to contact the developer of WattCat ;). I also tried your app, even I have bought an used F-Type. Your app is working well.
Nevertheless, I have issues with requesting tokens for RDL/RDU/HBLF:
HTTP Status 405 - Method Not Allowed
I cannot figure out what is wrong here :-( Any hint?
best regards
Winni
In device registration I get this error since about noon CEST today:
jlr.js:823 Uncaught TypeError: Cannot read properties of null (reading 'userId')
at jlr.js:823:31
at req.onreadystatechange (jlr.js:760:11)
and follow-up errors from my proxy. It was working as expected this morning.
Also, I noted the offical JLR app is now at version 1.8.1 - that one works as expected.
Edit: jlr.js is based on jlrpy 1.6.0, where it does also not connect anymore (no access to logs currently). WattCat is also not working anymore.
thx @ardevd , you did an excellent job providing this lib! I am running this on my brand new Jaguar I-Pace now.
As I want to know more about the charging behaviour and compare e.g. like this
Example Charging Curves the charging details about power, current, and SoC are required.
Up to now I could not find it. Did I miss something?
Hi again
When I call get_departure_timers()
, I am getting an HTTP error 404. This is on a 2022 I-Pace. Is this another of those header change issues or some other limitation of the I-Pace?
File "<string>", line 1, in <module>
File "/opt/scripts/jlr2mqtt/jlrpy.py", line 243, in get_departure_timers
return self.get("departuretimers", headers)
File "/opt/scripts/jlr2mqtt/jlrpy.py", line 639, in get
return self.connection.get(command, '%s/vehicles/%s' % (IF9_BASE_URL, self.vin), headers)
File "/opt/scripts/jlr2mqtt/jlrpy.py", line 71, in get
return self.post(command, url, headers, None)
File "/opt/scripts/jlr2mqtt/jlrpy.py", line 80, in post
return self.__open("%s/%s" % (url, command), headers=headers, data=data)
File "/opt/scripts/jlr2mqtt/jlrpy.py", line 102, in __open
resp = opener.open(req)
File "/usr/lib/python3.9/urllib/request.py", line 523, in open
response = meth(req, response)
File "/usr/lib/python3.9/urllib/request.py", line 632, in http_response
response = self.parent.error(
File "/usr/lib/python3.9/urllib/request.py", line 561, in error
return self._call_chain(*args)
File "/usr/lib/python3.9/urllib/request.py", line 494, in _call_chain
result = func(*args)
File "/usr/lib/python3.9/urllib/request.py", line 641, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 404: Not Found
Thanks
The only real problem is the first one but it wasn't too hard to figure out. The others are just observations/suggestions.
Problem
Login user and all remaining commands after the initial authorization sequence require the presence of the access token in the header: 'Authorization: Bearer {{access_token}}'. You do mention that the access token is needed in your "device registration" section, it is just missing in the curl examples and header descriptions. There was also no mention that the word "Bearer" (followed by a space) is required before the access token.
Suggestions
JLR has recently introduced a Guardian Mode feature. I want to add it support for it in jlrpy.
Since the recent "security updates" my remote engine start on jlrpy has stopped working, been working flawlessly for some time before that
I upgraded to 1.6.0 after the new security header was put in, but this hasn't fixed the issue
Weirdly... lock and unlock (with PIN of course) works completely fine as before, it's just engine start that has stopped working
This is the error I get:
{'timestamp': 1709970317076, 'status': 415, 'error': 'Unsupported Media Type', 'path': '/remoteengine/app/xxx/engineOn'}
(xxx = VIN)
Also worth mentioning that my car is a Jag, not an LR - I know the two apps are seperate so I wonder if there's something different with the calls made from the Jag version?
Also worth confirming - remote engine start still works fine in the app itself, just broken in jlrpy. Let me know if I can provide any more debug/testing info
Thanks for very nice lib for retrieving data from my I-Pace!
Just wondering if there are any data available about currently installed software version(s)?
get_trips()
should include the Accept
header with a value of application/vnd.ngtp.org.triplist-v2+json
in order to return the complete data set from the API.
Hello,
thx for the script.
do you think to control the charging power outside?
issue to follow recent photovoltaic power?
Thx, for your answer
when I'm using get_trips I get right now "only" the last 775 trips.
Within the app / web of InControl I see all trips - so I assume the data is still available. So I assume that it gets cut due to the data volume.
Does someone know how to add a time frame to the request so that I would be able to pull them in different junks. Would be a one-time request only to get the full history and from there I could start building it up by adding only the new trips.
Hello,
I'm unable to see my vehicle's fuel level and estimated mileage using the API. This information is available via the app however.
Am I not calling the right methods or is that information not being pulled?
Thanks
The vehicle will enter a sleep mode after four days of inactivity. In order to use remote control features after this time a wake up timer is required.
By adding a wake up timer for a specific time before the vehicle enters sleep mode you can ensure that the vehicle is available for remote control for a period of time after the specified wake up time.
If I was a customer from China mainland, seems I would use a separate jaguar InControl server (like https://incontrol.jaguar.com.cn/ and the server shall be host in China mainland per Chinese regulation).
From the InControl web UI, I could observe that the request for example to poll vehicle status like the following
https://incontrol.jaguar.com.cn/jaguar-portal-owner-web/ajax/pollvehiclestatus
And it would return the following json response
{
"currentVehicleStolen": false,
"vehicles": [{
"continueSetupLink": "vehicle/add/3/VINVINVINVINVIN/continue",
"nickname": "My Car Name",
"fullVin": "VINVINVINVINVIN",
"registrationNumber": "XXXXXXX",
"vehicleBrand": "Jaguar",
"vehicleType": "XE",
"stolenVehicleTrackingCentrePhone": "+441926926049",
"stolen": false,
"state": "CUSTOMER_REGISTERED",
"vehicleBrandType": "Jaguar XE"
}]
}
Is there any chance that it could support the China mainland server, I suppose the interface shall be the same but only differs from the URL end, while I cannot find the real server URL
Thanks
JLR have seemingly blocked third party access to it's APIs. Need to investigate exactly what they have done.
Hello Ardevd,
I enabled Privacy mode and cannot get it disabled?
What am i doing wrong?
Fantastic Python interface!
Cheers!
def privacy(self, command):
c = jlrpy.Connection(self.email, self.password)
v = c.vehicles[0]
mode = int(float(command.get('value')))
if mode == 1:
v.enable_privacy_mode(self.pin)
self.setDriver('GV23', 0)
time.sleep(5)
self.reportDrivers()
elif mode == 0:
v.disable_privacy_mode(self.pin)
self.setDriver('GV23', 1)
time.sleep(5)
self.reportDrivers()
else:
logging.error('Unknown command for Privacy Mode {}'.format(command))
When you call trips with python they all show up.
for i in v.get_trips()["trips"]:#[size-4:size-3]:
#print(i)
#print('/n')
#print(i['id'])
print(i['routeDetails'])
print(i['tripDetails']['startPosition']['address'])
print(i['tripDetails']['endPosition']['address'])
#print('\n')
#print(int(i['tripDetails']['startOdometer']*0.00062137))
#print(int(i['tripDetails']['endOdometer']*0.00062137))
#print('\n')
speed = int(i['tripDetails']['averageSpeed'])
speed = speed
print(speed)
Open the Land Rover Remote app and trips do stop at November 17, 2023.
I guess it still logs trips no matter what Privacy mode is in, seems to just stop app logins.
Enable seems to works for the Remote Phone App however i does not re-enable and start to log there again.
I guess nothing is private anymore.
Thank you for your time,
Steve
JLR has updated their API again, breaking third party apps in the process.
Hi.
I'm trying to get this working on my Ubuntu 16.04 which had Pyhton 2.7.
Installed Python3 (alongside 2.7) and get the following:
root@shs2:/home/omr# pip install jlrpy
Collecting jlrpy
Downloading https://files.pythonhosted.org/packages/4a/94/53cb6c95c0a39ec6345a09242cdcd98ff6003541132381aefaa35ca60af3/jlrpy-1.1.2.tar.gz
Collecting uuid (from jlrpy)
Downloading https://files.pythonhosted.org/packages/ce/63/f42f5aa951ebf2c8dac81f77a8edcc1c218640a2a35a03b9ff2d4aa64c3d/uuid-1.30.tar.gz
Collecting datetime (from jlrpy)
Downloading https://files.pythonhosted.org/packages/73/22/a5297f3a1f92468cc737f8ce7ba6e5f245fcfafeae810ba37bd1039ea01c/DateTime-4.3-py2.py3-none-any.whl (60kB)
100% |████████████████████████████████| 61kB 2.5MB/s
Requirement already satisfied (use --upgrade to upgrade): pytz in /usr/lib/python2.7/dist-packages (from datetime->jlrpy)
Collecting zope.interface (from datetime->jlrpy)
Downloading https://files.pythonhosted.org/packages/a2/a2/e68c37eb2ef9bf942e0ace19f4cf6fe3e7c650932fb587bfde3c608f7d77/zope.interface-4.6.0-cp27-cp27mu-manylinux1_x86_64.whl (164kB)
100% |████████████████████████████████| 174kB 3.7MB/s
Requirement already satisfied (use --upgrade to upgrade): setuptools in /usr/lib/python2.7/dist-packages (from zope.interface->datetime->jlrpy)
Building wheels for collected packages: jlrpy, uuid
Running setup.py bdist_wheel for jlrpy ... done
Stored in directory: /root/.cache/pip/wheels/4a/b8/49/75f40ab8d3046726ccf3213aa8948203562ed81fcd4ec85a0f
Running setup.py bdist_wheel for uuid ... done
Stored in directory: /root/.cache/pip/wheels/2a/80/9b/015026567c29fdffe31d91edbe7ba1b17728db79194fca1f21
Successfully built jlrpy uuid
Installing collected packages: uuid, zope.interface, datetime, jlrpy
Successfully installed datetime-4.3 jlrpy-1.1.2 uuid-1.30 zope.interface-4.6.0
You are using pip version 8.1.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
root@shs2:/home/omr#
All looks good, but when I try to import I get:
omr@shs2:~$ python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import jlrpy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'jlrpy'
>>>
Any hints to what I'm doing wrong?
Implement the API request for retrieving data on a specific trip. This request probably returns more information on a specific trip than what get_trips()
provides.
Implement the ability to start and stop climate.
Let's add the ability to specify the number of trips to retrieve from the API instead of using the hard coded value of 1000 as we do currently.
I have noticed that after some time the car (RR Velar) seems to go to sleep, and the status is not updated to the servers. I requests status using JLRPY and it will report doors as unlocked for example, when actually they are locked.
Upon opening the official JLR app, it says "updating" then the correct status is returned, and then if I check with JLRPY it is then also correct.
Im not sure if this is an ICE car specific thing, as perhaps the i-pace stays awake with it being electric.
Just wondered if you had any thoughts or have seen this yourself?
Hi
Is there any way to integrate this into home assistant.
Thanks
Harry
Currently, a request with expired authentication is sent despite new authentication being retrieved first due to the fact that the request headers are not updated.
Hi
Many thanks for this library!
I am using it to get data from an I-Pace. One issue I am experiencing is that the 12V battery voltage value (from get_status()
) returned by the API ordinarily seems to stay fixed and not change over time, regardless of how often I call get_status()
, e.g. it is fixed at 14.1V. Once the ignition is off, this value should drop to 12.8v, and then gradually decline further over time, but instead I am seeing the same 14.1V even after leaving the car parked overnight. I cannot seem to get an updated value regardless of how often I call get_status()
.
If I check in WattCat (on its Details page), I initially see the same value as reported by your library. However, if I then do a refresh on WattCat, the value reported in WattCat drops to the 12.8V (or some lower amount). Going back to get_status() with your library now also returns the same 12.8V as WattCat.
Is there any way to force a refresh using your library in the same way that WattCat seems to do?
first I would like to thanks for that library ! driving a landrover defender p400e plug-inn and this library is quite useful :)
I have a struggle around the trip information. I can see EV distance but all other EV related information are empty
{'trips': [{'id': xxxx, 'name': None, 'category': None, 'routeDetails': {'route': None, 'totalWaypoints': 2, 'boundingBox': {'minLongitude': 6.xxx, 'minLatitude': 51.xxx, 'maxLongitude': 6.xxx, 'maxLatitude': 51.xxx}}, 'tripDetails': {'electricalConsumption': None, 'electricalRegeneration': None, 'fuelConsumption': None, 'distance': 6900, 'startOdometer': 1257000, 'startTime': '2022-05-02T16:58:18+0000', 'startPosition': {'latitude': 51.xxx, 'longitude': 6.xx, 'address': 'xxx, Deutschland', 'postalCode': 'xxxx', 'city': 'xxxx', 'region': 'Nordrhein-Westfalen', 'country': 'Deutschland'}, 'endOdometer': 1264000, 'endTime': '2022-05-02T17:11:13+0000', 'endPosition': {'latitude': 51.xxx, 'longitude': 6.xxx, 'address': 'xxx', 'postalCode': 'xxx', 'city': 'xxx', 'region': 'Nordrhein-Westfalen', 'country': 'Deutschland'}, 'totalEcoScore': {'score': 96.0, 'scoreStatus': 'VALID'}, 'throttleEcoScore': {'score': 4.8, 'scoreStatus': 'VALID'}, 'speedEcoScore': {'score': 4.9, 'scoreStatus': 'VALID'}, 'brakeEcoScore': {'score': 5.0, 'scoreStatus': 'VALID'}, 'averageSpeed': 34.0, 'averageFuelConsumption': 0.0, 'averageEnergyConsumption': 0.0, 'energyRegenerated': 0.0, 'averagePHEVFuelConsumption': 0.0, 'evDistance': 6900.0}}]}
Assume as they are all 0 - there is no way to get that information?
like electricalConsumption , electricalRegeneration , fuelConsumption , averageFuelConsumption , averageEnergyConsumption , energyRegenerated , averagePHEVFuelConsumption
Or I'm doing something wrong?
Thanks
Both get guardian mode user settings and get guardian mode system settings have the same URL.
The get guardian mode system settings path should be /gm/settings/system
.
Thanks for all the hard work that went into creating the collection 👍
Is this working currently?
The other features such as lock unlock horn blink etc work however when attempting to start climate, an error shows.
Spits a load of error lines out and then ends with HTTP Error 403: Forbidden
I noticed I have to put the pin number in to do the other features but don't require it for climate. I know that it authenticates differently for climate but when using the app it does require the pin for climate as well so could this be the issue?
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.