Skip to content

Commit f14ee9d

Browse files
author
Thomas Salm
committed
field types specified; OtaChrgCtrlStsResp init_from_dict() added #13
1 parent 260ddd1 commit f14ee9d

File tree

6 files changed

+303
-277
lines changed

6 files changed

+303
-277
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "saic_ismart_client"
7-
version = "1.6.5"
7+
version = "1.7.0"
88
authors = [
99
{ name = "Thomas Salm", email="[email protected]"},
1010
]

src/saic_ismart_client/common_model.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ def add_optional_field_to_data(self, data: dict, key: str, value) -> None:
132132
if value is not None:
133133
data[key] = value
134134

135+
@staticmethod
136+
def add_optional_bytes_field_to_data(data: dict, key: str, value: bytes | None):
137+
if value is not None:
138+
data[key] = value.decode()
139+
135140

136141
class AbstractMessageBody(Asn1Type):
137142
def __init__(self, asn_type: str):
@@ -407,7 +412,7 @@ def decode_response(self, message: str, decoded_message: MessageV1) -> None:
407412
netto_message_size = len(message[5:]) / 2 - self.header_length
408413
LOG.debug(f'Message size without header: {netto_message_size}')
409414

410-
dispatcher_message_size = header.dispatcher_message_length -self.header_length
415+
dispatcher_message_size = header.dispatcher_message_length - self.header_length
411416
LOG.debug(f'Dispatcher message bytes: {dispatcher_message_size}')
412417

413418
dispatcher_message_bytes_to_read = AbstractMessageCoder.validate_dispatcher_message_size(

src/saic_ismart_client/ota_v1_1/data_model.py

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ def init_from_dict(self, data: dict):
6464
class AlarmSwitchReq(ApplicationData):
6565
def __init__(self):
6666
super().__init__('AlarmSwitchReq')
67-
self.pin = None
68-
self.alarm_switch_list = []
69-
self.description = None
67+
self.pin: str | None = None # IA5String(SIZE(32))
68+
self.alarm_switch_list: [AlarmSwitch] = []
69+
self.description: bytes | None = None # OCTET STRING(SIZE(0..500)) OPTIONAL
7070

7171
def get_data(self) -> dict:
7272
alarm_switch_list = []
@@ -76,7 +76,7 @@ def get_data(self) -> dict:
7676
FIELD_PIN: self.pin,
7777
FIELD_ALARM_SWITCH_LIST: alarm_switch_list
7878
}
79-
self.add_optional_field_to_data(data, FIELD_DESCRIPTION, self.description)
79+
self.add_optional_bytes_field_to_data(data, FIELD_DESCRIPTION, self.description)
8080
return data
8181

8282
def init_from_dict(self, data: dict):
@@ -92,9 +92,9 @@ def init_from_dict(self, data: dict):
9292
class AlarmSwitch(Asn1Type):
9393
def __init__(self):
9494
super().__init__('AlarmSwitch')
95-
self.alarm_setting_type = None
96-
self.alarm_switch = None
97-
self.function_switch = None
95+
self.alarm_setting_type: MpAlarmSettingType | None = None
96+
self.alarm_switch: bool | None = None
97+
self.function_switch: bool | None = None
9898

9999
def get_data(self) -> dict:
100100
return {
@@ -112,28 +112,28 @@ def init_from_dict(self, data: dict):
112112
class MpUserInfoRsp(Asn1Type):
113113
def __init__(self):
114114
super().__init__('MPUserInfoResp')
115-
self.nick_name = None
116-
self.address = None
117-
self.mobile_phone = None
118-
self.emergency_name = None
119-
self.emergency_mobile = None
120-
self.user_photo = None
121-
self.gender = None
122-
self.birthday = None
123-
self.language_type = None
124-
self.real_name = None
125-
self.the_second_level_country_code = None
126-
self.the_third_level_country_code = None
127-
self.the_second_level_country_name = None
128-
self.the_third_level_country_name = None
129-
self.email = None
115+
self.nick_name: str | None = None # OCTET STRING(SIZE(1..50)) OPTIONAL
116+
self.address: str | None = None # OCTET STRING(SIZE(1..50)) OPTIONAL
117+
self.mobile_phone: str | None = None # IA5String(SIZE(1..19)) OPTIONAL
118+
self.emergency_name: str | None = None # OCTET STRING(SIZE(1..50)) OPTIONAL
119+
self.emergency_mobile: str | None = None # IA5String(SIZE(1..19)) OPTIONAL
120+
self.user_photo: str | None = None # IA5String(SIZE(1..128)) OPTIONAL
121+
self.gender: str | None = None # OCTET STRING(SIZE(1)) OPTIONAL
122+
self.birthday: str | None = None # IA5String(SIZE(8)) OPTIONAL
123+
self.language_type: int | None = None # LanguageType OPTIONAL
124+
self.real_name: str | None = None # OCTET STRING(SIZE(1..150)) OPTIONAL
125+
self.the_second_level_country_code: str | None = None # IA5String(SIZE(1..100)) OPTIONAL
126+
self.the_third_level_country_code: str | None = None # IA5String(SIZE(1..100)) OPTIONAL
127+
self.the_second_level_country_name: str | None = None # IA5String(SIZE(1..200)) OPTIONAL
128+
self.the_third_level_country_name: str | None = None # IA5String(SIZE(1..200)) OPTIONAL
129+
self.email: str | None = None # IA5String(SIZE(1..50)) OPTIONAL
130130

131131

132132
class MpUserLoggingInReq(ApplicationData):
133133
def __init__(self):
134134
super().__init__('MPUserLoggingInReq')
135-
self.password = None
136-
self.device_id = None
135+
self.password: str | None = None # IA5String(SIZE(6..30))
136+
self.device_id: str | None = None # IA5String(SIZE(1..200)) OPTIONAL
137137

138138
def get_data(self) -> dict:
139139
data = {FIELD_PASSWORD: self.password}
@@ -149,13 +149,13 @@ def init_from_dict(self, data: dict):
149149
class MpUserLoggingInRsp(ApplicationData):
150150
def __init__(self):
151151
super().__init__('MPUserLoggingInResp')
152-
self.token = None
153-
self.refresh_token = None
154-
self.token_expiration = None
155-
self.vin_list = []
156-
self.user_photo = None
157-
self.user_name = None
158-
self.language_type = None
152+
self.token: str | None = None # IA5String(SIZE(40)) OPTIONAL
153+
self.refresh_token: str | None = None # IA5String(SIZE(40)) OPTIONAL
154+
self.token_expiration: Timestamp | None = None
155+
self.vin_list: [VinInfo] = []
156+
self.user_photo: str | None = None # IA5String(SIZE(1..128)) OPTIONAL
157+
self.user_name: str | None = None # IA5String(SIZE(8..12))
158+
self.language_type: int | None = None
159159

160160
def get_data(self) -> dict:
161161
data = {
@@ -195,7 +195,7 @@ def init_from_dict(self, data: dict):
195195
class Timestamp(Asn1Type):
196196
def __init__(self):
197197
super().__init__('Timestamp')
198-
self.seconds = -1
198+
self.seconds: int = -1 # INTEGER(0..4294967295)
199199

200200
def get_data(self) -> dict:
201201
return {
@@ -212,50 +212,50 @@ def get_timestamp(self) -> datetime:
212212
class AppUpgradeInfoReq(Asn1Type):
213213
def __init__(self):
214214
super().__init__('APPUpgradeInfoReq')
215-
self.app_type = None
216-
self.app_version = None
215+
self.app_type = None # APPType
216+
self.app_version: str | None = None # IA5String(SIZE(1..50))
217217

218218

219219
class AppUpgradeInfoRsp(Asn1Type):
220220
def __init__(self):
221221
super().__init__('APPUpgradeInfoResp')
222-
self.has_new_version = None
223-
self.app_version = None
224-
self.force_update = None
225-
self.update_url = None
226-
self.update_info_en = None
227-
self.update_info_th = None
222+
self.has_new_version: bool | None = None # BOOLEAN
223+
self.app_version: str | None = None # IA5String(SIZE(1..50)) OPTIONAL
224+
self.force_update: bool | None = None # BOOLEAN OPTIONAL
225+
self.update_url: str | None = None # IA5String(SIZE(1..200)) OPTIONAL
226+
self.update_info_en: bytes | None = None # OCTET STRING(SIZE(1..500)) OPTIONAL
227+
self.update_info_th: bytes | None = None # OCTET STRING(SIZE(1..500)) OPTIONAL
228228

229229

230230
class MpAppAttributeRsp(Asn1Type):
231231
def __init__(self):
232232
super().__init__('MPAppAttributeResp')
233-
self.data_app_attribute = None
233+
self.data_app_attribute: str | None = None # IA5String(SIZE(1..65535)) OPTIONAL
234234

235235

236236
class AdvertiseRsp(Asn1Type):
237237
def __init__(self):
238238
super().__init__('AdvertiseResp')
239-
self.advertise_version = None
240-
self.advertises = []
239+
self.advertise_version: int | None = None # INTEGER(0..281474976710655) OPTIONAL
240+
self.advertises = [] # SEQUENCE SIZE(0..255) OF Advertise OPTIONAL
241241

242242

243243
class VinInfo(Asn1Type):
244244
def __init__(self):
245245
super().__init__('VinInfo')
246-
self.vin = None
247-
self.name = None
248-
self.series = None
249-
self.brand_name = None
250-
self.model_name = None
251-
self.vehicle_photo = None
252-
self.active = None
253-
self.current_vehicle = None
254-
self.model_year = None
255-
self.color_name = None
256-
self.model_configuration_json_str = None
257-
self.bind_time = None
258-
self.tbox_sim_no = None
246+
self.vin: str | None = None # IA5String(SIZE(17))
247+
self.name: bytes | None = None # OCTET STRING(SIZE(1..128)) OPTIONAL
248+
self.series: str | None = None # IA5String(SIZE(1..10))
249+
self.brand_name: bytes | None = None # OCTET STRING(SIZE(1..24))
250+
self.model_name: bytes | None = None # OCTET STRING(SIZE(1..100))
251+
self.vehicle_photo: str | None = None # IA5String(SIZE(1..128)) OPTIONAL
252+
self.active: bool | None = None # BOOLEAN
253+
self.current_vehicle: int | None = None # INTEGER(0..10) OPTIONAL
254+
self.model_year: str | None = None # IA5String(SIZE(4)) OPTIONAL
255+
self.color_name: bytes | None = None # OCTET STRING(SIZE(1..50)) OPTIONAL
256+
self.model_configuration_json_str: str | None = None # IA5String(SIZE(1..1024)) OPTIONAL
257+
self.bind_time: Timestamp | None = None
258+
self.tbox_sim_no: str | None = None # IA5String(SIZE(19)) OPTIONAL
259259

260260
def get_data(self) -> dict:
261261
data = {
@@ -265,29 +265,34 @@ def get_data(self) -> dict:
265265
FIELD_MODEL_NAME: self.model_name,
266266
FIELD_ACTIVE: self.active
267267
}
268-
self.add_optional_field_to_data(data, FIELD_NAME, self.name)
268+
VinInfo.add_optional_bytes_field_to_data(data, FIELD_NAME, self.name)
269269
self.add_optional_field_to_data(data, FIELD_VEHICLE_PHOTO, self.vehicle_photo)
270270
self.add_optional_field_to_data(data, FIELD_CURRENT_VEHICLE, self.current_vehicle)
271271
self.add_optional_field_to_data(data, FIELD_MODEL_YEAR, self.model_year)
272-
self.add_optional_field_to_data(data, FIELD_COLOR_NAME, self.color_name)
272+
VinInfo.add_optional_bytes_field_to_data(data, FIELD_COLOR_NAME, self.color_name)
273273
self.add_optional_field_to_data(data, FIELD_MODEL_CONF_JSON, self.model_configuration_json_str)
274274
self.add_optional_field_to_data(data, FIELD_BIND_TIME, self.bind_time)
275275
self.add_optional_field_to_data(data, FIELD_TBOX_SIM_NO, self.tbox_sim_no)
276276
return data
277277

278278
def init_from_dict(self, data: dict):
279279
self.vin = data.get(FIELD_VIN)
280-
self.name = data.get(FIELD_NAME)
280+
if FIELD_NAME in data:
281+
self.name = data.get(FIELD_NAME)
281282
self.series = data.get(FIELD_SERIES)
282283
self.brand_name = data.get(FIELD_BRAND_NAME)
283284
self.model_name = data.get(FIELD_MODEL_NAME)
284285
self.vehicle_photo = data.get(FIELD_VEHICLE_PHOTO)
285286
self.active = data.get(FIELD_ACTIVE)
286287
self.current_vehicle = data.get(FIELD_CURRENT_VEHICLE)
287288
self.model_year = data.get(FIELD_MODEL_YEAR)
288-
self.color_name = data.get(FIELD_COLOR_NAME)
289+
if FIELD_COLOR_NAME in data:
290+
self.color_name = data.get(FIELD_COLOR_NAME)
289291
self.model_configuration_json_str = data.get(FIELD_MODEL_CONF_JSON)
290-
self.bind_time = data.get(FIELD_BIND_TIME)
292+
if FIELD_BIND_TIME in data:
293+
timestamp = Timestamp()
294+
timestamp.init_from_dict(data.get(FIELD_BIND_TIME))
295+
self.bind_time = timestamp
291296
self.tbox_sim_no = data.get(FIELD_TBOX_SIM_NO)
292297

293298

@@ -304,8 +309,8 @@ class MpAlarmSettingType(Enum):
304309
class MessageListReq(ApplicationData):
305310
def __init__(self):
306311
super().__init__('MessageListReq')
307-
self.start_end_number = None
308-
self.message_group = None
312+
self.start_end_number: StartEndNumber | None = None
313+
self.message_group: str | None = None
309314

310315
def get_data(self) -> dict:
311316
data = {
@@ -322,9 +327,9 @@ def init_from_dict(self, data: dict):
322327
class AbortSendMessageReq(ApplicationData):
323328
def __init__(self):
324329
super().__init__('AbortSendMessageReq')
325-
self.messages = [] # SEQUENCE SIZE(1..256) OF Message OPTIONAL
326-
self.message_id = -1 # INTEGER(0..281474976710655) OPTIONAL
327-
self.action_type = '' # IA5String(SIZE(1..20)) OPTIONAL
330+
self.messages: [Message] = [] # SEQUENCE SIZE(1..256) OF Message OPTIONAL
331+
self.message_id: int = -1 # INTEGER(0..281474976710655) OPTIONAL
332+
self.action_type: str | None = None # IA5String(SIZE(1..20)) OPTIONAL
328333

329334
def get_data(self) -> dict:
330335
data = {}
@@ -335,7 +340,7 @@ def get_data(self) -> dict:
335340
data[FIELD_MESSAGES] = message_list
336341
if self.message_id != -1:
337342
data[FIELD_MESSAGE_ID] = self.message_id
338-
if len(self.action_type) > 0:
343+
if self.action_type:
339344
data[FIELD_ACTION_TYPE] = self.action_type
340345
return data
341346

@@ -354,21 +359,21 @@ def init_from_dict(self, data: dict):
354359
class Message(Asn1Type):
355360
def __init__(self):
356361
super().__init__('Message')
357-
self.message_id = None
358-
self.message_type = None
359-
self.title = None
360-
self.message_time = None
361-
self.sender = None
362-
self.content_id_list = None
363-
self.content = None
364-
self.read_status = None
365-
self.vin = None
362+
self.message_id: int | None = None # INTEGER(0..281474976710655)
363+
self.message_type: str | None = None # IA5String(SIZE(3))
364+
self.title: str | None = None # OCTET STRING(SIZE(1..128))
365+
self.message_time: Timestamp | None = None
366+
self.sender: str | None = None # OCTET STRING(SIZE(1..64))
367+
self.content_id_list: [ContentId] = []
368+
self.content: str | None = None # OCTET STRING(SIZE(1..2048)) OPTIONAL
369+
self.read_status: int | None = None # INTEGER(-128..128) OPTIONAL
370+
self.vin: str | None = None # IA5String(SIZE(17)) OPTIONAL
366371

367372
def get_data(self) -> dict:
368373
data = {
369374
FIELD_MESSAGE_ID: self.message_id,
370375
FIELD_MESSAGE_TYPE: self.message_type,
371-
FIELD_TITLE: self.title.decode(),
376+
FIELD_TITLE: self.title,
372377
FIELD_MESSAGE_TIME: self.message_time.get_data(),
373378
FIELD_SENDER: self.sender
374379
}
@@ -385,25 +390,26 @@ def get_data(self) -> dict:
385390
def init_from_dict(self, data: dict):
386391
self.message_id = data.get(FIELD_MESSAGE_ID)
387392
self.message_type = data.get(FIELD_MESSAGE_TYPE)
388-
self.title = data.get(FIELD_TITLE)
393+
self.title = data.get(FIELD_TITLE).decode()
389394
self.message_time = Timestamp()
390395
self.message_time.init_from_dict(data.get(FIELD_MESSAGE_TIME))
391-
self.sender = data.get(FIELD_SENDER)
396+
self.sender = data.get(FIELD_SENDER).decode()
392397
if FIELD_CONTENT_ID in data:
393-
self.content_id_list = []
394398
for item in data.get(FIELD_CONTENT_ID):
395399
content_id = ContentId()
396400
content_id.init_from_dict(item)
397401
self.content_id_list.append(content_id)
402+
if FIELD_CONTENT in data:
403+
self.content = data[FIELD_CONTENT].decode()
398404
self.read_status = data.get(FIELD_READ_STATUS)
399405
self.vin = data.get(FIELD_VIN)
400406

401407

402408
class MessageListResp(ApplicationData):
403409
def __init__(self):
404410
super().__init__('MessageListResp')
405-
self.records_number = 0
406-
self.messages = []
411+
self.records_number: int = 0 # INTEGER(0..281474976710655)
412+
self.messages: [Message] = []
407413

408414
def get_data(self) -> dict:
409415
messages = []
@@ -431,8 +437,8 @@ def add_message(self, message: Message):
431437
class StartEndNumber(Asn1Type):
432438
def __init__(self):
433439
super().__init__('StartEndNumber')
434-
self.start_number = None
435-
self.end_number = None
440+
self.start_number: int = -1 # INTEGER(0..281474976710655)
441+
self.end_number: int = -1 # INTEGER(0..281474976710655)
436442

437443
def get_data(self) -> dict:
438444
return {
@@ -448,15 +454,20 @@ def init_from_dict(self, data: dict):
448454
class ContentId(Asn1Type):
449455
def __init__(self):
450456
super().__init__('ContentId')
451-
self.content_id = None
457+
self.content_id = None # INTEGER(0..281474976710655)
458+
self.description: str | None = None # OCTET STRING(SIZE(1..255)) OPTIONAL
452459

453460
def get_data(self) -> dict:
454-
return {
461+
data = {
455462
FIELD_CONTENT_ID: self.content_id
456463
}
464+
self.add_optional_field_to_data(data, FIELD_DESCRIPTION, self.description)
465+
return data
457466

458467
def init_from_dict(self, data: dict):
459468
self.content_id = data.get(FIELD_CONTENT_ID)
469+
if FIELD_DESCRIPTION in data:
470+
self.description = data.get(FIELD_DESCRIPTION).decode()
460471

461472

462473
class MessageV11(MessageV1):

0 commit comments

Comments
 (0)