python-chargepoint 1.10.0__tar.gz → 2.0.1__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.
@@ -0,0 +1,388 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-chargepoint
3
+ Version: 2.0.1
4
+ Summary: A simple, Pythonic wrapper for the ChargePoint API.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: Marc Billow
8
+ Author-email: mbillow@users.noreply.github.compoetry
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Dist: aiohttp (>=3.9,<4.0)
18
+ Requires-Dist: click (>=8.1,<9.0)
19
+ Requires-Dist: pydantic (>=2.12,<3.0)
20
+ Description-Content-Type: text/markdown
21
+
22
+ # python-chargepoint
23
+
24
+ A simple, async Pythonic wrapper around the ChargePoint EV Charging Network API.
25
+
26
+ ## Disclaimer
27
+
28
+ This project is not affiliated with or endorsed by ChargePoint in any way. Use at your own risk.
29
+ ChargePoint is a registered trademark of ChargePoint, Inc.
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install python-chargepoint
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Library Usage
42
+
43
+ All client methods are `async` and must be called from an async context.
44
+
45
+ ### Authentication
46
+
47
+ Three authentication methods are supported. The client is created via the async factory `ChargePoint.create()`.
48
+
49
+ **Password:**
50
+ ```python
51
+ import asyncio
52
+ from python_chargepoint import ChargePoint
53
+
54
+ async def main():
55
+ client = await ChargePoint.create(username="user@example.com")
56
+ await client.login_with_password("password")
57
+ # ...
58
+ await client.close()
59
+
60
+ asyncio.run(main())
61
+ ```
62
+
63
+ **Long-lived session token** (recommended for automation):
64
+ ```python
65
+ client = await ChargePoint.create(
66
+ username="user@example.com",
67
+ coulomb_token="<coulomb_sess cookie value>",
68
+ )
69
+ ```
70
+
71
+ **SSO JWT:**
72
+ ```python
73
+ client = await ChargePoint.create(username="user@example.com")
74
+ await client.login_with_sso_session("<sso jwt>")
75
+ # you can then grab client.coulomb_token and use the above pattern going forward
76
+ ```
77
+
78
+ ---
79
+
80
+ ### Obtaining Tokens Manually
81
+
82
+ Password-based login may be blocked by bot-protection (Datadome). When that happens,
83
+ you can capture a token directly from your browser and pass it to the client.
84
+
85
+ 1. Open [https://driver.chargepoint.com](https://driver.chargepoint.com) in your browser and log in normally.
86
+ 2. Open Developer Tools and navigate to **Application > Cookies > https://driver.chargepoint.com**.
87
+ 3. Copy the value of one of the following cookies:
88
+
89
+ | Cookie | Use as |
90
+ |---|---|
91
+ | `coulomb_sess` | `coulomb_token=` (recommended — long-lived) |
92
+ | `auth-session` | `login_with_sso_session()` (shorter-lived JWT) |
93
+
94
+ > **Note:** The `coulomb_sess` value contains `#` and `?` characters. The library handles both raw and URL-encoded (`%23`, `%3F`) forms automatically. When setting it as a shell environment variable, always wrap the value in **double quotes** to prevent the shell from interpreting `#` as a comment:
95
+ >
96
+ > ```bash
97
+ > export CP_COULOMB_TOKEN="Ab3dEf...token...#D???????#RNA-US"
98
+ > ```
99
+
100
+ ---
101
+
102
+ ### Account
103
+
104
+ ```python
105
+ acct = await client.get_account()
106
+ print(acct.user.full_name) # "Jane Smith"
107
+ print(acct.account_balance.amount) # "12.34"
108
+
109
+ evs = await client.get_vehicles()
110
+ for ev in evs:
111
+ print(f"{ev.year} {ev.make} {ev.model}") # "2023 Polestar 2"
112
+ print(f" AC: {ev.charging_speed} kW DC: {ev.dc_charging_speed} kW")
113
+ ```
114
+
115
+ ---
116
+
117
+ ### Home Charger
118
+
119
+ ```python
120
+ charger_ids = await client.get_home_chargers()
121
+ # [12345678]
122
+
123
+ charger_id = charger_ids[0]
124
+
125
+ status = await client.get_home_charger_status(charger_id)
126
+ # HomeChargerStatus(
127
+ # charger_id=12345678,
128
+ # brand='CP',
129
+ # model='HOME FLEX',
130
+ # charging_status='AVAILABLE',
131
+ # is_plugged_in=True,
132
+ # is_connected=True,
133
+ # amperage_limit=28,
134
+ # possible_amperage_limits=[20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32])
135
+
136
+ tech = await client.get_home_charger_technical_info(charger_id)
137
+ # HomeChargerTechnicalInfo(
138
+ # model_number='CPH50-NEMA6-50-L23',
139
+ # serial_number='...',
140
+ # software_version='1.2.3.4',
141
+ # last_connected_at=datetime(...))
142
+
143
+ config = await client.get_home_charger_config(charger_id)
144
+ # HomeChargerConfiguration(
145
+ # station_nickname='Home Flex',
146
+ # led_brightness=LEDBrightness(level=5, supported_levels=[0,1,2,3,4,5]),
147
+ # utility=PowerUtility(name='Austin Energy', ...))
148
+ ```
149
+
150
+ #### Amperage limit
151
+
152
+ ```python
153
+ # Print valid amperage values
154
+ print(status.possible_amperage_limits)
155
+ # [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
156
+
157
+ await client.set_amperage_limit(charger_id, 24)
158
+ ```
159
+
160
+ #### LED brightness
161
+
162
+ Levels map to: `0`=off, `1`=20%, `2`=40%, `3`=60%, `4`=80%, `5`=100%.
163
+ Available levels are returned by `get_home_charger_config()`.
164
+
165
+ ```python
166
+ await client.set_led_brightness(charger_id, 3) # 60%
167
+ ```
168
+
169
+ #### Restart
170
+
171
+ ```python
172
+ await client.restart_home_charger(charger_id)
173
+ ```
174
+
175
+ ---
176
+
177
+ ### Charging Status and Sessions
178
+
179
+ ```python
180
+ status = await client.get_user_charging_status()
181
+ if status:
182
+ print(status.state) # "fully_charged"
183
+ print(status.session_id) # 1234567890
184
+
185
+ session = await client.get_charging_session(status.session_id)
186
+ print(session.charging_state) # "fully_charged"
187
+ print(session.energy_kwh) # 6.42
188
+ print(session.miles_added) # 22.3
189
+ ```
190
+
191
+ #### Starting and stopping a session
192
+
193
+ ```python
194
+ # Stop the current session
195
+ session = await client.get_charging_session(status.session_id)
196
+ await session.stop()
197
+
198
+ # Start a new session on any device
199
+ new_session = await client.start_charging_session(device_id=charger_id)
200
+ print(new_session.session_id)
201
+ ```
202
+
203
+ ---
204
+
205
+ ### Station Info
206
+
207
+ Fetch detailed information about any station by device ID — ports, pricing, connector types, and real-time status.
208
+
209
+ ```python
210
+ info = await client.get_station(device_id=13055991)
211
+ print(f"{' / '.join(info.name)}") # "DOMAIN TOWER 2 / LVL 2_STATION 2"
212
+ print(info.address.address1) # "10025 Alterra Pkwy"
213
+ print(info.station_status_v2) # "available"
214
+ print(info.ports_info.port_count) # 2
215
+
216
+ for port in info.ports_info.ports:
217
+ print(f"Port {port.outlet_number}: {port.status_v2} ({port.level})")
218
+ for c in port.connector_list:
219
+ print(f" {c.display_plug_type}: {c.status_v2}")
220
+
221
+ if info.station_price:
222
+ for tou in info.station_price.tou_fees:
223
+ print(f"Rate: {tou.fee.amount} {info.station_price.currency_code}/{tou.fee.unit}")
224
+ ```
225
+
226
+ ---
227
+
228
+ ### Nearby Stations
229
+
230
+ Fetch all charging stations visible within a geographic bounding box. Results include
231
+ both public stations and the user's home charger (if it falls within the bounds).
232
+
233
+ ```python
234
+ from python_chargepoint.types import MapFilter, ZoomBounds
235
+
236
+ bounds = ZoomBounds(sw_lat=30.37, sw_lon=-97.66, ne_lat=30.40, ne_lon=-97.64)
237
+
238
+ # No filter — return all stations
239
+ stations = await client.get_nearby_stations(bounds)
240
+
241
+ # Optional: filter by connector type or status
242
+ f = MapFilter(connector_l2=True, connector_combo=True, status_available=True)
243
+ stations = await client.get_nearby_stations(bounds, station_filter=f)
244
+
245
+ for s in stations:
246
+ print(f"{s.name1} — {s.station_status_v2}")
247
+ if s.is_home and s.charging_info:
248
+ print(f" Charging: {s.charging_info.current_charging}")
249
+ ```
250
+
251
+ **`MapFilter` fields** (all `bool`, default `False`):
252
+
253
+ | Field | Description |
254
+ |---|---|
255
+ | `connector_l2` | Level 2 AC |
256
+ | `connector_combo` | CCS combo (DC) |
257
+ | `connector_chademo` | CHAdeMO (DC) |
258
+ | `connector_tesla` | Tesla proprietary |
259
+ | `connector_l1` | Level 1 AC |
260
+ | `connector_l2_tesla` | Tesla Level 2 |
261
+ | `connector_l2_nema_1450` | NEMA 14-50 |
262
+ | `dc_fast_charging` | Any DC fast charger |
263
+ | `status_available` | Only available stations |
264
+ | `price_free` | Only free stations |
265
+ | `van_accessible` | Van-accessible spaces |
266
+ | `disabled_parking` | Disability-accessible parking |
267
+ | `network_chargepoint` | ChargePoint network |
268
+ | `network_blink` | Blink network |
269
+ | `network_evgo` | EVgo network |
270
+ | `network_flo` | FLO network |
271
+ | `network_ionna` | IONNA network |
272
+ | `network_evconnect` | EV Connect |
273
+ | `network_evgateway` | EV Gateway |
274
+ | `network_bchydro` | BC Hydro |
275
+ | `network_greenlots` | Greenlots |
276
+ | `network_mercedes` | Mercedes-Benz |
277
+ | `network_circuitelectric` | Circuit Électrique |
278
+
279
+ ---
280
+
281
+ ## CLI
282
+
283
+ After installation, a `chargepoint` command is available.
284
+
285
+ ### Authentication
286
+
287
+ Credentials are read from environment variables. The CLI falls back to prompting for a password if no token is set.
288
+
289
+ ```bash
290
+ export CP_USERNAME="user@example.com"
291
+ export CP_COULOMB_TOKEN="<coulomb_sess cookie value>"
292
+ # or
293
+ export CP_SSO_JWT="<sso jwt>"
294
+ ```
295
+
296
+ ### Global options
297
+
298
+ ```
299
+ chargepoint [--debug] [--json] <command>
300
+ ```
301
+
302
+ `--json` dumps the raw API response as JSON — useful for scripting.
303
+
304
+ ### Commands
305
+
306
+ ```bash
307
+ # Account
308
+ chargepoint account
309
+ chargepoint vehicles
310
+
311
+ # Charging status
312
+ chargepoint charging-status
313
+
314
+ # Station info
315
+ chargepoint station <device_id>
316
+
317
+ # Nearby stations
318
+ chargepoint nearby --sw-lat 30.37 --sw-lon -97.66 --ne-lat 30.40 --ne-lon -97.64 \
319
+ [--connector-l2] [--connector-combo] [--connector-chademo] [--connector-tesla] \
320
+ [--dc-fast] [--available-only] [--free-only]
321
+
322
+ # Home charger
323
+ chargepoint charger list
324
+ chargepoint charger status <charger_id>
325
+ chargepoint charger tech-info <charger_id>
326
+ chargepoint charger config <charger_id>
327
+ chargepoint charger set-amperage <charger_id> <amps>
328
+ chargepoint charger set-led <charger_id> <level> # 0=off 1=20% 2=40% 3=60% 4=80% 5=100%
329
+ chargepoint charger restart <charger_id>
330
+
331
+ # Sessions
332
+ chargepoint session get <session_id>
333
+ chargepoint session start <device_id>
334
+ chargepoint session stop <session_id>
335
+ ```
336
+
337
+ Use `--help` on any command or subgroup for details:
338
+
339
+ ```bash
340
+ chargepoint nearby --help
341
+ chargepoint charger --help
342
+ ```
343
+
344
+ ---
345
+
346
+ ## Development
347
+
348
+ ### Setup
349
+
350
+ ```bash
351
+ git clone https://github.com/mbillow/python-chargepoint.git
352
+ cd python-chargepoint
353
+ poetry install
354
+ poetry run pre-commit install
355
+ ```
356
+
357
+ ### Checks
358
+
359
+ The following checks run automatically on every commit via pre-commit, and are also enforced in CI:
360
+
361
+ | Tool | Purpose |
362
+ |---|---|
363
+ | `black` | Code formatting |
364
+ | `flake8` | Style and error linting |
365
+ | `mypy` | Static type checking |
366
+ | `pyright` | Pylance-compatible type checking |
367
+
368
+ To run them manually:
369
+
370
+ ```bash
371
+ poetry run pre-commit run --all-files
372
+ ```
373
+
374
+ Or individually:
375
+
376
+ ```bash
377
+ poetry run black --check python_chargepoint/ tests/
378
+ poetry run flake8 python_chargepoint/ tests/
379
+ poetry run mypy python_chargepoint/
380
+ poetry run pyright python_chargepoint/
381
+ ```
382
+
383
+ ### Tests
384
+
385
+ ```bash
386
+ poetry run pytest
387
+ ```
388
+