chargealong 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chargealong-0.1.0/.github/workflows/ci.yml +21 -0
- chargealong-0.1.0/.github/workflows/release.yml +25 -0
- chargealong-0.1.0/.gitignore +6 -0
- chargealong-0.1.0/CHANGELOG.md +15 -0
- chargealong-0.1.0/LICENSE +21 -0
- chargealong-0.1.0/PKG-INFO +215 -0
- chargealong-0.1.0/README.md +168 -0
- chargealong-0.1.0/pyproject.toml +51 -0
- chargealong-0.1.0/src/chargealong/__init__.py +66 -0
- chargealong-0.1.0/src/chargealong/_client.py +502 -0
- chargealong-0.1.0/src/chargealong/_errors.py +71 -0
- chargealong-0.1.0/src/chargealong/_models.py +750 -0
- chargealong-0.1.0/src/chargealong/py.typed +0 -0
- chargealong-0.1.0/tests/fixtures/bad_nearby.json +6 -0
- chargealong-0.1.0/tests/fixtures/countries.json +35 -0
- chargealong-0.1.0/tests/fixtures/country.json +47 -0
- chargealong-0.1.0/tests/fixtures/locality.json +112 -0
- chargealong-0.1.0/tests/fixtures/nearby.json +55 -0
- chargealong-0.1.0/tests/fixtures/network.json +87 -0
- chargealong-0.1.0/tests/fixtures/networks.json +31 -0
- chargealong-0.1.0/tests/fixtures/not_found.json +5 -0
- chargealong-0.1.0/tests/fixtures/overview.json +52 -0
- chargealong-0.1.0/tests/fixtures/redirect.json +8 -0
- chargealong-0.1.0/tests/fixtures/region.json +37 -0
- chargealong-0.1.0/tests/fixtures/search.json +64 -0
- chargealong-0.1.0/tests/fixtures/site.json +147 -0
- chargealong-0.1.0/tests/fixtures/trip.json +72 -0
- chargealong-0.1.0/tests/fixtures/trip_gap.json +28 -0
- chargealong-0.1.0/tests/fixtures/vehicle.json +59 -0
- chargealong-0.1.0/tests/fixtures/vehicles.json +85 -0
- chargealong-0.1.0/tests/test_client.py +483 -0
- chargealong-0.1.0/tests/test_security.py +235 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python }}
|
|
19
|
+
# No install step: the library has no dependencies and the suite runs on
|
|
20
|
+
# stdlib unittest, so this is the real "does it work from scratch".
|
|
21
|
+
- run: PYTHONPATH=src python -m unittest discover -s tests -v
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
# Trusted publishing: PyPI verifies this workflow's identity, so there is no
|
|
8
|
+
# long lived API token in the repository to leak. Configure the publisher at
|
|
9
|
+
# pypi.org/manage/project/chargealong/settings/publishing/ before the first tag.
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
publish:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment: pypi
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
- run: PYTHONPATH=src python -m unittest discover -s tests
|
|
24
|
+
- run: pip install build && python -m build
|
|
25
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
- `nearby`, `site`, `search`, `plan_trip`, `vehicles`, `vehicle`, `countries`,
|
|
8
|
+
`overview`, `country`, `region`, `networks`, `network`, `locality` and
|
|
9
|
+
`redirect`, covering the free read only surface of api.chargealong.io.
|
|
10
|
+
- Every row that carries a `path` has a `url` for its page on chargealong.io.
|
|
11
|
+
- `NotFound` for an id that never existed; a retired charger answers with
|
|
12
|
+
`status` of `"removed"`. `NoRoute` tells a trip with no road from a parameter to fix.
|
|
13
|
+
- Every parameter is checked against the service's own bounds before a
|
|
14
|
+
request is spent on it.
|
|
15
|
+
- No dependencies.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ChargeAlong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: chargealong
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Find EV chargers near a point, plan a road trip through charging stops, and look up electric car charging speeds. Free and keyless.
|
|
5
|
+
Project-URL: Homepage, https://chargealong.io
|
|
6
|
+
Project-URL: Documentation, https://chargealong.io/docs/
|
|
7
|
+
Project-URL: Source, https://github.com/chargealong/chargealong-python
|
|
8
|
+
Project-URL: Changelog, https://github.com/chargealong/chargealong-python/blob/main/CHANGELOG.md
|
|
9
|
+
Author: ChargeAlong
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 ChargeAlong
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: australia,charging network,charging station locator,electric car charging,electric vehicle,ev charger api,ev charging stations,ev trip planner,new zealand,open charge map
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
43
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
44
|
+
Classifier: Typing :: Typed
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# chargealong
|
|
49
|
+
|
|
50
|
+
**Public EV chargers, road trips through charging stops, and how fast electric
|
|
51
|
+
cars charge, as an API.** Find the chargers nearest a point, plan Melbourne to
|
|
52
|
+
Sydney with the stops and the minutes at each, or look up a car's charging
|
|
53
|
+
curve.
|
|
54
|
+
|
|
55
|
+
- Free and keyless. No account, nothing to configure
|
|
56
|
+
- No dependencies: the standard library only
|
|
57
|
+
- Typed dataclasses with the field names the API sends, so the docs and your
|
|
58
|
+
editor agree
|
|
59
|
+
- Every parameter checked against the service's own limits before a request is
|
|
60
|
+
spent on it
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
pip install chargealong
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from chargealong import ChargeAlong
|
|
70
|
+
|
|
71
|
+
ca = ChargeAlong()
|
|
72
|
+
|
|
73
|
+
near = ca.nearby(-37.7404, 144.9633, min_kw=50, limit=5)
|
|
74
|
+
for site in near.sites:
|
|
75
|
+
print(site.name, site.network_name, site.max_kw, "kW", site.distance_m, "m")
|
|
76
|
+
print(site.url)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Nearest first, within 50 km unless you pass `radius_km` (up to 150), at most
|
|
80
|
+
30 sites unless you pass `limit` (up to 50). `near.near` is the closest named
|
|
81
|
+
place, for a heading.
|
|
82
|
+
|
|
83
|
+
Only `status == "active"` sites are worth sending a driver to.
|
|
84
|
+
|
|
85
|
+
### Filters
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
ca.nearby(lat, lng,
|
|
89
|
+
min_kw=100, # a stop, not a top up
|
|
90
|
+
connector=["ccs2", "chademo"], # any of these
|
|
91
|
+
network="evie-networks")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`CONNECTORS` lists the standards: `ccs2`, `chademo`, `type-2`, `nacs`,
|
|
95
|
+
`ccs1`, `type-1`, `gbt`.
|
|
96
|
+
|
|
97
|
+
## Plan a trip
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
plan = ca.plan_trip((-37.8136, 144.9631), (-33.8688, 151.2093), range_km=400)
|
|
101
|
+
|
|
102
|
+
print(plan.route.distance_km, "km,", plan.total_min, "minutes in all")
|
|
103
|
+
for stop in plan.stops:
|
|
104
|
+
print(f"{stop.site.name}: arrive {stop.arrive_pct}%, "
|
|
105
|
+
f"charge {stop.charge_min} min to {stop.depart_pct}%")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`range_km` is how far the car really goes on a full battery. The rest is
|
|
109
|
+
optional: `reserve` (never arrive below, default 20%), `start` (default 100%),
|
|
110
|
+
`charge_to` (default 80%), `battery_kwh`, `max_dc_kw`, `max_ac_kw`, `min_kw`
|
|
111
|
+
(ignore slower chargers, default 50) and `connectors` (default `ccs2` and
|
|
112
|
+
`type-2`).
|
|
113
|
+
|
|
114
|
+
`plan.feasible` false is an answer, not an error: the car cannot make it
|
|
115
|
+
without dropping below the reserve, and `plan.gap` says where, in km from the
|
|
116
|
+
start. No road between the points raises `NoRoute`: Sydney to Auckland, say.
|
|
117
|
+
Trips are planned in Australia and New Zealand.
|
|
118
|
+
|
|
119
|
+
`plan.route.line` is the road as `(longitude, latitude)` pairs, ready for a
|
|
120
|
+
GeoJSON LineString.
|
|
121
|
+
|
|
122
|
+
## Electric cars
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
for car in ca.vehicles("model 3", limit=5):
|
|
126
|
+
print(car.brand, car.model, car.range_km, "km", car.dc_kw, "kW DC")
|
|
127
|
+
|
|
128
|
+
car = ca.vehicle("tesla-model-3")
|
|
129
|
+
for t in car.charging:
|
|
130
|
+
print(f"10 to 80% on {t.charger_kw} kW: {t.minutes_10_80} min")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## One charging site
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
detail = ca.site("hwqb4abf")
|
|
137
|
+
|
|
138
|
+
print(detail.site.name, detail.site.cost.text)
|
|
139
|
+
for c in detail.connectors:
|
|
140
|
+
print(c.label, c.power_kw, "kW x", c.quantity)
|
|
141
|
+
print(detail.reviews.summary.count, "reviews, last worked", detail.reviews.summary.last_worked_at)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The public id is permanent: store it rather than a name or a path. A site
|
|
145
|
+
removed from its source still answers, with `site.status` of `"removed"`, and an
|
|
146
|
+
id that never existed raises `NotFound`, so code holding stored ids can tell a
|
|
147
|
+
retired charger from a typo.
|
|
148
|
+
|
|
149
|
+
## Search
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
found = ca.search("coburg", prefer="AU")
|
|
153
|
+
found.localities # suburbs and towns, exact matches first
|
|
154
|
+
found.postcodes # a postcode's centre, for nearby()
|
|
155
|
+
found.sites # sites by name
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`prefer` is a two letter country code whose places rank first. A term with
|
|
159
|
+
fewer than three letters or digits answers empty without a request.
|
|
160
|
+
|
|
161
|
+
## Browsing
|
|
162
|
+
|
|
163
|
+
`countries()`, `overview()`, `country("australia")`,
|
|
164
|
+
`region("australia", "victoria")`, `networks("australia")`,
|
|
165
|
+
`network("australia", "chargefox")` and
|
|
166
|
+
`locality("australia", "victoria", "coburg")` read the directory the way the
|
|
167
|
+
site's pages do. Rows that carry a `path` have a `url` for that page on
|
|
168
|
+
chargealong.io.
|
|
169
|
+
|
|
170
|
+
`redirect("/en/...")` says where a moved page went, or `None` if it did not
|
|
171
|
+
move.
|
|
172
|
+
|
|
173
|
+
## Errors
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from chargealong import BadRequest, NoRoute, NotFound, RateLimited
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
ca.plan_trip(a, b, range_km=400)
|
|
180
|
+
except NoRoute:
|
|
181
|
+
... # no road between them
|
|
182
|
+
except BadRequest as e:
|
|
183
|
+
print(e.detail) # "range_km: must be between 50 and 1500"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Every error is a `ChargeAlongError` carrying the service's own `title` and
|
|
187
|
+
`detail`, which say what to do. `RateLimited` carries `retry_after` in seconds
|
|
188
|
+
when the service said.
|
|
189
|
+
|
|
190
|
+
## Being a good citizen
|
|
191
|
+
|
|
192
|
+
The API is free and cached at the edge. Keep answers rather than fetching them
|
|
193
|
+
again, debounce anything a person types, and make one client and share it.
|
|
194
|
+
|
|
195
|
+
## Attribution
|
|
196
|
+
|
|
197
|
+
Charging site data is from [Open Charge Map](https://openchargemap.org/)
|
|
198
|
+
contributors, Transport for NSW and the Queensland Government, and places from
|
|
199
|
+
[GeoNames](https://www.geonames.org/), all under
|
|
200
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Car data is from
|
|
201
|
+
Open EV Data. Publishing what you get back means carrying those credits: see
|
|
202
|
+
[where the data comes from](https://chargealong.io/en/guides/where-the-data-comes-from/)
|
|
203
|
+
and the [terms](https://chargealong.io/en/terms/).
|
|
204
|
+
|
|
205
|
+
## Also available
|
|
206
|
+
|
|
207
|
+
| Language | Package |
|
|
208
|
+
|---|---|
|
|
209
|
+
| JavaScript and TypeScript | [`@chargealong/client`](https://www.npmjs.com/package/@chargealong/client) ([source](https://github.com/chargealong/chargealong-js)) |
|
|
210
|
+
|
|
211
|
+
API reference: [chargealong.io/docs](https://chargealong.io/docs/).
|
|
212
|
+
|
|
213
|
+
## Licence
|
|
214
|
+
|
|
215
|
+
MIT for this library. The data carries its own licences, above.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# chargealong
|
|
2
|
+
|
|
3
|
+
**Public EV chargers, road trips through charging stops, and how fast electric
|
|
4
|
+
cars charge, as an API.** Find the chargers nearest a point, plan Melbourne to
|
|
5
|
+
Sydney with the stops and the minutes at each, or look up a car's charging
|
|
6
|
+
curve.
|
|
7
|
+
|
|
8
|
+
- Free and keyless. No account, nothing to configure
|
|
9
|
+
- No dependencies: the standard library only
|
|
10
|
+
- Typed dataclasses with the field names the API sends, so the docs and your
|
|
11
|
+
editor agree
|
|
12
|
+
- Every parameter checked against the service's own limits before a request is
|
|
13
|
+
spent on it
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pip install chargealong
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from chargealong import ChargeAlong
|
|
23
|
+
|
|
24
|
+
ca = ChargeAlong()
|
|
25
|
+
|
|
26
|
+
near = ca.nearby(-37.7404, 144.9633, min_kw=50, limit=5)
|
|
27
|
+
for site in near.sites:
|
|
28
|
+
print(site.name, site.network_name, site.max_kw, "kW", site.distance_m, "m")
|
|
29
|
+
print(site.url)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Nearest first, within 50 km unless you pass `radius_km` (up to 150), at most
|
|
33
|
+
30 sites unless you pass `limit` (up to 50). `near.near` is the closest named
|
|
34
|
+
place, for a heading.
|
|
35
|
+
|
|
36
|
+
Only `status == "active"` sites are worth sending a driver to.
|
|
37
|
+
|
|
38
|
+
### Filters
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
ca.nearby(lat, lng,
|
|
42
|
+
min_kw=100, # a stop, not a top up
|
|
43
|
+
connector=["ccs2", "chademo"], # any of these
|
|
44
|
+
network="evie-networks")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`CONNECTORS` lists the standards: `ccs2`, `chademo`, `type-2`, `nacs`,
|
|
48
|
+
`ccs1`, `type-1`, `gbt`.
|
|
49
|
+
|
|
50
|
+
## Plan a trip
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
plan = ca.plan_trip((-37.8136, 144.9631), (-33.8688, 151.2093), range_km=400)
|
|
54
|
+
|
|
55
|
+
print(plan.route.distance_km, "km,", plan.total_min, "minutes in all")
|
|
56
|
+
for stop in plan.stops:
|
|
57
|
+
print(f"{stop.site.name}: arrive {stop.arrive_pct}%, "
|
|
58
|
+
f"charge {stop.charge_min} min to {stop.depart_pct}%")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`range_km` is how far the car really goes on a full battery. The rest is
|
|
62
|
+
optional: `reserve` (never arrive below, default 20%), `start` (default 100%),
|
|
63
|
+
`charge_to` (default 80%), `battery_kwh`, `max_dc_kw`, `max_ac_kw`, `min_kw`
|
|
64
|
+
(ignore slower chargers, default 50) and `connectors` (default `ccs2` and
|
|
65
|
+
`type-2`).
|
|
66
|
+
|
|
67
|
+
`plan.feasible` false is an answer, not an error: the car cannot make it
|
|
68
|
+
without dropping below the reserve, and `plan.gap` says where, in km from the
|
|
69
|
+
start. No road between the points raises `NoRoute`: Sydney to Auckland, say.
|
|
70
|
+
Trips are planned in Australia and New Zealand.
|
|
71
|
+
|
|
72
|
+
`plan.route.line` is the road as `(longitude, latitude)` pairs, ready for a
|
|
73
|
+
GeoJSON LineString.
|
|
74
|
+
|
|
75
|
+
## Electric cars
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
for car in ca.vehicles("model 3", limit=5):
|
|
79
|
+
print(car.brand, car.model, car.range_km, "km", car.dc_kw, "kW DC")
|
|
80
|
+
|
|
81
|
+
car = ca.vehicle("tesla-model-3")
|
|
82
|
+
for t in car.charging:
|
|
83
|
+
print(f"10 to 80% on {t.charger_kw} kW: {t.minutes_10_80} min")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## One charging site
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
detail = ca.site("hwqb4abf")
|
|
90
|
+
|
|
91
|
+
print(detail.site.name, detail.site.cost.text)
|
|
92
|
+
for c in detail.connectors:
|
|
93
|
+
print(c.label, c.power_kw, "kW x", c.quantity)
|
|
94
|
+
print(detail.reviews.summary.count, "reviews, last worked", detail.reviews.summary.last_worked_at)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The public id is permanent: store it rather than a name or a path. A site
|
|
98
|
+
removed from its source still answers, with `site.status` of `"removed"`, and an
|
|
99
|
+
id that never existed raises `NotFound`, so code holding stored ids can tell a
|
|
100
|
+
retired charger from a typo.
|
|
101
|
+
|
|
102
|
+
## Search
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
found = ca.search("coburg", prefer="AU")
|
|
106
|
+
found.localities # suburbs and towns, exact matches first
|
|
107
|
+
found.postcodes # a postcode's centre, for nearby()
|
|
108
|
+
found.sites # sites by name
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`prefer` is a two letter country code whose places rank first. A term with
|
|
112
|
+
fewer than three letters or digits answers empty without a request.
|
|
113
|
+
|
|
114
|
+
## Browsing
|
|
115
|
+
|
|
116
|
+
`countries()`, `overview()`, `country("australia")`,
|
|
117
|
+
`region("australia", "victoria")`, `networks("australia")`,
|
|
118
|
+
`network("australia", "chargefox")` and
|
|
119
|
+
`locality("australia", "victoria", "coburg")` read the directory the way the
|
|
120
|
+
site's pages do. Rows that carry a `path` have a `url` for that page on
|
|
121
|
+
chargealong.io.
|
|
122
|
+
|
|
123
|
+
`redirect("/en/...")` says where a moved page went, or `None` if it did not
|
|
124
|
+
move.
|
|
125
|
+
|
|
126
|
+
## Errors
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from chargealong import BadRequest, NoRoute, NotFound, RateLimited
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
ca.plan_trip(a, b, range_km=400)
|
|
133
|
+
except NoRoute:
|
|
134
|
+
... # no road between them
|
|
135
|
+
except BadRequest as e:
|
|
136
|
+
print(e.detail) # "range_km: must be between 50 and 1500"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Every error is a `ChargeAlongError` carrying the service's own `title` and
|
|
140
|
+
`detail`, which say what to do. `RateLimited` carries `retry_after` in seconds
|
|
141
|
+
when the service said.
|
|
142
|
+
|
|
143
|
+
## Being a good citizen
|
|
144
|
+
|
|
145
|
+
The API is free and cached at the edge. Keep answers rather than fetching them
|
|
146
|
+
again, debounce anything a person types, and make one client and share it.
|
|
147
|
+
|
|
148
|
+
## Attribution
|
|
149
|
+
|
|
150
|
+
Charging site data is from [Open Charge Map](https://openchargemap.org/)
|
|
151
|
+
contributors, Transport for NSW and the Queensland Government, and places from
|
|
152
|
+
[GeoNames](https://www.geonames.org/), all under
|
|
153
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Car data is from
|
|
154
|
+
Open EV Data. Publishing what you get back means carrying those credits: see
|
|
155
|
+
[where the data comes from](https://chargealong.io/en/guides/where-the-data-comes-from/)
|
|
156
|
+
and the [terms](https://chargealong.io/en/terms/).
|
|
157
|
+
|
|
158
|
+
## Also available
|
|
159
|
+
|
|
160
|
+
| Language | Package |
|
|
161
|
+
|---|---|
|
|
162
|
+
| JavaScript and TypeScript | [`@chargealong/client`](https://www.npmjs.com/package/@chargealong/client) ([source](https://github.com/chargealong/chargealong-js)) |
|
|
163
|
+
|
|
164
|
+
API reference: [chargealong.io/docs](https://chargealong.io/docs/).
|
|
165
|
+
|
|
166
|
+
## Licence
|
|
167
|
+
|
|
168
|
+
MIT for this library. The data carries its own licences, above.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "chargealong"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Find EV chargers near a point, plan a road trip through charging stops, and look up electric car charging speeds. Free and keyless."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [{ name = "ChargeAlong" }]
|
|
13
|
+
keywords = [
|
|
14
|
+
"ev charger api",
|
|
15
|
+
"ev charging stations",
|
|
16
|
+
"charging station locator",
|
|
17
|
+
"ev trip planner",
|
|
18
|
+
"electric vehicle",
|
|
19
|
+
"electric car charging",
|
|
20
|
+
"charging network",
|
|
21
|
+
"open charge map",
|
|
22
|
+
"australia",
|
|
23
|
+
"new zealand",
|
|
24
|
+
]
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Development Status :: 4 - Beta",
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"License :: OSI Approved :: MIT License",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.9",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Programming Language :: Python :: 3.13",
|
|
35
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
36
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
37
|
+
"Typing :: Typed",
|
|
38
|
+
]
|
|
39
|
+
# No dependencies, on purpose. The whole client is one urllib call and a set of
|
|
40
|
+
# dataclasses; asking for requests would make this the heaviest thing in
|
|
41
|
+
# somebody's lambda for no gain.
|
|
42
|
+
dependencies = []
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://chargealong.io"
|
|
46
|
+
Documentation = "https://chargealong.io/docs/"
|
|
47
|
+
Source = "https://github.com/chargealong/chargealong-python"
|
|
48
|
+
Changelog = "https://github.com/chargealong/chargealong-python/blob/main/CHANGELOG.md"
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/chargealong"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""ChargeAlong: public EV charging sites, trip planning and electric cars, as an API.
|
|
2
|
+
|
|
3
|
+
Free, keyless and cached at the edge. The directory behind chargealong.io.
|
|
4
|
+
|
|
5
|
+
>>> from chargealong import ChargeAlong
|
|
6
|
+
>>> ca = ChargeAlong()
|
|
7
|
+
>>> near = ca.nearby(-37.7404, 144.9633, min_kw=50)
|
|
8
|
+
>>> near.sites[0].name, near.sites[0].max_kw
|
|
9
|
+
('Coburg Civic Centre / Moreland City', 50)
|
|
10
|
+
|
|
11
|
+
Charging site data from Open Charge Map contributors, Transport for NSW and the
|
|
12
|
+
Queensland Government, places from GeoNames, all CC BY 4.0. Publishing what you
|
|
13
|
+
get back means carrying those credits:
|
|
14
|
+
chargealong.io/en/guides/where-the-data-comes-from/.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from ._client import DEFAULT_BASE_URL, ChargeAlong, Transport, __version__
|
|
18
|
+
from ._errors import BadRequest, ChargeAlongError, NoRoute, NotFound, RateLimited
|
|
19
|
+
from ._models import (
|
|
20
|
+
CONNECTORS,
|
|
21
|
+
SITE,
|
|
22
|
+
ChargeTime,
|
|
23
|
+
Connector,
|
|
24
|
+
Cost,
|
|
25
|
+
Country,
|
|
26
|
+
CountryDetail,
|
|
27
|
+
CountryOverview,
|
|
28
|
+
CurvePoint,
|
|
29
|
+
Facet,
|
|
30
|
+
Gap,
|
|
31
|
+
Locality,
|
|
32
|
+
LocalityDetail,
|
|
33
|
+
NearPlace,
|
|
34
|
+
Nearby,
|
|
35
|
+
Network,
|
|
36
|
+
NetworkDetail,
|
|
37
|
+
NetworkList,
|
|
38
|
+
Overview,
|
|
39
|
+
Photo,
|
|
40
|
+
PlaceMatch,
|
|
41
|
+
PostcodeMatch,
|
|
42
|
+
Redirect,
|
|
43
|
+
Region,
|
|
44
|
+
RegionDetail,
|
|
45
|
+
Review,
|
|
46
|
+
Reviews,
|
|
47
|
+
ReviewSummary,
|
|
48
|
+
Route,
|
|
49
|
+
SearchResult,
|
|
50
|
+
Site,
|
|
51
|
+
SiteDetail,
|
|
52
|
+
Source,
|
|
53
|
+
TripPlan,
|
|
54
|
+
TripStop,
|
|
55
|
+
Vehicle,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
"BadRequest", "CONNECTORS", "ChargeAlong", "ChargeAlongError", "ChargeTime", "Connector", "Cost",
|
|
60
|
+
"Country", "CountryDetail", "CountryOverview", "CurvePoint", "DEFAULT_BASE_URL", "Facet", "Gap",
|
|
61
|
+
"Locality", "LocalityDetail", "NearPlace", "Nearby", "Network", "NetworkDetail",
|
|
62
|
+
"NetworkList", "NoRoute", "NotFound", "Overview", "Photo", "PlaceMatch", "PostcodeMatch",
|
|
63
|
+
"RateLimited", "Redirect", "Region", "RegionDetail", "Review", "ReviewSummary", "Reviews",
|
|
64
|
+
"Route", "SITE", "SearchResult", "Site", "SiteDetail", "Source", "Transport", "TripPlan",
|
|
65
|
+
"TripStop", "Vehicle", "__version__",
|
|
66
|
+
]
|