mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-02-19 00:43:54 +08:00
This reverts commit 6d04251517.
This commit is contained in:
@@ -65,6 +65,10 @@ class ThermalConfig:
|
||||
return ret
|
||||
|
||||
class LPABase(ABC):
|
||||
@abstractmethod
|
||||
def bootstrap(self) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def list_profiles(self) -> list[Profile]:
|
||||
pass
|
||||
@@ -73,6 +77,10 @@ class LPABase(ABC):
|
||||
def get_active_profile(self) -> Profile | None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_profile(self, iccid: str) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def download_profile(self, qr: str, nickname: str | None = None) -> None:
|
||||
pass
|
||||
@@ -85,6 +93,9 @@ class LPABase(ABC):
|
||||
def switch_profile(self, iccid: str) -> None:
|
||||
pass
|
||||
|
||||
def is_comma_profile(self, iccid: str) -> bool:
|
||||
return any(iccid.startswith(prefix) for prefix in ('8985235',))
|
||||
|
||||
class HardwareBase(ABC):
|
||||
@staticmethod
|
||||
def get_cmdline() -> dict[str, str]:
|
||||
|
||||
@@ -3,21 +3,55 @@
|
||||
import argparse
|
||||
import time
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.hardware.base import LPABase
|
||||
|
||||
|
||||
def bootstrap(lpa: LPABase) -> None:
|
||||
print('┌──────────────────────────────────────────────────────────────────────────────┐')
|
||||
print('│ WARNING, PLEASE READ BEFORE PROCEEDING │')
|
||||
print('│ │')
|
||||
print('│ this is an irreversible operation that will remove the comma-provisioned │')
|
||||
print('│ profile. │')
|
||||
print('│ │')
|
||||
print('│ after this operation, you must purchase a new eSIM from comma in order to │')
|
||||
print('│ use the comma prime subscription again. │')
|
||||
print('└──────────────────────────────────────────────────────────────────────────────┘')
|
||||
print()
|
||||
for severity in ('sure', '100% sure'):
|
||||
print(f'are you {severity} you want to proceed? (y/N) ', end='')
|
||||
confirm = input()
|
||||
if confirm != 'y':
|
||||
print('aborting')
|
||||
exit(0)
|
||||
lpa.bootstrap()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(prog='esim.py', description='manage eSIM profiles on your comma device', epilog='comma.ai')
|
||||
parser.add_argument('--bootstrap', action='store_true', help='bootstrap the eUICC (required before downloading profiles)')
|
||||
parser.add_argument('--backend', choices=['qmi', 'at'], default='qmi', help='use the specified backend, defaults to qmi')
|
||||
parser.add_argument('--switch', metavar='iccid', help='switch to profile')
|
||||
parser.add_argument('--delete', metavar='iccid', help='delete profile (warning: this cannot be undone)')
|
||||
parser.add_argument('--download', nargs=2, metavar=('qr', 'name'), help='download a profile using QR code (format: LPA:1$rsp.truphone.com$QRF-SPEEDTEST)')
|
||||
parser.add_argument('--nickname', nargs=2, metavar=('iccid', 'name'), help='update the nickname for a profile')
|
||||
args = parser.parse_args()
|
||||
|
||||
mutated = False
|
||||
lpa = HARDWARE.get_sim_lpa()
|
||||
if args.switch:
|
||||
if args.bootstrap:
|
||||
bootstrap(lpa)
|
||||
mutated = True
|
||||
elif args.switch:
|
||||
lpa.switch_profile(args.switch)
|
||||
mutated = True
|
||||
elif args.delete:
|
||||
confirm = input('are you sure you want to delete this profile? (y/N) ')
|
||||
if confirm == 'y':
|
||||
lpa.delete_profile(args.delete)
|
||||
mutated = True
|
||||
else:
|
||||
print('cancelled')
|
||||
exit(0)
|
||||
elif args.download:
|
||||
lpa.download_profile(args.download[0], args.download[1])
|
||||
elif args.nickname:
|
||||
|
||||
@@ -31,7 +31,16 @@ class TiciLPA(LPABase):
|
||||
def get_active_profile(self) -> Profile | None:
|
||||
return next((p for p in self.list_profiles() if p.enabled), None)
|
||||
|
||||
def delete_profile(self, iccid: str) -> None:
|
||||
self._validate_profile_exists(iccid)
|
||||
latest = self.get_active_profile()
|
||||
if latest is not None and latest.iccid == iccid:
|
||||
raise LPAError('cannot delete active profile, switch to another profile first')
|
||||
self._validate_successful(self._invoke('profile', 'delete', iccid))
|
||||
self._process_notifications()
|
||||
|
||||
def download_profile(self, qr: str, nickname: str | None = None) -> None:
|
||||
self._check_bootstrapped()
|
||||
msgs = self._invoke('profile', 'download', '-a', qr)
|
||||
self._validate_successful(msgs)
|
||||
new_profile = next((m for m in msgs if m['payload']['message'] == 'es8p_meatadata_parse'), None)
|
||||
@@ -46,6 +55,7 @@ class TiciLPA(LPABase):
|
||||
self._validate_successful(self._invoke('profile', 'nickname', iccid, nickname))
|
||||
|
||||
def switch_profile(self, iccid: str) -> None:
|
||||
self._check_bootstrapped()
|
||||
self._validate_profile_exists(iccid)
|
||||
latest = self.get_active_profile()
|
||||
if latest and latest.iccid == iccid:
|
||||
@@ -53,10 +63,33 @@ class TiciLPA(LPABase):
|
||||
self._validate_successful(self._invoke('profile', 'enable', iccid))
|
||||
self._process_notifications()
|
||||
|
||||
def bootstrap(self) -> None:
|
||||
"""
|
||||
find all comma-provisioned profiles and delete them. they conflict with user-provisioned profiles
|
||||
and must be deleted.
|
||||
|
||||
**note**: this is a **very** destructive operation. you **must** purchase a new comma SIM in order
|
||||
to use comma prime again.
|
||||
"""
|
||||
if self._is_bootstrapped():
|
||||
return
|
||||
|
||||
for p in self.list_profiles():
|
||||
if self.is_comma_profile(p.iccid):
|
||||
self._disable_profile(p.iccid)
|
||||
self.delete_profile(p.iccid)
|
||||
|
||||
def _disable_profile(self, iccid: str) -> None:
|
||||
self._validate_successful(self._invoke('profile', 'disable', iccid))
|
||||
self._process_notifications()
|
||||
|
||||
def _check_bootstrapped(self) -> None:
|
||||
assert self._is_bootstrapped(), 'eUICC is not bootstrapped, please bootstrap before performing this operation'
|
||||
|
||||
def _is_bootstrapped(self) -> bool:
|
||||
""" check if any comma provisioned profiles are on the eUICC """
|
||||
return not any(self.is_comma_profile(iccid) for iccid in (p.iccid for p in self.list_profiles()))
|
||||
|
||||
def _invoke(self, *cmd: str):
|
||||
proc = subprocess.Popen(['sudo', '-E', 'lpac'] + list(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.env)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user