pycupra 0.0.11__tar.gz → 0.0.12__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.
@@ -6,4 +6,5 @@ dist/
6
6
  __pycache__/
7
7
  *.json
8
8
  *.txt
9
+ *.log
9
10
  www/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycupra
3
- Version: 0.0.11
3
+ Version: 0.0.12
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
@@ -48,6 +48,7 @@ RESOURCES = [
48
48
  "charging",
49
49
  "charge_rate",
50
50
  "charging_power",
51
+ "charging_state",
51
52
  "charging_cable_connected",
52
53
  "charging_cable_locked",
53
54
  "charging_time_left",
@@ -70,7 +71,7 @@ RESOURCES = [
70
71
  "door_locked",
71
72
  "electric_climatisation",
72
73
  "electric_range",
73
- "energy_flow",
74
+ #"energy_flow",
74
75
  "external_power",
75
76
  "fuel_level",
76
77
  "hood_closed",
@@ -204,9 +205,28 @@ async def demo_set_timer_schedule(vehicle):
204
205
  print(" Request failed.")
205
206
  return success
206
207
 
208
+ async def demo_set_departure_profile_schedule(vehicle):
209
+ print('########################################')
210
+ print('# Change one departure profile #')
211
+ print('########################################')
212
+ success= await vehicle.set_departure_profile_schedule(id = 3, # id = 1, 2, 3
213
+ schedule = { # Set the departure time, date and periodicity
214
+ "enabled": True, # Set the timer active or not, True or False, required
215
+ "recurring": True, # True or False for recurring, required
216
+ "time": "12:34", # Time for departure, required
217
+ "days": "nyynnnn", # Days (mon-sun) for recurring schedule (n=disable, y=enable), required if recurring=True
218
+ "chargingProgramId": 2, # Id of the charging program to be used for the departure profile
219
+ }
220
+ )
221
+ if success:
222
+ print(" Request completed successfully.")
223
+ else:
224
+ print(" Request failed.")
225
+ return success
226
+
207
227
  async def demo_set_timer_active(vehicle, id=1, action="off"):
208
228
  print('########################################')
209
- print('# Active/Deactivate one timer #')
229
+ print('# (De-)Activate one timer #')
210
230
  print('########################################')
211
231
  success= await vehicle.set_timer_active(id, action) # id = 1, 2, 3, action = "on" or "off".
212
232
  if success:
@@ -215,6 +235,17 @@ async def demo_set_timer_active(vehicle, id=1, action="off"):
215
235
  print(" Request failed.")
216
236
  return success
217
237
 
238
+ async def demo_set_departure_profile_active(vehicle, id=1, action="off"):
239
+ print('########################################')
240
+ print('# (De-)Activate one departure profile #')
241
+ print('########################################')
242
+ success= await vehicle.set_departure_profile_active(id, action) # id = 1, 2, 3, action = "on" or "off".
243
+ if success:
244
+ print(" Request completed successfully.")
245
+ else:
246
+ print(" Request failed.")
247
+ return success
248
+
218
249
  async def demo_set_charge_limit(vehicle, limit=30):
219
250
  print('########################################')
220
251
  print('# Change minimum charge limit #')
@@ -502,6 +533,9 @@ async def main():
502
533
  #await demo_set_timer_active(vehicle, id=3, action="off") # id = 1, 2, 3, action = "on" or "off".
503
534
  #await demo_set_charge_limit(vehicle, 30) # limit = PHEV: 0/10/20/30/40/50, EV: 50/60/70/80/90/100
504
535
 
536
+ #await demo_set_departure_profile_schedule(vehicle) # arguments id and schedule can be found in the demo function
537
+ #await demo_set_departure_profile_active(vehicle, id=3, action="off") # id = 1, 2, 3, action = "on" or "off".
538
+
505
539
  #await demo_set_lock(vehicle,action = "lock",
506
540
  # spin = credentials.get('spin','')) # action = "unlock" or "lock". spin = SPIN, needed for both
507
541
 
@@ -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.11"
6
+ __version__ = "0.0.12"
@@ -1284,6 +1284,11 @@ def create_instruments():
1284
1284
  name="Energy flow",
1285
1285
  device_class="power"
1286
1286
  ),
1287
+ BinarySensor(
1288
+ attr="charging_state",
1289
+ name="Charging state",
1290
+ device_class="power"
1291
+ ),
1287
1292
  BinarySensor(
1288
1293
  attr="parking_light",
1289
1294
  name="Parking light",
@@ -471,7 +471,7 @@ class Vehicle:
471
471
  raise SeatInvalidRequestException('Departure timers are not supported.')
472
472
 
473
473
  async def set_timer_schedule(self, id, schedule={}):
474
- """ Set departure schedules. """
474
+ """ Set departure timer schedule. """
475
475
  data = {}
476
476
  # Validate required user inputs
477
477
  supported = "is_departure" + str(id) + "_supported"
@@ -518,7 +518,7 @@ class Vehicle:
518
518
  if not 16 <= int(schedule.get("targetTemp", None)) <= 30:
519
519
  raise SeatInvalidRequestException('Target temp must be integer value from 16 to 30')
520
520
  else:
521
- data['temp'] = schedule.get('targetTemp')
521
+ data['temp'] = int(schedule.get('targetTemp'))
522
522
  raise SeatInvalidRequestException('Target temp (yet) not supported.')
523
523
 
524
524
  # Validate charge target and current
@@ -666,6 +666,98 @@ class Vehicle:
666
666
  self._requests['departuretimer'] = {'status': 'Exception'}
667
667
  raise SeatException('Failed to set departure timer schedule')
668
668
 
669
+ async def set_departure_profile_schedule(self, id, schedule={}):
670
+ """ Set departure profile schedule. """
671
+ data = {}
672
+ # Validate required user inputs
673
+ supported = "is_departure_profile" + str(id) + "_supported"
674
+ if getattr(self, supported) is not True:
675
+ raise SeatConfigException(f'Departure profile id {id} is not supported for this vehicle.')
676
+ else:
677
+ _LOGGER.debug(f'Departure profile id {id} is supported')
678
+ if not schedule:
679
+ raise SeatInvalidRequestException('A schedule must be set.')
680
+ if not isinstance(schedule.get('enabled', ''), bool):
681
+ raise SeatInvalidRequestException('The enabled variable must be set to True or False.')
682
+ if not isinstance(schedule.get('recurring', ''), bool):
683
+ raise SeatInvalidRequestException('The recurring variable must be set to True or False.')
684
+ if not re.match('^[0-9]{2}:[0-9]{2}$', schedule.get('time', '')):
685
+ raise SeatInvalidRequestException('The time for departure must be set in 24h format HH:MM.')
686
+
687
+ # Validate optional inputs
688
+ if schedule.get('recurring', False):
689
+ if not re.match('^[yn]{7}$', schedule.get('days', '')):
690
+ raise SeatInvalidRequestException('For recurring schedules the days variable must be set to y/n mask (mon-sun with only wed enabled): nnynnnn.')
691
+ elif not schedule.get('recurring'):
692
+ if not re.match('^[0-9]{4}-[0-9]{2}-[0-9]{2}$', schedule.get('date', '')):
693
+ raise SeatInvalidRequestException('For single departure profile schedule the date variable must be set to YYYY-mm-dd.')
694
+
695
+ if self._relevantCapabilties.get('departureProfiles', {}).get('active', False):
696
+ # Check if profileIds is set and correct
697
+ if schedule.get('chargingProgramId', False):
698
+ # At the moment, only one charging program id is supported
699
+ chargingProgramId = int(schedule.get('chargingProgramId', False))
700
+ found = False
701
+ for chargingProgram in self.attrs.get('departureProfiles', {}).get('profileIds', []):
702
+ if chargingProgram.get('id',None) == chargingProgramId:
703
+ found = True
704
+ break
705
+ if not found:
706
+ raise SeatInvalidRequestException('The charging program id provided for the departure profile schedule is unknown.')
707
+ else:
708
+ profileIds = []
709
+ profileIds.append(chargingProgramId)
710
+ else:
711
+ raise SeatInvalidRequestException('No charging program id provided for departure profile schedule.')
712
+
713
+ newDepProfileSchedule = {}
714
+ # Prepare data and execute
715
+ newDepProfileSchedule['id'] = id
716
+ # Converting schedule to data map
717
+ if schedule.get("enabled",False):
718
+ newDepProfileSchedule['enabled']=True
719
+ else:
720
+ newDepProfileSchedule['enabled']=False
721
+ if schedule.get("recurring",False):
722
+ newDepProfileSchedule['recurringTimer']= {
723
+ "startTime": schedule.get('time',"00:00"),
724
+ "recurringOn":{""
725
+ "mondays":(schedule.get('days',"nnnnnnn")[0]=='y'),
726
+ "tuesdays":(schedule.get('days',"nnnnnnn")[1]=='y'),
727
+ "wednesdays":(schedule.get('days',"nnnnnnn")[2]=='y'),
728
+ "thursdays":(schedule.get('days',"nnnnnnn")[3]=='y'),
729
+ "fridays":(schedule.get('days',"nnnnnnn")[4]=='y'),
730
+ "saturdays":(schedule.get('days',"nnnnnnn")[5]=='y'),
731
+ "sundays":(schedule.get('days',"nnnnnnn")[6]=='y'),
732
+ }
733
+ }
734
+ else:
735
+ if self._relevantCapabilties.get('departureProfiles', {}).get('supportsSingleTimer', False):
736
+ startDateTime = datetime.fromisoformat(schedule.get('date',"2025-01-01")+'T'+schedule.get('time',"00:00"))
737
+ _LOGGER.info(f'startDateTime={startDateTime.isoformat()}')
738
+ newDepProfileSchedule['singleTimer']= {
739
+ "startDateTimeLocal": startDateTime.isoformat(),
740
+ }
741
+ else:
742
+ raise SeatInvalidRequestException('Vehicle does not support single timer.')
743
+ newDepProfileSchedule["profileIds"]= profileIds
744
+
745
+ # Now we have to substitute the current departure profile schedule with the given id by the new one
746
+ data= deepcopy(self.attrs.get('departureProfiles'))
747
+ if len(data.get('timers', []))<1:
748
+ raise SeatInvalidRequestException(f'No timers found in departure profile: {data}.')
749
+ idFound=False
750
+ for e in range(len(data.get('timers', []))):
751
+ if data['timers'][e].get('id',-1)==id:
752
+ data['timers'][e] = newDepProfileSchedule
753
+ idFound=True
754
+ if idFound:
755
+ return await self._set_departure_profiles(data, action='set')
756
+ raise SeatInvalidRequestException(f'Departure profile id {id} not found in {data.get('timers',[])}.')
757
+ else:
758
+ _LOGGER.info('Departure profiles are not supported.')
759
+ raise SeatInvalidRequestException('Departure profiles are not supported.')
760
+
669
761
  async def set_departure_profile_active(self, id=1, action='off'):
670
762
  """ Activate/deactivate departure profiles. """
671
763
  data = {}
@@ -1552,18 +1644,22 @@ class Vehicle:
1552
1644
  return True
1553
1645
 
1554
1646
  @property
1555
- def energy_flow(self):
1556
- """Return true if energy is flowing through charging port."""
1557
- check = self.attrs.get('charger', {}).get('status', {}).get('chargingStatusData', {}).get('energyFlow', {}).get('content', 'off')
1558
- if check == 'on':
1647
+ #def energy_flow(self):
1648
+ # """Return true if energy is flowing through charging port."""
1649
+ def charging_state(self):
1650
+ """Return true if vehicle is charging."""
1651
+ check = self.attrs.get('charging', {}).get('status', {}).get('state', '')
1652
+ if check == 'charging':
1559
1653
  return True
1560
1654
  else:
1561
1655
  return False
1562
1656
 
1563
1657
  @property
1564
- def is_energy_flow_supported(self):
1565
- """Energy flow supported."""
1566
- if self.attrs.get('charger', {}).get('status', {}).get('chargingStatusData', {}).get('energyFlow', False):
1658
+ #def is_energy_flow_supported(self):
1659
+ # """Energy flow supported."""
1660
+ def is_charging_state_supported(self):
1661
+ """Charging state supported."""
1662
+ if self.attrs.get('charging', {}).get('status', {}).get('state', False):
1567
1663
  return True
1568
1664
 
1569
1665
  # Vehicle location states
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycupra
3
- Version: 0.0.11
3
+ Version: 0.0.12
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes