Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 69dd8b5

Browse files
author
Islam Wahdan
authored
Merge pull request #352 from pycom/release-pybytes-library-1.2.0
feat: Pybytes library release 1.2.0
2 parents 3138a13 + 42847bc commit 69dd8b5

File tree

5 files changed

+159
-62
lines changed

5 files changed

+159
-62
lines changed

.gitignore

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*.dis
1010
*.exe
1111

12-
# Packages
12+
# Packages
1313
############
1414

1515
# Logs and Databases
@@ -50,8 +50,9 @@ secure_boot_signing_key.pem
5050
signature_verification_key.bin
5151
secure-bootloader-key.bin
5252
flash_encryption_key.bin
53-
53+
5454
.DS_Store
5555
org.eclipse.cdt.ui.prefs
5656
org.eclipse.cdt.core.prefs
5757
language.settings.xml
58+
.idea

esp32/frozen/Pybytes/_OTA.py

+45-35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
see the Pycom Licence v1.0 document supplied with this file, or
66
available at https://www.pycom.io/opensource/licensing
77
'''
8+
try:
9+
from pybytes_debug import print_debug
10+
except:
11+
from _pybytes_debug import print_debug
812

913
import network
1014
import socket
@@ -56,9 +60,9 @@ def get_update_manifest(self):
5660
gc.collect()
5761
return manifest
5862

59-
def update(self):
63+
def update(self, customManifest=None):
6064
try:
61-
manifest = self.get_update_manifest()
65+
manifest = self.get_update_manifest() if not customManifest else customManifest
6266
except Exception as e:
6367
print('Error reading the manifest, aborting: {}'.format(e))
6468
return 0
@@ -68,36 +72,38 @@ def update(self):
6872
return 1
6973

7074
# Download new files and verify hashes
71-
for f in manifest['new'] + manifest['update']:
72-
# Upto 5 retries
73-
for _ in range(5):
74-
try:
75-
self.get_file(f)
76-
break
77-
except Exception as e:
78-
print(e)
79-
msg = "Error downloading `{}` retrying..."
80-
print(msg.format(f['URL']))
81-
return 0
82-
else:
83-
raise Exception("Failed to download `{}`".format(f['URL']))
84-
85-
# Backup old files
86-
# only once all files have been successfully downloaded
87-
for f in manifest['update']:
88-
self.backup_file(f)
89-
90-
# Rename new files to proper name
91-
for f in manifest['new'] + manifest['update']:
92-
new_path = "{}.new".format(f['dst_path'])
93-
dest_path = "{}".format(f['dst_path'])
94-
95-
os.rename(new_path, dest_path)
96-
97-
# `Delete` files no longer required
98-
# This actually makes a backup of the files incase we need to roll back
99-
for f in manifest['delete']:
100-
self.delete_file(f)
75+
if "new" in manifest and "update" in manifest:
76+
for f in manifest['new'] + manifest['update']:
77+
# Upto 5 retries
78+
for _ in range(5):
79+
try:
80+
self.get_file(f)
81+
break
82+
except Exception as e:
83+
print(e)
84+
msg = "Error downloading `{}` retrying..."
85+
print(msg.format(f['URL']))
86+
return 0
87+
else:
88+
raise Exception("Failed to download `{}`".format(f['URL']))
89+
90+
# Backup old files
91+
# only once all files have been successfully downloaded
92+
for f in manifest['update']:
93+
self.backup_file(f)
94+
95+
# Rename new files to proper name
96+
for f in manifest['new'] + manifest['update']:
97+
new_path = "{}.new".format(f['dst_path'])
98+
dest_path = "{}".format(f['dst_path'])
99+
100+
os.rename(new_path, dest_path)
101+
102+
if "delete" in manifest:
103+
# `Delete` files no longer required
104+
# This actually makes a backup of the files incase we need to roll back
105+
for f in manifest['delete']:
106+
self.delete_file(f)
101107

102108
# Flash firmware
103109
if "firmware" in manifest:
@@ -162,9 +168,12 @@ def delete_file(self, f):
162168
os.rename(dest_path, bak_path)
163169

164170
def write_firmware(self, f):
165-
hash = self.get_data(f['URL'].split("/", 3)[-1],
166-
hash=True,
167-
firmware=True)
171+
# hash =
172+
self.get_data(
173+
f['URL'].split("/", 3)[-1],
174+
hash=True,
175+
firmware=True
176+
)
168177
# TODO: Add verification when released in future firmware
169178

170179

@@ -258,6 +267,7 @@ def get_data(self, req, dest_path=None, hash=False, firmware=False):
258267
if fp is not None:
259268
fp.close()
260269
if firmware:
270+
print_debug(6, 'ota_finish')
261271
pycom.ota_finish()
262272

263273
except Exception as e:

esp32/frozen/Pybytes/_pybytes_constants.py

+4
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,7 @@ class constants:
129129
__DEFAULT_PYCONFIG_DOMAIN = pycom.nvs_get('pyconfig_host', 'pyconfig.eu-central-1.elasticbeanstalk.com')
130130
except:
131131
__DEFAULT_PYCONFIG_DOMAIN = 'pyconfig.eu-central-1.elasticbeanstalk.com'
132+
try:
133+
__DEFAULT_PYCONFIG_PROTOCOL = pycom.nvs_get('pyconfig_protocol', 'https')
134+
except:
135+
__DEFAULT_PYCONFIG_PROTOCOL = "https"

esp32/frozen/Pybytes/_pybytes_protocol.py

+106-24
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ def __send_terminal_message(self, data):
496496

497497
def enable_terminal(self):
498498
self.__terminal_enabled = True
499-
#os.dupterm(self.__terminal)
499+
# os.dupterm(self.__terminal)
500500

501501
def __send_pybytes_message(self, command, pin_number, value):
502502
self.__send_message(
@@ -522,14 +522,28 @@ def __send_pybytes_message_variable(
522522
def set_battery_level(self, battery_level):
523523
self.__battery_level = battery_level
524524

525-
def deploy_new_release(self, body):
526-
application = self.__conf.get('application')
527-
try:
528-
body = ujson.loads(body.decode())
529-
except Exception as e:
530-
print_debug(0, "error while loading body {}".format(e))
531-
return
525+
def write_firmware(self, customManifest=None):
526+
ota = WiFiOTA(
527+
self.__conf['wifi']['ssid'],
528+
self.__conf['wifi']['password'],
529+
self.__conf['ota_server']['domain'],
530+
self.__conf['ota_server']['port']
531+
)
532+
533+
if (self.__pybytes_connection.__connection_status == constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
534+
print_debug(5, 'Connecting to WiFi')
535+
ota.connect()
532536

537+
print_debug(5, "Performing OTA")
538+
result = ota.update(customManifest)
539+
self.send_ota_response(result)
540+
time.sleep(1.5)
541+
if (result == 2):
542+
# Reboot the device to run the new decode
543+
machine.reset()
544+
545+
def get_application_details(self, body):
546+
application = self.__conf.get('application')
533547
if application is not None:
534548
if 'id' in application and application['id']:
535549
applicationID = application['id']
@@ -542,23 +556,32 @@ def deploy_new_release(self, body):
542556
else:
543557
applicationID = body['applicationId']
544558
currentReleaseID = None
559+
self.__conf['application'] = {
560+
"id": "",
561+
"release": {
562+
"id": "",
563+
"codeFilename": "",
564+
"version": 0
565+
}
566+
}
567+
return (applicationID, currentReleaseID)
545568

546-
baseWebConfigUrl = 'https://{}'.format(constants.__DEFAULT_PYCONFIG_DOMAIN)
547-
manifestURL = '{}/manifest.json?'.format(baseWebConfigUrl)
548-
fileUrl = '{}/files?'.format(baseWebConfigUrl)
549-
newReleaseID = body["releaseId"]
550-
targetURL = '{}app_id={}&target_ver={}&current_ver={}'.format(
569+
def get_update_manifest(self, applicationID, newReleaseID, currentReleaseID):
570+
manifestURL = '{}://{}/manifest.json?'.format(constants.__DEFAULT_PYCONFIG_PROTOCOL, constants.__DEFAULT_PYCONFIG_DOMAIN)
571+
targetURL = '{}app_id={}&target_ver={}&current_ver={}&device_id={}'.format(
551572
manifestURL,
552573
applicationID,
553574
newReleaseID,
554-
currentReleaseID
575+
currentReleaseID,
576+
self.__conf['device_id']
555577
)
556578
print_debug(6, "manifest URL: {}".format(targetURL))
557579
try:
558580
pybytes_activation = urequest.get(targetURL, headers={'content-type': 'application/json'})
559581
letResp = pybytes_activation.json()
560582
pybytes_activation.close()
561583
print_debug(6, "letResp: {}".format(letResp))
584+
return letResp
562585
except Exception as ex:
563586
print_debug(1, "error while calling {}!: {}".format(targetURL, ex))
564587
return
@@ -567,6 +590,8 @@ def deploy_new_release(self, body):
567590
print_debug(1, letResp['errorMessage'])
568591
return
569592

593+
def update_files(self, letResp, applicationID, newReleaseID):
594+
fileUrl = '{}://{}/files?'.format(constants.__DEFAULT_PYCONFIG_PROTOCOL, constants.__DEFAULT_PYCONFIG_DOMAIN)
570595
try:
571596
newFiles = letResp['newFiles']
572597
updatedFiles = letResp['updatedFiles']
@@ -591,22 +616,14 @@ def deploy_new_release(self, body):
591616
fileContent = getFile.content
592617
self.__FCOTA.update_file_content(file['fileName'], fileContent)
593618

619+
def delete_files(self, letResp):
594620
if 'deletedFiles' in letResp:
595621
deletedFiles = letResp['deletedFiles']
596622
for file in deletedFiles:
597623
self.__FCOTA.delete_file(file['fileName'])
598624

625+
def update_application_config(self, letResp, applicationID):
599626
try:
600-
if application is None:
601-
self.__conf['application'] = {
602-
"id": "",
603-
"release": {
604-
"id": "",
605-
"codeFilename": "",
606-
"version": 0
607-
}
608-
}
609-
610627
self.__conf['application']["id"] = applicationID
611628
self.__conf['application']['release']['id'] = letResp['target_version']['id']
612629
self.__conf['application']['release']['codeFilename'] = letResp['target_version']['codeFileName']
@@ -621,4 +638,69 @@ def deploy_new_release(self, body):
621638
except Exception as e:
622639
print_debug(1, "error while updating pybytes_config.json! {}".format(e))
623640

641+
def update_network_config(self, letResp):
642+
try:
643+
if 'networkConfig' in letResp:
644+
netConf = letResp['networkConfig']
645+
self.__conf['network_preferences'] = netConf['networkPreferences']
646+
if 'wifi' in netConf:
647+
self.__conf['wifi'] = netConf['wifi']
648+
elif 'wifi' in self.__conf:
649+
del self.__conf['wifi']
650+
651+
if 'lte' in netConf:
652+
self.__conf['lte'] = netConf['lte']
653+
elif 'lte' in self.__conf:
654+
del self.__conf['lte']
655+
656+
if 'lora' in netConf:
657+
self.__conf['lora'] = {
658+
'otaa': netConf['lora']['otaa'],
659+
'abp': netConf['lora']['abp']
660+
}
661+
elif 'lora' in self.__conf:
662+
del self.__conf['lora']
663+
664+
json_string = ujson.dumps(self.__conf)
665+
print_debug(1, "update_network_config : {}".format(json_string))
666+
self.__FCOTA.update_file_content('/flash/pybytes_config.json', json_string)
667+
except Exception as e:
668+
print_debug(1, "error while updating network config pybytes_config.json! {}".format(e))
669+
670+
def update_firmware(self, body):
671+
if "firmware" not in body:
672+
print_debug(0, "no firmware to update")
673+
return
674+
version = body['firmware']["version"]
675+
print_debug(0, "updating firmware to {}".format(version))
676+
customManifest = {
677+
"firmware": {
678+
"URL": "https://{}/downloads/appimg/firmware_{}_{}.bin".format(
679+
constants.__DEFAULT_SW_HOST,
680+
os.uname().sysname,
681+
version),
682+
}
683+
}
684+
self.write_firmware(customManifest)
685+
686+
def deploy_new_release(self, body):
687+
try:
688+
body = ujson.loads(body.decode())
689+
print_debug(6, "body {}".format(body))
690+
except Exception as e:
691+
print_debug(0, "error while loading body {}".format(e))
692+
return
693+
694+
newReleaseID = body["releaseId"]
695+
applicationID, currentReleaseID = self.get_application_details(body)
696+
697+
letResp = self.get_update_manifest(applicationID, newReleaseID, currentReleaseID)
698+
if not letResp:
699+
return
700+
701+
self.update_files(letResp, applicationID, newReleaseID)
702+
self.delete_files(letResp)
703+
self.update_application_config(letResp, applicationID)
704+
self.update_network_config(letResp)
705+
self.update_firmware(letResp)
624706
machine.reset()

esp32/pycom_version.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#define SIGFOX_VERSION_NUMBER "1.0.1"
1818

1919
#if (VARIANT == PYBYTES)
20-
#define PYBYTES_VERSION_NUMBER "1.1.3"
20+
#define PYBYTES_VERSION_NUMBER "1.2.0"
2121
#endif
2222

2323
#endif /* VERSION_H_ */

0 commit comments

Comments
 (0)