提交 9caa15a5 authored 作者: blu's avatar blu

ota updater

上级 84fd85b4
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.16
# Generated by "Unix Makefiles" Generator, CMake Version 3.17
# Default target executed when no arguments are given to make.
default_target: all
......@@ -17,8 +17,25 @@ default_target: all
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
# Disable VCS-based implicit rules.
% : %,v
# Disable VCS-based implicit rules.
% : RCS/%
# Disable VCS-based implicit rules.
% : RCS/%,v
# Disable VCS-based implicit rules.
% : SCCS/s.%
# Disable VCS-based implicit rules.
% : s.%
.SUFFIXES: .hpux_make_needs_suffix_list
......@@ -39,10 +56,10 @@ cmake_force:
SHELL = /bin/sh
# The CMake executable.
CMAKE_COMMAND = /usr/local/Cellar/cmake/3.16.5/bin/cmake
CMAKE_COMMAND = /usr/local/Cellar/cmake/3.17.0_1/bin/cmake
# The command to remove a file.
RM = /usr/local/Cellar/cmake/3.16.5/bin/cmake -E remove -f
RM = /usr/local/Cellar/cmake/3.17.0_1/bin/cmake -E rm -f
# Escaping for special characters.
EQUALS = =
......@@ -59,7 +76,7 @@ CMAKE_BINARY_DIR = /Users/blu/work/opencv-projects/opencv-motion-detect
# Special rule for the target rebuild_cache
rebuild_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
/usr/local/Cellar/cmake/3.16.5/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
/usr/local/Cellar/cmake/3.17.0_1/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
......@@ -636,21 +653,21 @@ help:
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... edit_cache"
@echo "... rebuild_cache"
@echo "... database"
@echo "... dirmon"
@echo "... evcloudsvc"
@echo "... evdaemon"
@echo "... evmgr"
@echo "... evmlmotion"
@echo "... evslicer"
@echo "... evpuller"
@echo "... evmgr"
@echo "... evpusher"
@echo "... evslicer"
@echo "... evwifi"
@echo "... evdaemon"
@echo "... evcloudsvc"
@echo "... rebuild_cache"
@echo "... zmqhelper"
@echo "... util"
@echo "... edit_cache"
@echo "... database"
@echo "... post"
@echo "... evpusher"
@echo "... dirmon"
@echo "... util"
@echo "... zmqhelper"
@echo "... database.o"
@echo "... database.i"
@echo "... database.s"
......
import requests, os, logging, time, datetime, threading, json, subprocess, shlex, re, string
import pdb, traceback, sys, socket
import paho.mqtt.client as mqtt
import zipfile
logger = logging.getLogger(__file__)
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setFormatter(logging.Formatter(('[%(asctime)s][ota][%(lineno)d][%(levelname)s] %(message)s')))
logger.addHandler(ch)
MQTT_HOST = os.getenv('MQTT_HOST', 'evcloud.ilabservice.cloud')
MQTT_PORT = int(os.getenv('MQTT_PORT', 1883))
MQTT_CLIENT_ID = os.getenv('MQTT_CID', None)
MQTT_USER_NAME = os.getenv('MQTT_USER', None)
MQTT_USER_PASSWORD = os.getenv('MQTT_PASSWORD', None)
SN_FILE = '/etc/devsn.cfg'
VER_FILE = '/etc/devversion.cfg'
LOCAL_CFG_URL = 'http://localhost:8088/config'
MIN_SN_LEN = 8
DOWNLOAD_PATH = '/tmp/update_package/update_package.zip'
EXTRACT_PATH = '/tmp/update_extract/'
BIN_DIR = '/tmp/work/opencv-pocs/opencv-motion-detect/'
LIB_DIR = BIN_DIR + 'vendor/lib/'
SKU = 'ILSA-HW-TM0401'
REPLY_TOPIC='/device/ota/update'
class OTAClient:
def __init__(self, host, port, username, password):
self.host = host
self.port = port
self.username = username
self.password = password
self.connect()
def _get_sn_from_file(self):
if os.path.exists(SN_FILE):
with open(SN_FILE, 'r') as f:
while True:
sn = f.readline()
sn = sn.rstrip()
sn = sn.strip()
if len(sn) < MIN_SN_LEN:
continue
else:
return sn
return ''
def _get_sn_from_evdaemon(self):
errmsg = 'failed connect to evdameon, please check network'
try:
r = requests.get(LOCAL_CFG_URL, timeout=2)
if r.status_code != 200:
logger.error(errmsg)
else:
for k,v in r.json().items():
return k
except requests.exceptions.ConnectionError as e:
logger.error("Error Connecting: {}".format(e))
except requests.exceptions.Timeout as e:
logger.error("Timeout Error: {}".format(e))
except requests.exceptions.RequestException as e:
logger.error("Request Exception: {}".format(e))
except IOError as e:
logger.error("IOError Exception: {}".format(e))
except Exception as e:
logger.error("General Exception: {}".format(e))
return ''
def get_version(self):
if os.path.exists(VER_FILE):
with open(VER_FILE, 'r') as f:
while True:
sn = f.readline()
sn = sn.rstrip()
sn = sn.strip()
if len(sn) < 1:
continue
else:
return sn
return ''
def get_sn(self):
sn = self._get_sn_from_evdaemon()
if not sn:
sn = self._get_sn_from_file()
if not sn:
msg = "failed to get sn, please check network and host files"
logger.error(msg)
raise Exception(msg)
self.sn = sn
return sn
@staticmethod
def on_connect(client, ud, flags, rc):
topic = '/device/ota/init/' + ud.sn
client.subscribe(topic, qos=1)
logger.info('subscribed to {} '.format(topic))
@staticmethod
def on_message(client, ud, msg):
payload = msg.payload.decode('utf-8')
logger.info(msg.topic+" " + payload)
try:
jd = json.loads(payload)
ud.handle(jd)
except Exception as e:
logger.info('exception in process message: %s', e)
extype, value, tb = sys.exc_info()
traceback.print_exc()
def connect(self):
self.version = self.get_version()
sn = self.get_sn()
if not sn:
logger.error("exiting since no sn config could be retrived")
exit(1)
self.client = mqtt.Client(sn, userdata=self) # , protocol=mqtt.MQTTv5)
if self.username and self.password:
self.client.username_pw_set(username=self.username, password=self.password)
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
th = threading.Thread()
self.client.connect_async(self.host, self.port, 30)
#self.client.loop_start()
self.client.loop_forever()
def download(self, url):
os.system('mkdir -p ' + DOWNLOAD_PATH)
os.system('mkdir -p '+ EXTRACT_PATH)
msg = ''
try:
with requests.get(url, stream=True) as r:
r.raise_for_status()
logger.info("download {} -> {}".format(url, DOWNLOAD_PATH))
with open(DOWNLOAD_PATH, 'wb') as f:
for ch in r.iter_content(chunk_size=8000):
f.write(ch)
except requests.exceptions.ConnectionError as e:
msg = "Error Connecting: {}".format(e)
logger.error(msg)
except requests.exceptions.Timeout as e:
msg = "Timeout Error: {}".format(e)
logger.error(msg)
except requests.exceptions.RequestException as e:
msg = "Request Exception: {}".format(e)
logger.error(msg)
except IOError as e:
msg = "IOError Exception: {}".format(e)
logger.error(msg)
except Exception as e:
msg = "General Exception: {}".format(e)
logger.error(msg)
return msg
def reply(self, batchId, version, status, message):
if status not in ['confirm', 'refuse', 'fail', 'complete']:
logger.error("invalid reply status: %s", status)
return
rep = {}
rep['sn'] = self.sn
rep['sku'] = SKU
rep['batchId'] = batchId
rep['message'] = message
rep['firmware'] = version
rep['status'] = status
try:
self.client.publish(REPLY_TOPIC, json.dumps(rep), 1)
except Exception as e:
logger.info('exception in publish reply message: %s', e)
extype, value, tb = sys.exc_info()
traceback.print_exc()
def handle(self, req):
logger.info(req)
sku = req.get('sku')
sn = req.get('sn')
ver = req.get('firmware')
url = req.get('url')
batchId = req.get('batchId')
valid = True
msg = 'OK'
if not sku or sku != SKU:
msg = "invalid sku {} in update request, expected {}. ignored".format(sku, SKU)
logger.warn(msg);
valid = False
if not sn or sn != self.sn:
msg = "invalid sn {} in update request, expected {} ignored".format(sn, self.sn)
logger.warn(msg);
valid = False
if not url or url[:7] != 'http://':
msg = "invalid url {} in update request, ignored".format(url)
logger.warn(msg);
valid = False
if not batchId or not str(batchId).isnumeric:
msg = "invalid batchId {} in update request, ignored".format(batchId)
logger.warn(msg);
valid = False
if not self.version:
logger.warn("no local version file, update initialized")
if not valid:
self.reply(batchId, ver, 'refuse', msg)
return
# process on
# download package
msg = self.download(url)
if msg:
self.reply(batchId, ver, 'fail', msg)
return
# extract
try:
with zipfile.ZipFile(DOWNLOAD_PATH, 'r') as zip_ref:
zip_ref.extractall(EXTRACT_PATH)
except Exception as e:
msg = 'failed to extract pakage: {}'.format(str(e))
logger.error(msg)
extype, value, tb = sys.exc_info()
traceback.print_exc()
self.reply(batchId, ver, 'fail', msg)
return
# copy files
os.system('mv -f ' + EXTRACT_PATH + 'bin/*', BIN_DIR)
os.system('mv -f ' + EXTRACT_PATH + 'lib/*', LIB_DIR)
# run extra scripts
runsh = EXTRACT_PATH + 'run.sh'
if os.path.exists(runsh):
os.system('chmod +x ' + runsh)
try:
ans = subprocess.check_output(['sh', runsh])
logger.info(ans)
except Exception as e:
msg = "failed to execute run.sh: " + str(e)
self.reply(batchId, ver, 'fail', msg)
logger.error(msg)
extype, value, tb = sys.exc_info()
traceback.print_exc()
return
# write version
with open(VER_FILE, 'w') as f:
f.writelines(self.version)
# report status
self.reply(batchId, ver, 'complete', 'OK')
if __name__ == "__main__":
# avoid multiple instance
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 45432))
logger.setLevel(logging.INFO)
OTAClient(MQTT_HOST, MQTT_PORT, MQTT_USER_NAME, MQTT_USER_PASSWORD)
......@@ -121,7 +121,6 @@ def cleanup(target):
if mts < v:
oldest_n_mtime[k] = v
oldest_n_files[k] = fn
cnt += 1
# clean up
for f in oldest_n_files:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论