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

Commit

Permalink
Merge pull request #352 from pycom/release-pybytes-library-1.2.0
Browse files Browse the repository at this point in the history
feat: Pybytes library release 1.2.0
  • Loading branch information
Islam Wahdan authored Oct 30, 2019
2 parents 3138a13 + 42847bc commit 69dd8b5
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 62 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*.dis
*.exe

# Packages
# Packages
############

# Logs and Databases
Expand Down Expand Up @@ -50,8 +50,9 @@ secure_boot_signing_key.pem
signature_verification_key.bin
secure-bootloader-key.bin
flash_encryption_key.bin

.DS_Store
org.eclipse.cdt.ui.prefs
org.eclipse.cdt.core.prefs
language.settings.xml
.idea
80 changes: 45 additions & 35 deletions esp32/frozen/Pybytes/_OTA.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
see the Pycom Licence v1.0 document supplied with this file, or
available at https://www.pycom.io/opensource/licensing
'''
try:
from pybytes_debug import print_debug
except:
from _pybytes_debug import print_debug

import network
import socket
Expand Down Expand Up @@ -56,9 +60,9 @@ def get_update_manifest(self):
gc.collect()
return manifest

def update(self):
def update(self, customManifest=None):
try:
manifest = self.get_update_manifest()
manifest = self.get_update_manifest() if not customManifest else customManifest
except Exception as e:
print('Error reading the manifest, aborting: {}'.format(e))
return 0
Expand All @@ -68,36 +72,38 @@ def update(self):
return 1

# Download new files and verify hashes
for f in manifest['new'] + manifest['update']:
# Upto 5 retries
for _ in range(5):
try:
self.get_file(f)
break
except Exception as e:
print(e)
msg = "Error downloading `{}` retrying..."
print(msg.format(f['URL']))
return 0
else:
raise Exception("Failed to download `{}`".format(f['URL']))

# Backup old files
# only once all files have been successfully downloaded
for f in manifest['update']:
self.backup_file(f)

# Rename new files to proper name
for f in manifest['new'] + manifest['update']:
new_path = "{}.new".format(f['dst_path'])
dest_path = "{}".format(f['dst_path'])

os.rename(new_path, dest_path)

# `Delete` files no longer required
# This actually makes a backup of the files incase we need to roll back
for f in manifest['delete']:
self.delete_file(f)
if "new" in manifest and "update" in manifest:
for f in manifest['new'] + manifest['update']:
# Upto 5 retries
for _ in range(5):
try:
self.get_file(f)
break
except Exception as e:
print(e)
msg = "Error downloading `{}` retrying..."
print(msg.format(f['URL']))
return 0
else:
raise Exception("Failed to download `{}`".format(f['URL']))

# Backup old files
# only once all files have been successfully downloaded
for f in manifest['update']:
self.backup_file(f)

# Rename new files to proper name
for f in manifest['new'] + manifest['update']:
new_path = "{}.new".format(f['dst_path'])
dest_path = "{}".format(f['dst_path'])

os.rename(new_path, dest_path)

if "delete" in manifest:
# `Delete` files no longer required
# This actually makes a backup of the files incase we need to roll back
for f in manifest['delete']:
self.delete_file(f)

# Flash firmware
if "firmware" in manifest:
Expand Down Expand Up @@ -162,9 +168,12 @@ def delete_file(self, f):
os.rename(dest_path, bak_path)

def write_firmware(self, f):
hash = self.get_data(f['URL'].split("/", 3)[-1],
hash=True,
firmware=True)
# hash =
self.get_data(
f['URL'].split("/", 3)[-1],
hash=True,
firmware=True
)
# TODO: Add verification when released in future firmware


Expand Down Expand Up @@ -258,6 +267,7 @@ def get_data(self, req, dest_path=None, hash=False, firmware=False):
if fp is not None:
fp.close()
if firmware:
print_debug(6, 'ota_finish')
pycom.ota_finish()

except Exception as e:
Expand Down
4 changes: 4 additions & 0 deletions esp32/frozen/Pybytes/_pybytes_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,7 @@ class constants:
__DEFAULT_PYCONFIG_DOMAIN = pycom.nvs_get('pyconfig_host', 'pyconfig.eu-central-1.elasticbeanstalk.com')
except:
__DEFAULT_PYCONFIG_DOMAIN = 'pyconfig.eu-central-1.elasticbeanstalk.com'
try:
__DEFAULT_PYCONFIG_PROTOCOL = pycom.nvs_get('pyconfig_protocol', 'https')
except:
__DEFAULT_PYCONFIG_PROTOCOL = "https"
130 changes: 106 additions & 24 deletions esp32/frozen/Pybytes/_pybytes_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def __send_terminal_message(self, data):

def enable_terminal(self):
self.__terminal_enabled = True
#os.dupterm(self.__terminal)
# os.dupterm(self.__terminal)

def __send_pybytes_message(self, command, pin_number, value):
self.__send_message(
Expand All @@ -522,14 +522,28 @@ def __send_pybytes_message_variable(
def set_battery_level(self, battery_level):
self.__battery_level = battery_level

def deploy_new_release(self, body):
application = self.__conf.get('application')
try:
body = ujson.loads(body.decode())
except Exception as e:
print_debug(0, "error while loading body {}".format(e))
return
def write_firmware(self, customManifest=None):
ota = WiFiOTA(
self.__conf['wifi']['ssid'],
self.__conf['wifi']['password'],
self.__conf['ota_server']['domain'],
self.__conf['ota_server']['port']
)

if (self.__pybytes_connection.__connection_status == constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
print_debug(5, 'Connecting to WiFi')
ota.connect()

print_debug(5, "Performing OTA")
result = ota.update(customManifest)
self.send_ota_response(result)
time.sleep(1.5)
if (result == 2):
# Reboot the device to run the new decode
machine.reset()

def get_application_details(self, body):
application = self.__conf.get('application')
if application is not None:
if 'id' in application and application['id']:
applicationID = application['id']
Expand All @@ -542,23 +556,32 @@ def deploy_new_release(self, body):
else:
applicationID = body['applicationId']
currentReleaseID = None
self.__conf['application'] = {
"id": "",
"release": {
"id": "",
"codeFilename": "",
"version": 0
}
}
return (applicationID, currentReleaseID)

baseWebConfigUrl = 'https://{}'.format(constants.__DEFAULT_PYCONFIG_DOMAIN)
manifestURL = '{}/manifest.json?'.format(baseWebConfigUrl)
fileUrl = '{}/files?'.format(baseWebConfigUrl)
newReleaseID = body["releaseId"]
targetURL = '{}app_id={}&target_ver={}&current_ver={}'.format(
def get_update_manifest(self, applicationID, newReleaseID, currentReleaseID):
manifestURL = '{}://{}/manifest.json?'.format(constants.__DEFAULT_PYCONFIG_PROTOCOL, constants.__DEFAULT_PYCONFIG_DOMAIN)
targetURL = '{}app_id={}&target_ver={}&current_ver={}&device_id={}'.format(
manifestURL,
applicationID,
newReleaseID,
currentReleaseID
currentReleaseID,
self.__conf['device_id']
)
print_debug(6, "manifest URL: {}".format(targetURL))
try:
pybytes_activation = urequest.get(targetURL, headers={'content-type': 'application/json'})
letResp = pybytes_activation.json()
pybytes_activation.close()
print_debug(6, "letResp: {}".format(letResp))
return letResp
except Exception as ex:
print_debug(1, "error while calling {}!: {}".format(targetURL, ex))
return
Expand All @@ -567,6 +590,8 @@ def deploy_new_release(self, body):
print_debug(1, letResp['errorMessage'])
return

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

def delete_files(self, letResp):
if 'deletedFiles' in letResp:
deletedFiles = letResp['deletedFiles']
for file in deletedFiles:
self.__FCOTA.delete_file(file['fileName'])

def update_application_config(self, letResp, applicationID):
try:
if application is None:
self.__conf['application'] = {
"id": "",
"release": {
"id": "",
"codeFilename": "",
"version": 0
}
}

self.__conf['application']["id"] = applicationID
self.__conf['application']['release']['id'] = letResp['target_version']['id']
self.__conf['application']['release']['codeFilename'] = letResp['target_version']['codeFileName']
Expand All @@ -621,4 +638,69 @@ def deploy_new_release(self, body):
except Exception as e:
print_debug(1, "error while updating pybytes_config.json! {}".format(e))

def update_network_config(self, letResp):
try:
if 'networkConfig' in letResp:
netConf = letResp['networkConfig']
self.__conf['network_preferences'] = netConf['networkPreferences']
if 'wifi' in netConf:
self.__conf['wifi'] = netConf['wifi']
elif 'wifi' in self.__conf:
del self.__conf['wifi']

if 'lte' in netConf:
self.__conf['lte'] = netConf['lte']
elif 'lte' in self.__conf:
del self.__conf['lte']

if 'lora' in netConf:
self.__conf['lora'] = {
'otaa': netConf['lora']['otaa'],
'abp': netConf['lora']['abp']
}
elif 'lora' in self.__conf:
del self.__conf['lora']

json_string = ujson.dumps(self.__conf)
print_debug(1, "update_network_config : {}".format(json_string))
self.__FCOTA.update_file_content('/flash/pybytes_config.json', json_string)
except Exception as e:
print_debug(1, "error while updating network config pybytes_config.json! {}".format(e))

def update_firmware(self, body):
if "firmware" not in body:
print_debug(0, "no firmware to update")
return
version = body['firmware']["version"]
print_debug(0, "updating firmware to {}".format(version))
customManifest = {
"firmware": {
"URL": "https://{}/downloads/appimg/firmware_{}_{}.bin".format(
constants.__DEFAULT_SW_HOST,
os.uname().sysname,
version),
}
}
self.write_firmware(customManifest)

def deploy_new_release(self, body):
try:
body = ujson.loads(body.decode())
print_debug(6, "body {}".format(body))
except Exception as e:
print_debug(0, "error while loading body {}".format(e))
return

newReleaseID = body["releaseId"]
applicationID, currentReleaseID = self.get_application_details(body)

letResp = self.get_update_manifest(applicationID, newReleaseID, currentReleaseID)
if not letResp:
return

self.update_files(letResp, applicationID, newReleaseID)
self.delete_files(letResp)
self.update_application_config(letResp, applicationID)
self.update_network_config(letResp)
self.update_firmware(letResp)
machine.reset()
2 changes: 1 addition & 1 deletion esp32/pycom_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define SIGFOX_VERSION_NUMBER "1.0.1"

#if (VARIANT == PYBYTES)
#define PYBYTES_VERSION_NUMBER "1.1.3"
#define PYBYTES_VERSION_NUMBER "1.2.0"
#endif

#endif /* VERSION_H_ */

0 comments on commit 69dd8b5

Please sign in to comment.