pycupra 0.0.13__py3-none-any.whl → 0.0.15__py3-none-any.whl

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.
pycupra/__version__.py CHANGED
@@ -3,4 +3,4 @@ pycupra - A Python 3 library for interacting with the My Cupra/My Seat portal.
3
3
 
4
4
  For more details and documentation, visit the github page at https://github.com/WulfgarW/pycupra
5
5
  """
6
- __version__ = "0.0.13"
6
+ __version__ = "0.0.15"
pycupra/connection.py CHANGED
@@ -108,11 +108,12 @@ TIMEOUT = timedelta(seconds=90)
108
108
  class Connection:
109
109
  """ Connection to Connect services """
110
110
  # Init connection class
111
- def __init__(self, session, brand='cupra', username='', password='', fulldebug=False, **optional):
111
+ def __init__(self, session, brand='cupra', username='', password='', fulldebug=False, nightlyUpdateReduction=False, **optional):
112
112
  """ Initialize """
113
113
  self._session = session
114
114
  self._lock = asyncio.Lock()
115
115
  self._session_fulldebug = fulldebug
116
+ self._session_nightlyUpdateReduction = nightlyUpdateReduction
116
117
  self._session_headers = HEADERS_SESSION.get(brand).copy()
117
118
  self._session_base = BASE_SESSION
118
119
  self._session_auth_headers = HEADERS_AUTH.copy()
@@ -1369,6 +1370,8 @@ class Connection:
1369
1370
  if mode in {'start', 'stop'}:
1370
1371
  capability='charging'
1371
1372
  return await self._setViaAPI(eval(f"f'{API_REQUESTS}/{mode}'"))
1373
+ elif mode=='settings':
1374
+ return await self._setViaAPI(eval(f"f'{API_CHARGING}/{mode}'"), json=data)
1372
1375
  else:
1373
1376
  _LOGGER.error(f'Not yet implemented. Mode: {mode}. Command ignored')
1374
1377
  raise
pycupra/dashboard.py CHANGED
@@ -715,6 +715,32 @@ class PHeaterVentilation(Switch):
715
715
  return dict(last_result = self.vehicle.pheater_action_status)
716
716
 
717
717
 
718
+ class SlowCharge(Switch):
719
+ def __init__(self):
720
+ super().__init__(attr="slow_charge", name="Slow charge", icon="mdi:battery")
721
+
722
+ @property
723
+ def state(self):
724
+ return self.vehicle.slow_charge
725
+
726
+ async def turn_on(self):
727
+ await self.vehicle.set_charger_current('reduced')
728
+ #await self.vehicle.update()
729
+
730
+ async def turn_off(self):
731
+ await self.vehicle.set_charger_current('maximum')
732
+ #await self.vehicle.update()
733
+
734
+ @property
735
+ def assumed_state(self):
736
+ return False
737
+
738
+
739
+ @property
740
+ def attributes(self):
741
+ return dict(last_result = self.vehicle.charger_action_status)
742
+
743
+
718
744
  class Warnings(Sensor):
719
745
  def __init__(self):
720
746
  super().__init__(attr="warnings", name="Warnings", icon="mdi:alarm-light")
@@ -948,11 +974,14 @@ class ChargingState(BinarySensor):
948
974
  @property
949
975
  def attributes(self):
950
976
  attr = {}
951
- state = self.vehicle.attrs.get('charging', {}).get('status', {}).get('state', '')
977
+ #state = self.vehicle.attrs.get('charging', {}).get('status', {}).get('state', '')
978
+ #type = self.vehicle.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('type', '')
979
+ #mode = self.vehicle.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('mode', '')
980
+ state = self.vehicle.attrs.get('mycar', {}).get('services', {}).get('charging', {}).get('status', '')
952
981
  type = self.vehicle.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('type', '')
953
- mode = self.vehicle.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('mode', '')
954
- if state in {'charging', 'conservation'}:
955
- attr['state']=state
982
+ mode = self.vehicle.attrs.get('mycar', {}).get('services', {}).get('charging', {}).get('chargeMode', '')
983
+ if state in {'charging','Charging', 'conservation','Conservation'}:
984
+ attr['state']=state.lower()
956
985
  if type != '':
957
986
  attr['type']=type
958
987
  if mode != '':
@@ -978,6 +1007,7 @@ def create_instruments():
978
1007
  #CombustionClimatisationClimate(),
979
1008
  Charging(),
980
1009
  Warnings(),
1010
+ SlowCharge(),
981
1011
  RequestResults(),
982
1012
  DepartureTimer1(),
983
1013
  DepartureTimer2(),
@@ -1110,8 +1140,8 @@ def create_instruments():
1110
1140
  attr="charge_max_ampere",
1111
1141
  name="Charger max ampere",
1112
1142
  icon="mdi:flash",
1113
- unit="A",
1114
- device_class="current"
1143
+ #unit="A",
1144
+ #device_class="current"
1115
1145
  ),
1116
1146
  Sensor(
1117
1147
  attr="climatisation_target_temperature",
pycupra/vehicle.py CHANGED
@@ -129,9 +129,20 @@ class Vehicle:
129
129
  # Fetch all data if car is not deactivated
130
130
  if not self.deactivated:
131
131
  try:
132
+ if self._connection._session_nightlyUpdateReduction:
133
+ # nightlyUpdateReduction is activated
134
+ if datetime.now(tz=None).hour<5 or datetime.now(tz=None).hour>=22:
135
+ # current time is within the night interval
136
+ fullUpdateExpired = datetime.now(tz=None) - timedelta(seconds= 1100)
137
+ if hasattr(self, '_last_full_update'):
138
+ _LOGGER.debug(f'last_full_update= {self._last_full_update}, fullUpdateExpired= {fullUpdateExpired}.')
139
+ if updateType!=1 and (hasattr(self, '_last_full_update') and self._last_full_update>fullUpdateExpired):
140
+ _LOGGER.debug('Nightly update reduction is active and current time within 22:00 and 5:00. So we skip small update.')
141
+ return True
142
+
132
143
  # Data to be updated most often
133
144
  await asyncio.gather(
134
- self.get_charger(),
145
+ #self.get_charger(),
135
146
  self.get_basiccardata(),
136
147
  self.get_statusreport(),
137
148
  return_exceptions=True
@@ -146,6 +157,8 @@ class Vehicle:
146
157
 
147
158
  # Data to be updated less often
148
159
  await asyncio.gather(
160
+ #self.get_statusreport(),
161
+ self.get_charger(),
149
162
  self.get_preheater(),
150
163
  self.get_climater(),
151
164
  self.get_trip_statistic(),
@@ -320,7 +333,11 @@ class Vehicle:
320
333
  if 1 <= int(value) <= 255:
321
334
  # VW-Group API charger current request
322
335
  if self._relevantCapabilties.get('charging', {}).get('active', False):
323
- data = {'action': {'settings': {'maxChargeCurrentAC': int(value)}, 'type': 'setSettings'}}
336
+ data = {'maxChargeCurrentAc': int(value)}
337
+ if int(value)==252:
338
+ data = {'maxChargeCurrentAc': 'reduced'}
339
+ if int(value)==254:
340
+ data = {'maxChargeCurrentAc': 'maximum'}
324
341
  else:
325
342
  _LOGGER.error(f'Set charger maximum current to {value} is not supported.')
326
343
  raise SeatInvalidRequestException(f'Set charger maximum current to {value} is not supported.')
@@ -330,9 +347,7 @@ class Vehicle:
330
347
  # VW-Group API charger current request
331
348
  if self._relevantCapabilties.get('charging', {}).get('active', False):
332
349
  value = 'maximum' if value in ['Maximum', 'maximum', 'Max', 'max'] else 'reduced'
333
- data = {'settings':
334
- {'maxChargeCurrentAC': value}
335
- }
350
+ data = {'maxChargeCurrentAc': value}
336
351
  else:
337
352
  _LOGGER.error(f'Set charger maximum current to {value} is not supported.')
338
353
  raise SeatInvalidRequestException(f'Set charger maximum current to {value} is not supported.')
@@ -344,7 +359,7 @@ class Vehicle:
344
359
  _LOGGER.error('No charger support.')
345
360
  raise SeatInvalidRequestException('No charger support.')
346
361
 
347
- async def set_charger(self, action, **data):
362
+ async def set_charger(self, action, data=None):
348
363
  """Charging actions."""
349
364
  if not self._relevantCapabilties.get('charging', {}).get('active', False):
350
365
  _LOGGER.info('Remote start/stop of charger is not supported.')
@@ -361,7 +376,7 @@ class Vehicle:
361
376
  mode='start'
362
377
  elif action in ['stop', 'Stop', 'Off', 'off']:
363
378
  mode='stop'
364
- elif isinstance(action.get('action', None), dict):
379
+ elif action=='settings':
365
380
  mode=action
366
381
  else:
367
382
  _LOGGER.error(f'Invalid charger action: {action}. Must be either start, stop or setSettings')
@@ -386,6 +401,7 @@ class Vehicle:
386
401
  while not actionSuccessful and retry < 2:
387
402
  await asyncio.sleep(15)
388
403
  await self.get_charger()
404
+ await self.get_basiccardata() # We get both, get_charger() and get_basiccardata()
389
405
  if mode == 'start':
390
406
  if self.charging:
391
407
  actionSuccessful = True
@@ -393,7 +409,7 @@ class Vehicle:
393
409
  if not self.charging:
394
410
  actionSuccessful = True
395
411
  elif mode == 'settings':
396
- if data.get('settings',0).get('maxChargeCurrentAC','') == self.charge_max_ampere:
412
+ if data.get('maxChargeCurrentAc','') == self.charge_max_ampere:
397
413
  actionSuccessful = True
398
414
  else:
399
415
  _LOGGER.error(f'Missing code in vehicle._set_charger() for mode {mode}')
@@ -1473,16 +1489,22 @@ class Vehicle:
1473
1489
  @property
1474
1490
  def charging(self):
1475
1491
  """Return battery level"""
1476
- cstate = self.attrs.get('charging').get('status').get('charging').get('state','')
1492
+ #cstate = self.attrs.get('charging').get('status').get('charging').get('state','')
1493
+ cstate = self.attrs.get('mycar',{}).get('services',{}).get('charging',{}).get('status','')
1477
1494
  return 1 if cstate in ['charging', 'Charging'] else 0
1478
1495
 
1479
1496
  @property
1480
1497
  def is_charging_supported(self):
1481
1498
  """Return true if charging is supported"""
1482
- if self.attrs.get('charging', False):
1483
- if 'status' in self.attrs.get('charging', {}):
1484
- if 'charging' in self.attrs.get('charging')['status']:
1485
- if 'state' in self.attrs.get('charging')['status']['charging']:
1499
+ #if self.attrs.get('charging', False):
1500
+ # if 'status' in self.attrs.get('charging', {}):
1501
+ # if 'charging' in self.attrs.get('charging')['status']:
1502
+ # if 'state' in self.attrs.get('charging')['status']['charging']:
1503
+ # return True
1504
+ if self.attrs.get('mycar', False):
1505
+ if 'services' in self.attrs.get('mycar', {}):
1506
+ if 'charging' in self.attrs.get('mycar')['services']:
1507
+ if 'status' in self.attrs.get('mycar')['services']['charging']:
1486
1508
  return True
1487
1509
  return False
1488
1510
 
@@ -1504,26 +1526,33 @@ class Vehicle:
1504
1526
  @property
1505
1527
  def battery_level(self):
1506
1528
  """Return battery level"""
1507
- if self.attrs.get('charging', False):
1508
- return int(self.attrs.get('charging').get('status', {}).get('battery', {}).get('currentSocPercentage', 0))
1529
+ #if self.attrs.get('charging', False):
1530
+ # return int(self.attrs.get('charging').get('status', {}).get('battery', {}).get('currentSocPercentage', 0))
1531
+ if self.attrs.get('mycar', False):
1532
+ return int(self.attrs.get('mycar',{}).get('services', {}).get('charging', {}).get('currentPct', 0))
1509
1533
  else:
1510
1534
  return 0
1511
1535
 
1512
1536
  @property
1513
1537
  def is_battery_level_supported(self):
1514
1538
  """Return true if battery level is supported"""
1515
- if self.attrs.get('charging', False):
1516
- if 'status' in self.attrs.get('charging'):
1517
- if 'battery' in self.attrs.get('charging')['status']:
1518
- if 'currentSocPercentage' in self.attrs.get('charging')['status']['battery']:
1539
+ #if self.attrs.get('charging', False):
1540
+ # if 'status' in self.attrs.get('charging'):
1541
+ # if 'battery' in self.attrs.get('charging')['status']:
1542
+ # if 'currentSocPercentage' in self.attrs.get('charging')['status']['battery']:
1543
+ # return True
1544
+ if self.attrs.get('mycar', False):
1545
+ if 'services' in self.attrs.get('mycar'):
1546
+ if 'charging' in self.attrs.get('mycar')['services']:
1547
+ if 'currentPct' in self.attrs.get('mycar')['services']['charging']:
1519
1548
  return True
1520
1549
  return False
1521
1550
 
1522
1551
  @property
1523
1552
  def charge_max_ampere(self):
1524
1553
  """Return charger max ampere setting."""
1525
- if self.attrs.get('charger', False):
1526
- return self.attrs.get('charger').get('info').get('settings').get('maxChargeCurrentAC')
1554
+ if self.attrs.get('charging', False):
1555
+ return self.attrs.get('charging').get('info').get('settings').get('maxChargeCurrentAc')
1527
1556
  return 0
1528
1557
 
1529
1558
  @property
@@ -1532,10 +1561,25 @@ class Vehicle:
1532
1561
  if self.attrs.get('charging', False):
1533
1562
  if 'info' in self.attrs.get('charging', {}):
1534
1563
  if 'settings' in self.attrs.get('charging')['info']:
1535
- if 'maxChargeCurrentAC' in self.attrs.get('charging', {})['info']['settings']:
1564
+ if 'maxChargeCurrentAc' in self.attrs.get('charging', {})['info']['settings']:
1536
1565
  return True
1537
1566
  return False
1538
1567
 
1568
+ @property
1569
+ def slow_charge(self):
1570
+ """Return charger max ampere setting."""
1571
+ if self.charge_max_ampere=='reduced':
1572
+ return True
1573
+ return False
1574
+
1575
+ @property
1576
+ def is_slow_charge_supported(self):
1577
+ """Return true if Slow Charge is supported"""
1578
+ if self.is_charge_max_ampere_supported:
1579
+ if self.charge_max_ampere in ('reduced', 'maximum'):
1580
+ return True
1581
+ return False
1582
+
1539
1583
  @property
1540
1584
  def charging_cable_locked(self):
1541
1585
  """Return plug locked state"""
@@ -1575,9 +1619,12 @@ class Vehicle:
1575
1619
  @property
1576
1620
  def charging_time_left(self):
1577
1621
  """Return minutes to charging complete"""
1578
- if self.external_power:
1579
- if self.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('remainingTimeInMinutes', False):
1580
- minutes = int(self.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('remainingTimeInMinutes', 0))
1622
+ #if self.external_power:
1623
+ if self.charging:
1624
+ #if self.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('remainingTimeInMinutes', False):
1625
+ # minutes = int(self.attrs.get('charging', {}).get('status', {}).get('charging', {}).get('remainingTimeInMinutes', 0))
1626
+ if self.attrs.get('mycar', {}).get('services', {}).get('charging', {}).get('remainingTime', False):
1627
+ minutes = int(self.attrs.get('mycar', {}).get('services', {}).get('charging', {}).get('remainingTime', 0))
1581
1628
  else:
1582
1629
  minutes = 0
1583
1630
  return minutes
@@ -1646,8 +1693,9 @@ class Vehicle:
1646
1693
  @property
1647
1694
  def charging_state(self):
1648
1695
  """Return true if vehicle is charging."""
1649
- check = self.attrs.get('charging', {}).get('status', {}).get('state', '')
1650
- if check == 'charging':
1696
+ #check = self.attrs.get('charging', {}).get('status', {}).get('state', '')
1697
+ check = self.attrs.get('mycar',{}).get('services',{}).get('charging',{}).get('status','')
1698
+ if check in ('charging','Charging'):
1651
1699
  return True
1652
1700
  else:
1653
1701
  return False
@@ -1655,17 +1703,23 @@ class Vehicle:
1655
1703
  @property
1656
1704
  def is_charging_state_supported(self):
1657
1705
  """Charging state supported."""
1658
- if self.attrs.get('charging', {}).get('status', {}).get('state', False):
1659
- return True
1706
+ #if self.attrs.get('charging', {}).get('status', {}).get('state', False):
1707
+ # return True
1708
+ if self.attrs.get('mycar', False):
1709
+ if 'services' in self.attrs.get('mycar', {}):
1710
+ if 'charging' in self.attrs.get('mycar')['services']:
1711
+ if 'status' in self.attrs.get('mycar')['services']['charging']:
1712
+ return True
1660
1713
 
1661
1714
  @property
1662
1715
  def energy_flow(self):
1663
1716
  """Return true if energy is flowing to (i.e. charging) or from (i.e. climating with battery power) the battery."""
1664
1717
  if self.charging_state:
1665
1718
  return True
1666
- check = self.attrs.get('charging', {}).get('status', {}).get('state', '')
1719
+ #check = self.attrs.get('charging', {}).get('status', {}).get('state', '')
1720
+ check = self.attrs.get('mycar',{}).get('services',{}).get('charging',{}).get('status','')
1667
1721
  if self.is_electric_climatisation_supported:
1668
- if self.electric_climatisation and check not in {'charging', 'conservation'}:
1722
+ if self.electric_climatisation and check not in {'charging','Charging', 'conservation','Conservation'}:
1669
1723
  # electric climatisation is on and car is not charging or conserving power
1670
1724
  return True
1671
1725
  return False
@@ -2921,7 +2975,8 @@ class Vehicle:
2921
2975
  @property
2922
2976
  def is_request_results_supported(self):
2923
2977
  """Request results is supported if in progress is supported."""
2924
- return self.is_request_in_progress_supported
2978
+ return False # deactivated because it provides no usefull information
2979
+ #return self.is_request_in_progress_supported
2925
2980
 
2926
2981
  @property
2927
2982
  def requests_remaining(self):
@@ -2937,8 +2992,9 @@ class Vehicle:
2937
2992
 
2938
2993
  @property
2939
2994
  def is_requests_remaining_supported(self):
2940
- if self.is_request_in_progress_supported:
2941
- return True if self._requests.get('remaining', False) else False
2995
+ return False # deactivated because it provides no usefull information
2996
+ #if self.is_request_in_progress_supported:
2997
+ # return True if self._requests.get('remaining', False) else False
2942
2998
 
2943
2999
  #### Helper functions ####
2944
3000
  def __str__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycupra
3
- Version: 0.0.13
3
+ Version: 0.0.15
4
4
  Summary: A library to read and send vehicle data via Cupra/Seat portal using the same API calls as the MyCupra/MySeat mobile app.
5
5
  Home-page: https://github.com/WulfgarW/pycupra
6
6
  Author: WulfgarW
@@ -0,0 +1,13 @@
1
+ pycupra/__init__.py,sha256=VPzUfKd5mBFD1UERNV61FbGHih5dQPupLgIfYtmIUi4,230
2
+ pycupra/__version__.py,sha256=TaiHHyrm9YZkkLYWZtVPPNSF68UvwKMIg0DY3rZCtfQ,208
3
+ pycupra/connection.py,sha256=0SA-2UcL_uJhKMfluzyw_N4ZCqmsNEg3jU18XacMm5w,82641
4
+ pycupra/const.py,sha256=mgl29DcZz_J5hSzxknteu0ocDOXmQAgP0x17kvVSSi0,10234
5
+ pycupra/dashboard.py,sha256=GNMBVJx-iF2vtmOpCJQBcyVBsKBxa049KfZDuQaimJs,43497
6
+ pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
7
+ pycupra/utilities.py,sha256=cH4MiIzT2WlHgmnl_E7rR0R5LvCXfDNvirJolct50V8,2563
8
+ pycupra/vehicle.py,sha256=dTAFaANVzXp05d3kMd8bgDmzzD-kD8Rdywdi96aG63c,135973
9
+ pycupra-0.0.15.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
10
+ pycupra-0.0.15.dist-info/METADATA,sha256=-gVU6f2phktNe1sqg4nD-h-x-iXY3z-ZdjsSz6X5oBU,2579
11
+ pycupra-0.0.15.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
12
+ pycupra-0.0.15.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
13
+ pycupra-0.0.15.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- pycupra/__init__.py,sha256=VPzUfKd5mBFD1UERNV61FbGHih5dQPupLgIfYtmIUi4,230
2
- pycupra/__version__.py,sha256=TaTBX6INREWajim6xVOUYCFZYeyoJA-OFOU2qeaT5nk,208
3
- pycupra/connection.py,sha256=_bTo1sBsUUDEf6Q8-u4H079KT_IN5sW5vlYI26ZB9mc,82423
4
- pycupra/const.py,sha256=mgl29DcZz_J5hSzxknteu0ocDOXmQAgP0x17kvVSSi0,10234
5
- pycupra/dashboard.py,sha256=FYheQ_U_mJ6BpgGq0auzcL-MsGOzSIlRo9vPvjf2pGQ,42434
6
- pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
7
- pycupra/utilities.py,sha256=cH4MiIzT2WlHgmnl_E7rR0R5LvCXfDNvirJolct50V8,2563
8
- pycupra/vehicle.py,sha256=DTbUzd31lyXON77_6no1mCrw5uajx24K5qDKA70PL9M,132533
9
- pycupra-0.0.13.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
10
- pycupra-0.0.13.dist-info/METADATA,sha256=8xEMN1iXZC6Cc5sIOp_5dkzEpN9YXhdF_YoD07cFjLs,2579
11
- pycupra-0.0.13.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
12
- pycupra-0.0.13.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
13
- pycupra-0.0.13.dist-info/RECORD,,