mirror of
https://gitee.com/quecpython/helios-service.git
synced 2025-05-18 21:58:23 +08:00
initial commit
This commit is contained in:
parent
4333f64e96
commit
46c4af2024
BIN
API文档/HeliosServices框架使用及API文档.pdf
Normal file
BIN
API文档/HeliosServices框架使用及API文档.pdf
Normal file
Binary file not shown.
BIN
API文档/三方组件文档/offline_storage.pdf
Normal file
BIN
API文档/三方组件文档/offline_storage.pdf
Normal file
Binary file not shown.
BIN
API文档/三方组件文档/中断及看门狗文档.pdf
Normal file
BIN
API文档/三方组件文档/中断及看门狗文档.pdf
Normal file
Binary file not shown.
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# HeliosService
|
||||
|
||||
|
||||
|
||||
**API文档 - 里面有API文档**
|
||||
|
||||
**helios service文档 \- 框架文档**
|
||||
|
||||
**Code \- 代码**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**API documentation - It has API documentation**
|
||||
|
||||
**Helios Service document \- Framework document**
|
||||
|
||||
**Code \- code**
|
||||
|
98
code/usr/bin/cloud_service.py
Normal file
98
code/usr/bin/cloud_service.py
Normal file
@ -0,0 +1,98 @@
|
||||
__all__ = [
|
||||
"CloudService",
|
||||
"CloudServiceMonitor",
|
||||
]
|
||||
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
from usr.utils.service_utils import Singleton
|
||||
from usr.bin.components.OTA import UCloudOTA
|
||||
import _thread
|
||||
|
||||
SH_UPGRADE = 1
|
||||
BIN_UPGRADE = 0
|
||||
ENABLE_ = "enable"
|
||||
|
||||
|
||||
class CloudServiceMonitor(ServiceMonitor):
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
if config is None:
|
||||
return None
|
||||
level = 0
|
||||
try:
|
||||
level = config.get("level", 0)
|
||||
uid = config["params"]["uid"]
|
||||
module_type = config["params"]["module_type"]
|
||||
pk = config["params"]["pk"]
|
||||
battery = config["params"].get("battery", 100)
|
||||
reboot = config["params"].get("reboot", False)
|
||||
cloud_service = CloudService(uid=uid, module_type=module_type, pk=pk, battery=battery, reboot=bool(reboot))
|
||||
except Exception as e:
|
||||
return None
|
||||
else:
|
||||
m = CloudServiceMonitor(cloud_service)
|
||||
m.set_level(level)
|
||||
if config is not None:
|
||||
m.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return m
|
||||
|
||||
|
||||
@Singleton
|
||||
class CloudService(AbstractService):
|
||||
def __init__(self, uid, module_type, pk, battery=100, reboot=False):
|
||||
super().__init__("CLOUD")
|
||||
self.reboot = reboot
|
||||
self.module_type = module_type
|
||||
self.pk = pk
|
||||
self.uid = uid
|
||||
self.ota_upgrade = UCloudOTA(battery)
|
||||
self.__upgrade_status_info = {
|
||||
SH_UPGRADE: None,
|
||||
BIN_UPGRADE: None
|
||||
}
|
||||
self.server_status = {
|
||||
SH_UPGRADE: {ENABLE_: True},
|
||||
BIN_UPGRADE: {ENABLE_: False}
|
||||
}
|
||||
|
||||
@property
|
||||
def upgrade_status_info(self):
|
||||
return self.__upgrade_status_info
|
||||
|
||||
def set_enable(self, sr, enable):
|
||||
"""set start"""
|
||||
self.server_status[sr][ENABLE_] = enable
|
||||
|
||||
def __upgrade_sh(self):
|
||||
# 触发升级脚本操作
|
||||
if self.server_status[SH_UPGRADE][ENABLE_]:
|
||||
code = self.ota_upgrade.start_upgrade_sh_event(self.module_type, self.uid, self.pk, reboot=self.reboot)
|
||||
self.send_msg(message=dict(code=code), msg_type=SH_UPGRADE)
|
||||
|
||||
def __upgrade_bin(self):
|
||||
# 触发升级bin包操作
|
||||
if self.server_status[BIN_UPGRADE][ENABLE_]:
|
||||
code = self.ota_upgrade.start_upgrade_bin_event(self.module_type, self.uid, self.pk, reboot=self.reboot)
|
||||
self.send_msg(message=dict(code=code), msg_type=BIN_UPGRADE)
|
||||
|
||||
def _status_update(self, *args, **kwargs):
|
||||
msg = "message"
|
||||
em = kwargs.get(msg, False)
|
||||
if em:
|
||||
msg_type = em["msg_type"]
|
||||
self.__upgrade_status_info[msg_type] = em[msg]["code"]
|
||||
|
||||
def get_app_code(self):
|
||||
return self.__upgrade_status_info[SH_UPGRADE]
|
||||
|
||||
def prepare_before_start(self):
|
||||
self.signal.connect(self._status_update, sender="anonymous")
|
||||
|
||||
def start(self):
|
||||
super().start()
|
||||
# _thread.start_new_thread(self.__upgrade_bin, ())
|
||||
_thread.start_new_thread(self.__upgrade_sh, ())
|
||||
|
||||
def commit_log(self, message):
|
||||
self.ota_upgrade.commit_log(self.pk, message)
|
499
code/usr/bin/components/OTA.py
Normal file
499
code/usr/bin/components/OTA.py
Normal file
@ -0,0 +1,499 @@
|
||||
import modem, ubinascii, net, uhashlib, request, ujson, app_fota, fota, utime, uos, log
|
||||
from misc import Power
|
||||
from unzip import UnZipUtils
|
||||
from app_fota_download import update_download_stat, delete_update_file
|
||||
|
||||
PROCESS_CODE = {
|
||||
"DO_NOT_UPGRADE": 0,
|
||||
"DOWNLOADING_FIRMWARE": 3,
|
||||
"DOWNLOADED_NOTIFY_UPDATE": 4,
|
||||
"DOWNLOAD_FAILED": 5,
|
||||
"UPDATE_START": 6,
|
||||
"UPGRADE_SUCCESS": 7,
|
||||
"UPGRADE_FAILED": 8,
|
||||
}
|
||||
USR = "/usr/"
|
||||
CONFIG_PATH = "ota_config.json"
|
||||
MAIN_PY = "main.py"
|
||||
BIN_MODE = "0"
|
||||
APP_MODE = "1"
|
||||
UPDATER_DIR = '/usr/.updater'
|
||||
# 后续版本支持批量升级
|
||||
# BULK_APP_MODE = "2"
|
||||
log.basicConfig(level=log.INFO)
|
||||
ota_log = log.getLogger("ota")
|
||||
fota_bin_file = "FotaFile.bin"
|
||||
MODE_MAP = {
|
||||
BIN_MODE: "_upgrade_fota_bin",
|
||||
APP_MODE: "_upgrade_fota_sh",
|
||||
# 后续支持BULK升级
|
||||
# BULK_APP_MODE: "_upgrade_fota_bulk_sh",
|
||||
}
|
||||
ZIP = ".zip"
|
||||
|
||||
|
||||
class RET:
|
||||
OK = "20000"
|
||||
# 系统组件错误
|
||||
UPGRADE = "3001"
|
||||
NOUPGRADE = "3002"
|
||||
# 网络协议错误
|
||||
TOKENERR = "4001"
|
||||
GETUPGRADEURLERR = "4002"
|
||||
DOWNLOADERR = "4003"
|
||||
PARAMSERR = "4004"
|
||||
MODENOTEXIST = "4005"
|
||||
FOTAVERIFAILD = "4006"
|
||||
COMMIT_LOG_ERROR = "4007"
|
||||
# 配置错误
|
||||
SAVECONFIGERR = "4021"
|
||||
GETCONFIGERR = "4022"
|
||||
NETERR = "4023"
|
||||
REQERR = "4024"
|
||||
WIOERR = "4025"
|
||||
FWSTREAMERR = "4026"
|
||||
RIOERR = "4027"
|
||||
UNZIPERROR = "4028"
|
||||
UNZIPFILEPROTOCOLERROR = "4029"
|
||||
|
||||
|
||||
error_map = {
|
||||
RET.OK: u"成功",
|
||||
# 系统
|
||||
RET.UPGRADE: u"有升级计刿",
|
||||
RET.NOUPGRADE: u"无升级计刿",
|
||||
# 协议
|
||||
RET.TOKENERR: u"获取token失败",
|
||||
RET.GETUPGRADEURLERR: u"获取升级地址失败",
|
||||
RET.DOWNLOADERR: u"下载固件失败",
|
||||
RET.PARAMSERR: u"参数获取失败",
|
||||
RET.MODENOTEXIST: u"模式不存圿",
|
||||
###
|
||||
RET.SAVECONFIGERR: u"保存配置错误",
|
||||
RET.GETCONFIGERR: u"获取配置错误",
|
||||
RET.NETERR: u"网络错误",
|
||||
RET.WIOERR: u"文件写错诿",
|
||||
RET.FWSTREAMERR: u"FOTA字节流作牿",
|
||||
RET.RIOERR: u"文件读错诿",
|
||||
RET.UNZIPERROR: u"文件解压失败",
|
||||
RET.UNZIPFILEPROTOCOLERROR: u"压缩文件解析失败",
|
||||
}
|
||||
|
||||
|
||||
class OTAUtil(object):
|
||||
@classmethod
|
||||
def rm_upgrade_file(cls, file_name):
|
||||
uos.remove(UPDATER_DIR + file_name)
|
||||
delete_update_file(file_name)
|
||||
|
||||
@classmethod
|
||||
def add_upgrade_file(cls, url, file_name):
|
||||
update_download_stat(url, USR + file_name, uos.stat(UPDATER_DIR + USR + file_name)[6])
|
||||
|
||||
|
||||
class UCloudOTA(object):
|
||||
|
||||
def __init__(self, battery=100, url="http://220.180.239.212:8274/v1"):
|
||||
self.imei = modem.getDevImei()
|
||||
self.rsrp = net.csqQueryPoll()
|
||||
self.url = url
|
||||
self.module_type = ""
|
||||
self.battery = battery
|
||||
self.version = ""
|
||||
self.uid = ""
|
||||
self.pk = ""
|
||||
self.cellId = ""
|
||||
self.mnc = ""
|
||||
self.mcc = ""
|
||||
self.lac = ""
|
||||
self.report_url = "/fota/status/report"
|
||||
self.access_token = ""
|
||||
self.upgrade_info = {}
|
||||
self.bin_path = "/usr/FotaFile.bin"
|
||||
self.ota_config_info = {
|
||||
"version": "V1.0.0",
|
||||
"flag": "0",
|
||||
"fw_version": modem.getDevFwVersion()
|
||||
}
|
||||
self.info_map = {
|
||||
APP_MODE: {
|
||||
"reboot": True,
|
||||
"uid": "",
|
||||
"pk": ""
|
||||
},
|
||||
BIN_MODE: {
|
||||
"reboot": True,
|
||||
"uid": "",
|
||||
"pk": ""
|
||||
}
|
||||
}
|
||||
|
||||
def _upgrade_fota(self, mode):
|
||||
"升级fota bin"
|
||||
try:
|
||||
action = self.upgrade_info["action"]
|
||||
url = self.upgrade_info["url"]
|
||||
except Exception as e:
|
||||
return RET.PARAMSERR
|
||||
try:
|
||||
if action:
|
||||
self.report("DOWNLOADING_FIRMWARE")
|
||||
if mode == APP_MODE:
|
||||
if url.endswith(ZIP):
|
||||
# APP 升级
|
||||
code = self._upgrade_fota_bulk_sh(url)
|
||||
if code != RET.OK:
|
||||
return code
|
||||
else:
|
||||
self._upgrade_fota_sh(url)
|
||||
if self.info_map[APP_MODE]["reboot"]:
|
||||
self.power_restart()
|
||||
elif mode == BIN_MODE:
|
||||
# fota 升级
|
||||
self._upgrade_fota_bin(url)
|
||||
ota_log.info("self.info_map[BIN_MODE][reboot] === {}".format(self.info_map[BIN_MODE]["reboot"]))
|
||||
if self.info_map[BIN_MODE]["reboot"]:
|
||||
self.power_restart()
|
||||
else:
|
||||
# 模式 不匹酿
|
||||
return RET.MODENOTEXIST
|
||||
self.report("DOWNLOADED_NOTIFY_UPDATE")
|
||||
return RET.UPGRADE
|
||||
else:
|
||||
self.report("DO_NOT_UPGRADE")
|
||||
return RET.NOUPGRADE
|
||||
except Exception as e:
|
||||
ota_log.error(e)
|
||||
self.report(PROCESS_CODE[5])
|
||||
return RET.DOWNLOADERR
|
||||
|
||||
def _upgrade_fota_bulk_sh(self, url):
|
||||
"""
|
||||
批量升级
|
||||
:param url:
|
||||
:return:
|
||||
"""
|
||||
zip_file = url.split("/")[-1]
|
||||
fota = app_fota.new()
|
||||
fota.download(url, USR + zip_file)
|
||||
zip_util = UnZipUtils(dest_dir=UPDATER_DIR + USR)
|
||||
try:
|
||||
zip_util.set_data(zip_file)
|
||||
except Exception as e:
|
||||
ota_log.error(e)
|
||||
return RET.UNZIPERROR
|
||||
|
||||
try:
|
||||
code = zip_util.run()
|
||||
if not code:
|
||||
return code
|
||||
except Exception as e:
|
||||
return RET.UNZIPFILEPROTOCOLERROR
|
||||
for file_name in zip_util.file_name_list:
|
||||
OTAUtil.add_upgrade_file(url, file_name)
|
||||
OTAUtil.rm_upgrade_file(USR + zip_file)
|
||||
self.report("DOWNLOADED_NOTIFY_UPDATE")
|
||||
fota.set_update_flag()
|
||||
try:
|
||||
self.ota_config_info["version"] = self.upgrade_info["targetVersion"]
|
||||
self.ota_config_info["flag"] = "1"
|
||||
with open(USR + CONFIG_PATH, "w") as f:
|
||||
f.write(ujson.dumps(self.ota_config_info))
|
||||
except Exception as e:
|
||||
ota_log.info(e)
|
||||
self.report("UPDATE_START")
|
||||
return RET.OK
|
||||
|
||||
def _upgrade_fota_sh(self, url):
|
||||
"""
|
||||
升级单个脚本
|
||||
:param cover_file: 升级后覆盖的文件
|
||||
:return:
|
||||
"""
|
||||
zip_file = url.split("/")[-1]
|
||||
fota = app_fota.new()
|
||||
# 覆盖cover_file
|
||||
cover_file = USR + zip_file[zip_file.find("_") + 1:]
|
||||
fota.download(url, cover_file)
|
||||
self.report("DOWNLOADED_NOTIFY_UPDATE")
|
||||
fota.set_update_flag()
|
||||
try:
|
||||
self.ota_config_info["version"] = self.upgrade_info["targetVersion"]
|
||||
self.ota_config_info["flag"] = "1"
|
||||
with open(USR + CONFIG_PATH, "w") as f:
|
||||
f.write(ujson.dumps(self.ota_config_info))
|
||||
except Exception as e:
|
||||
ota_log.info(e)
|
||||
self.report("UPDATE_START")
|
||||
|
||||
def _upgrade_fota_bin(self, url):
|
||||
self.report("DOWNLOADED_NOTIFY_UPDATE")
|
||||
try:
|
||||
r = request.get(url, sizeof=4096)
|
||||
except Exception as e:
|
||||
return RET.REQERR
|
||||
if r.status_code == 200 or r.status_code == 206:
|
||||
file_size = int(r.headers['Content-Length'])
|
||||
fota_obj = fota()
|
||||
count = 0
|
||||
try:
|
||||
while True:
|
||||
c = next(r.content)
|
||||
length = len(c)
|
||||
for i in range(0, length, 4096):
|
||||
count += len(c[i:i + 4096])
|
||||
fota_obj.write(c[i:i + 4096], file_size)
|
||||
except StopIteration:
|
||||
r.close()
|
||||
except Exception as e:
|
||||
r.close()
|
||||
return RET.FWSTREAMERR
|
||||
else:
|
||||
r.close()
|
||||
res = fota_obj.verify()
|
||||
if res != 0:
|
||||
return RET.FOTAVERIFAILD
|
||||
self.report("DOWNLOADED_NOTIFY_UPDATE")
|
||||
return RET.OK
|
||||
else:
|
||||
return RET.REQERR
|
||||
|
||||
def _upgrade_template(self, mode, module_type="", version=""):
|
||||
"""
|
||||
开启固件脚本升级方弿
|
||||
:return: STATE
|
||||
"""
|
||||
self.module_type = modem.getDevFwVersion()[:5] if not module_type else module_type
|
||||
|
||||
# 判斷模式
|
||||
if mode == APP_MODE:
|
||||
state = self.register_upgrade_sh(version=version)
|
||||
ota_log.info("the device app currently version is {}".format(self.version))
|
||||
elif mode == BIN_MODE:
|
||||
state = self.register_upgrade_bin()
|
||||
ota_log.info("the device fireware currently version is {}".format(self.version))
|
||||
else:
|
||||
return RET.MODENOTEXIST
|
||||
# 注册upgrade sh
|
||||
if state != RET.OK:
|
||||
return state
|
||||
# 升级脚本
|
||||
state = self.get_upgrade_url(mode)
|
||||
if state != RET.OK:
|
||||
return state
|
||||
# 升级脚本
|
||||
state = self._upgrade_fota(mode)
|
||||
return state
|
||||
|
||||
def get_token(self, prefix="/oauth/token", kwargs=None):
|
||||
# 获取token
|
||||
if net.csqQueryPoll() == 99 or net.csqQueryPoll() == -1:
|
||||
return RET.NETERR
|
||||
uri = self.url + prefix
|
||||
try:
|
||||
secret = ubinascii.hexlify(uhashlib.md5("QUEC" + str(self.imei) + "TEL").digest())
|
||||
secret = secret.decode()
|
||||
uri = uri + "?imei=" + self.imei + "&" + "secret=" + secret
|
||||
ota_log.info("uri = {}".format(uri))
|
||||
resp = request.get(uri)
|
||||
json_data = resp.json()
|
||||
ota_log.info("get_token = {}".format(json_data))
|
||||
self.access_token = json_data["data"]["access_Token"]
|
||||
return RET.OK
|
||||
except Exception as e:
|
||||
ota_log.error("get_token error:{}".format(e))
|
||||
return RET.TOKENERR
|
||||
|
||||
def report(self, code, msg=None):
|
||||
data_info = {
|
||||
"version": str(self.version),
|
||||
"ver": "v1.0",
|
||||
"imei": str(self.imei),
|
||||
"code": PROCESS_CODE.get(code, 0),
|
||||
"msg": str(msg) if msg else code
|
||||
}
|
||||
|
||||
ota_log.info(data_info)
|
||||
|
||||
uri = self.url + self.report_url
|
||||
|
||||
headers = {"access_token": self.access_token, "Content-Type": "application/json"}
|
||||
try:
|
||||
resp = request.post(uri, data=ujson.dumps(data_info), headers=headers)
|
||||
return resp
|
||||
except Exception as e:
|
||||
return -1
|
||||
|
||||
def get_upgrade_url(self, mode, prefix="/fota/fw"):
|
||||
ota_log.info("module_type == {}".format(self.module_type))
|
||||
params = "?" + "version=" + str(self.version) + "&" + "imei=" + str(self.imei) + "&" + "moduleType=" + str(
|
||||
self.module_type) + "&" + "battery=" + str(
|
||||
self.battery) + "&" + "rsrp=" + str(
|
||||
self.rsrp) + "&" + "uid=" + str(
|
||||
self.info_map[mode]["uid"]) + "&" + "pk=" + str(
|
||||
self.info_map[mode]["pk"])
|
||||
ota_log.info(params)
|
||||
uri = self.url + prefix + params
|
||||
headers = dict(access_token=self.access_token)
|
||||
try:
|
||||
resp = request.get(uri, headers=headers)
|
||||
json_data = resp.json()
|
||||
ota_log.info("get_upgrade_url json data {}".format(json_data))
|
||||
if json_data["code"] == 200:
|
||||
self.upgrade_info = json_data
|
||||
return RET.OK
|
||||
else:
|
||||
ota_log.info("no upgrade plan for this device")
|
||||
return RET.NOUPGRADE
|
||||
except Exception as e:
|
||||
ota_log.info("get_upgrade_url {}".format(e))
|
||||
return RET.GETUPGRADEURLERR
|
||||
|
||||
def _register_upgrade(self, mode, version=""):
|
||||
"""
|
||||
注册脚本升级
|
||||
:param version:版本叿
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
list_dirs = uos.listdir(USR)
|
||||
if CONFIG_PATH in list_dirs:
|
||||
|
||||
with open(USR + CONFIG_PATH, "r") as f:
|
||||
self.ota_config_info = ujson.loads(f.read())
|
||||
else:
|
||||
if mode == APP_MODE:
|
||||
# 应用检测版本号
|
||||
if version:
|
||||
self.ota_config_info["version"] = version
|
||||
with open(USR + CONFIG_PATH, "w") as f:
|
||||
f.write(ujson.dumps(self.ota_config_info))
|
||||
except Exception as e:
|
||||
ota_log.error("register_upgrade_sh = {}".format(e))
|
||||
# 读写config 错误
|
||||
return RET.GETCONFIGERR
|
||||
|
||||
# 获取token
|
||||
state = self.get_token()
|
||||
if state != RET.OK:
|
||||
return state
|
||||
|
||||
try:
|
||||
if mode == APP_MODE:
|
||||
# app mode
|
||||
self.version = self.ota_config_info["version"]
|
||||
if self.ota_config_info["flag"] == "1":
|
||||
# 升级成功
|
||||
self.report("UPGRADE_SUCCESS", self.ota_config_info["version"])
|
||||
self.ota_config_info["flag"] = "0"
|
||||
with open(USR + CONFIG_PATH, "w") as f:
|
||||
f.write(ujson.dumps(self.ota_config_info))
|
||||
elif mode == BIN_MODE:
|
||||
# bin mode
|
||||
self.version = modem.getDevFwVersion()
|
||||
if self.ota_config_info["fw_version"] != self.version:
|
||||
# OTA升级成功
|
||||
self.report("UPGRADE_SUCCESS", self.version)
|
||||
self.ota_config_info['fw_version'] = self.version
|
||||
with open(USR + CONFIG_PATH, "w") as f:
|
||||
f.write(ujson.dumps(self.ota_config_info))
|
||||
else:
|
||||
return RET.MODENOTEXIST
|
||||
return RET.OK
|
||||
except Exception as e:
|
||||
return RET.SAVECONFIGERR
|
||||
|
||||
def register_upgrade_sh(self, version=""):
|
||||
return self._register_upgrade(APP_MODE, version=version)
|
||||
|
||||
def register_upgrade_bin(self):
|
||||
return self._register_upgrade(BIN_MODE)
|
||||
|
||||
def start_upgrade_sh_event(self, module_type, uid, pk, version="", reboot=True):
|
||||
"""
|
||||
开启固件脚本升级方弿
|
||||
:return: STATE
|
||||
"""
|
||||
self.info_map[APP_MODE]["reboot"] = reboot
|
||||
self.info_map[APP_MODE]["uid"] = uid
|
||||
self.info_map[APP_MODE]["pk"] = pk
|
||||
return self._upgrade_template(APP_MODE, module_type=module_type, version=version)
|
||||
|
||||
def start_upgrade_bin_event(self, module_type, uid, pk, reboot=True):
|
||||
"""
|
||||
开启固件升级方弿
|
||||
:return: STATE
|
||||
"""
|
||||
# 升级脚本
|
||||
self.info_map[BIN_MODE]["reboot"] = reboot
|
||||
self.info_map[BIN_MODE]["uid"] = uid
|
||||
self.info_map[BIN_MODE]["pk"] = pk
|
||||
return self._upgrade_template(BIN_MODE, module_type=module_type)
|
||||
|
||||
def power_restart(self):
|
||||
"""
|
||||
重启前的动作
|
||||
重启设备
|
||||
:return:
|
||||
"""
|
||||
self.power_restart_before()
|
||||
Power.powerRestart()
|
||||
|
||||
def power_restart_before(self):
|
||||
"""
|
||||
定义重启的动使
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def commit_log(self, pk, message, battery=100, prefix="/fota/msg/report"):
|
||||
v2_url = self.url[:-2] + "v2"
|
||||
access_token = self.__get_v2_token(pk, v2_url)
|
||||
if access_token == RET.TOKENERR:
|
||||
return RET.TOKENERR
|
||||
try:
|
||||
cl = net.getCellInfo()[2][0]
|
||||
data_info = {
|
||||
"imei": self.imei,
|
||||
"version": self.ota_config_info["version"],
|
||||
"reportMsg": str(message),
|
||||
"battery": battery,
|
||||
"signalStrength": net.csqQueryPoll(),
|
||||
"cellInfos": [
|
||||
{
|
||||
"lac": cl[5],
|
||||
"mcc": str(cl[2]),
|
||||
"mnc": str(cl[3]),
|
||||
"cid": cl[1],
|
||||
"signalStrength": net.csqQueryPoll(),
|
||||
}
|
||||
]
|
||||
}
|
||||
headers = {
|
||||
"access_token": access_token,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
resp = request.post(self.url + prefix, data=ujson.dumps(data_info),
|
||||
headers=headers)
|
||||
return resp.json()
|
||||
except Exception as e:
|
||||
ota_log.info("commit_log exception {}".format(e))
|
||||
return RET.COMMIT_LOG_ERROR
|
||||
|
||||
def __get_v2_token(self, pk, v2_url, prefix="/oauth/token"):
|
||||
# 获取token
|
||||
if net.csqQueryPoll() == 99 or net.csqQueryPoll() == -1:
|
||||
return RET.NETERR
|
||||
uri = v2_url + prefix
|
||||
try:
|
||||
uri = uri + "?imei=" + self.imei + "&" + "pk=" + pk + "&" + "grantType=1"
|
||||
ota_log.info("uri = {}".format(uri))
|
||||
resp = request.get(uri)
|
||||
json_data = resp.json()
|
||||
ota_log.info("get_v2_token = {}".format(json_data))
|
||||
access_token = json_data["data"]["access_Token"]
|
||||
return access_token
|
||||
except Exception as e:
|
||||
ota_log.error("get_v2_token error:{}".format(e))
|
||||
return RET.TOKENERR
|
||||
|
203
code/usr/bin/components/abstract_service.py
Normal file
203
code/usr/bin/components/abstract_service.py
Normal file
@ -0,0 +1,203 @@
|
||||
from usr.bin.components.blinker_min import Signal, signal
|
||||
from event_message import Event, EventManager, EventMessageObject
|
||||
from usr.bin.components.service_models import QMessageModel, LockMsgModel
|
||||
import _thread
|
||||
|
||||
ANY = "anonymous"
|
||||
|
||||
|
||||
class AbstractService(object):
|
||||
def __init__(self, sign):
|
||||
self.__name = sign
|
||||
|
||||
self.__signal = signal(sign)
|
||||
|
||||
self.__event = Event(sign)
|
||||
|
||||
self.__em = EventManager()
|
||||
|
||||
self.__message_id = 0
|
||||
|
||||
self.__service_status = 0
|
||||
|
||||
self.__em.register_event(self.__event)
|
||||
|
||||
self.__mode = 1
|
||||
|
||||
def set_mode(self, mode):
|
||||
self.__mode = mode
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
return self.__mode
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.__name
|
||||
|
||||
@property
|
||||
def message_id(self):
|
||||
"""return self.next message id."""
|
||||
return self.__message_id + 1
|
||||
|
||||
@property
|
||||
def signal(self):
|
||||
"""signal to get by this method"""
|
||||
return self.__signal
|
||||
|
||||
def ms_id_increase(self):
|
||||
if self.__message_id > 99999:
|
||||
self.__message_id = 0
|
||||
else:
|
||||
self.__message_id += 1
|
||||
return self.message_id
|
||||
|
||||
def _get_message(self, sender=None, msg_type=0xFF, message=None, callback=None, lock_msg=None):
|
||||
"""get message"""
|
||||
if callback is not None and not callable(callback):
|
||||
return None
|
||||
ms_id = self.ms_id_increase()
|
||||
qm = QMessageModel(ms_id=ms_id, msg_type=msg_type, message=message, sender=sender, from_event=self.__event.name,
|
||||
lock_msg=lock_msg)
|
||||
return qm
|
||||
|
||||
def _callback(self, **kwargs):
|
||||
"""event callback"""
|
||||
em = kwargs.get("event_message", False)
|
||||
if em.msg:
|
||||
msg = em.msg
|
||||
try:
|
||||
self.signal.send(em.msg.sender, message=msg())
|
||||
except Exception as e:
|
||||
success = 0
|
||||
else:
|
||||
success = 1
|
||||
resp_data = dict(message=msg(), success=success)
|
||||
if em.callback is not None:
|
||||
try:
|
||||
em.callback(**resp_data)
|
||||
except Exception as e:
|
||||
pass
|
||||
if msg.lock_msg is not None:
|
||||
msg.lock_msg.msg = resp_data
|
||||
msg.lock_msg.lock.release()
|
||||
|
||||
def _clear(self, *args, **kwargs):
|
||||
""" stop crontab task"""
|
||||
self.__event.clear()
|
||||
|
||||
def _add_default_handler(self):
|
||||
"""add default handler"""
|
||||
self.add_handler(self._callback)
|
||||
|
||||
def register_event(self):
|
||||
"""achieve by class extend AbstractService"""
|
||||
pass
|
||||
|
||||
def prepare_before_start(self):
|
||||
"""prepare before start action"""
|
||||
pass
|
||||
|
||||
def prepare_before_stop(self):
|
||||
"""prepare after start action"""
|
||||
pass
|
||||
|
||||
def start_crontab(self, *args, **kwargs):
|
||||
"""achieve by timer task"""
|
||||
pass
|
||||
|
||||
def add_handler(self, handler):
|
||||
"""
|
||||
support for scan addition and manual sword
|
||||
:param handler: deal handler
|
||||
:return:
|
||||
"""
|
||||
self.__event.add_handler(handler)
|
||||
return handler
|
||||
|
||||
def add_handler_via(self):
|
||||
"""
|
||||
Support for multiple annotations
|
||||
:return:
|
||||
"""
|
||||
|
||||
def decorator(fn):
|
||||
self.add_handler(fn)
|
||||
return fn
|
||||
|
||||
return decorator
|
||||
|
||||
def send_msg_async(self, msg_type=0xFF, message=None, callback=None, sender=None):
|
||||
if self.status():
|
||||
qm = self._get_message(sender=sender, msg_type=msg_type, message=message, callback=callback)
|
||||
self.__event.post(qm, callback=callback)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def send_msg_sync(self, msg_type=0xFF, message=None, callback=None, sender=None):
|
||||
if self.status():
|
||||
lock = _thread.allocate_lock()
|
||||
lock_msg = LockMsgModel(lock)
|
||||
qm = self._get_message(sender=sender, msg_type=msg_type, message=message, callback=callback,
|
||||
lock_msg=lock_msg)
|
||||
self.__event.post(qm, callback=callback)
|
||||
lock_msg.lock.acquire()
|
||||
msg = lock_msg.msg
|
||||
del lock_msg
|
||||
return msg
|
||||
else:
|
||||
return 0
|
||||
|
||||
def send_msg(self, msg_type=0xFF, message=None, callback=None, sender=None, mode=None):
|
||||
mode_pattern = self.mode
|
||||
if mode is not None:
|
||||
mode_pattern = mode
|
||||
if mode_pattern:
|
||||
return self.send_msg_async(msg_type=msg_type, message=message, callback=callback, sender=sender)
|
||||
else:
|
||||
return self.send_msg_sync(msg_type=msg_type, message=message, callback=callback, sender=sender)
|
||||
|
||||
def _component_start(self):
|
||||
"""start components"""
|
||||
if not self.__service_status:
|
||||
self.register_event()
|
||||
self._add_default_handler()
|
||||
self.prepare_before_start()
|
||||
self.start_crontab()
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
start the service
|
||||
:return: 1 or 0
|
||||
"""
|
||||
self._component_start()
|
||||
self.__service_status = self.__em.start()
|
||||
return self.__service_status
|
||||
|
||||
def status(self):
|
||||
"""
|
||||
status of service
|
||||
:return:
|
||||
"""
|
||||
return self.__em.status
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
stop the service
|
||||
:return:
|
||||
"""
|
||||
self.prepare_before_stop()
|
||||
self.__service_status = self.__em.stop()
|
||||
return self.__service_status
|
||||
|
||||
def close(self):
|
||||
self._clear()
|
||||
|
||||
def subscribe(self, cb, sender=ANY):
|
||||
self.signal.connect(cb, sender=sender)
|
||||
|
||||
def unsubscribe(self, cb, sender=ANY):
|
||||
self.signal.disconnect(cb, sender=sender)
|
||||
|
||||
def publish(self, msg, sender=ANY, msg_type=0XFF):
|
||||
self.send_msg(message=msg, msg_type=msg_type, sender=sender)
|
541
code/usr/bin/components/blinker_min.py
Normal file
541
code/usr/bin/components/blinker_min.py
Normal file
@ -0,0 +1,541 @@
|
||||
# -*- coding: utf-8; fill-column: 76 -*-
|
||||
|
||||
import gc
|
||||
|
||||
__all__ = ["signal", "Signal"]
|
||||
|
||||
|
||||
class attrgetter:
|
||||
__slots__ = ('_attrs', '_call')
|
||||
|
||||
def __init__(self, attr, *attrs):
|
||||
if not attrs:
|
||||
if not isinstance(attr, str):
|
||||
raise TypeError('attribute name must be a string')
|
||||
self._attrs = (attr,)
|
||||
names = attr.split('.')
|
||||
|
||||
def func(obj):
|
||||
for name in names:
|
||||
obj = getattr(obj, name)
|
||||
return obj
|
||||
|
||||
self._call = func
|
||||
else:
|
||||
self._attrs = (attr,) + attrs
|
||||
getters = tuple(map(attrgetter, self._attrs))
|
||||
|
||||
def func(obj):
|
||||
return tuple(getter(obj) for getter in getters)
|
||||
|
||||
self._call = func
|
||||
|
||||
def __call__(self, obj):
|
||||
return self._call(obj)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s.%s(%s)' % (self.__class__.__module__,
|
||||
self.__class__.__qualname__,
|
||||
', '.join(map(repr, self._attrs)))
|
||||
|
||||
|
||||
class ReferenceType(object):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
return super(ReferenceType, cls).__new__(cls)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.params = dict()
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.__dict__[key] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key not in self.__dict__:
|
||||
self.__dict__[key] = None
|
||||
return self.__dict__[key]
|
||||
|
||||
__callback__ = property(lambda self: object(), lambda self, v: None, lambda self: None) # default
|
||||
|
||||
|
||||
ref = ReferenceType
|
||||
|
||||
|
||||
class KeyedRef(ref):
|
||||
__slots__ = "key",
|
||||
|
||||
def __new__(type, ob, callback, key):
|
||||
self = ref.__new__(type, ob, callback)
|
||||
self.key = key
|
||||
return self
|
||||
|
||||
def __init__(self, ob, callback, key):
|
||||
super().__init__(ob, callback)
|
||||
|
||||
|
||||
class WeakValueDictionary(dict):
|
||||
def __init__(self, dict=None):
|
||||
self.data = {}
|
||||
|
||||
def remove(k, selfref=ref(self)):
|
||||
self = selfref()
|
||||
if self is not None:
|
||||
if self._iterating:
|
||||
self._pending_removals.append(k)
|
||||
else:
|
||||
del self.data[k]
|
||||
|
||||
self._remove = remove
|
||||
self._pending_removals = []
|
||||
self._iterating = set()
|
||||
self._dirty_len = False
|
||||
if dict is not None:
|
||||
self.update(dict)
|
||||
|
||||
def _commit_removals(self):
|
||||
gc.collect()
|
||||
|
||||
def __getitem__(self, key):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
o = self.data[key]()
|
||||
if o is None:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
return o
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data[key] = KeyedRef(value, self._remove, key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
try:
|
||||
wr = self.data[key]
|
||||
except KeyError:
|
||||
return default
|
||||
else:
|
||||
o = wr()
|
||||
if o is None:
|
||||
return default
|
||||
else:
|
||||
return o
|
||||
|
||||
def update(self, other=None, **kwargs):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
d = self.data
|
||||
if other is not None:
|
||||
if not hasattr(other, "items"):
|
||||
other = dict(other)
|
||||
for key, o in other.items():
|
||||
d[key] = KeyedRef(o, self._remove, key)
|
||||
for key, o in kwargs.items():
|
||||
d[key] = KeyedRef(o, self._remove, key)
|
||||
|
||||
|
||||
try:
|
||||
callable
|
||||
except NameError:
|
||||
def callable(object):
|
||||
return hasattr(object, '__call__')
|
||||
|
||||
get_self = attrgetter('__self__')
|
||||
get_func = attrgetter('__func__')
|
||||
|
||||
|
||||
class BoundMethodWeakref(object):
|
||||
_all_instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, target, on_delete=None, *arguments, **named):
|
||||
key = cls.calculate_key(target)
|
||||
current = cls._all_instances.get(key)
|
||||
if current is not None:
|
||||
current.deletion_methods.append(on_delete)
|
||||
return current
|
||||
else:
|
||||
base = super(BoundMethodWeakref, cls).__new__(cls)
|
||||
cls._all_instances[key] = base
|
||||
base.__init__(target, on_delete, *arguments, **named)
|
||||
return base
|
||||
|
||||
def __init__(self, target, on_delete=None):
|
||||
def remove(self=self):
|
||||
methods = self.deletion_methods[:]
|
||||
del self.deletion_methods[:]
|
||||
try:
|
||||
del self.__class__._all_instances[self.key]
|
||||
except KeyError:
|
||||
pass
|
||||
for function in methods:
|
||||
try:
|
||||
if callable(function):
|
||||
function(self)
|
||||
except Exception as e:
|
||||
print('Exception during saferef %s '
|
||||
'cleanup function %s: %s' % (self, function, e))
|
||||
|
||||
self.deletion_methods = [on_delete]
|
||||
self.key = self.calculate_key(target)
|
||||
im_self = get_self(target)
|
||||
im_func = get_func(target)
|
||||
self.weak_self = ref(im_self, remove)
|
||||
self.weak_func = ref(im_func, remove)
|
||||
self.self_name = str(im_self)
|
||||
self.func_name = str(im_func.__name__)
|
||||
|
||||
def calculate_key(cls, target):
|
||||
return (id(get_self(target)), id(get_func(target)))
|
||||
|
||||
calculate_key = classmethod(calculate_key)
|
||||
|
||||
def __str__(self):
|
||||
return "%s(%s.%s)" % (
|
||||
self.__class__.__name__,
|
||||
self.self_name,
|
||||
self.func_name,
|
||||
)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
def __call__(self):
|
||||
target = self.weak_self()
|
||||
if target is not None:
|
||||
function = self.weak_func()
|
||||
if function is not None:
|
||||
return function.__get__(target)
|
||||
return None
|
||||
|
||||
|
||||
class defaultdict(object):
|
||||
params = dict()
|
||||
|
||||
def __init__(self, default_factory=None, *a, **kw):
|
||||
super().__init__(*a, **kw)
|
||||
self.default_factory = default_factory
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
result = self.params[key]
|
||||
return result
|
||||
except KeyError:
|
||||
return self.__missing__(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
try:
|
||||
self.params[key] = set(value)
|
||||
except TypeError:
|
||||
return "Type error"
|
||||
|
||||
def __missing__(self, key):
|
||||
if self.default_factory is None:
|
||||
raise KeyError(key)
|
||||
self.params[key] = value = self.default_factory()
|
||||
return value
|
||||
|
||||
def __reduce__(self):
|
||||
if self.default_factory is None:
|
||||
args = tuple()
|
||||
else:
|
||||
args = self.default_factory,
|
||||
return type(self), args, None, None, self.items()
|
||||
|
||||
def copy(self):
|
||||
return self.__copy__()
|
||||
|
||||
def pop(self, key, default):
|
||||
return self.params.pop(key, default)
|
||||
|
||||
def values(self):
|
||||
return self.params.values()
|
||||
|
||||
def items(self):
|
||||
return self.params.items()
|
||||
|
||||
def clear(self):
|
||||
return self.params.clear()
|
||||
|
||||
def __copy__(self):
|
||||
return type(self)(self.default_factory, self)
|
||||
|
||||
def __repr__(self):
|
||||
return 'defaultdict(%s, %s)' % (self.default_factory,
|
||||
dict.__repr__(self))
|
||||
|
||||
def __contains__(self, key):
|
||||
if key in self.params:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class _symbol(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.__name__ = self.name = name
|
||||
|
||||
def __reduce__(self):
|
||||
return symbol, (self.name,)
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
_symbol.__name__ = 'symbol'
|
||||
|
||||
|
||||
class symbol(object):
|
||||
symbols = {}
|
||||
|
||||
def __new__(cls, name):
|
||||
try:
|
||||
return cls.symbols[name]
|
||||
except KeyError:
|
||||
return cls.symbols.setdefault(name, _symbol(name))
|
||||
|
||||
|
||||
try:
|
||||
text = (str, unicode)
|
||||
except NameError:
|
||||
text = str
|
||||
|
||||
|
||||
def hashable_identity(obj):
|
||||
if hasattr(obj, '__func__'):
|
||||
return (id(obj.__func__), id(obj.__self__))
|
||||
elif isinstance(obj, text):
|
||||
return obj
|
||||
else:
|
||||
return id(obj)
|
||||
|
||||
|
||||
WeakTypes = (ref, BoundMethodWeakref)
|
||||
|
||||
|
||||
class annotatable_weakref(ref):
|
||||
"""A weakref.ref that supports custom instance attributes."""
|
||||
|
||||
|
||||
def reference(object, callback=None, **annotations):
|
||||
if callable(object):
|
||||
weak = callable_reference(object, callback)
|
||||
else:
|
||||
weak = annotatable_weakref(object, callback)
|
||||
for key, value in annotations.items():
|
||||
setattr(weak, key, value)
|
||||
return weak
|
||||
|
||||
|
||||
def callable_reference(object, callback=None):
|
||||
if hasattr(object, 'im_self') and object.im_self is not None:
|
||||
return BoundMethodWeakref(target=object, on_delete=callback)
|
||||
elif hasattr(object, '__self__') and object.__self__ is not None:
|
||||
return BoundMethodWeakref(target=object, on_delete=callback)
|
||||
return annotatable_weakref(object, callback)
|
||||
|
||||
|
||||
ANY = symbol('ANY')
|
||||
ANY.__doc__ = 'Token for "any sender".'
|
||||
ANY_ID = 0
|
||||
|
||||
|
||||
class Signal(object):
|
||||
ANY = ANY
|
||||
|
||||
def receiver_connected(self):
|
||||
return Signal(doc="Emitted after a receiver connects.")
|
||||
|
||||
def receiver_disconnected(self):
|
||||
return Signal(doc="Emitted after a receiver disconnects.")
|
||||
|
||||
def __init__(self, doc=None):
|
||||
self.receivers = {}
|
||||
self._by_receiver = defaultdict(default_factory=set)
|
||||
self._by_sender = defaultdict(default_factory=set)
|
||||
self._weak_senders = {}
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s at %#x>" % (self.__class__.__name__, id(self))
|
||||
|
||||
def connect(self, receiver, sender=ANY, weak=False):
|
||||
receiver_id = hashable_identity(receiver)
|
||||
weak = False
|
||||
receiver_ref = receiver
|
||||
if sender is ANY:
|
||||
sender_id = ANY_ID
|
||||
else:
|
||||
sender_id = hashable_identity(sender)
|
||||
self.receivers.setdefault(receiver_id, receiver_ref)
|
||||
self._by_sender[sender_id].add(receiver_id)
|
||||
self._by_receiver[receiver_id].add(sender_id)
|
||||
del receiver_ref
|
||||
|
||||
if sender is not ANY and sender_id not in self._weak_senders:
|
||||
try:
|
||||
sender_ref = reference(sender, self._cleanup_sender)
|
||||
sender_ref.sender_id = sender_id
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
self._weak_senders.setdefault(sender_id, sender_ref)
|
||||
del sender_ref
|
||||
|
||||
if ('receiver_connected' in self.__dict__ and
|
||||
self.receiver_connected.receivers):
|
||||
try:
|
||||
self.receiver_connected.send(self,
|
||||
receiver=receiver,
|
||||
sender=sender,
|
||||
weak=weak)
|
||||
except:
|
||||
self.disconnect(receiver, sender)
|
||||
raise
|
||||
if receiver_connected.receivers and self is not receiver_connected:
|
||||
try:
|
||||
receiver_connected.send(self,
|
||||
receiver_arg=receiver,
|
||||
sender_arg=sender,
|
||||
weak_arg=weak)
|
||||
except:
|
||||
self.disconnect(receiver, sender)
|
||||
raise
|
||||
return receiver
|
||||
|
||||
def connect_via(self, sender=ANY, weak=False):
|
||||
def decorator(fn):
|
||||
self.connect(fn, sender, weak)
|
||||
return fn
|
||||
|
||||
return decorator
|
||||
|
||||
def send(self, *sender, **kwargs):
|
||||
if len(sender) == 0:
|
||||
sender = None
|
||||
elif len(sender) > 1:
|
||||
raise TypeError('send() accepts only one positional argument, '
|
||||
'%s given' % len(sender))
|
||||
else:
|
||||
sender = sender[0]
|
||||
if not self.receivers:
|
||||
return []
|
||||
else:
|
||||
return [(receiver, receiver(sender, **kwargs))
|
||||
for receiver in self.receivers_for(sender)]
|
||||
|
||||
def has_receivers_for(self, sender):
|
||||
if not self.receivers:
|
||||
return False
|
||||
if self._by_sender[ANY_ID]:
|
||||
return True
|
||||
if sender is ANY:
|
||||
return False
|
||||
return hashable_identity(sender) in self._by_sender
|
||||
|
||||
def receivers_for(self, sender):
|
||||
if self.receivers:
|
||||
sender_id = hashable_identity(sender)
|
||||
if sender_id in self._by_sender:
|
||||
ids = (self._by_sender[ANY_ID] |
|
||||
self._by_sender[sender_id])
|
||||
else:
|
||||
ids = self._by_sender[ANY_ID].copy()
|
||||
for receiver_id in ids:
|
||||
receiver = self.receivers.get(receiver_id)
|
||||
if receiver is None:
|
||||
continue
|
||||
if isinstance(receiver, WeakTypes):
|
||||
strong = receiver()
|
||||
if strong is None:
|
||||
self._disconnect(receiver_id, ANY_ID)
|
||||
continue
|
||||
receiver = strong
|
||||
yield receiver
|
||||
|
||||
def disconnect(self, receiver, sender=ANY):
|
||||
if sender is ANY:
|
||||
sender_id = ANY_ID
|
||||
else:
|
||||
sender_id = hashable_identity(sender)
|
||||
receiver_id = hashable_identity(receiver)
|
||||
self._disconnect(receiver_id, sender_id)
|
||||
|
||||
if ('receiver_disconnected' in self.__dict__ and
|
||||
self.receiver_disconnected.receivers):
|
||||
self.receiver_disconnected.send(self,
|
||||
receiver=receiver,
|
||||
sender=sender)
|
||||
|
||||
def _disconnect(self, receiver_id, sender_id):
|
||||
if sender_id == ANY_ID:
|
||||
if self._by_receiver.pop(receiver_id, False):
|
||||
for bucket in self._by_sender.values():
|
||||
bucket.discard(receiver_id)
|
||||
self.receivers.pop(receiver_id, None)
|
||||
else:
|
||||
self._by_sender[sender_id].discard(receiver_id)
|
||||
self._by_receiver[receiver_id].discard(sender_id)
|
||||
|
||||
def _cleanup_receiver(self, receiver_ref):
|
||||
self._disconnect(receiver_ref.receiver_id, ANY_ID)
|
||||
|
||||
def _cleanup_sender(self, sender_ref):
|
||||
sender_id = sender_ref.sender_id
|
||||
assert sender_id != ANY_ID
|
||||
self._weak_senders.pop(sender_id, None)
|
||||
for receiver_id in self._by_sender.pop(sender_id, ()):
|
||||
self._by_receiver[receiver_id].discard(sender_id)
|
||||
|
||||
def _cleanup_bookkeeping(self):
|
||||
for mapping in (self._by_sender, self._by_receiver):
|
||||
for _id, bucket in list(mapping.items()):
|
||||
if not bucket:
|
||||
mapping.pop(_id, None)
|
||||
|
||||
def _clear_state(self):
|
||||
self._weak_senders.clear()
|
||||
self.receivers.clear()
|
||||
self._by_sender.clear()
|
||||
self._by_receiver.clear()
|
||||
|
||||
|
||||
receiver_connected = Signal("""\
|
||||
Sent by a :class:`Signal` after a receiver connects.
|
||||
""")
|
||||
|
||||
|
||||
class NamedSignal(Signal):
|
||||
|
||||
def __init__(self, name, doc=None):
|
||||
Signal.__init__(self, doc)
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
base = Signal.__repr__(self)
|
||||
return "%s; %r>" % (base[:-1], self.name)
|
||||
|
||||
|
||||
class Namespace(dict):
|
||||
|
||||
def signal(self, name, doc=None):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return self.setdefault(name, NamedSignal(name, doc))
|
||||
|
||||
|
||||
signal = Namespace().signal
|
||||
if __name__ == '__main__':
|
||||
dice_roll = signal('dice_roll')
|
||||
|
||||
|
||||
def odd_subscriber(sender, **kwargs):
|
||||
print("Observed dice roll %r. %r" % (sender, kwargs))
|
||||
|
||||
|
||||
dice_roll.connect(odd_subscriber, sender=0x03)
|
||||
result = dice_roll.send(3)
|
96
code/usr/bin/components/monitor.py
Normal file
96
code/usr/bin/components/monitor.py
Normal file
@ -0,0 +1,96 @@
|
||||
__all__ = [
|
||||
"ServiceMonitor",
|
||||
]
|
||||
|
||||
from misc import Power
|
||||
import osTimer
|
||||
|
||||
|
||||
class MonitorInterface(object):
|
||||
def start(self):
|
||||
"""start"""
|
||||
|
||||
def stop(self):
|
||||
"""stop"""
|
||||
|
||||
def status(self):
|
||||
"""status"""
|
||||
|
||||
|
||||
class ServiceMonitor(MonitorInterface):
|
||||
THRESHOLD = 3
|
||||
|
||||
def __init__(self, service):
|
||||
self.service = service
|
||||
self.__failed_count = 0
|
||||
self.__level = 0
|
||||
self.__timer = None
|
||||
self.__ping_count = 0
|
||||
self.__exception_handlers = {}
|
||||
self.service.signal.connect(self.ping_handler, sender=0xFE)
|
||||
|
||||
def set_level(self, level):
|
||||
if self.__level != level:
|
||||
self.__level = level
|
||||
|
||||
def __timer_handle(self, *args):
|
||||
"""定时器调度"""
|
||||
if self.__ping_count:
|
||||
self.__failed_count += 1
|
||||
self.__ping_count = self.__ping_count + 1
|
||||
self.service.signal.send(0xFE)
|
||||
if self.__failed_count:
|
||||
self.__failed_handle()
|
||||
|
||||
def set_exception_handlers(self, handler):
|
||||
if handler is not None:
|
||||
self.__exception_handlers = handler
|
||||
|
||||
def __failed_handle(self):
|
||||
"""失败处理"""
|
||||
try:
|
||||
for k, v in self.__exception_handlers.items():
|
||||
if k == "reboot":
|
||||
if v.get("failCount") == self.__failed_count:
|
||||
# 关机
|
||||
Power.powerDown()
|
||||
elif k == "stop":
|
||||
if v.get("failCount") == self.__failed_count:
|
||||
# 停止服务
|
||||
self.stop()
|
||||
else:
|
||||
continue
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def ping_handler(self, *args, **kwargs):
|
||||
self.__ping_count = 0
|
||||
|
||||
def start(self):
|
||||
if self.__level != self.THRESHOLD:
|
||||
self.service.start()
|
||||
if self.__timer is None:
|
||||
self.__timer = osTimer()
|
||||
self.__timer.start(15000, 1, self.__timer_handle)
|
||||
return self.status()
|
||||
|
||||
def status(self):
|
||||
return self.service.status()
|
||||
|
||||
def clear(self):
|
||||
self.__failed_count = 0
|
||||
self.__level = 0
|
||||
if self.__timer is not None:
|
||||
self.__timer.stop()
|
||||
self.__timer.delete()
|
||||
self.__timer = None
|
||||
self.__ping_count = 0
|
||||
|
||||
def stop(self):
|
||||
if self.__level != self.THRESHOLD:
|
||||
self.service.stop()
|
||||
self.clear()
|
||||
return self.status
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.service
|
72
code/usr/bin/components/service_models.py
Normal file
72
code/usr/bin/components/service_models.py
Normal file
@ -0,0 +1,72 @@
|
||||
__all__ = [
|
||||
"QMessageModel"
|
||||
]
|
||||
|
||||
|
||||
class ModelDTO(object):
|
||||
def model_to_dict(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.model_to_dict(*args, **kwargs)
|
||||
|
||||
|
||||
class QMessageModel(ModelDTO):
|
||||
def __init__(self, ms_id=None, msg_type=0xFF, message=None, sender=None, from_event=None, lock_msg=None):
|
||||
self.__msg_type = msg_type
|
||||
self.__message_id = ms_id
|
||||
self.__message = message
|
||||
self.__sender = "anonymous" if sender is None else sender
|
||||
self.__from_event = from_event
|
||||
self.__lock_msg = lock_msg
|
||||
|
||||
@property
|
||||
def msg_type(self):
|
||||
return self.__msg_type
|
||||
|
||||
@property
|
||||
def lock_msg(self):
|
||||
return self.__lock_msg
|
||||
|
||||
@property
|
||||
def message_id(self):
|
||||
return self.__message_id
|
||||
|
||||
@property
|
||||
def sender(self):
|
||||
return self.__sender
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
return self.__message
|
||||
|
||||
@property
|
||||
def from_event(self):
|
||||
return self.__from_event
|
||||
|
||||
def model_to_dict(self):
|
||||
return dict(message_id=self.message_id, msg_type=self.msg_type, message=self.message, sender=self.sender,
|
||||
from_event=self.from_event)
|
||||
|
||||
|
||||
class LockMsgModel(ModelDTO):
|
||||
"""传输对象"""
|
||||
|
||||
def __init__(self, lock):
|
||||
self.__lock = lock
|
||||
self.__msg = dict(message=None)
|
||||
|
||||
@property
|
||||
def msg(self):
|
||||
return self.__msg
|
||||
|
||||
@msg.setter
|
||||
def msg(self, msg):
|
||||
self.__msg = msg
|
||||
|
||||
@property
|
||||
def lock(self):
|
||||
return self.__lock
|
||||
|
||||
def model_to_dict(self, *args, **kwargs):
|
||||
return dict(lock=self.__lock, msg=self.__msg)
|
32
code/usr/bin/exception_service.py
Normal file
32
code/usr/bin/exception_service.py
Normal file
@ -0,0 +1,32 @@
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
from usr.utils.service_utils import Singleton
|
||||
|
||||
|
||||
class ExceptionServiceMonitor(ServiceMonitor):
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
esm = ExceptionServiceMonitor(ExceptionService())
|
||||
if config is not None:
|
||||
esm.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return esm
|
||||
|
||||
|
||||
@Singleton
|
||||
class ExceptionService(AbstractService):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("EXCEPTION")
|
||||
self.error_message = []
|
||||
|
||||
def handler_error(self, *args, **kwargs):
|
||||
msg = "message"
|
||||
em = kwargs.get(msg, False)
|
||||
if em:
|
||||
print(em[msg])
|
||||
|
||||
def prepare_before_start(self):
|
||||
self.signal.connect(self.handler_error, sender="anonymous")
|
||||
|
||||
def __call__(self, message):
|
||||
self.send_msg(message=message)
|
232
code/usr/bin/guard.py
Normal file
232
code/usr/bin/guard.py
Normal file
@ -0,0 +1,232 @@
|
||||
from usr.utils.JsonParserUtils import JsonParser
|
||||
from usr.bin.exception_service import ExceptionService
|
||||
from usr.utils.service_utils import Singleton
|
||||
from usr.bin.components.monitor import MonitorInterface
|
||||
from usr.bin.log_service import LogAdapter
|
||||
import uos as os
|
||||
|
||||
__GROUP_ID = "qpy.quectel.com"
|
||||
__ARTIFACT_ID = "qpy-framework"
|
||||
__VERSION = "1.0.0.RELEASE"
|
||||
|
||||
|
||||
def version():
|
||||
return {"GROUP_ID": __GROUP_ID, "artifact_id": __ARTIFACT_ID, "VERSION": __VERSION}
|
||||
|
||||
|
||||
@Singleton
|
||||
class Guard(object):
|
||||
def __init__(self):
|
||||
self.monitor_service = set()
|
||||
self.timer = None
|
||||
self.__status = 0
|
||||
|
||||
def register_monitor(self, monitor):
|
||||
self.monitor_service.add(monitor)
|
||||
|
||||
def start(self):
|
||||
for monitor in self.monitor_service:
|
||||
monitor.start()
|
||||
self.__status = 1
|
||||
|
||||
def reload_level(self):
|
||||
for monitor in self.monitor_service:
|
||||
monitor.set_level(0)
|
||||
monitor.start()
|
||||
self.__status = 1
|
||||
|
||||
def stop(self):
|
||||
for monitor in self.monitor_service:
|
||||
monitor.stop()
|
||||
self.__status = 0
|
||||
|
||||
def status(self):
|
||||
return self.__status
|
||||
|
||||
def upgrade(self):
|
||||
pass
|
||||
|
||||
def monitor_map(self):
|
||||
return {m.service.name: m.service for m in self.monitor_service}
|
||||
|
||||
|
||||
@Singleton
|
||||
class GuardContext(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__guard = Guard()
|
||||
self.system_config = {}
|
||||
self.service_config = {}
|
||||
self.config_map = {
|
||||
"/usr/etc/system_config": self.system_config,
|
||||
"/usr/etc/app_config": self.service_config
|
||||
}
|
||||
self.config_parser = JsonParser()
|
||||
self.monitor_map = dict()
|
||||
self.error_handler = ExceptionService()
|
||||
self.error_handler.start()
|
||||
|
||||
def servers(self):
|
||||
return self.monitor_map.copy()
|
||||
|
||||
def get_server(self, name):
|
||||
return self.monitor_map[name]()
|
||||
|
||||
def stop_server(self, name):
|
||||
return self.monitor_map[name].stop()
|
||||
|
||||
@staticmethod
|
||||
def get_logger(name):
|
||||
return LogAdapter(name)
|
||||
|
||||
@staticmethod
|
||||
def path_exist(check_path):
|
||||
try:
|
||||
os.stat(check_path)
|
||||
except Exception as e:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
def load_config_definitions(self):
|
||||
# load config
|
||||
# root path /usr/etc
|
||||
root_path = "/usr/etc/"
|
||||
stat = self.path_exist(root_path)
|
||||
if not stat:
|
||||
return
|
||||
self.load_configs(root_path)
|
||||
|
||||
def load_configs(self, root_path):
|
||||
|
||||
# system_path of service /usr/etc/system_config
|
||||
stat = self.path_exist(root_path)
|
||||
if not stat:
|
||||
self.error_handler("[ WARN ] {} path is not exist".format(root_path))
|
||||
return True
|
||||
for par_path in os.listdir(root_path):
|
||||
abs_path = root_path + par_path
|
||||
for sub_path in os.listdir(abs_path):
|
||||
truth_path = abs_path + "/" + sub_path
|
||||
rep_d = self.config_parser.parse(truth_path)
|
||||
if rep_d["status"] == 0:
|
||||
# 错误日志收集
|
||||
self.error_handler("[ WARN ] read {} status {}".format(truth_path, 0))
|
||||
else:
|
||||
self.config_map[abs_path][sub_path] = rep_d["data"]
|
||||
|
||||
def create_monitors(self):
|
||||
# 创建monitors
|
||||
monitor_map = dict()
|
||||
monitor_map.update(self.create_system_monitors())
|
||||
monitor_map.update(self.create_app_monitors())
|
||||
self.monitor_map = monitor_map
|
||||
|
||||
def start(self):
|
||||
# 启动守卫 拉起所有的服务
|
||||
self.__guard.start()
|
||||
|
||||
def register_monitors(self):
|
||||
# 注册monitor
|
||||
for k, v in self.monitor_map.items():
|
||||
self.__guard.register_monitor(v)
|
||||
|
||||
def register_monitor(self, k, v):
|
||||
flag = False
|
||||
if isinstance(v, MonitorInterface) and isinstance(k, str):
|
||||
self.monitor_map[k] = v
|
||||
self.__guard.register_monitor(v)
|
||||
flag = not flag
|
||||
return flag
|
||||
|
||||
def refresh(self):
|
||||
self.load_config_definitions()
|
||||
# 初始化monitor
|
||||
self.create_monitors()
|
||||
self.register_monitors()
|
||||
self.start()
|
||||
|
||||
def reload(self):
|
||||
# 刷新通知
|
||||
self.__guard.reload_level()
|
||||
|
||||
def create_system_monitors(self):
|
||||
monitor_map = dict()
|
||||
try:
|
||||
from usr.bin.net_service import NetServiceMonitor
|
||||
NET = "net"
|
||||
net_monitor = NetServiceMonitor.create_monitor(self.system_config.get(NET, None))
|
||||
monitor_map[NET] = net_monitor
|
||||
print("[ OK ] create sys monitor net service")
|
||||
except Exception as e:
|
||||
# 异常重定向
|
||||
self.error_handler("[ FAILED ] load net monitor error reason:{}".format(e))
|
||||
|
||||
try:
|
||||
from usr.bin.log_service import LogServiceMonitor
|
||||
LOG = "log"
|
||||
log_monitor = LogServiceMonitor.create_monitor(self.system_config.get(LOG, None))
|
||||
monitor_map[LOG] = log_monitor
|
||||
print("[ OK ] create sys monitor log service")
|
||||
except Exception as e:
|
||||
self.error_handler("[ FAILED ] load log monitor error reason:{}".format(e))
|
||||
return monitor_map
|
||||
|
||||
def create_app_monitors(self):
|
||||
monitor_map = dict()
|
||||
try:
|
||||
from usr.bin.media_service import MediaServiceMonitor
|
||||
MEDIA = "media"
|
||||
md_monitor = MediaServiceMonitor.create_monitor(self.service_config.get(MEDIA, None))
|
||||
if md_monitor is not None:
|
||||
monitor_map[MEDIA] = md_monitor
|
||||
else:
|
||||
raise Exception("media service load error")
|
||||
print("[ OK ] create app monitor media service")
|
||||
except Exception as e:
|
||||
# 异常重定向
|
||||
self.error_handler("[ FAILED ] load exception monitor error reason: [{}]".format(e))
|
||||
|
||||
try:
|
||||
from usr.bin.exception_service import ExceptionServiceMonitor
|
||||
EXCEPTION = "exception"
|
||||
ex_monitor = ExceptionServiceMonitor.create_monitor(self.service_config.get(EXCEPTION, None))
|
||||
if ex_monitor is not None:
|
||||
monitor_map[EXCEPTION] = ex_monitor
|
||||
else:
|
||||
raise Exception("exception service load error")
|
||||
print("[ OK ] create app monitor exception service")
|
||||
except Exception as e:
|
||||
# 异常重定向
|
||||
self.error_handler("[ FAILED ] load exception monitor error reason:[{}]".format(e))
|
||||
|
||||
try:
|
||||
from usr.bin.cloud_service import CloudServiceMonitor
|
||||
CLOUD = "cloud"
|
||||
cd_monitor = CloudServiceMonitor.create_monitor(self.service_config.get(CLOUD, None))
|
||||
if cd_monitor is not None:
|
||||
monitor_map[CLOUD] = cd_monitor
|
||||
else:
|
||||
raise Exception("cloud service load error")
|
||||
print("[ OK ] create app monitor cloud service")
|
||||
except Exception as e:
|
||||
# 异常重定向
|
||||
self.error_handler("[ FAILED ] load cloud monitor error reason:[{}]".format(e))
|
||||
|
||||
try:
|
||||
from usr.bin.pm_service import PMServiceMonitor
|
||||
PM = "pm"
|
||||
pm_monitor = PMServiceMonitor.create_monitor(self.service_config.get(PM, None))
|
||||
if pm_monitor is not None:
|
||||
monitor_map[PM] = pm_monitor
|
||||
else:
|
||||
raise Exception("pm service load error")
|
||||
print("[ OK ] create app monitor pm service")
|
||||
except Exception as e:
|
||||
# 异常重定向
|
||||
self.error_handler("[ FAILED ] load pm monitor error reason:[{}]".format(e))
|
||||
|
||||
return monitor_map
|
||||
|
||||
def version(self):
|
||||
return version()
|
232
code/usr/bin/log_service.py
Normal file
232
code/usr/bin/log_service.py
Normal file
@ -0,0 +1,232 @@
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.utils.service_utils import Singleton
|
||||
from usr.utils.resolver import TimeResolver
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
from machine import UART
|
||||
import uos
|
||||
|
||||
LOGGER = "LOG"
|
||||
|
||||
|
||||
class LOG_LV:
|
||||
DEBUG = "DEBUG"
|
||||
INFO = "INFO"
|
||||
WARNING = "WARNING"
|
||||
ERROR = "ERROR"
|
||||
CRITICAL = "CRITICAL"
|
||||
|
||||
|
||||
class AbstractLogOutputUtil(object):
|
||||
def open(self):
|
||||
pass
|
||||
|
||||
def output(self, message, **kwargs):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def __call__(self, message, **kwargs):
|
||||
self.output(message, **kwargs)
|
||||
|
||||
|
||||
@Singleton
|
||||
class UartLogOutputUtil(AbstractLogOutputUtil):
|
||||
def __init__(self, UARTn=UART.UART2):
|
||||
self.uart = UART(UARTn, 115200, 8, 0, 1, 0)
|
||||
|
||||
def output(self, message, **kwargs):
|
||||
self.uart.write(message)
|
||||
|
||||
|
||||
@Singleton
|
||||
class PrintLogOutputUtil(AbstractLogOutputUtil):
|
||||
def output(self, message, **kwargs):
|
||||
print(message)
|
||||
|
||||
|
||||
@Singleton
|
||||
class MqttLogOutputUtil(AbstractLogOutputUtil):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def output(self, message, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
@Singleton
|
||||
class ConsoleLogOutputUtil(AbstractLogOutputUtil):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def output(self, message, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
@Singleton
|
||||
class FileLogOutputUtil(AbstractLogOutputUtil):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.file_name = "log.txt"
|
||||
self.abs_path = "/usr/log/"
|
||||
self.content = []
|
||||
self.f = None
|
||||
|
||||
def open(self):
|
||||
if "log" not in uos.listdir("/usr"):
|
||||
uos.mkdir(self.abs_path)
|
||||
self.f = open(self.abs_path + self.file_name, "w+")
|
||||
|
||||
def output(self, message, **kwargs):
|
||||
self.open()
|
||||
if len(self.content) > 10:
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
self.f.close()
|
||||
self.f = None
|
||||
|
||||
|
||||
class AbstractFormatUtil(object):
|
||||
def format(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class LogFormatUtil(AbstractFormatUtil):
|
||||
def format(self, *args, **kwargs):
|
||||
log_format = "{} {} [{}] - {}\n".format(args[0], args[1], args[2], args[3])
|
||||
return log_format
|
||||
|
||||
|
||||
class LogServiceMonitor(ServiceMonitor):
|
||||
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
log_service = LogService()
|
||||
if config is not None:
|
||||
level = config.get('level')
|
||||
log_service.set_level(level)
|
||||
lsm = LogServiceMonitor(log_service)
|
||||
if config is not None:
|
||||
lsm.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return lsm
|
||||
|
||||
|
||||
@Singleton
|
||||
class LogService(AbstractService):
|
||||
"""
|
||||
default log is async queue
|
||||
you can set
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(LOGGER)
|
||||
self.__reporter = PrintLogOutputUtil()
|
||||
self.__tr = TimeResolver()
|
||||
self.format_util = LogFormatUtil()
|
||||
self.__level_map = {
|
||||
LOG_LV.DEBUG: 0,
|
||||
LOG_LV.INFO: 1,
|
||||
LOG_LV.WARNING: 2,
|
||||
LOG_LV.ERROR: 3,
|
||||
LOG_LV.CRITICAL: 4
|
||||
}
|
||||
self.low_level = 0
|
||||
|
||||
def __set_report(self, report):
|
||||
if isinstance(report, AbstractLogOutputUtil):
|
||||
self.__reporter = report
|
||||
|
||||
def set_output(self, out_obj):
|
||||
if isinstance(out_obj, AbstractLogOutputUtil):
|
||||
self.__reporter.close()
|
||||
self.__reporter = out_obj
|
||||
self.__reporter.open()
|
||||
else:
|
||||
self.log_send(self.name, LOG_LV.ERROR, '"{}" is not extend AbstractLogOutputUtil'.format(out_obj))
|
||||
raise Exception('"{}" is not extend AbstractLogOutputUtil'.format(out_obj))
|
||||
|
||||
def set_level(self, level):
|
||||
if level in self.__level_map:
|
||||
self.low_level = self.__level_map[level]
|
||||
else:
|
||||
self.low_level = 0
|
||||
|
||||
def log_send(self, sign, level, msg, mode=1):
|
||||
"""send log deal"""
|
||||
if self.mode is not None:
|
||||
mode = self.mode
|
||||
if self.__level_map[level] >= self.low_level:
|
||||
if mode:
|
||||
self.send_msg_async(message=self.format_msg(sign, level, msg))
|
||||
else:
|
||||
self.send_msg_sync(message=self.format_msg(sign, level, msg))
|
||||
|
||||
def format_msg(self, sign, level, msg):
|
||||
"""
|
||||
format msg
|
||||
year-month-day hour-minute-second weekday service [level] - message
|
||||
"""
|
||||
return self.format_util.format(self.__tr.resolver(), sign, level, msg)
|
||||
|
||||
def output_msg(self, *args, **kwargs):
|
||||
msg = "message"
|
||||
em = kwargs.get(msg, False)
|
||||
if em:
|
||||
self.__reporter.output(em[msg])
|
||||
|
||||
def prepare_before_stop(self):
|
||||
self.__reporter.close()
|
||||
|
||||
def prepare_before_start(self):
|
||||
self.signal.connect(self.output_msg, sender="anonymous")
|
||||
self.__reporter.open()
|
||||
|
||||
|
||||
class LogAdapter(object):
|
||||
"""
|
||||
log adapter mode
|
||||
mode used : adapter proxy single LogService
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, enable=1):
|
||||
self.log_service = LogService()
|
||||
self.name = name
|
||||
self.enable = enable
|
||||
self.mode = 1
|
||||
self.tag = None
|
||||
|
||||
def get_tag(self):
|
||||
if self.tag is None:
|
||||
return self.name
|
||||
else:
|
||||
return self.tag
|
||||
|
||||
def critical(self, msg):
|
||||
if self.enable:
|
||||
self.log_service.log_send(self.name, LOG_LV.CRITICAL, msg, self.mode)
|
||||
|
||||
def debug(self, msg):
|
||||
if self.enable:
|
||||
self.log_service.log_send(self.name, LOG_LV.DEBUG, msg, self.mode)
|
||||
|
||||
def info(self, msg):
|
||||
if self.enable:
|
||||
self.log_service.log_send(self.name, LOG_LV.INFO, msg, self.mode)
|
||||
|
||||
def warning(self, msg):
|
||||
if self.enable:
|
||||
self.log_service.log_send(self.name, LOG_LV.WARNING, msg, self.mode)
|
||||
|
||||
def error(self, msg):
|
||||
if self.enable:
|
||||
self.log_service.log_send(self.name, LOG_LV.ERROR, msg, self.mode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
net_ser = LogAdapter("Net")
|
||||
ls = LogService()
|
||||
ls.start()
|
||||
net_ser.debug("111")
|
98
code/usr/bin/media_service.py
Normal file
98
code/usr/bin/media_service.py
Normal file
@ -0,0 +1,98 @@
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
import audio
|
||||
import utime
|
||||
|
||||
MEDIA = "MEDIA"
|
||||
MEDIA_TYPE_MAP = {
|
||||
"AUDIO": 0,
|
||||
"TTS": 1
|
||||
}
|
||||
|
||||
|
||||
class MediaServiceMonitor(ServiceMonitor):
|
||||
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
media_service = MediaService()
|
||||
if config is not None:
|
||||
try:
|
||||
if config.get('enable', True):
|
||||
mode = config["params"]["mode"]
|
||||
return MediaServiceMonitor(media_service)
|
||||
except Exception as e:
|
||||
# 这里异常重定向
|
||||
return None
|
||||
msm = MediaServiceMonitor(media_service)
|
||||
if config is not None:
|
||||
msm.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return msm
|
||||
|
||||
|
||||
class MediaService(AbstractService):
|
||||
|
||||
def __init__(self, device=0):
|
||||
super().__init__(MEDIA)
|
||||
self.__tts = audio.TTS(device)
|
||||
self.__audio = audio.Audio(device)
|
||||
|
||||
def set_tts(self, mode):
|
||||
self.__tts = audio.TTS(mode)
|
||||
|
||||
def set_audio(self, mode):
|
||||
self.__audio = audio.Audio(mode)
|
||||
|
||||
def set_pa(self, pa):
|
||||
return self.__audio.set_pa(pa)
|
||||
|
||||
def set_mode(self, mode):
|
||||
if mode in range(0x03):
|
||||
self.set_audio(mode)
|
||||
self.set_tts(mode)
|
||||
else:
|
||||
raise Exception("mode {} must in mid of [0,1,2]".format(mode))
|
||||
|
||||
@property
|
||||
def tts(self):
|
||||
return self.__tts
|
||||
|
||||
@property
|
||||
def audio(self):
|
||||
return self.__audio
|
||||
|
||||
def _play(self, sender, **kwargs):
|
||||
msg_type = kwargs["message"]['msg_type']
|
||||
msg = kwargs["message"]['message']
|
||||
# 策略
|
||||
ret = self.__start_play(msg_type, msg)
|
||||
|
||||
while ret == -2:
|
||||
print(ret, msg)
|
||||
ret = self.__start_play(msg_type, msg)
|
||||
utime.sleep(1)
|
||||
|
||||
def __start_play(self, msg_type, msg):
|
||||
if msg_type == MEDIA_TYPE_MAP["TTS"]:
|
||||
ret = self.__tts.play(msg["priority"], msg["breakin"], msg["mode"], msg['play_data'])
|
||||
else:
|
||||
ret = self.__audio.play(msg["priority"], msg["breakin"], msg['play_data'])
|
||||
return ret
|
||||
|
||||
def tts_play(self, priority=4, breakin=0, mode=2, play_data="", sender=None):
|
||||
message = dict(priority=priority, breakin=breakin, mode=mode, play_data=play_data)
|
||||
self.send_msg(msg_type=MEDIA_TYPE_MAP["TTS"], sender=sender, message=message)
|
||||
|
||||
def audio_play(self, priority=4, breakin=0, play_data="", sender=None):
|
||||
message = dict(priority=priority, breakin=breakin, play_data=play_data)
|
||||
self.send_msg(msg_type=MEDIA_TYPE_MAP["AUDIO"], sender=sender, message=message)
|
||||
|
||||
def register_event(self):
|
||||
super().register_event()
|
||||
self.signal.connect(self._play, sender="anonymous")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
media = MediaService()
|
||||
media.start()
|
||||
media.audio.setVolume(2)
|
||||
media.tts_play(play_data="123")
|
143
code/usr/bin/net_service.py
Normal file
143
code/usr/bin/net_service.py
Normal file
@ -0,0 +1,143 @@
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.utils.service_utils import Singleton
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
import dataCall
|
||||
import net
|
||||
import sim
|
||||
import checkNet
|
||||
|
||||
__all__ = ["NetService"]
|
||||
NET = "NET"
|
||||
|
||||
ENABLE_ = "enable"
|
||||
NET_ = "NET"
|
||||
DATACALL_ = "DATACALL"
|
||||
|
||||
|
||||
class NetServiceMonitor(ServiceMonitor):
|
||||
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
net_service = NetService()
|
||||
nsm = NetServiceMonitor(net_service)
|
||||
if config is not None:
|
||||
nsm.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return nsm
|
||||
|
||||
|
||||
@Singleton
|
||||
class NetService(AbstractService):
|
||||
def __init__(self):
|
||||
super().__init__(NET)
|
||||
|
||||
self.__data_call = dataCall
|
||||
|
||||
self.__net = net
|
||||
|
||||
self.__sim = sim
|
||||
|
||||
self.__net_connect_status = False
|
||||
|
||||
self.__data_call_status = False
|
||||
|
||||
self.server_status = {
|
||||
DATACALL_: {ENABLE_: 1},
|
||||
NET_: {ENABLE_: 0}
|
||||
}
|
||||
self.check_net = checkNet.CheckNetwork("QuecPython_Helios_Framework", "this latest version")
|
||||
|
||||
@property
|
||||
def sim(self):
|
||||
return self.__sim
|
||||
|
||||
@property
|
||||
def data_call(self):
|
||||
return self.__data_call
|
||||
|
||||
@property
|
||||
def net(self):
|
||||
return self.__net
|
||||
|
||||
def set_enable(self, sr, enable):
|
||||
"""set start"""
|
||||
self.server_status[sr][ENABLE_] = enable
|
||||
|
||||
def set_apn(self, profileIdx, ipType, apn, username, password, authType):
|
||||
return self.__data_call.setApn(profileIdx, ipType, apn, username, password, authType)
|
||||
|
||||
def ev_dc(self, args):
|
||||
if self.server_status[DATACALL_][ENABLE_]:
|
||||
profile_idx = args[0]
|
||||
datacall_status = args[1]
|
||||
|
||||
msg_dict = \
|
||||
{
|
||||
"sim_status": None,
|
||||
"net_status": None,
|
||||
"datacall_status": datacall_status,
|
||||
"profile_id": profile_idx,
|
||||
"ip_type": None,
|
||||
"IPv4": None,
|
||||
"IPv4_DNS1": None,
|
||||
"IPv4_DNS2": None,
|
||||
"IPv6": None,
|
||||
"IPv6_DNS1": None,
|
||||
"IPv6_DNS2": None,
|
||||
}
|
||||
|
||||
sim_status = self.__sim.getStatus()
|
||||
net_status = self.__net.getState()
|
||||
datacall_info = self.__data_call.getInfo(profile_idx, 2)
|
||||
|
||||
msg_dict.update({"sim_status": sim_status})
|
||||
|
||||
if net_status != -1:
|
||||
if net_status[0][0] == 0 or net_status[1][0] == 0:
|
||||
msg_dict.update({"net_status": 0})
|
||||
else:
|
||||
msg_dict.update({"net_status": net_status[1][0]})
|
||||
else:
|
||||
msg_dict.update({"net_status": -1})
|
||||
if datacall_info != -1:
|
||||
if datacall_info[2][0] == 1 or datacall_info[3][0] == 1:
|
||||
msg_dict.update({"datacall_status": 1})
|
||||
else:
|
||||
msg_dict.update({"datacall_status": 0})
|
||||
msg_dict.update({"ip_type": datacall_info[1]})
|
||||
msg_dict.update({"IPv4": datacall_info[2][2]})
|
||||
msg_dict.update({"IPv4_DNS1": datacall_info[2][3]})
|
||||
msg_dict.update({"IPv4_DNS2": datacall_info[2][4]})
|
||||
msg_dict.update({"IPv6": datacall_info[3][2]})
|
||||
msg_dict.update({"IPv6_DNS1": datacall_info[3][3]})
|
||||
msg_dict.update({"IPv6_DNS2": datacall_info[3][4]})
|
||||
self.send_msg(msg_type=1, message=msg_dict)
|
||||
|
||||
def ev_nc(self, args):
|
||||
if self.server_status[NET_][ENABLE_]:
|
||||
net_status = args[1]
|
||||
self.send_msg(msg_type=0, message={"network_register_status": net_status})
|
||||
|
||||
def wait_connect(self, timeout):
|
||||
self.check_net.poweron_print_once()
|
||||
return self.check_net.wait_network_connected(timeout)
|
||||
|
||||
def get_net_status(self):
|
||||
self.__data_call_status = self.__data_call.getInfo(1, 0)[2][0]
|
||||
return self.__data_call_status
|
||||
|
||||
def register_event(self):
|
||||
self.__data_call.setCallback(self.ev_dc)
|
||||
# self.__net.setCallback(self.ev_nc)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
net_ser = NetService()
|
||||
|
||||
|
||||
@net_ser.signal.connect_via(0X01)
|
||||
def test(*args, **kwargs):
|
||||
print(kwargs)
|
||||
|
||||
|
||||
net_ser.start()
|
||||
net_ser.send(sender=1, message={})
|
52
code/usr/bin/pm_service.py
Normal file
52
code/usr/bin/pm_service.py
Normal file
@ -0,0 +1,52 @@
|
||||
import pm
|
||||
from usr.bin.components.abstract_service import AbstractService
|
||||
from usr.utils.service_utils import Singleton
|
||||
from usr.bin.components.monitor import ServiceMonitor
|
||||
|
||||
ENABLE_ = "enable"
|
||||
NET_ = "NET"
|
||||
DATACALL_ = "DATACALL"
|
||||
|
||||
|
||||
class PMServiceMonitor(ServiceMonitor):
|
||||
|
||||
@staticmethod
|
||||
def create_monitor(config=None):
|
||||
ps_service = PMService()
|
||||
psm = PMServiceMonitor(ps_service)
|
||||
if config is not None:
|
||||
psm.set_exception_handlers(config.get('exceptionHandlers', None))
|
||||
return psm
|
||||
|
||||
|
||||
PM = "pm"
|
||||
|
||||
|
||||
@Singleton
|
||||
class PMService(AbstractService):
|
||||
def __init__(self, flag=1):
|
||||
super().__init__(PM)
|
||||
self.pm = pm
|
||||
self.__pm_lock = pm.create_wakelock("pm_lock", len("pm_lock"))
|
||||
self.__flag = flag
|
||||
self.__count = 0
|
||||
|
||||
def lock(self):
|
||||
self.__count += 1
|
||||
self.pm.wakelock_lock(self.__pm_lock)
|
||||
|
||||
def unlock(self):
|
||||
self.__count -= 1
|
||||
if self.count() < 1:
|
||||
self.pm.wakelock_unlock(self.__pm_lock)
|
||||
|
||||
def count(self):
|
||||
if self.__count < 0:
|
||||
self.__count = 0
|
||||
return self.__count
|
||||
|
||||
def auto_sleep(self, flag):
|
||||
self.pm.autosleep(flag)
|
||||
|
||||
def register_event(self):
|
||||
self.pm.autosleep(1)
|
202
code/usr/bin/third_party/offline_storage.py
vendored
Normal file
202
code/usr/bin/third_party/offline_storage.py
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
try:
|
||||
import uos as os
|
||||
import utime as time
|
||||
import ujson as json
|
||||
except:
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
|
||||
def Singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def _singleton(*args, **kargs):
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls(*args, **kargs)
|
||||
return _instance[cls]
|
||||
|
||||
return _singleton
|
||||
|
||||
|
||||
@Singleton
|
||||
class OfflineStorage:
|
||||
|
||||
def __init__(self):
|
||||
self.status = None
|
||||
self.split_file = False
|
||||
self.single_file_max = 100
|
||||
self._file_name_no = 1
|
||||
self._rec_count = 1
|
||||
# self.default_dir = "/usr/offline_storage/"
|
||||
self.default_dir = "./"
|
||||
self._check_dir()
|
||||
|
||||
def _check_dir(self):
|
||||
try:
|
||||
os.chdir(self.default_dir)
|
||||
except:
|
||||
raise SystemError("Directory is not exist!")
|
||||
|
||||
@staticmethod
|
||||
def _msg_no_gen():
|
||||
# ts = time.time()
|
||||
ts = int(time.time())
|
||||
ts_str = str(ts)
|
||||
if len(ts_str) > 5:
|
||||
ts = int(ts_str[-5:])
|
||||
# 避免时间戳生成时间太短导致重复
|
||||
time.sleep(1)
|
||||
return ts
|
||||
|
||||
def _get_file_list(self):
|
||||
file_list = os.listdir(self.default_dir)
|
||||
file_list.sort()
|
||||
# 筛选后缀名
|
||||
file_filtered = []
|
||||
for file in file_list:
|
||||
try:
|
||||
if file[-5:] == ".json":
|
||||
file_filtered.append(file)
|
||||
except:
|
||||
continue
|
||||
return file_filtered
|
||||
|
||||
def _pre_load(self):
|
||||
# 预读取
|
||||
data_map = dict()
|
||||
file_list = self._get_file_list()
|
||||
if not file_list:
|
||||
return data_map
|
||||
file = file_list.pop()
|
||||
with open(self.default_dir + file, 'r', encoding="utf-8") as f:
|
||||
try:
|
||||
file_map = json.load(f)
|
||||
except:
|
||||
file_map = dict()
|
||||
self._rec_count = len(file_map.keys())
|
||||
data_map.update(file_map)
|
||||
return data_map
|
||||
|
||||
def _write_file(self, data):
|
||||
file_list = self._get_file_list()
|
||||
file_list.sort()
|
||||
if not file_list:
|
||||
if self.split_file:
|
||||
if self._rec_count > self.single_file_max:
|
||||
self._file_name_no += 1
|
||||
file_name = "data%d.json" % self._file_name_no
|
||||
else:
|
||||
file_name = "data.json"
|
||||
else:
|
||||
file_name = file_list.pop()
|
||||
with open(self.default_dir+file_name, "w+", encoding="utf-8") as f:
|
||||
json.dump(data, f)
|
||||
self._rec_count += 1
|
||||
|
||||
def deposit(self, data):
|
||||
if self.status == 'r':
|
||||
return False
|
||||
self.status = 'w'
|
||||
# 序号生成
|
||||
index = self._msg_no_gen()
|
||||
format_data = {index: data}
|
||||
data_map = self._pre_load()
|
||||
data_map.update(format_data)
|
||||
self._write_file(data_map)
|
||||
self.status = None
|
||||
return index
|
||||
|
||||
def take_out(self):
|
||||
if self.status == 'w':
|
||||
return False
|
||||
self.status = 'r'
|
||||
file_list = self._get_file_list()
|
||||
if not file_list:
|
||||
return False
|
||||
file_list.sort()
|
||||
data_map = dict()
|
||||
for file in file_list:
|
||||
with open(self.default_dir + file, 'r', encoding="utf-8") as f:
|
||||
try:
|
||||
data_map.update(json.load(f))
|
||||
except:
|
||||
pass
|
||||
os.remove(self.default_dir + file)
|
||||
self.status = None
|
||||
return data_map
|
||||
|
||||
def take_out_iter(self):
|
||||
data_map = self.take_out()
|
||||
for k, v in data_map.items():
|
||||
yield k, v
|
||||
|
||||
def take_out_list(self):
|
||||
data_map = self.take_out()
|
||||
return list(data_map.values())
|
||||
|
||||
def take_out_by_index(self, index):
|
||||
if self.status == 'w':
|
||||
return False
|
||||
self.status = 'r'
|
||||
file_list = self._get_file_list()
|
||||
if not file_list:
|
||||
return None
|
||||
file_list.sort()
|
||||
for file in file_list:
|
||||
with open(self.default_dir + file, 'r+', encoding="utf-8") as f:
|
||||
file_map = json.load(f)
|
||||
if index in file_map:
|
||||
data = file_map.pop(index)
|
||||
json.dump(file_map, f)
|
||||
return data
|
||||
return None
|
||||
|
||||
def take_out_last(self, count=1):
|
||||
if self.status == 'w':
|
||||
return False
|
||||
self.status = 'r'
|
||||
file_list = self._get_file_list()
|
||||
if not file_list:
|
||||
return None
|
||||
file_list.sort(reverse=True)
|
||||
take_out_count = 0
|
||||
data_map = dict()
|
||||
for file in file_list:
|
||||
with open(self.default_dir + file, 'r+', encoding="utf-8") as f:
|
||||
file_map = json.load(f)
|
||||
items = sorted(file_map.items())
|
||||
while take_out_count <= count and items:
|
||||
key, values = items.pop()
|
||||
data_map[key] = values
|
||||
file_map.pop(key)
|
||||
json.dump(file_map, f)
|
||||
if not items:
|
||||
os.remove(self.default_dir + file)
|
||||
return data_map
|
||||
|
||||
def count(self):
|
||||
file_list = self._get_file_list()
|
||||
data_count = 0
|
||||
for file in file_list:
|
||||
with open(self.default_dir + file, 'r', encoding="utf-8") as f:
|
||||
try:
|
||||
data_count += len(json.load(f))
|
||||
except:
|
||||
pass
|
||||
return data_count
|
||||
|
||||
def preview_data(self):
|
||||
data_map = dict()
|
||||
file_list = self._get_file_list()
|
||||
if not file_list:
|
||||
return data_map
|
||||
file_list.sort()
|
||||
for file in file_list:
|
||||
with open(self.default_dir + file, 'r', encoding="utf-8") as f:
|
||||
try:
|
||||
data_map.update(json.load(f))
|
||||
except:
|
||||
pass
|
||||
return data_map
|
||||
|
189
code/usr/bin/third_party/ql_interrupter.py
vendored
Normal file
189
code/usr/bin/third_party/ql_interrupter.py
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
import osTimer, sys_bus, utime
|
||||
from machine import Pin, ExtInt
|
||||
import _thread
|
||||
|
||||
"""
|
||||
ExInt阻断器
|
||||
enable
|
||||
disable
|
||||
"""
|
||||
|
||||
|
||||
class ExIntInterrupter(object):
|
||||
def __init__(self, gpio, trige_mode=ExtInt.IRQ_RISING, pull_mode=ExtInt.PULL_DISABLE, callback=None):
|
||||
self.__ext = ExtInt(gpio, trige_mode, pull_mode, callback)
|
||||
|
||||
def enable(self):
|
||||
return self.__ext.enable()
|
||||
|
||||
def disable(self):
|
||||
return self.__ext.disable()
|
||||
|
||||
def start(self):
|
||||
return self.enable()
|
||||
|
||||
def stop(self):
|
||||
return self.disable()
|
||||
|
||||
|
||||
"""
|
||||
Pin阻断器
|
||||
write
|
||||
read
|
||||
"""
|
||||
|
||||
|
||||
class PinInterrupter(object):
|
||||
|
||||
def __init__(self, gpio, trige_mode=Pin.OUT, pull_mode=Pin.PULL_DISABLE, mode=0):
|
||||
self.gpio = Pin(gpio, trige_mode, pull_mode, mode)
|
||||
|
||||
def write(self, value):
|
||||
self.gpio.write(value)
|
||||
|
||||
def read(self):
|
||||
return self.gpio.read()
|
||||
|
||||
def blinker(self, keep_time):
|
||||
self.write(1)
|
||||
utime.sleep(keep_time)
|
||||
self.write(0)
|
||||
|
||||
def __blinker(self, count, keep_time):
|
||||
while count > 0:
|
||||
self.blinker(keep_time)
|
||||
|
||||
def freq_blinker(self, freq, keep_time):
|
||||
return _thread.start_new_thread(self.blinker, (freq, keep_time))
|
||||
|
||||
|
||||
"""
|
||||
具有BUS功能的ExInt阻断器
|
||||
publish
|
||||
"""
|
||||
|
||||
|
||||
class BusInterrupter(object):
|
||||
|
||||
def register_callback(self, callback):
|
||||
if callback is not None:
|
||||
sys_bus.subscribe(self.topic, callback)
|
||||
|
||||
def default_callback(self, *args, **kwargs):
|
||||
self.publish(*args, **kwargs)
|
||||
|
||||
def publish(self, *args, **kwargs):
|
||||
sys_bus.publish(self.topic, kwargs)
|
||||
|
||||
|
||||
class BusExIntInterrupter(ExIntInterrupter, BusInterrupter):
|
||||
def __init__(self, topic, gpio, trige_mode=ExtInt.IRQ_RISING, pull_mode=ExtInt.PULL_DISABLE):
|
||||
self.topic = topic
|
||||
super().__init__(gpio, trige_mode, pull_mode, self.default_callback)
|
||||
|
||||
def default_callback(self, *args, **kwargs):
|
||||
self.publish(**dict(gpio=args[0][0], pressure=args[0][1]))
|
||||
|
||||
|
||||
"""
|
||||
定时器阻断器
|
||||
start
|
||||
stop
|
||||
"""
|
||||
|
||||
|
||||
class TimerInterrupter(object):
|
||||
def __init__(self, keep_time, callback, period=1):
|
||||
"""
|
||||
|
||||
@param period: 周期
|
||||
@param callback: 回调
|
||||
@param loop: 1 循环 0 是一次
|
||||
"""
|
||||
self.__timer = osTimer()
|
||||
self.__keep_time = keep_time
|
||||
self.__callback = callback
|
||||
self.__period = period
|
||||
|
||||
def start(self):
|
||||
self.__timer.start(self.__keep_time, self.__period, self.__callback)
|
||||
|
||||
def stop(self):
|
||||
self.__timer.stop()
|
||||
|
||||
|
||||
"""
|
||||
看门狗
|
||||
继承于BusExInt 具有bus和ExInt的能力
|
||||
组合了
|
||||
定时器阻断器
|
||||
Pin阻断器
|
||||
"""
|
||||
|
||||
|
||||
class WatchDog(object):
|
||||
TOPIC = "WDT_KICK_TOPIC"
|
||||
|
||||
def __init__(self, gpio, mode, keep_time, done_pin=None, trige_mode=ExtInt.IRQ_RISING,
|
||||
pull_mode=ExtInt.PULL_DISABLE):
|
||||
self.timer_inter = TimerInterrupter(keep_time, self.__process)
|
||||
self.pin_inter = PinInterrupter(gpio, mode=mode)
|
||||
if done_pin is not None:
|
||||
self.bus_ext = BusExIntInterrupter(self.TOPIC, done_pin, trige_mode=trige_mode, pull_mode=pull_mode)
|
||||
self.bus_ext.enable()
|
||||
|
||||
def start(self):
|
||||
self.timer_inter.start()
|
||||
|
||||
def stop(self):
|
||||
self.timer_inter.stop()
|
||||
|
||||
def __process(self, *args, **kwargs):
|
||||
self.pin_inter.blinker(1)
|
||||
kwargs.update(dict(msg=self.TOPIC + "_FEED"))
|
||||
sys_bus.publish(self.TOPIC + "_FEED", kwargs)
|
||||
|
||||
|
||||
"""
|
||||
ExInt处理器
|
||||
继承于BusExInt 具有bus和ExInt的能力
|
||||
"""
|
||||
|
||||
|
||||
class ExIntProcess(BusExIntInterrupter):
|
||||
TOPIC = "GPIO{}_EXINT"
|
||||
|
||||
def __init__(self, pin, trige_mode=Pin.OUT, pull_mode=Pin.PULL_DISABLE):
|
||||
super().__init__(self.TOPIC.format(pin), pin, trige_mode, pull_mode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def pin_interrupt_callback(topic, message):
|
||||
print("pin_interrupt_callback, topic: {}, message: {}".format(topic, message))
|
||||
|
||||
|
||||
def ext_interrupt_callback(topic, message):
|
||||
print("ext_interrupt_callback, topic: {}, message: {}".format(topic, message))
|
||||
|
||||
|
||||
def kick_feed_interrupt_callback(topic, message):
|
||||
print("kick_feed_interrupt_callback, topic: {}, message: {}".format(topic, message))
|
||||
|
||||
|
||||
# 订阅gpio的中断
|
||||
sys_bus.subscribe("GPIO18_EXINT", pin_interrupt_callback)
|
||||
|
||||
# 订阅WDT_KICK_TOPIC订阅喂狗中断的回调
|
||||
sys_bus.subscribe("WDT_KICK_TOPIC", ext_interrupt_callback)
|
||||
|
||||
# 订阅喂狗的回调, 每次喂狗都会触发次订阅的回调
|
||||
sys_bus.subscribe("WDT_KICK_TOPIC_FEED", kick_feed_interrupt_callback)
|
||||
# 初始化狗
|
||||
wd = WatchDog(Pin.GPIO15, 1, 20000, Pin.GPIO8)
|
||||
# 开启喂狗
|
||||
wd.start()
|
||||
|
||||
# 初始化中断的处理器
|
||||
ep = ExIntProcess(Pin.GPIO5)
|
||||
# 开启中断
|
||||
ep.start()
|
33
code/usr/utils/JsonParserUtils.py
Normal file
33
code/usr/utils/JsonParserUtils.py
Normal file
@ -0,0 +1,33 @@
|
||||
import uos
|
||||
import ujson
|
||||
|
||||
|
||||
class Parse(object):
|
||||
def parse(self, *args, **kwargs):
|
||||
"""parse interface"""
|
||||
|
||||
|
||||
class JsonParser(object):
|
||||
DEFAULT_FILE_NAME = "config.json"
|
||||
|
||||
@classmethod
|
||||
def composite_url(cls, url):
|
||||
if not url.endswith("/"):
|
||||
url += "/"
|
||||
return url + cls.DEFAULT_FILE_NAME
|
||||
|
||||
@classmethod
|
||||
def parse(cls, url):
|
||||
rep_d = dict(
|
||||
status=1,
|
||||
data=dict()
|
||||
)
|
||||
try:
|
||||
url = cls.composite_url(url)
|
||||
with open(url, "r") as f:
|
||||
rep_d["data"] = ujson.load(f)
|
||||
except Exception as e:
|
||||
rep_d["status"] = 0
|
||||
return rep_d
|
||||
else:
|
||||
return rep_d
|
21
code/usr/utils/resolver.py
Normal file
21
code/usr/utils/resolver.py
Normal file
@ -0,0 +1,21 @@
|
||||
import utime
|
||||
|
||||
|
||||
class TimeResolver(object):
|
||||
|
||||
def __init__(self):
|
||||
self.output_format = "{ascdate} {asctime} {ascweek}"
|
||||
self.weekday_list = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||
|
||||
def resolver(self, rt=None):
|
||||
if rt is None:
|
||||
rt = utime.localtime()
|
||||
d_f = "{0:02}"
|
||||
return self.output_format.format(
|
||||
ascdate=str(rt[0]) + "-" + d_f.format(rt[1]) + "-" + d_f.format(rt[2])
|
||||
, asctime=d_f.format(rt[3]) + ":" + d_f.format(rt[4]) + ":" + d_f.format(rt[5]),
|
||||
ascweek=self.weekday_list[rt[6]])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(TimeResolver().resolver())
|
9
code/usr/utils/service_utils.py
Normal file
9
code/usr/utils/service_utils.py
Normal file
@ -0,0 +1,9 @@
|
||||
def Singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def _singleton(*args, **kargs):
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls(*args, **kargs)
|
||||
return _instance[cls]
|
||||
|
||||
return _singleton
|
BIN
helios service文档/Helio_Service指南(1)_入门.pdf
Normal file
BIN
helios service文档/Helio_Service指南(1)_入门.pdf
Normal file
Binary file not shown.
BIN
helios service文档/Helio_Service指南(2)_进阶.pdf
Normal file
BIN
helios service文档/Helio_Service指南(2)_进阶.pdf
Normal file
Binary file not shown.
BIN
helios service文档/Helio_Service指南(3)_高级.pdf
Normal file
BIN
helios service文档/Helio_Service指南(3)_高级.pdf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user