mirror of
https://gitee.com/qpy-solutions/tracker-v2.git
synced 2025-05-19 11:08:26 +08:00
structor optimization
This commit is contained in:
parent
ab755f42d4
commit
4199e87391
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "code/modules"]
|
||||
path = code/modules
|
||||
url = https://gitee.com/qpy-solutions/modules.git
|
@ -1,697 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ujson
|
||||
import utime
|
||||
import _thread
|
||||
import osTimer
|
||||
|
||||
from aLiYun import aLiYun
|
||||
|
||||
from usr.logging import getLogger
|
||||
from usr.common import numiter, option_lock, CloudObservable, CloudObjectModel
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
_gps_read_lock = _thread.allocate_lock()
|
||||
|
||||
|
||||
class AliObjectModel(CloudObjectModel):
|
||||
"""This class is aliyun object model
|
||||
|
||||
This class extend CloudObjectModel.
|
||||
|
||||
Attribute:
|
||||
items:
|
||||
- object model dictionary
|
||||
- data format:
|
||||
{
|
||||
"events": {
|
||||
"name": "events",
|
||||
"id": "",
|
||||
"perm": "",
|
||||
"struct_info": {
|
||||
"name": "struct",
|
||||
"id": "",
|
||||
"struct_info": {
|
||||
"key": {
|
||||
"name": "key"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"properties": {
|
||||
"name": "event",
|
||||
"id": "",
|
||||
"perm": "",
|
||||
"struct_info": {}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, om_file="/usr/aliyun_object_model.json"):
|
||||
super().__init__(om_file)
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
with open(self.om_file, "rb") as f:
|
||||
cloud_object_model = ujson.load(f)
|
||||
for om_type in cloud_object_model.keys():
|
||||
if om_type not in ("events", "properties"):
|
||||
continue
|
||||
for om_item in cloud_object_model[om_type]:
|
||||
om_key = om_item["identifier"]
|
||||
om_key_id = ""
|
||||
om_key_perm = ""
|
||||
self.set_item(om_type, om_key, om_key_id, om_key_perm)
|
||||
|
||||
struct_info_list = []
|
||||
if om_type == "properties":
|
||||
if om_item["dataType"]["type"] == "struct":
|
||||
struct_info_list = om_item["dataType"]["specs"]
|
||||
elif om_type == "events":
|
||||
if om_item.get("outputData"):
|
||||
struct_info_list = om_item["outputData"]
|
||||
|
||||
for struct_info in struct_info_list:
|
||||
struct_key = struct_info["identifier"]
|
||||
struct_key_id = ""
|
||||
struct_key_struct = {}
|
||||
if struct_info["dataType"]["type"] == "struct":
|
||||
for struct_key_struct_key in struct_info["dataType"]["specs"]:
|
||||
struct_key_struct[struct_key_struct_key["identifier"]] = {
|
||||
"name": struct_key_struct_key["identifier"]
|
||||
}
|
||||
self.set_item_struct(
|
||||
om_type, om_key, struct_key,
|
||||
struct_key_id=struct_key_id,
|
||||
struct_key_struct=struct_key_struct
|
||||
)
|
||||
|
||||
|
||||
class AliYunIot(CloudObservable):
|
||||
"""This is a class for aliyun iot.
|
||||
|
||||
This class extend CloudObservable.
|
||||
|
||||
This class has the following functions:
|
||||
1. Cloud connect and disconnect
|
||||
|
||||
2. Publish data to cloud
|
||||
2.1 Publish object module
|
||||
2.2 Publish ota device info, ota upgrade process, ota plain info request
|
||||
2.3 Publish rrpc response
|
||||
|
||||
3. Subscribe data from cloud
|
||||
3.1 Subscribe publish object model result
|
||||
3.2 Subscribe cloud message
|
||||
3.3 Subscribe ota plain
|
||||
3.4 Subscribe rrpc request
|
||||
|
||||
Attribute:
|
||||
ica_topic_property_post: topic for publish object model property
|
||||
ica_topic_property_post_reply: topic for subscribe publish object model property result
|
||||
ica_topic_property_set: topic for subscribe cloud object model property set
|
||||
ica_topic_event_post: topic for publish object model event
|
||||
ica_topic_event_post_reply: topic for subscribe publish object model event result
|
||||
ota_topic_device_inform: topic for publish device information
|
||||
ota_topic_device_upgrade: topic for subscribe ota plain
|
||||
ota_topic_device_progress: topic for publish ota upgrade process
|
||||
ota_topic_firmware_get: topic for publish ota plain request
|
||||
ota_topic_firmware_get_reply: topic for subscribe ota plain request response
|
||||
ota_topic_file_download: topic for publish ota mqtt file download request
|
||||
ota_topic_file_download_reply: topic for publish ota mqtt file download request response
|
||||
rrpc_topic_request: topic for subscribe rrpc message
|
||||
rrpc_topic_response: topic for publish rrpc response
|
||||
|
||||
Run step:
|
||||
1. cloud = AliYunIot(pk, ps, dk, ds, server, client_id)
|
||||
2. cloud.addObserver(RemoteSubscribe)
|
||||
3. cloud.set_object_model(AliObjectModel)
|
||||
4. cloud.init()
|
||||
5. cloud.post_data(data)
|
||||
6. cloud.close()
|
||||
"""
|
||||
|
||||
def __init__(self, pk, ps, dk, ds, server, client_id, burning_method=0, life_time=120,
|
||||
mcu_name="", mcu_version="", firmware_name="", firmware_version=""):
|
||||
"""
|
||||
1. Init parent class CloudObservable
|
||||
2. Init cloud connect params and topic
|
||||
"""
|
||||
super().__init__()
|
||||
self.__pk = pk
|
||||
self.__ps = ps
|
||||
self.__dk = dk
|
||||
self.__ds = ds
|
||||
self.__server = server
|
||||
self.__burning_method = burning_method
|
||||
self.__life_time = life_time
|
||||
self.__mcu_name = mcu_name
|
||||
self.__mcu_version = mcu_version
|
||||
self.__firmware_name = firmware_name
|
||||
self.__firmware_version = firmware_version
|
||||
self.__object_model = None
|
||||
self.__client_id = client_id
|
||||
|
||||
self.__ali = None
|
||||
self.__post_res = {}
|
||||
self.__breack_flag = 0
|
||||
self.__ali_timer = osTimer()
|
||||
|
||||
self.__id_iter = numiter()
|
||||
self.__id_lock = _thread.allocate_lock()
|
||||
|
||||
self.ica_topic_property_post = "/sys/%s/%s/thing/event/property/post" % (self.__pk, self.__dk)
|
||||
self.ica_topic_property_post_reply = "/sys/%s/%s/thing/event/property/post_reply" % (self.__pk, self.__dk)
|
||||
self.ica_topic_property_set = "/sys/%s/%s/thing/service/property/set" % (self.__pk, self.__dk)
|
||||
self.ica_topic_event_post = "/sys/%s/%s/thing/event/{}/post" % (self.__pk, self.__dk)
|
||||
self.ica_topic_event_post_reply = "/sys/%s/%s/thing/event/{}/post_reply" % (self.__pk, self.__dk)
|
||||
self.ota_topic_device_inform = "/ota/device/inform/%s/%s" % (self.__pk, self.__dk)
|
||||
self.ota_topic_device_upgrade = "/ota/device/upgrade/%s/%s" % (self.__pk, self.__dk)
|
||||
self.ota_topic_device_progress = "/ota/device/progress/%s/%s" % (self.__pk, self.__dk)
|
||||
self.ota_topic_firmware_get = "/sys/%s/%s/thing/ota/firmware/get" % (self.__pk, self.__dk)
|
||||
self.ota_topic_firmware_get_reply = "/sys/%s/%s/thing/ota/firmware/get_reply" % (self.__pk, self.__dk)
|
||||
|
||||
# TODO: To Download OTA File For MQTT Association (Not Support Now.)
|
||||
self.ota_topic_file_download = "/sys/%s/%s/thing/file/download" % (self.__pk, self.__dk)
|
||||
self.ota_topic_file_download_reply = "/sys/%s/%s/thing/file/download_reply" % (self.__pk, self.__dk)
|
||||
|
||||
self.rrpc_topic_request = "/sys/%s/%s/rrpc/request/+" % (self.__pk, self.__dk)
|
||||
self.rrpc_topic_response = "/sys/%s/%s/rrpc/response/{}" % (self.__pk, self.__dk)
|
||||
|
||||
def __get_id(self):
|
||||
"""Get message id for publishing data"""
|
||||
with self.__id_lock:
|
||||
try:
|
||||
msg_id = next(self.__id_iter)
|
||||
except StopIteration:
|
||||
self.__id_iter = numiter()
|
||||
msg_id = next(self.__id_iter)
|
||||
|
||||
return str(msg_id)
|
||||
|
||||
def __put_post_res(self, msg_id, res):
|
||||
"""Save publish result by message id
|
||||
|
||||
Parameter:
|
||||
msg_id: publish message id
|
||||
res: publish result, True or False
|
||||
"""
|
||||
self.__post_res[msg_id] = res
|
||||
|
||||
def __ali_timer_cb(self, args):
|
||||
"""osTimer callback to break cycling of get publish result"""
|
||||
self.__breack_flag = 1
|
||||
|
||||
@option_lock(_gps_read_lock)
|
||||
def __get_post_res(self, msg_id):
|
||||
"""Get publish result by message id
|
||||
|
||||
Parameter:
|
||||
msg_id: publish message id
|
||||
|
||||
Return:
|
||||
True: publish success
|
||||
False: publish failed
|
||||
"""
|
||||
self.__ali_timer.start(1000 * 10, 0, self.__ali_timer_cb)
|
||||
while self.__post_res.get(msg_id) is None:
|
||||
if self.__breack_flag:
|
||||
self.__post_res[msg_id] = False
|
||||
break
|
||||
utime.sleep_ms(50)
|
||||
self.__ali_timer.stop()
|
||||
self.__breack_flag = 0
|
||||
res = self.__post_res.pop(msg_id)
|
||||
return res
|
||||
|
||||
def __ali_subscribe_topic(self):
|
||||
"""Subscribe aliyun topic"""
|
||||
if self.__ali.subscribe(self.ica_topic_property_post, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ica_topic_property_post)
|
||||
if self.__ali.subscribe(self.ica_topic_property_post_reply, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ica_topic_property_post_reply)
|
||||
if self.__ali.subscribe(self.ica_topic_property_set, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ica_topic_property_set)
|
||||
for tsl_event_identifier in self.__object_model.items["events"].keys():
|
||||
post_topic = self.ica_topic_event_post.format(tsl_event_identifier)
|
||||
if self.__ali.subscribe(post_topic, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % post_topic)
|
||||
|
||||
post_reply_topic = self.ica_topic_event_post_reply.format(tsl_event_identifier)
|
||||
if self.__ali.subscribe(post_reply_topic, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % post_reply_topic)
|
||||
|
||||
if self.__ali.subscribe(self.ota_topic_device_upgrade, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ota_topic_device_upgrade)
|
||||
if self.__ali.subscribe(self.ota_topic_firmware_get_reply, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ota_topic_firmware_get_reply)
|
||||
|
||||
# TODO: To Download OTA File For MQTT Association (Not Support Now.)
|
||||
if self.__ali.subscribe(self.ota_topic_file_download_reply, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.ota_topic_file_download_reply)
|
||||
|
||||
if self.__ali.subscribe(self.rrpc_topic_request, qos=0) == -1:
|
||||
log.error("Topic [%s] Subscribe Falied." % self.rrpc_topic_request)
|
||||
|
||||
def __ali_sub_cb(self, topic, data):
|
||||
"""Aliyun subscribe topic callback
|
||||
|
||||
Parameter:
|
||||
topic: topic info
|
||||
data: response dictionary info
|
||||
"""
|
||||
topic = topic.decode()
|
||||
data = ujson.loads(data)
|
||||
log.info("topic: %s, data: %s" % (topic, data))
|
||||
if topic.endswith("/post_reply"):
|
||||
self.__put_post_res(data["id"], True if data["code"] == 200 else False)
|
||||
elif topic.endswith("/property/set"):
|
||||
if data["method"] == "thing.service.property.set":
|
||||
dl_data = list(zip(data.get("params", {}).keys(), data.get("params", {}).values()))
|
||||
self.notifyObservers(self, *("object_model", dl_data))
|
||||
elif topic.startswith("/ota/device/upgrade/"):
|
||||
self.__put_post_res(data["id"], True if int(data["code"]) == 1000 else False)
|
||||
if int(data["code"]) == 1000:
|
||||
if data.get("data"):
|
||||
self.notifyObservers(self, *("object_model", [("ota_status", (data["data"]["module"], 1, data["data"]["version"]))]))
|
||||
self.notifyObservers(self, *("ota_plain", data["data"]))
|
||||
elif topic.endswith("/thing/ota/firmware/get_reply"):
|
||||
self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False)
|
||||
if data["code"] == 200:
|
||||
if data.get("data"):
|
||||
self.notifyObservers(self, *("object_model", [("ota_status", (data["data"]["module"], 1, data["data"]["version"]))]))
|
||||
self.notifyObservers(self, *("ota_plain", data["data"]))
|
||||
# TODO: To Download OTA File For MQTT Association (Not Support Now.)
|
||||
elif topic.endswith("/thing/file/download_reply"):
|
||||
self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False)
|
||||
if data["code"] == 200:
|
||||
self.notifyObservers(self, *("ota_file_download", data["data"]))
|
||||
elif topic.find("/rrpc/request/") != -1:
|
||||
self.notifyObservers(self, *("rrpc_request", topic, data))
|
||||
else:
|
||||
pass
|
||||
|
||||
def __data_format(self, data):
|
||||
"""Publish data format by AliObjectModel
|
||||
|
||||
Parameter:
|
||||
data format:
|
||||
{
|
||||
"phone_num": "123456789",
|
||||
"energy": 100,
|
||||
"GeoLocation": {
|
||||
"Longtitude": 100.26,
|
||||
"Latitude": 26.86,
|
||||
"Altitude": 0.0,
|
||||
"CoordinateSystem": 1
|
||||
},
|
||||
}
|
||||
|
||||
Return:
|
||||
{
|
||||
"event": [
|
||||
{
|
||||
"id": 1,
|
||||
"version": "1.0",
|
||||
"sys": {
|
||||
"ack": 1
|
||||
},
|
||||
"params": {
|
||||
"sos_alert": {
|
||||
"value": {},
|
||||
"time": 1649991780000
|
||||
},
|
||||
},
|
||||
"method": "thing.event.sos_alert.post"
|
||||
}
|
||||
],
|
||||
"property": [
|
||||
{
|
||||
"id": 2,
|
||||
"version": "1.0",
|
||||
"sys": {
|
||||
"ack": 1
|
||||
},
|
||||
"params": {
|
||||
"phone_num": {
|
||||
"value": "123456789",
|
||||
"time": 1649991780000
|
||||
},
|
||||
"energy": {
|
||||
"value": 100,
|
||||
"time": 1649991780000
|
||||
},
|
||||
},
|
||||
"method": "thing.event.property.post"
|
||||
}
|
||||
],
|
||||
"msg_ids": [1, 2],
|
||||
"event_topic": {
|
||||
1: "/sys/{product_key}/{device_key}/thing/event/{event}/post",
|
||||
2: "/sys/{product_key}/{device_key}/thing/event/property/post",
|
||||
}
|
||||
}
|
||||
"""
|
||||
res = {"event": [], "property": [], "msg_ids": [], "event_topic": {}}
|
||||
property_params = {}
|
||||
event_params = {}
|
||||
# Format Publish Params.
|
||||
for k, v in data.items():
|
||||
if k in self.__object_model.items["properties"].keys():
|
||||
property_params[k] = {
|
||||
"value": v,
|
||||
"time": utime.mktime(utime.localtime()) * 1000
|
||||
}
|
||||
elif k in self.__object_model.items["events"].keys():
|
||||
event_params[k] = {
|
||||
"value": {},
|
||||
"time": utime.mktime(utime.localtime()) * 1000
|
||||
}
|
||||
else:
|
||||
log.error("Publish Key [%s] is not in property and event" % k)
|
||||
|
||||
if property_params:
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"version": "1.0",
|
||||
"sys": {
|
||||
"ack": 1
|
||||
},
|
||||
"params": property_params,
|
||||
"method": "thing.event.property.post"
|
||||
}
|
||||
res["property"].append(publish_data)
|
||||
res["msg_ids"].append(msg_id)
|
||||
|
||||
if event_params:
|
||||
for event in event_params.keys():
|
||||
topic = self.ica_topic_event_post.format(event)
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"version": "1.0",
|
||||
"sys": {
|
||||
"ack": 1
|
||||
},
|
||||
"params": event_params[event],
|
||||
"method": "thing.event.%s.post" % event
|
||||
}
|
||||
res["event"].append(publish_data)
|
||||
res["event_topic"][msg_id] = topic
|
||||
res["msg_ids"].append(msg_id)
|
||||
|
||||
return res
|
||||
|
||||
def set_object_model(self, object_model):
|
||||
"""Register AliObjectModel to this class"""
|
||||
if object_model and isinstance(object_model, AliObjectModel):
|
||||
self.__object_model = object_model
|
||||
return True
|
||||
return False
|
||||
|
||||
def init(self, enforce=False):
|
||||
"""Aliyun connect and subscribe topic
|
||||
|
||||
Parameter:
|
||||
enforce:
|
||||
True: enfore cloud connect and subscribe topic
|
||||
False: check connect status, return True if cloud connected
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
log.debug("[init start] enforce: %s" % enforce)
|
||||
if enforce is False and self.__ali is not None:
|
||||
log.debug("self.__ali.getAliyunSta(): %s" % self.__ali.getAliyunSta())
|
||||
if self.__ali.getAliyunSta() == 0:
|
||||
return True
|
||||
|
||||
if self.__burning_method == 0:
|
||||
self.__dk = None
|
||||
elif self.__burning_method == 1:
|
||||
self.__ps = None
|
||||
|
||||
log.debug("aLiYun init. self.__pk: %s, self.__ps: %s, self.__dk: %s, self.__ds: %s, self.__server: %s" % (self.__pk, self.__ps, self.__dk, self.__ds, self.__server))
|
||||
self.__ali = aLiYun(self.__pk, self.__ps, self.__dk, self.__ds, self.__server)
|
||||
log.debug("aLiYun setMqtt.")
|
||||
setMqttres = self.__ali.setMqtt(self.__client_id, clean_session=False, keepAlive=self.__life_time, reconn=True)
|
||||
log.debug("aLiYun setMqttres: %s" % setMqttres)
|
||||
if setMqttres != -1:
|
||||
self.__ali.setCallback(self.__ali_sub_cb)
|
||||
self.__ali_subscribe_topic()
|
||||
self.__ali.start()
|
||||
else:
|
||||
log.error("setMqtt Falied!")
|
||||
return False
|
||||
|
||||
log.debug("self.__ali.getAliyunSta(): %s" % self.__ali.getAliyunSta())
|
||||
if self.__ali.getAliyunSta() == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""Aliyun disconnect"""
|
||||
self.__ali.disconnect()
|
||||
return True
|
||||
|
||||
def post_data(self, data):
|
||||
"""Publish object model property, event
|
||||
|
||||
Parameter:
|
||||
data format:
|
||||
{
|
||||
"phone_num": "123456789",
|
||||
"energy": 100,
|
||||
"GeoLocation": {
|
||||
"Longtitude": 100.26,
|
||||
"Latitude": 26.86,
|
||||
"Altitude": 0.0,
|
||||
"CoordinateSystem": 1
|
||||
},
|
||||
}
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
if self.__ali.getAliyunSta() == 0:
|
||||
try:
|
||||
publish_data = self.__data_format(data)
|
||||
# Publish Property Data.
|
||||
for item in publish_data["property"]:
|
||||
self.__ali.publish(self.ica_topic_property_post, ujson.dumps(item), qos=0)
|
||||
# Publish Event Data.
|
||||
for item in publish_data["event"]:
|
||||
self.__ali.publish(publish_data["event_topic"][item["id"]], ujson.dumps(item), qos=0)
|
||||
pub_res = [self.__get_post_res(msg_id) for msg_id in publish_data["msg_ids"]]
|
||||
return True if False not in pub_res else False
|
||||
except Exception:
|
||||
log.error("AliYun publish topic %s failed. data: %s" % (data.get("topic"), data.get("data")))
|
||||
|
||||
return False
|
||||
|
||||
def rrpc_response(self, message_id, data):
|
||||
"""Publish rrpc response
|
||||
|
||||
Parameter:
|
||||
message_id: rrpc request messasge id
|
||||
data: response message
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
topic = self.rrpc_topic_response.format(message_id)
|
||||
pub_data = ujson.dumps(data) if isinstance(data, dict) else data
|
||||
self.__ali.publish(topic, pub_data, qos=0)
|
||||
return True
|
||||
|
||||
def device_report(self):
|
||||
"""Publish mcu and firmware name, version
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
muc_res = self.ota_device_inform(self.__mcu_version, module=self.__mcu_name)
|
||||
fw_res = self.ota_device_inform(self.__firmware_version, module=self.__firmware_name)
|
||||
return True if muc_res and fw_res else False
|
||||
|
||||
def ota_request(self):
|
||||
"""Publish mcu and firmware ota plain request
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
sota_res = self.ota_firmware_get(self.__mcu_name)
|
||||
fota_res = self.ota_firmware_get(self.__firmware_name)
|
||||
return True if sota_res and fota_res else False
|
||||
|
||||
def ota_action(self, action, module=None):
|
||||
"""Publish ota upgrade start or cancel ota upgrade
|
||||
|
||||
Parameter:
|
||||
action: confirm or cancel upgrade
|
||||
- 0: cancel upgrade
|
||||
- 1: confirm upgrade
|
||||
|
||||
module: mcu or firmare model name
|
||||
- e.g.: `QuecPython-Tracker`, `EC600N-CNLC`
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
if not module:
|
||||
log.error("Params[module] Is Empty.")
|
||||
return False
|
||||
if action not in (0, 1):
|
||||
log.error("Params[action] Should Be 0 Or 1, Not %s." % action)
|
||||
return False
|
||||
|
||||
if action == 1:
|
||||
return self.ota_device_progress(step=1, module=module)
|
||||
else:
|
||||
return self.ota_device_progress(step=-1, desc="User cancels upgrade.", module=module)
|
||||
|
||||
def ota_device_inform(self, version, module="default"):
|
||||
"""Publish device information
|
||||
|
||||
Parameter:
|
||||
version: module version
|
||||
- e.g.: `2.1.0`
|
||||
|
||||
module: mcu or firmare model name
|
||||
- e.g.: `QuecPython-Tracker`
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"params": {
|
||||
"version": version,
|
||||
"module": module,
|
||||
},
|
||||
}
|
||||
publish_res = self.__ali.publish(self.ota_topic_device_inform, ujson.dumps(publish_data), qos=0)
|
||||
log.debug("version: %s, module: %s, publish_res: %s" % (version, module, publish_res))
|
||||
return publish_res
|
||||
|
||||
def ota_device_progress(self, step, desc, module="default"):
|
||||
"""Publish ota upgrade process
|
||||
|
||||
Parameter:
|
||||
step: upgrade process
|
||||
- 1 ~ 100: Upgrade progress percentage
|
||||
- -1: Upgrade failed
|
||||
- -2: Download failed
|
||||
- -3: Verification failed
|
||||
- -4: Programming failed
|
||||
|
||||
desc: Description of the current step, no more than 128 characters long. If an exception occurs, this field can carry error information.
|
||||
|
||||
module: mcu or firmare model name
|
||||
- e.g.: `QuecPython-Tracker`
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"params": {
|
||||
"step": step,
|
||||
"desc": desc,
|
||||
"module": module,
|
||||
}
|
||||
}
|
||||
publish_res = self.__ali.publish(self.ota_topic_device_progress, ujson.dumps(publish_data), qos=0)
|
||||
if publish_res:
|
||||
return self.__get_post_res(msg_id)
|
||||
else:
|
||||
log.error("ota_device_progress publish_res: %s" % publish_res)
|
||||
return False
|
||||
|
||||
def ota_firmware_get(self, module):
|
||||
"""Publish ota plain info request
|
||||
|
||||
Parameter:
|
||||
module: mcu or firmare model name
|
||||
- e.g.: `QuecPython-Tracker`
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"version": "1.0",
|
||||
"params": {
|
||||
"module": module,
|
||||
},
|
||||
"method": "thing.ota.firmware.get"
|
||||
}
|
||||
publish_res = self.__ali.publish(self.ota_topic_firmware_get, ujson.dumps(publish_data), qos=0)
|
||||
log.debug("module: %s, publish_res: %s" % (module, publish_res))
|
||||
if publish_res:
|
||||
return self.__get_post_res(msg_id)
|
||||
else:
|
||||
log.error("ota_firmware_get publish_res: %s" % publish_res)
|
||||
return False
|
||||
|
||||
def ota_file_download(self, params):
|
||||
"""Publish mqtt ota plain file info request
|
||||
|
||||
Parameter:
|
||||
params: file download info
|
||||
params format:
|
||||
{
|
||||
"fileToken": "1bb8***",
|
||||
"fileInfo": {
|
||||
"streamId": 1234565,
|
||||
"fileId": 1
|
||||
},
|
||||
"fileBlock": {
|
||||
"size": 256,
|
||||
"offset": 2
|
||||
}
|
||||
}
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
msg_id = self.__get_id()
|
||||
publish_data = {
|
||||
"id": msg_id,
|
||||
"version": "1.0",
|
||||
"params": params
|
||||
}
|
||||
publish_res = self.__ali.publish(self.ota_topic_file_download, ujson.dumps(publish_data), qos=0)
|
||||
if publish_res:
|
||||
return self.__get_post_res(msg_id)
|
||||
else:
|
||||
log.error("ota_file_download publish_res: %s" % publish_res)
|
||||
return False
|
@ -1,94 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from misc import Power
|
||||
from usr.logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
BATTERY_OCV_TABLE = {
|
||||
"nix_coy_mnzo2": {
|
||||
55: {
|
||||
4152: 100, 4083: 95, 4023: 90, 3967: 85, 3915: 80, 3864: 75, 3816: 70, 3773: 65, 3737: 60, 3685: 55,
|
||||
3656: 50, 3638: 45, 3625: 40, 3612: 35, 3596: 30, 3564: 25, 3534: 20, 3492: 15, 3457: 10, 3410: 5, 3380: 0,
|
||||
},
|
||||
20: {
|
||||
4143: 100, 4079: 95, 4023: 90, 3972: 85, 3923: 80, 3876: 75, 3831: 70, 3790: 65, 3754: 60, 3720: 55,
|
||||
3680: 50, 3652: 45, 3634: 40, 3621: 35, 3608: 30, 3595: 25, 3579: 20, 3548: 15, 3511: 10, 3468: 5, 3430: 0,
|
||||
},
|
||||
0: {
|
||||
4147: 100, 4089: 95, 4038: 90, 3990: 85, 3944: 80, 3899: 75, 3853: 70, 3811: 65, 3774: 60, 3741: 55,
|
||||
3708: 50, 3675: 45, 3651: 40, 3633: 35, 3620: 30, 3608: 25, 3597: 20, 3585: 15, 3571: 10, 3550: 5, 3500: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Battery(object):
|
||||
"""This class is for battery info.
|
||||
|
||||
This class can get battery voltage and energy.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.__energy = 100
|
||||
self.__temp = 20
|
||||
|
||||
def __get_soc_from_dict(self, key, volt_arg):
|
||||
"""Get battery energy from map"""
|
||||
if key in BATTERY_OCV_TABLE["nix_coy_mnzo2"]:
|
||||
volts = sorted(BATTERY_OCV_TABLE["nix_coy_mnzo2"][key].keys(), reverse=True)
|
||||
pre_volt = 0
|
||||
volt_not_under = 0 # Determine whether the voltage is lower than the minimum voltage value of soc.
|
||||
for volt in volts:
|
||||
if volt_arg > volt:
|
||||
volt_not_under = 1
|
||||
soc1 = BATTERY_OCV_TABLE["nix_coy_mnzo2"][key].get(volt, 0)
|
||||
soc2 = BATTERY_OCV_TABLE["nix_coy_mnzo2"][key].get(pre_volt, 0)
|
||||
break
|
||||
else:
|
||||
pre_volt = volt
|
||||
if pre_volt == 0: # Input Voltarg > Highest Voltarg
|
||||
return soc1
|
||||
elif volt_not_under == 0:
|
||||
return 0
|
||||
else:
|
||||
return soc2 - (soc2 - soc1) * (pre_volt - volt_arg) // (pre_volt - volt)
|
||||
|
||||
def __get_soc(self, temp, volt_arg, bat_type="nix_coy_mnzo2"):
|
||||
"""Get battery energy by temperature and voltage"""
|
||||
if bat_type == "nix_coy_mnzo2":
|
||||
if temp > 30:
|
||||
return self.__get_soc_from_dict(55, volt_arg)
|
||||
elif temp < 10:
|
||||
return self.__get_soc_from_dict(0, volt_arg)
|
||||
else:
|
||||
return self.__get_soc_from_dict(20, volt_arg)
|
||||
|
||||
def set_temp(self, temp):
|
||||
"""Set now temperature."""
|
||||
if isinstance(temp, int) or isinstance(temp, float):
|
||||
self.__temp = temp
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_voltage(self):
|
||||
"""Get battery voltage"""
|
||||
# Get voltage from vbat
|
||||
# TODO: Get voltage by ADC
|
||||
return int(sum([Power.getVbatt() for i in range(100)]) / 100)
|
||||
|
||||
def get_energy(self):
|
||||
"""Get battery energy"""
|
||||
self.__energy = self.__get_soc(self.__temp, self.get_voltage())
|
||||
return self.__energy
|
276
code/common.py
276
code/common.py
@ -1,276 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import _thread
|
||||
|
||||
LOWENERGYMAP = {
|
||||
"EC200U": [
|
||||
"POWERDOWN",
|
||||
"PM",
|
||||
],
|
||||
"EC200U": [
|
||||
"POWERDOWN",
|
||||
"PM",
|
||||
],
|
||||
"EC600N": [
|
||||
"PM",
|
||||
],
|
||||
"EC800G": [
|
||||
"PM"
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def numiter(num=99999):
|
||||
"""Number generation iterator"""
|
||||
for i in range(num):
|
||||
yield i
|
||||
|
||||
|
||||
def option_lock(thread_lock):
|
||||
"""Function thread lock decorator"""
|
||||
def function_lock(func):
|
||||
def wrapperd_fun(*args, **kwargs):
|
||||
with thread_lock:
|
||||
return func(*args, **kwargs)
|
||||
return wrapperd_fun
|
||||
return function_lock
|
||||
|
||||
|
||||
class BaseError(Exception):
|
||||
"""Exception base class"""
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
class Singleton(object):
|
||||
"""Singleton base class"""
|
||||
_instance_lock = _thread.allocate_lock()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not hasattr(cls, "instance_dict"):
|
||||
Singleton.instance_dict = {}
|
||||
|
||||
if str(cls) not in Singleton.instance_dict.keys():
|
||||
with Singleton._instance_lock:
|
||||
_instance = super().__new__(cls)
|
||||
Singleton.instance_dict[str(cls)] = _instance
|
||||
|
||||
return Singleton.instance_dict[str(cls)]
|
||||
|
||||
|
||||
class Observer(object):
|
||||
"""Observer base class"""
|
||||
|
||||
def update(self, observable, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class Observable(Singleton):
|
||||
"""Observable base class"""
|
||||
|
||||
def __init__(self):
|
||||
self.__observers = []
|
||||
|
||||
def addObserver(self, observer):
|
||||
"""Add observer"""
|
||||
try:
|
||||
self.__observers.append(observer)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def delObserver(self, observer):
|
||||
"""Delete observer"""
|
||||
try:
|
||||
self.__observers.remove(observer)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def notifyObservers(self, *args, **kwargs):
|
||||
"""Notify observer"""
|
||||
for o in self.__observers:
|
||||
o.update(self, *args, **kwargs)
|
||||
|
||||
|
||||
class CloudObserver(object):
|
||||
"""Cloud observer base class"""
|
||||
|
||||
def execute(self, observable, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class CloudObservable(Singleton):
|
||||
"""Cloud observable base class"""
|
||||
|
||||
def __init__(self):
|
||||
self.__observers = []
|
||||
|
||||
def addObserver(self, observer):
|
||||
"""Add observer"""
|
||||
self.__observers.append(observer)
|
||||
|
||||
def delObserver(self, observer):
|
||||
"""Delete observer"""
|
||||
self.__observers.remove(observer)
|
||||
|
||||
def notifyObservers(self, *args, **kwargs):
|
||||
"""Notify observer"""
|
||||
for o in self.__observers:
|
||||
o.execute(self, *args, **kwargs)
|
||||
|
||||
def init(self, enforce=False):
|
||||
"""Cloud init"""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""Cloud disconnect"""
|
||||
pass
|
||||
|
||||
def post_data(self, data):
|
||||
"""Cloud publish data"""
|
||||
pass
|
||||
|
||||
def ota_request(self, *args, **kwargs):
|
||||
"""Cloud publish ota plain request"""
|
||||
pass
|
||||
|
||||
def ota_action(self, action, module=None):
|
||||
"""Cloud publish ota upgrade or not request"""
|
||||
pass
|
||||
|
||||
|
||||
class CloudObjectModel(Singleton):
|
||||
"""This is a cloud object model base class
|
||||
|
||||
Attribute:
|
||||
items: object model dictionary, default two keys
|
||||
events: object model events
|
||||
property: object model property
|
||||
|
||||
items data format:
|
||||
{
|
||||
"events": {
|
||||
"name": "events",
|
||||
"id": "",
|
||||
"perm": "rw",
|
||||
"struct_info": {
|
||||
"name": "struct",
|
||||
"id": "",
|
||||
"struct_info": {
|
||||
"key": {
|
||||
"name": "key"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"property": {
|
||||
"name": "event",
|
||||
"id": "",
|
||||
"perm": "rw",
|
||||
"struct_info": {}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, om_file):
|
||||
self.items = {
|
||||
"events": {},
|
||||
"properties": {},
|
||||
}
|
||||
self.om_file = om_file
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def set_item(self, om_type, om_key, om_key_id=None, om_key_perm=None):
|
||||
""" Set object model item
|
||||
|
||||
Parameter:
|
||||
om_type: object model type
|
||||
- e.g.: `events`, `properties`
|
||||
|
||||
om_key: object model code
|
||||
- e.g.: `local_time`, `speed`, `GeoLocation`
|
||||
|
||||
om_key_id: object model id, not necessary, necessary for quecthing.
|
||||
|
||||
om_key_perm: object model permission, not necessary
|
||||
- e.g.: `rw`, `w`, `r`
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Failed
|
||||
"""
|
||||
om_data = {
|
||||
"name": om_key,
|
||||
"id": om_key_id,
|
||||
"perm": om_key_perm,
|
||||
"struct_info": {}
|
||||
}
|
||||
if self.items.get(om_type) is not None:
|
||||
self.items[om_type][om_key] = om_data
|
||||
return True
|
||||
return False
|
||||
|
||||
def del_item(self, om_type, om_key):
|
||||
"""Delete object model item
|
||||
|
||||
Parameter:
|
||||
om_type: object model type
|
||||
om_key: object model code
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Failed
|
||||
"""
|
||||
if self.items.get(om_type) is not None:
|
||||
if self.items[om_type].get(om_key) is not None:
|
||||
self.items[om_type].pop(om_key)
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_item_struct(self, om_type, om_key, struct_key, struct_key_id=None, struct_key_struct=None):
|
||||
"""Set object model item struct
|
||||
|
||||
Parameter:
|
||||
om_type: object model type
|
||||
om_key: object model code
|
||||
struct_key: object model item struct key name
|
||||
struct_key_id: object model item struct key id, not necessary
|
||||
struct_key_struct: object model item struct key struct, not necessary
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Failed
|
||||
"""
|
||||
if self.items.get(om_type) is not None:
|
||||
if self.items[om_type].get(om_key) is not None:
|
||||
if self.items[om_type][om_key].get("struct_info") is None:
|
||||
self.items[om_type][om_key]["struct_info"] = {}
|
||||
self.items[om_type][om_key]["struct_info"][struct_key] = {
|
||||
"name": struct_key,
|
||||
"id": struct_key_id,
|
||||
"struct_info": struct_key_struct,
|
||||
}
|
||||
return True
|
||||
return False
|
146
code/history.py
146
code/history.py
@ -1,146 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import uos
|
||||
import ql_fs
|
||||
import ujson
|
||||
import _thread
|
||||
|
||||
from usr.logging import getLogger
|
||||
from usr.common import Singleton, option_lock
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
_history_lock = _thread.allocate_lock()
|
||||
|
||||
|
||||
class History(Singleton):
|
||||
"""This class is for manage history file."""
|
||||
|
||||
def __init__(self, history_file="/usr/tracker_data.hist", max_hist_num=100):
|
||||
"""
|
||||
Parameter:
|
||||
history_file: filename include full path
|
||||
max_hist_num: history data list max size
|
||||
"""
|
||||
self.__history = history_file
|
||||
self.__max_hist_num = max_hist_num
|
||||
|
||||
def __read_hist(self):
|
||||
"""Read history file info
|
||||
|
||||
Return:
|
||||
data format:
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"xxx": "wwww"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
res = {"data": []}
|
||||
if ql_fs.path_exists(self.__history):
|
||||
with open(self.__history, "r") as f:
|
||||
try:
|
||||
hist_data = ujson.load(f)
|
||||
if isinstance(hist_data, dict):
|
||||
res["data"] = hist_data.get("data", [])
|
||||
except Exception:
|
||||
pass
|
||||
return res
|
||||
|
||||
def __write_hist(self, data):
|
||||
"""Write data to history file
|
||||
|
||||
Parameter:
|
||||
data format:
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"xxx": "wwww"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Falied
|
||||
"""
|
||||
try:
|
||||
with open(self.__history, "w") as f:
|
||||
ujson.dump(data, f)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
@option_lock(_history_lock)
|
||||
def read(self):
|
||||
"""Read history info
|
||||
|
||||
Return:
|
||||
data format:
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"switch": True,
|
||||
"energy": 100,
|
||||
"gps": ["$GPRMCx,x,x,x", "$GPGGAx,x,x,x"],
|
||||
},
|
||||
{
|
||||
"switch": True,
|
||||
"energy": 100,
|
||||
"non_gps": ["LBS"],
|
||||
},
|
||||
],
|
||||
}
|
||||
"""
|
||||
res = self.__read_hist()
|
||||
self.__write_hist({"data": []})
|
||||
return res
|
||||
|
||||
@option_lock(_history_lock)
|
||||
def write(self, data):
|
||||
"""
|
||||
Data Format For Write History:
|
||||
|
||||
[
|
||||
{
|
||||
"switch": True,
|
||||
"energy": 100,
|
||||
"gps": ["$GPRMCx,x,x,x", "$GPGGAx,x,x,x"],
|
||||
},
|
||||
{
|
||||
"switch": True,
|
||||
"energy": 100,
|
||||
"non_gps": ["LBS"],
|
||||
},
|
||||
]
|
||||
"""
|
||||
res = self.__read_hist()
|
||||
res["data"].extend(data)
|
||||
if len(res["data"]) > self.__max_hist_num:
|
||||
res["data"] = res["data"][self.__max_hist_num * -1:]
|
||||
return self.__write_hist(res)
|
||||
|
||||
@option_lock(_history_lock)
|
||||
def clean(self):
|
||||
try:
|
||||
uos.remove(self.__history)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def update(self, observable, *args, **kwargs):
|
||||
return self.write(list(args[1:]))
|
72
code/led.py
72
code/led.py
@ -1,72 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import _thread
|
||||
import osTimer
|
||||
from machine import Pin
|
||||
from usr.logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class LED(object):
|
||||
def __init__(self, GPIOn, direction=Pin.OUT, pullMode=Pin.PULL_DISABLE, level=0):
|
||||
self.__gpio = Pin(GPIOn, direction, pullMode, level)
|
||||
self.__period = 0
|
||||
self.__led_timer = osTimer()
|
||||
self.__led_lock = _thread.allocate_lock()
|
||||
|
||||
def __led_timer_cb(self, args):
|
||||
self.switch()
|
||||
|
||||
def get_period(self):
|
||||
return self.__period
|
||||
|
||||
def set_period(self, period):
|
||||
if isinstance(period, int) and period >= 0:
|
||||
self.__period = period
|
||||
return True
|
||||
return False
|
||||
|
||||
def led_timer_start(self):
|
||||
# __period is 0, not start led timer and stop led timer.
|
||||
if self.__period > 0:
|
||||
self.led_timer_stop()
|
||||
if self.led_timer.start(self.__period, 1, self.__led_timer_cb) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def led_timer_stop(self):
|
||||
return True if self.__led_timer.stop() == 0 else False
|
||||
|
||||
def get_led_status(self):
|
||||
# TODO: Get LED Status From Pin
|
||||
# Return:
|
||||
# 1 LED ON (high level).
|
||||
# 0 LED OFF (low level).
|
||||
with self.__led_lock:
|
||||
return self.__gpio.read()
|
||||
|
||||
def set_led_status(self, onoff):
|
||||
# TODO: Set LED Status
|
||||
with self.__led_lock:
|
||||
return True if self.__gpio.write(onoff) == 0 else False
|
||||
|
||||
def switch(self):
|
||||
# Auto Check LED Status ON To OFF or OFF To ON.
|
||||
if self.get_led_status() == 1:
|
||||
self.set_led_status(0)
|
||||
else:
|
||||
self.set_led_status(1)
|
618
code/location.py
618
code/location.py
@ -1,618 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ure
|
||||
import osTimer
|
||||
import _thread
|
||||
import cellLocator
|
||||
|
||||
from queue import Queue
|
||||
from machine import UART
|
||||
from wifilocator import wifilocator
|
||||
|
||||
from usr.logging import getLogger
|
||||
from usr.common import Singleton
|
||||
from usr.common import option_lock
|
||||
|
||||
try:
|
||||
import quecgnss
|
||||
except ImportError:
|
||||
quecgnss = None
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
_gps_read_lock = _thread.allocate_lock()
|
||||
|
||||
|
||||
class _loc_method(object):
|
||||
gps = 0x1
|
||||
cell = 0x2
|
||||
wifi = 0x4
|
||||
|
||||
|
||||
class _gps_mode(object):
|
||||
none = 0x0
|
||||
internal = 0x1
|
||||
external = 0x2
|
||||
|
||||
|
||||
class GPSMatch(object):
|
||||
"""This class is match gps NEMA 0183"""
|
||||
|
||||
def GxRMC(self, gps_data):
|
||||
"""Match Recommended Minimum Specific GPS/TRANSIT Data(RMC)"""
|
||||
if gps_data:
|
||||
rmc_re = ure.search(
|
||||
r"\$G[NP]RMC,\d+\.\d+,[AV],\d+\.\d+,[NS],\d+\.\d+,[EW],\d+\.\d+,\d+\.\d+,\d+,\d*\.*\d*,[EW]*,[ADEN]*,[SCUV]*\**(\d|\w)*",
|
||||
gps_data)
|
||||
if rmc_re:
|
||||
return rmc_re.group(0)
|
||||
return ""
|
||||
|
||||
def GxGGA(self, gps_data):
|
||||
"""Match Global Positioning System Fix Data(GGA)"""
|
||||
if gps_data:
|
||||
gga_re = ure.search(
|
||||
r"\$G[BLPN]GGA,\d+\.\d+,\d+\.\d+,[NS],\d+\.\d+,[EW],[0126],\d+,\d+\.\d+,-*\d+\.\d+,M,-*\d+\.\d+,M,\d*,\**(\d|\w)*",
|
||||
gps_data)
|
||||
if gga_re:
|
||||
return gga_re.group(0)
|
||||
return ""
|
||||
|
||||
def GxVTG(self, gps_data):
|
||||
"""Match Track Made Good and Ground Speed(VTG)"""
|
||||
if gps_data:
|
||||
vtg_re = ure.search(r"\$G[NP]VTG,\d+\.\d+,T,\d*\.*\d*,M,\d+\.\d+,N,\d+\.\d+,K,[ADEN]*\*(\d|\w)*", gps_data)
|
||||
if vtg_re:
|
||||
return vtg_re.group(0)
|
||||
return ""
|
||||
|
||||
def GxGSV(self, gps_data):
|
||||
"""Mactch GPS Satellites in View(GSV)"""
|
||||
if gps_data:
|
||||
gsv_re = ure.search(r"\$G[NP]GSV,\d+,\d+,\d+,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*,\d*\**(\d|\w)*", gps_data)
|
||||
if gsv_re:
|
||||
return gsv_re.group(0)
|
||||
return ""
|
||||
|
||||
|
||||
class GPSParse(object):
|
||||
"""Parse details from gps data"""
|
||||
|
||||
def GxGGA_satellite_num(self, gga_data):
|
||||
"""Parse satellite num from GGA"""
|
||||
if gga_data:
|
||||
satellite_num_re = ure.search(r",[EW],[0126],\d+,", gga_data)
|
||||
if satellite_num_re:
|
||||
return satellite_num_re.group(0).split(",")[-2]
|
||||
return ""
|
||||
|
||||
def GxVTG_speed(self, vtg_data):
|
||||
"""Parse speed from VTG"""
|
||||
if vtg_data:
|
||||
speed_re = ure.search(r",N,\d+\.\d+,K,", vtg_data)
|
||||
if speed_re:
|
||||
return speed_re.group(0)[3:-3]
|
||||
return ""
|
||||
|
||||
def GxGSV_satellite_num(self, gsv_data):
|
||||
"""Parse satellite num from GSV"""
|
||||
if gsv_data:
|
||||
satellite_num_re = ure.search(r"\$G[NP]GSV,\d+,\d+,\d+,", gsv_data)
|
||||
if satellite_num_re:
|
||||
return satellite_num_re.group(0).split(",")[-2]
|
||||
return ""
|
||||
|
||||
def GxGGA_latitude(self, gga_data):
|
||||
"""Parse latitude from GGA"""
|
||||
if gga_data:
|
||||
latitude_re = ure.search(r",[0-9]+\.[0-9]+,[NS],", gga_data)
|
||||
if latitude_re:
|
||||
return latitude_re.group(0)[1:-3]
|
||||
return ""
|
||||
|
||||
def GxGGA_longtitude(self, gga_data):
|
||||
"""Parse longtitude from GGA"""
|
||||
if gga_data:
|
||||
longtitude_re = ure.search(r",[0-9]+\.[0-9]+,[EW],", gga_data)
|
||||
if longtitude_re:
|
||||
return longtitude_re.group(0)[1:-3]
|
||||
return ""
|
||||
|
||||
def GxGGA_altitude(self, gga_data):
|
||||
"""Parse altitude from GGA"""
|
||||
if gga_data:
|
||||
altitude_re = ure.search(r",-*[0-9]+\.[0-9]+,M,", gga_data)
|
||||
if altitude_re:
|
||||
return altitude_re.group(0)[1:-3]
|
||||
return ""
|
||||
|
||||
|
||||
class GPS(Singleton):
|
||||
"""This class if for reading gps data.
|
||||
|
||||
Now support external gps and internal gps.
|
||||
"""
|
||||
|
||||
def __init__(self, gps_cfg, gps_mode):
|
||||
""" Init gps params
|
||||
|
||||
Parameter:
|
||||
gps_cfg: this is uart init params for external gps
|
||||
gps_mode: `internal` or `external`
|
||||
|
||||
"""
|
||||
self.__gps_cfg = gps_cfg
|
||||
self.__gps_mode = gps_mode
|
||||
self.__external_obj = None
|
||||
self.__internal_obj = quecgnss
|
||||
self.__gps_match = GPSMatch()
|
||||
self.__gps_parse = GPSParse()
|
||||
|
||||
self.__external_retrieve_queue = None
|
||||
self.__first_break = 0
|
||||
self.__break = 0
|
||||
self.__gps_data = ""
|
||||
self.__rmc_data = ""
|
||||
self.__gga_data = ""
|
||||
self.__vtg_data = ""
|
||||
self.__gsv_data = ""
|
||||
self.__gps_timer = osTimer()
|
||||
self.__gps_clean_timer = osTimer()
|
||||
|
||||
if self.__gps_mode & _gps_mode.external:
|
||||
self.__external_init()
|
||||
elif self.__gps_mode & _gps_mode.internal:
|
||||
self.__internal_init()
|
||||
|
||||
def __gps_timer_callback(self, args):
|
||||
"""GPS read timer callback
|
||||
When over time to get uart data, break queue wait
|
||||
"""
|
||||
self.__break = 1
|
||||
if self.__external_retrieve_queue is not None:
|
||||
self.__external_retrieve_queue.put(0)
|
||||
|
||||
def __gps_clean_callback(self, args):
|
||||
"""GPS read old data clean timer callback
|
||||
When GPS read over time, clean old gps data, wait to read new gps data.
|
||||
"""
|
||||
if self.__break == 0:
|
||||
self.__gps_data = ""
|
||||
self.__rmc_data = ""
|
||||
self.__gga_data = ""
|
||||
self.__vtg_data = ""
|
||||
self.__gsv_data = ""
|
||||
|
||||
def __external_init(self):
|
||||
"""External GPS init"""
|
||||
self.__external_retrieve_queue = Queue(maxsize=8)
|
||||
self.__external_open()
|
||||
|
||||
def __external_open(self):
|
||||
"""External GPS start, UART init"""
|
||||
self.__external_obj = UART(
|
||||
self.__gps_cfg["UARTn"], self.__gps_cfg["buadrate"], self.__gps_cfg["databits"],
|
||||
self.__gps_cfg["parity"], self.__gps_cfg["stopbits"], self.__gps_cfg["flowctl"]
|
||||
)
|
||||
self.__external_obj.set_callback(self.__external_retrieve_cb)
|
||||
|
||||
def __external_close(self):
|
||||
"""External GPS close, UART close, NOT GPS stop"""
|
||||
self.__external_obj.close()
|
||||
|
||||
def __external_retrieve_cb(self, args):
|
||||
"""
|
||||
GPS data retrieve callback from UART
|
||||
When data comes, send a message to queue of data length
|
||||
"""
|
||||
toRead = args[2]
|
||||
log.debug("GPS __external_retrieve_cb args: %s" % str(args))
|
||||
if toRead:
|
||||
if self.__external_retrieve_queue.size() >= 8:
|
||||
self.__external_retrieve_queue.get()
|
||||
self.__external_retrieve_queue.put(toRead)
|
||||
|
||||
def __internal_init(self):
|
||||
"""Internal GPS init"""
|
||||
if self.__internal_obj:
|
||||
if self.__internal_obj.init() != 0:
|
||||
self.__insternal_open()
|
||||
log.error("GNSS INIT Failed.")
|
||||
else:
|
||||
log.debug("GNSS INIT Success.")
|
||||
else:
|
||||
log.error("Module quecgnss Import Error.")
|
||||
|
||||
def __insternal_open(self):
|
||||
"""Internal GPS enable"""
|
||||
if self.__internal_obj.get_state() == 0:
|
||||
self.__internal_obj.gnssEnable(1)
|
||||
|
||||
def __internal_close(self):
|
||||
"""Internal GPS close"""
|
||||
self.__internal_obj.gnssEnable(0)
|
||||
|
||||
@option_lock(_gps_read_lock)
|
||||
def __external_read(self):
|
||||
"""Read external GPS data
|
||||
|
||||
Return:
|
||||
$GPTXT,01,01,02,ANTSTATUS=OPEN*2B
|
||||
$GNRMC,073144.000,A,3149.330773,N,11706.946971,E,0.00,337.47,150422,,,D,V*07
|
||||
$GNVTG,337.47,T,,M,0.00,N,0.00,K,D*22
|
||||
$GNGGA,073144.000,3149.330773,N,11706.946971,E,2,19,0.66,85.161,M,-0.335,M,,*56
|
||||
$GNGSA,A,3,01,195,06,03,21,194,19,17,30,14,,,0.94,0.66,0.66,1*02
|
||||
$GNGSA,A,3,13,26,07,10,24,25,08,03,22,,,,0.94,0.66,0.66,4*03
|
||||
$GPGSV,3,1,12,14,84,210,31,195,67,057,46,17,52,328,28,50,51,161,33,1*54
|
||||
$GPGSV,3,2,12,194,49,157,33,03,48,090,37,19,36,305,32,06,34,242,32,1*58
|
||||
$GPGSV,3,3,12,01,32,041,35,30,17,204,22,21,07,051,13,07,03,183,,1*6B
|
||||
$BDGSV,5,1,18,07,86,063,30,10,75,322,30,08,60,211,34,03,52,192,33,1*71
|
||||
$BDGSV,5,2,18,24,44,276,33,13,43,215,33,01,43,135,30,26,40,208,37,1*71
|
||||
$BDGSV,5,3,18,02,38,230,,04,32,119,,22,26,135,30,19,25,076,,1*70
|
||||
$BDGSV,5,4,18,05,17,251,,25,06,322,27,09,02,211,22,21,02,179,,1*78
|
||||
$BDGSV,5,5,18,29,02,075,,20,01,035,,1*72
|
||||
$GNGLL,3149.330773,N,11706.946971,E,073144.000,A,D*4E
|
||||
"""
|
||||
self.__external_open()
|
||||
log.debug("__external_read start")
|
||||
|
||||
while self.__break == 0:
|
||||
self.__gps_timer.start(50, 0, self.__gps_timer_callback)
|
||||
nread = self.__external_retrieve_queue.get()
|
||||
log.debug("[first] nread: %s" % nread)
|
||||
self.__gps_data = self.__external_obj.read(nread).decode()
|
||||
self.__break = 0
|
||||
|
||||
self.__gps_data = ""
|
||||
self.__rmc_data = ""
|
||||
self.__gga_data = ""
|
||||
self.__vtg_data = ""
|
||||
self.__gsv_data = ""
|
||||
self.__gps_clean_timer.start(1050, 1, self.__gps_clean_callback)
|
||||
while self.__break == 0:
|
||||
self.__gps_timer.start(1500, 0, self.__gps_timer_callback)
|
||||
nread = self.__external_retrieve_queue.get()
|
||||
log.debug("[second] nread: %s" % nread)
|
||||
if nread:
|
||||
self.__gps_data += self.__external_obj.read(nread).decode()
|
||||
if not self.__rmc_data:
|
||||
self.__rmc_data = self.__gps_match.GxRMC(self.__gps_data)
|
||||
if not self.__gga_data:
|
||||
self.__gga_data = self.__gps_match.GxGGA(self.__gps_data)
|
||||
if not self.__vtg_data:
|
||||
self.__vtg_data = self.__gps_match.GxVTG(self.__gps_data)
|
||||
if not self.__gsv_data:
|
||||
self.__gsv_data = self.__gps_match.GxGSV(self.__gps_data)
|
||||
if self.__rmc_data and self.__gga_data and self.__vtg_data and self.__gsv_data:
|
||||
self.__break = 1
|
||||
self.__gps_timer.stop()
|
||||
self.__gps_clean_timer.stop()
|
||||
self.__break = 0
|
||||
|
||||
self.__external_close()
|
||||
log.debug("__external_read data: %s" % self.__gps_data)
|
||||
return self.__gps_data
|
||||
|
||||
@option_lock(_gps_read_lock)
|
||||
def __internal_read(self):
|
||||
"""Read internal GPS data
|
||||
|
||||
Return:
|
||||
$GPTXT,01,01,02,ANTSTATUS=OPEN*2B
|
||||
$GNRMC,073144.000,A,3149.330773,N,11706.946971,E,0.00,337.47,150422,,,D,V*07
|
||||
$GNVTG,337.47,T,,M,0.00,N,0.00,K,D*22
|
||||
$GNGGA,073144.000,3149.330773,N,11706.946971,E,2,19,0.66,85.161,M,-0.335,M,,*56
|
||||
$GNGSA,A,3,01,195,06,03,21,194,19,17,30,14,,,0.94,0.66,0.66,1*02
|
||||
$GNGSA,A,3,13,26,07,10,24,25,08,03,22,,,,0.94,0.66,0.66,4*03
|
||||
$GPGSV,3,1,12,14,84,210,31,195,67,057,46,17,52,328,28,50,51,161,33,1*54
|
||||
$GPGSV,3,2,12,194,49,157,33,03,48,090,37,19,36,305,32,06,34,242,32,1*58
|
||||
$GPGSV,3,3,12,01,32,041,35,30,17,204,22,21,07,051,13,07,03,183,,1*6B
|
||||
$BDGSV,5,1,18,07,86,063,30,10,75,322,30,08,60,211,34,03,52,192,33,1*71
|
||||
$BDGSV,5,2,18,24,44,276,33,13,43,215,33,01,43,135,30,26,40,208,37,1*71
|
||||
$BDGSV,5,3,18,02,38,230,,04,32,119,,22,26,135,30,19,25,076,,1*70
|
||||
$BDGSV,5,4,18,05,17,251,,25,06,322,27,09,02,211,22,21,02,179,,1*78
|
||||
$BDGSV,5,5,18,29,02,075,,20,01,035,,1*72
|
||||
$GNGLL,3149.330773,N,11706.946971,E,073144.000,A,D*4E
|
||||
"""
|
||||
self.__external_open()
|
||||
|
||||
while self.__break == 0:
|
||||
self.__gps_timer.start(50, 0, self.__gps_timer_callback)
|
||||
self.__gps_data = quecgnss.read(1024)
|
||||
self.__gps_timer.stop()
|
||||
self.__break = 0
|
||||
|
||||
self.__gps_data = ""
|
||||
self.__rmc_data = ""
|
||||
self.__gga_data = ""
|
||||
self.__vtg_data = ""
|
||||
self.__gsv_data = ""
|
||||
self.__gps_clean_timer.start(1050, 1, self.__gps_clean_callback)
|
||||
while self.__break == 0:
|
||||
self.__gps_timer.start(1500, 0, self.__gps_timer_callback)
|
||||
gnss_data = quecgnss.read(1024)
|
||||
if gnss_data and gnss_data[1]:
|
||||
self.__gps_data += gnss_data[1].decode() if len(gnss_data) > 1 and gnss_data[1] else ""
|
||||
if not self.__rmc_data:
|
||||
self.__rmc_data = self.__gps_match.GxRMC(self.__gps_data)
|
||||
if not self.__gga_data:
|
||||
self.__gga_data = self.__gps_match.GxGGA(self.__gps_data)
|
||||
if not self.__vtg_data:
|
||||
self.__vtg_data = self.__gps_match.GxVTG(self.__gps_data)
|
||||
if not self.__gsv_data:
|
||||
self.__gsv_data = self.__gps_match.GxGSV(self.__gps_data)
|
||||
if self.__rmc_data and self.__gga_data and self.__vtg_data and self.__gsv_data:
|
||||
self.__break = 1
|
||||
self.__gps_timer.stop()
|
||||
self.__gps_clean_timer.stop()
|
||||
self.__break = 0
|
||||
|
||||
self.__internal_close()
|
||||
return self.__gps_data
|
||||
|
||||
def read(self):
|
||||
"""For user to read gps data
|
||||
|
||||
Return: (res_code, gps_data)
|
||||
res_code:
|
||||
- 0: Success
|
||||
- -1: Failed
|
||||
gps_data:
|
||||
$GPTXT,01,01,02,ANTSTATUS=OPEN*2B
|
||||
$GNRMC,073144.000,A,3149.330773,N,11706.946971,E,0.00,337.47,150422,,,D,V*07
|
||||
$GNVTG,337.47,T,,M,0.00,N,0.00,K,D*22
|
||||
$GNGGA,073144.000,3149.330773,N,11706.946971,E,2,19,0.66,85.161,M,-0.335,M,,*56
|
||||
$GNGSA,A,3,01,195,06,03,21,194,19,17,30,14,,,0.94,0.66,0.66,1*02
|
||||
$GNGSA,A,3,13,26,07,10,24,25,08,03,22,,,,0.94,0.66,0.66,4*03
|
||||
$GPGSV,3,1,12,14,84,210,31,195,67,057,46,17,52,328,28,50,51,161,33,1*54
|
||||
$GPGSV,3,2,12,194,49,157,33,03,48,090,37,19,36,305,32,06,34,242,32,1*58
|
||||
$GPGSV,3,3,12,01,32,041,35,30,17,204,22,21,07,051,13,07,03,183,,1*6B
|
||||
$BDGSV,5,1,18,07,86,063,30,10,75,322,30,08,60,211,34,03,52,192,33,1*71
|
||||
$BDGSV,5,2,18,24,44,276,33,13,43,215,33,01,43,135,30,26,40,208,37,1*71
|
||||
$BDGSV,5,3,18,02,38,230,,04,32,119,,22,26,135,30,19,25,076,,1*70
|
||||
$BDGSV,5,4,18,05,17,251,,25,06,322,27,09,02,211,22,21,02,179,,1*78
|
||||
$BDGSV,5,5,18,29,02,075,,20,01,035,,1*72
|
||||
$GNGLL,3149.330773,N,11706.946971,E,073144.000,A,D*4E
|
||||
"""
|
||||
gps_data = ""
|
||||
if self.__gps_mode & _gps_mode.external:
|
||||
gps_data = self.__external_read()
|
||||
elif self.__gps_mode & _gps_mode.internal:
|
||||
gps_data = self.__internal_read()
|
||||
|
||||
res = 0 if gps_data else -1
|
||||
return (res, gps_data)
|
||||
|
||||
def read_latitude(self, gps_data):
|
||||
"""Read latitude from gps data"""
|
||||
return self.__gps_parse.GxGGA_latitude(self.__gps_match.GxGGA(gps_data))
|
||||
|
||||
def read_longtitude(self, gps_data):
|
||||
"""Read longtitude from gps data"""
|
||||
return self.__gps_parse.GxGGA_longtitude(self.__gps_match.GxGGA(gps_data))
|
||||
|
||||
def read_altitude(self, gps_data):
|
||||
"""Read altitude from gps data"""
|
||||
return self.__gps_parse.GxGGA_altitude(self.__gps_match.GxGGA(gps_data))
|
||||
|
||||
def on(self):
|
||||
"""GPS Module switch on"""
|
||||
# TODO: Set GPS ON
|
||||
return True
|
||||
|
||||
def off(self):
|
||||
"""GPS Module switch off"""
|
||||
# TODO: Set GPS OFF
|
||||
return True
|
||||
|
||||
|
||||
class CellLocator(object):
|
||||
"""This class is for reading cell location data"""
|
||||
|
||||
def __init__(self, cell_cfg):
|
||||
self.cell_cfg = cell_cfg
|
||||
|
||||
def read(self):
|
||||
"""Read cell location data.
|
||||
|
||||
Return: (res_code, loc_data)
|
||||
res_code:
|
||||
- 0: Success
|
||||
- -1: Initialization failed
|
||||
- -2: The server address is too long (more than 255 bytes)
|
||||
- -3: Wrong key length, must be 16 bytes
|
||||
- -4: The timeout period is out of range, the supported range is (1 ~ 300) s
|
||||
- -5: The specified PDP network is not connected, please confirm whether the PDP is correct
|
||||
- -6: Error getting coordinates
|
||||
loc_data:
|
||||
(117.1138, 31.82279, 550)
|
||||
"""
|
||||
res = -1
|
||||
loc_data = cellLocator.getLocation(
|
||||
self.cell_cfg["serverAddr"],
|
||||
self.cell_cfg["port"],
|
||||
self.cell_cfg["token"],
|
||||
self.cell_cfg["timeout"],
|
||||
self.cell_cfg["profileIdx"]
|
||||
)
|
||||
if isinstance(loc_data, tuple) and len(loc_data) == 3:
|
||||
res = 0
|
||||
else:
|
||||
res = loc_data
|
||||
loc_data = ()
|
||||
|
||||
return (res, loc_data)
|
||||
|
||||
|
||||
class WiFiLocator(object):
|
||||
"""This class is for reading wifi location data"""
|
||||
|
||||
def __init__(self, wifi_cfg):
|
||||
self.wifilocator_obj = wifilocator(wifi_cfg["token"])
|
||||
|
||||
def read(self):
|
||||
"""Read wifi location data.
|
||||
|
||||
Return: (res_code, loc_data)
|
||||
res_code:
|
||||
- 0: Success
|
||||
- -1: The current network is abnormal, please confirm whether the dial-up is normal
|
||||
- -2: Wrong key length, must be 16 bytes
|
||||
- -3: Error getting coordinates
|
||||
loc_data:
|
||||
(117.1138, 31.82279, 550)
|
||||
"""
|
||||
res = -1
|
||||
loc_data = self.wifilocator_obj.getwifilocator()
|
||||
if isinstance(loc_data, tuple) and len(loc_data) == 3:
|
||||
res = 0
|
||||
else:
|
||||
res = loc_data
|
||||
loc_data = ()
|
||||
|
||||
return (res, loc_data)
|
||||
|
||||
|
||||
class Location(Singleton):
|
||||
"""This class is for reading location data from gps, cell, wifi"""
|
||||
gps = None
|
||||
cellLoc = None
|
||||
wifiLoc = None
|
||||
|
||||
def __init__(self, gps_mode, locator_init_params):
|
||||
self.__gps_mode = gps_mode
|
||||
self.__locator_init_params = locator_init_params
|
||||
|
||||
def __locater_init(self, loc_method):
|
||||
"""Init gps, cell, wifi by loc_method
|
||||
|
||||
Parameter:
|
||||
loc_method:
|
||||
- 1: gps
|
||||
- 2: cell
|
||||
- 3: cell & gps
|
||||
- 4: wifi
|
||||
- 5: wifi & gps
|
||||
- 6: wifi & cell
|
||||
- 7: wifi & cell & gps
|
||||
"""
|
||||
|
||||
if loc_method & _loc_method.gps:
|
||||
if self.gps is None:
|
||||
if self.__locator_init_params.get("gps_cfg"):
|
||||
self.gps = GPS(self.__locator_init_params["gps_cfg"], self.__gps_mode)
|
||||
else:
|
||||
raise ValueError("Invalid gps init parameters.")
|
||||
else:
|
||||
self.gps = None
|
||||
|
||||
if loc_method & _loc_method.cell:
|
||||
if self.cellLoc is None:
|
||||
if self.__locator_init_params.get("cell_cfg"):
|
||||
self.cellLoc = CellLocator(self.__locator_init_params["cell_cfg"])
|
||||
else:
|
||||
raise ValueError("Invalid cell-locator init parameters.")
|
||||
else:
|
||||
self.cellLoc = None
|
||||
|
||||
if loc_method & _loc_method.wifi:
|
||||
if self.wifiLoc is None:
|
||||
if self.__locator_init_params.get("wifi_cfg"):
|
||||
self.wifiLoc = WiFiLocator(self.__locator_init_params["wifi_cfg"])
|
||||
else:
|
||||
raise ValueError("Invalid wifi-locator init parameters.")
|
||||
else:
|
||||
self.wifiLoc = None
|
||||
|
||||
def __read_gps(self):
|
||||
"""Read loction data from gps module
|
||||
|
||||
Return:
|
||||
$GPTXT,01,01,02,ANTSTATUS=OPEN*2B
|
||||
$GNRMC,073144.000,A,3149.330773,N,11706.946971,E,0.00,337.47,150422,,,D,V*07
|
||||
$GNVTG,337.47,T,,M,0.00,N,0.00,K,D*22
|
||||
$GNGGA,073144.000,3149.330773,N,11706.946971,E,2,19,0.66,85.161,M,-0.335,M,,*56
|
||||
$GNGSA,A,3,01,195,06,03,21,194,19,17,30,14,,,0.94,0.66,0.66,1*02
|
||||
$GNGSA,A,3,13,26,07,10,24,25,08,03,22,,,,0.94,0.66,0.66,4*03
|
||||
$GPGSV,3,1,12,14,84,210,31,195,67,057,46,17,52,328,28,50,51,161,33,1*54
|
||||
$GPGSV,3,2,12,194,49,157,33,03,48,090,37,19,36,305,32,06,34,242,32,1*58
|
||||
$GPGSV,3,3,12,01,32,041,35,30,17,204,22,21,07,051,13,07,03,183,,1*6B
|
||||
$BDGSV,5,1,18,07,86,063,30,10,75,322,30,08,60,211,34,03,52,192,33,1*71
|
||||
$BDGSV,5,2,18,24,44,276,33,13,43,215,33,01,43,135,30,26,40,208,37,1*71
|
||||
$BDGSV,5,3,18,02,38,230,,04,32,119,,22,26,135,30,19,25,076,,1*70
|
||||
$BDGSV,5,4,18,05,17,251,,25,06,322,27,09,02,211,22,21,02,179,,1*78
|
||||
$BDGSV,5,5,18,29,02,075,,20,01,035,,1*72
|
||||
$GNGLL,3149.330773,N,11706.946971,E,073144.000,A,D*4E
|
||||
"""
|
||||
if self.gps:
|
||||
return self.gps.read()[1]
|
||||
return ""
|
||||
|
||||
def __read_cell(self):
|
||||
"""Read loction data from cell module
|
||||
|
||||
Return:
|
||||
(117.1138, 31.82279, 550) or ()
|
||||
"""
|
||||
if self.cellLoc:
|
||||
return self.cellLoc.read()[1]
|
||||
return ()
|
||||
|
||||
def __read_wifi(self):
|
||||
"""Read loction data from wifi module
|
||||
|
||||
Return:
|
||||
(117.1138, 31.82279, 550) or ()
|
||||
"""
|
||||
if self.wifiLoc:
|
||||
return self.wifiLoc.read()[1]
|
||||
return ()
|
||||
|
||||
def read(self, loc_method):
|
||||
"""Read location data by loc_method
|
||||
1. If loc_method include gps then get gps data;
|
||||
2. If loc_method inculde cell then get cell data;
|
||||
3. If loc_method Include wifi then get wifi data;
|
||||
|
||||
Parameter:
|
||||
loc_method:
|
||||
- 1: gps
|
||||
- 2: cell
|
||||
- 3: cell & gps
|
||||
- 4: wifi
|
||||
- 5: wifi & gps
|
||||
- 6: wifi & cell
|
||||
- 7: wifi & cell & gps
|
||||
|
||||
Return Data Format:
|
||||
{
|
||||
1: "$GPGGA,XXX",
|
||||
2: (0.00, 0.00, 0.00),
|
||||
4: (0.00, 0.00, 0.00),
|
||||
}
|
||||
"""
|
||||
loc_data = {}
|
||||
self.__locater_init(loc_method)
|
||||
|
||||
if loc_method & _loc_method.gps:
|
||||
loc_data[_loc_method.gps] = self.__read_gps()
|
||||
|
||||
if loc_method & _loc_method.cell:
|
||||
loc_data[_loc_method.cell] = self.__read_cell()
|
||||
|
||||
if loc_method & _loc_method.wifi:
|
||||
loc_data[_loc_method.wifi] = self.__read_wifi()
|
||||
|
||||
return loc_data
|
@ -1,87 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import utime
|
||||
|
||||
|
||||
class Logger:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.__debug = True
|
||||
self.__level = "debug"
|
||||
self.__level_code = {
|
||||
"debug": 0,
|
||||
"info": 1,
|
||||
"warn": 2,
|
||||
"error": 3,
|
||||
"critical": 4,
|
||||
}
|
||||
|
||||
def get_debug(self):
|
||||
return self.__debug
|
||||
|
||||
def set_debug(self, debug):
|
||||
if isinstance(debug, bool):
|
||||
self.__debug = debug
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_level(self):
|
||||
return self.__level
|
||||
|
||||
def set_level(self, level):
|
||||
if self.__level_code.get(level) is not None:
|
||||
self.__level = level
|
||||
return True
|
||||
return False
|
||||
|
||||
def log(self, name, level, *message):
|
||||
if self.__debug is False:
|
||||
if self.__level_code.get(level) < self.__level_code.get(self.__level):
|
||||
return
|
||||
|
||||
if hasattr(utime, "strftime"):
|
||||
print(
|
||||
"[{}]".format(utime.strftime("%Y-%m-%d %H:%M:%S")),
|
||||
"[{}]".format(name),
|
||||
"[{}]".format(level),
|
||||
*message
|
||||
)
|
||||
else:
|
||||
t = utime.localtime()
|
||||
print(
|
||||
"[{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}]".format(*t),
|
||||
"[{}]".format(name),
|
||||
"[{}]".format(level),
|
||||
*message
|
||||
)
|
||||
|
||||
def critical(self, *message):
|
||||
self.log(self.name, "critical", *message)
|
||||
|
||||
def error(self, *message):
|
||||
self.log(self.name, "error", *message)
|
||||
|
||||
def warn(self, *message):
|
||||
self.log(self.name, "warn", *message)
|
||||
|
||||
def info(self, *message):
|
||||
self.log(self.name, "info", *message)
|
||||
|
||||
def debug(self, *message):
|
||||
self.log(self.name, "debug", *message)
|
||||
|
||||
|
||||
def getLogger(name):
|
||||
return Logger(name)
|
@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from usr.logging import getLogger
|
||||
from usr.modules.logging import getLogger
|
||||
from usr.tracker import tracker
|
||||
from usr.settings import PROJECT_NAME, PROJECT_VERSION, DEVICE_FIRMWARE_NAME, DEVICE_FIRMWARE_VERSION
|
||||
|
||||
|
1
code/modules
Submodule
1
code/modules
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 561ad0c23a8f81e8f5f2e7a0cecb4b1151aeab40
|
159
code/mpower.py
159
code/mpower.py
@ -1,159 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import pm
|
||||
import utime
|
||||
import _thread
|
||||
import osTimer
|
||||
|
||||
from queue import Queue
|
||||
|
||||
from usr.common import Observable
|
||||
from usr.logging import getLogger
|
||||
|
||||
try:
|
||||
from machine import RTC
|
||||
except ImportError:
|
||||
RTC = None
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
LOW_ENERGY_METHOD = ("NULL", "PM", "PSM", "POWERDOWN")
|
||||
|
||||
|
||||
class LowEnergyManage(Observable):
|
||||
"""This class is managing low energy wake up"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.__timer = None
|
||||
|
||||
self.__period = 60
|
||||
self.__low_energy_method = "PM"
|
||||
self.__thread_id = None
|
||||
|
||||
self.__lpm_fd = None
|
||||
self.__pm_lock_name = "low_energy_pm_lock"
|
||||
self.__low_energy_queue = Queue(maxsize=8)
|
||||
|
||||
def __timer_callback(self, args):
|
||||
self.__low_energy_queue.put(self.__low_energy_method)
|
||||
|
||||
def __low_energy_work(self, lowenergy_tag):
|
||||
while True:
|
||||
data = self.__low_energy_queue.get()
|
||||
log.debug("__low_energy_work data: %s, lowenergy_tag: %s" % (data, lowenergy_tag))
|
||||
if data:
|
||||
if lowenergy_tag:
|
||||
if self.__lpm_fd is None:
|
||||
self.__lpm_fd = pm.create_wakelock(self.__pm_lock_name, len(self.__pm_lock_name))
|
||||
pm.autosleep(1)
|
||||
wlk_res = pm.wakelock_lock(self.__lpm_fd)
|
||||
log.debug("pm.wakelock_lock %s." % ("Success" if wlk_res == 0 else "Falied"))
|
||||
|
||||
self.notifyObservers(self, *(data,))
|
||||
|
||||
if lowenergy_tag:
|
||||
wulk_res = pm.wakelock_unlock(self.__lpm_fd)
|
||||
log.debug("pm.wakelock_unlock %s." % ("Success" if wulk_res == 0 else "Falied"))
|
||||
|
||||
def __timer_init(self):
|
||||
if RTC is not None:
|
||||
self.__timer = RTC()
|
||||
else:
|
||||
if self.__low_energy_method in ("PSM", "POWERDOWN"):
|
||||
raise TypeError("osTimer not support %s!" % self.__low_energy_method)
|
||||
self.__timer = osTimer()
|
||||
|
||||
def __rtc_enable(self, enable):
|
||||
enable_alarm_res = self.__timer.enable_alarm(enable)
|
||||
return True if enable_alarm_res == 0 else False
|
||||
|
||||
def __rtc_start(self):
|
||||
self.__rtc_enable(0)
|
||||
atime = utime.localtime(utime.mktime(utime.localtime()) + self.__period)
|
||||
alarm_time = [atime[0], atime[1], atime[2], atime[6], atime[3], atime[4], atime[5], 0]
|
||||
self.__timer.register_callback(self.__timer_callback)
|
||||
if self.__timer.set_alarm(alarm_time) == 0:
|
||||
return self.__rtc_enable(1)
|
||||
return False
|
||||
|
||||
def __rtc_stop(self):
|
||||
return self.__rtc_enable(0)
|
||||
|
||||
def __timer_start(self):
|
||||
res = self.__timer.start(self.__period * 1000, 0, self.__timer_callback)
|
||||
return True if res == 0 else False
|
||||
|
||||
def __timer_stop(self):
|
||||
res = self.__timer.stop()
|
||||
log.debug("__timer_stop res: %s" % res)
|
||||
return True if res == 0 else False
|
||||
|
||||
def get_period(self):
|
||||
return self.__period
|
||||
|
||||
def set_period(self, seconds=0):
|
||||
if isinstance(seconds, int) and seconds > 0:
|
||||
self.__period = seconds
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_low_energy_method(self):
|
||||
return self.__low_energy_method
|
||||
|
||||
def set_low_energy_method(self, method):
|
||||
if method in LOW_ENERGY_METHOD:
|
||||
if RTC is None and method in ("PSM", "POWERDOWN"):
|
||||
return False
|
||||
self.__low_energy_method = method
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_lpm_fd(self):
|
||||
return self.__lpm_fd
|
||||
|
||||
def low_energy_init(self):
|
||||
try:
|
||||
if self.__thread_id is not None:
|
||||
_thread.stop_thread(self.__thread_id)
|
||||
if self.__lpm_fd is not None:
|
||||
pm.delete_wakelock(self.__lpm_fd)
|
||||
self.__lpm_fd = None
|
||||
|
||||
if self.__low_energy_method == "PM":
|
||||
self.__thread_id = _thread.start_new_thread(self.__low_energy_work, (True,))
|
||||
self.__lpm_fd = pm.create_wakelock(self.__pm_lock_name, len(self.__pm_lock_name))
|
||||
pm.autosleep(1)
|
||||
elif self.__low_energy_method == "NULL":
|
||||
self.__thread_id = _thread.start_new_thread(self.__low_energy_work, (False,))
|
||||
elif self.__low_energy_method in ("PSM", "POWERDOWN"):
|
||||
pass
|
||||
self.__timer_init()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
if RTC is not None:
|
||||
return self.__rtc_start()
|
||||
else:
|
||||
return self.__timer_start()
|
||||
|
||||
def stop(self):
|
||||
if RTC is not None:
|
||||
return self.__rtc_stop()
|
||||
else:
|
||||
return self.__timer_stop()
|
238
code/ota.py
238
code/ota.py
@ -1,238 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import uos
|
||||
import fota
|
||||
import uzlib
|
||||
import ql_fs
|
||||
import app_fota
|
||||
import uhashlib
|
||||
import ubinascii
|
||||
import app_fota_download
|
||||
|
||||
from queue import Queue
|
||||
|
||||
from usr.logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
FOTA_ERROR_CODE = {
|
||||
1001: "FOTA_DOMAIN_NOT_EXIST",
|
||||
1002: "FOTA_DOMAIN_TIMEOUT",
|
||||
1003: "FOTA_DOMAIN_UNKNOWN",
|
||||
1004: "FOTA_SERVER_CONN_FAIL",
|
||||
1005: "FOTA_AUTH_FAILED",
|
||||
1006: "FOTA_FILE_NOT_EXIST",
|
||||
1007: "FOTA_FILE_SIZE_INVALID",
|
||||
1008: "FOTA_FILE_GET_ERR",
|
||||
1009: "FOTA_FILE_CHECK_ERR",
|
||||
1010: "FOTA_INTERNAL_ERR",
|
||||
1011: "FOTA_NOT_INPROGRESS",
|
||||
1012: "FOTA_NO_MEMORY",
|
||||
1013: "FOTA_FILE_SIZE_TOO_LARGE",
|
||||
1014: "FOTA_PARAM_SIZE_INVALID",
|
||||
}
|
||||
|
||||
|
||||
class OTA(object):
|
||||
|
||||
def __init__(self, file_info, ota_type="FOTA", ota_cb=None):
|
||||
self.file_info = file_info
|
||||
self.ota_type = ota_type
|
||||
self.ota_cb = ota_cb
|
||||
self.fota_queue = Queue(maxsize=4)
|
||||
|
||||
def start(self):
|
||||
if self.ota_type == "FOTA":
|
||||
return self.start_fota()
|
||||
elif self.ota_type == "SOTA":
|
||||
return self.start_sota()
|
||||
else:
|
||||
log.error("OTA Type %s Is FOTA Or SOTA Error!" % self.ota_type)
|
||||
return False
|
||||
|
||||
def __fota_callback(self, args):
|
||||
down_status = args[0]
|
||||
down_process = args[1]
|
||||
if down_status in (0, 1):
|
||||
# TODO: Report To Cloud Upgrade Process.
|
||||
log.debug("DownStatus: %s [%s][%s%%]" % (down_status, "=" * down_process, down_process))
|
||||
elif down_status == 2:
|
||||
# Download Over & Check Over, To Power Restart Update.
|
||||
self.fota_queue.put(True)
|
||||
else:
|
||||
log.error("Down Failed. Error Code [%s] %s" % (down_process, FOTA_ERROR_CODE.get(down_process, down_process)))
|
||||
self.fota_queue.put(False)
|
||||
|
||||
if self.ota_cb:
|
||||
self.ota_cb(args)
|
||||
|
||||
def start_fota(self):
|
||||
fota_obj = fota()
|
||||
url1 = self.file_info[0]["url"]
|
||||
url2 = self.file_info[1]["url"] if len(self.file_info) > 1 else ""
|
||||
res = fota_obj.httpDownload(url1=url1, url2=url2, callback=self.__fota_callback)
|
||||
if res == 0:
|
||||
fota_res = self.fota_queue.get()
|
||||
return fota_res
|
||||
else:
|
||||
return False
|
||||
|
||||
def start_sota(self):
|
||||
ota_module_obj = SOTA()
|
||||
for file in self.file_info:
|
||||
if ota_module_obj.app_fota_down(file["url"]):
|
||||
if ota_module_obj.check_md5(file["md5"]):
|
||||
if ota_module_obj.file_update():
|
||||
continue
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
ota_module_obj.sota_set_flag()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class SOTA(object):
|
||||
def __init__(self, parent_dir="/usr/.updater/usr/"):
|
||||
self.fp_file = "/usr/sotaFile.tar.gz"
|
||||
self.parent_dir = parent_dir
|
||||
self.hash_obj = None
|
||||
|
||||
def __get_file_size(self, data):
|
||||
size = data.decode("ascii")
|
||||
size = size.rstrip("\0")
|
||||
if (len(size) == 0):
|
||||
return 0
|
||||
size = int(size, 8)
|
||||
return size
|
||||
|
||||
def __get_file_name(self, name):
|
||||
fileName = name.decode("ascii")
|
||||
fileName = fileName.rstrip("\0")
|
||||
return fileName
|
||||
|
||||
def write_update_data(self, data):
|
||||
with open(self.fp_file, "wb+") as fp:
|
||||
fp.write(data)
|
||||
self.hash_obj.update(data)
|
||||
|
||||
def app_fota_down(self, url):
|
||||
app_fota_obj = app_fota.new()
|
||||
res = app_fota_obj.download(url, self.fp_file)
|
||||
if res == 0:
|
||||
uos.rename("/usr/.updater" + self.fp_file, self.fp_file)
|
||||
self.hash_obj = uhashlib.md5()
|
||||
with open(self.fp_file, "rb+") as fp:
|
||||
for fpi in fp.readlines():
|
||||
self.hash_obj.update(fpi)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def check_md5(self, cloud_md5):
|
||||
file_md5 = ubinascii.hexlify(self.hash_obj.digest())
|
||||
file_md5 = file_md5.decode("ascii")
|
||||
log.debug("DMP Calc MD5 Value: %s, Device Calc MD5 Value: %s" % (cloud_md5, file_md5))
|
||||
if (cloud_md5 != file_md5):
|
||||
log.error("MD5 Verification Failed")
|
||||
return False
|
||||
|
||||
log.debug("MD5 Verification Success.")
|
||||
return True
|
||||
|
||||
def file_update(self):
|
||||
ota_file = open(self.fp_file, "rb+")
|
||||
ota_file.seek(10)
|
||||
unzipFp = uzlib.DecompIO(ota_file, -15)
|
||||
log.debug("Unzip File Success.")
|
||||
ql_fs.mkdirs(self.parent_dir)
|
||||
file_list = []
|
||||
try:
|
||||
while True:
|
||||
data = unzipFp.read(0x200)
|
||||
if not data:
|
||||
log.debug("Read File Size Zore.")
|
||||
break
|
||||
|
||||
size = self.__get_file_size(data[124:135])
|
||||
fileName = self.__get_file_name(data[:100])
|
||||
log.debug("File Name: %s, File Size: %s" % (fileName, size))
|
||||
|
||||
if not size:
|
||||
if len(fileName):
|
||||
log.debug("Create File: %s" % self.parent_dir + fileName)
|
||||
ql_fs.mkdirs(self.parent_dir + fileName)
|
||||
else:
|
||||
log.debug("Have No File Unzip.")
|
||||
break
|
||||
else:
|
||||
log.debug("File %s Write Size %s" % (self.parent_dir + fileName, size))
|
||||
fp = open(self.parent_dir + fileName, "wb+")
|
||||
fileSize = size
|
||||
while fileSize:
|
||||
data = unzipFp.read(0x200)
|
||||
if (fileSize < 0x200):
|
||||
fp.write(data[:fileSize])
|
||||
fileSize = 0
|
||||
fp.close()
|
||||
file_list.append({"fileName": "/usr/" + fileName, "size": size})
|
||||
break
|
||||
else:
|
||||
fileSize -= 0x200
|
||||
fp.write(data)
|
||||
|
||||
for fileName in file_list:
|
||||
app_fota_download.update_download_stat("/usr/.updater" + fileName["fileName"], fileName["fileName"], fileName["size"])
|
||||
|
||||
log.debug("Remove %s" % self.fp_file)
|
||||
uos.remove(self.fp_file)
|
||||
except Exception as e:
|
||||
log.error("Unpack Error: %s" % e)
|
||||
return False
|
||||
finally:
|
||||
ota_file.close()
|
||||
|
||||
return True
|
||||
|
||||
def sota_set_flag(self):
|
||||
app_fota_download.set_update_flag()
|
||||
|
||||
|
||||
class OTAFileClear(object):
|
||||
def __init__(self):
|
||||
self.usrList = uos.ilistdir("/usr/")
|
||||
|
||||
def __remove_updater_dir(self, path):
|
||||
dirList = uos.ilistdir(path)
|
||||
for fileInfo in dirList:
|
||||
if fileInfo[1] == 0x4000:
|
||||
self.__remove_updater_dir("%s/%s" % (path, fileInfo[0]))
|
||||
else:
|
||||
log.debug("remove file name: %s/%s" % (path, fileInfo[0]))
|
||||
uos.remove("%s/%s" % (path, fileInfo[0]))
|
||||
|
||||
log.debug("remove dir name: %s" % path)
|
||||
uos.remove(path)
|
||||
|
||||
def file_clear(self):
|
||||
for fileInfo in self.usrList:
|
||||
if fileInfo[0] == ".updater":
|
||||
self.__remove_updater_dir("/usr/.updater")
|
||||
elif fileInfo[0] == "sotaFile.tar.gz":
|
||||
log.debug("remove update file sotaFile.tar.gz")
|
||||
uos.remove("/usr/sotaFile.tar.gz")
|
@ -1,618 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ujson
|
||||
import utime
|
||||
import osTimer
|
||||
import quecIot
|
||||
|
||||
from queue import Queue
|
||||
|
||||
from usr.ota import SOTA
|
||||
from usr.logging import getLogger
|
||||
from usr.common import CloudObservable, CloudObjectModel
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
EVENT_CODE = {
|
||||
1: {
|
||||
10200: "Device authentication succeeded.",
|
||||
10420: "Bad request data (connection failed).",
|
||||
10422: "Device authenticated (connection failed).",
|
||||
10423: "No product information found (connection failed).",
|
||||
10424: "PAYLOAD parsing failed (connection failed).",
|
||||
10425: "Signature verification failed (connection failed).",
|
||||
10426: "Bad authentication version (connection failed).",
|
||||
10427: "Invalid hash information (connection failed).",
|
||||
10430: "PK changed (connection failed).",
|
||||
10431: "Invalid DK (connection failed).",
|
||||
10432: "PK does not match authentication version (connection failed).",
|
||||
10450: "Device internal error (connection failed).",
|
||||
10466: "Boot server address not found (connection failed).",
|
||||
10500: "Device authentication failed (an unknown exception occurred in the system).",
|
||||
10300: "Other errors.",
|
||||
},
|
||||
2: {
|
||||
10200: "Access is successful.",
|
||||
10430: "Incorrect device key (connection failed).",
|
||||
10431: "Device is disabled (connection failed).",
|
||||
10450: "Device internal error (connection failed).",
|
||||
10471: "Implementation version not supported (connection failed).",
|
||||
10473: "Abnormal access heartbeat (connection timed out).",
|
||||
10474: "Network exception (connection timed out).",
|
||||
10475: "Server changes.",
|
||||
10476: "Abnormal connection to AP.",
|
||||
10500: "Access failed (an unknown exception occurred in the system).",
|
||||
},
|
||||
3: {
|
||||
10200: "Subscription succeeded.",
|
||||
10300: "Subscription failed.",
|
||||
},
|
||||
4: {
|
||||
10200: "Transparent data sent successfully.",
|
||||
10210: "Object model data sent successfully.",
|
||||
10220: "Positioning data sent successfully.",
|
||||
10300: "Failed to send transparent data.",
|
||||
10310: "Failed to send object model data.",
|
||||
10320: "Failed to send positioning data.",
|
||||
},
|
||||
5: {
|
||||
10200: "Receive transparent data.",
|
||||
10210: "Receive data from the object model.",
|
||||
10211: "Received object model query command.",
|
||||
10473: "Received data but the length exceeds the module buffer limit, receive failed.",
|
||||
10428: "The device receives too much buffer and causes current limit.",
|
||||
},
|
||||
6: {
|
||||
10200: "Logout succeeded (disconnection succeeded).",
|
||||
},
|
||||
7: {
|
||||
10700: "New OTA plain.",
|
||||
10701: "The module starts to download.",
|
||||
10702: "Package download.",
|
||||
10703: "Package download complete.",
|
||||
10704: "Package update.",
|
||||
10705: "Firmware update complete.",
|
||||
10706: "Failed to update firmware.",
|
||||
10707: "Received confirmation broadcast.",
|
||||
},
|
||||
8: {
|
||||
10428: "High-frequency messages on the device cause current throttling.",
|
||||
10429: "Exceeds the number of activations per device or daily requests current limit.",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class QuecObjectModel(CloudObjectModel):
|
||||
"""This class is queccloud object model
|
||||
|
||||
This class extend CloudObjectModel
|
||||
|
||||
Attribute:
|
||||
items:
|
||||
- object model dictionary
|
||||
- data format:
|
||||
{
|
||||
"event": {
|
||||
"name": "event",
|
||||
"id": "",
|
||||
"perm": "",
|
||||
"struct_info": {
|
||||
"name": "struct",
|
||||
"id": "",
|
||||
"struct_info": {
|
||||
"key": {
|
||||
"name": "key"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"property": {
|
||||
"name": "event",
|
||||
"id": "",
|
||||
"perm": "",
|
||||
"struct_info": {}
|
||||
}
|
||||
}
|
||||
items_id:
|
||||
- queccloud object model id and name map
|
||||
- data format
|
||||
{
|
||||
4: "energy",
|
||||
9: "power_switch",
|
||||
23: "phone_num",
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, om_file="/usr/quec_object_model.json"):
|
||||
super().__init__(om_file)
|
||||
self.items_id = {}
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
with open(self.om_file, "rb") as f:
|
||||
cloud_object_model = ujson.load(f)
|
||||
for om_type in cloud_object_model.keys():
|
||||
if om_type not in ("events", "properties"):
|
||||
continue
|
||||
for om_item in cloud_object_model[om_type]:
|
||||
om_key = om_item["code"]
|
||||
om_key_id = om_item["id"]
|
||||
om_key_perm = om_item["subType"].lower()
|
||||
self.set_item(om_type, om_key, om_key_id, om_key_perm)
|
||||
|
||||
struct_info_list = []
|
||||
event_out_put = []
|
||||
if om_type == "properties":
|
||||
if om_item["dataType"] == "STRUCT":
|
||||
struct_info_list = om_item["specs"]
|
||||
elif om_type == "events":
|
||||
if om_item.get("outputData"):
|
||||
event_out_put = [int(struct_item.get("$ref", "").split("/")[-1]) for struct_item in om_item["outputData"]]
|
||||
|
||||
for struct_info in struct_info_list:
|
||||
struct_key = struct_info["code"]
|
||||
struct_key_id = struct_info["id"]
|
||||
struct_key_struct = {}
|
||||
if struct_info["dataType"] == "STRUCT":
|
||||
for struct_key_struct_key in struct_info["dataType"]["specs"]:
|
||||
struct_key_struct[struct_key_struct_key["identifier"]] = {
|
||||
"name": struct_key_struct_key["identifier"]
|
||||
}
|
||||
self.set_item_struct(
|
||||
om_type, om_key, struct_key,
|
||||
struct_key_id=struct_key_id,
|
||||
struct_key_struct=struct_key_struct
|
||||
)
|
||||
|
||||
for property_id in event_out_put:
|
||||
struct_key = self.items_id.get(property_id, "")
|
||||
struct_key_id = property_id
|
||||
struct_key_struct = self.items.get(struct_key, {}).get("struct_info", {})
|
||||
self.set_item_struct(
|
||||
om_type, om_key, struct_key,
|
||||
struct_key_id=struct_key_id,
|
||||
struct_key_struct=struct_key_struct
|
||||
)
|
||||
|
||||
def __set_items_id(self, om_key, om_key_id):
|
||||
"""Set object model id, name to items_id
|
||||
|
||||
Parameter:
|
||||
om_key: object model name
|
||||
om_key_id: object model id
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Falied
|
||||
"""
|
||||
self.items_id[om_key_id] = om_key
|
||||
return True
|
||||
|
||||
def __del_items_id(self, om_type, om_key):
|
||||
"""Delete object model id, name from items_id
|
||||
|
||||
Parameter:
|
||||
om_type: object model type, `event` or `property`
|
||||
om_key: object model name
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Falied
|
||||
"""
|
||||
if self.items.get(om_type) is not None:
|
||||
if self.items[om_type].get(om_key):
|
||||
om_key_id = self.items[om_type][om_key]["id"]
|
||||
self.items_id.pop(om_key_id)
|
||||
return True
|
||||
|
||||
def set_item(self, om_type, om_key, om_key_id, om_key_perm):
|
||||
"""Set object model item to items
|
||||
This function extend CloudObjectModel.set_item and add __set_items_id function
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Falied
|
||||
"""
|
||||
if super().set_item(om_type, om_key, om_key_id=om_key_id, om_key_perm=om_key_perm):
|
||||
self.__set_items_id(om_key, om_key_id)
|
||||
return True
|
||||
return False
|
||||
|
||||
def del_item(self, om_type, om_key):
|
||||
"""Delete object model item from items
|
||||
This function extend CloudObjectModel.del_item and add __del_items_id function
|
||||
|
||||
Return:
|
||||
True: Success
|
||||
False: Falied
|
||||
"""
|
||||
if super().del_item(om_type, om_key):
|
||||
self.__del_items_id(om_type, om_key)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class QuecThing(CloudObservable):
|
||||
"""This is a class for queccloud iot.
|
||||
|
||||
This class extend CloudObservable.
|
||||
|
||||
This class has the following functions:
|
||||
1. Cloud connect and disconnect
|
||||
2. Publish data to cloud
|
||||
3. Monitor data from cloud by event callback
|
||||
|
||||
Run step:
|
||||
1. cloud = QuecThing(pk, ps, dk, ds, server)
|
||||
2. cloud.addObserver(RemoteSubscribe)
|
||||
3. cloud.set_object_model(QuecObjectModel)
|
||||
4. cloud.init()
|
||||
5. cloud.post_data(data)
|
||||
6. cloud.close()
|
||||
"""
|
||||
|
||||
def __init__(self, pk, ps, dk, ds, server, life_time=120, mcu_name="", mcu_version=""):
|
||||
"""
|
||||
1. Init parent class CloudObservable
|
||||
2. Init cloud connect params
|
||||
"""
|
||||
super().__init__()
|
||||
self.__pk = pk
|
||||
self.__ps = ps
|
||||
self.__dk = dk
|
||||
self.__ds = ds
|
||||
self.__server = server
|
||||
self.__life_time = life_time
|
||||
self.__mcu_name = mcu_name
|
||||
self.__mcu_version = mcu_version
|
||||
self.__object_model = None
|
||||
|
||||
self.__file_size = 0
|
||||
self.__md5_value = ""
|
||||
self.__post_result_wait_queue = Queue(maxsize=16)
|
||||
self.__quec_timer = osTimer()
|
||||
|
||||
def __rm_empty_data(self, data):
|
||||
"""Remove post success data item from data"""
|
||||
for k, v in data.items():
|
||||
if not v:
|
||||
del data[k]
|
||||
|
||||
def __quec_timer_cb(self, args):
|
||||
"""osTimer callback to break waiting of get publish result"""
|
||||
self.__put_post_res(False)
|
||||
|
||||
def __get_post_res(self):
|
||||
"""Get publish result"""
|
||||
self.__quec_timer.start(1000 * 10, 0, self.__quec_timer_cb)
|
||||
res = self.__post_result_wait_queue.get()
|
||||
self.__quec_timer.stop()
|
||||
return res
|
||||
|
||||
def __put_post_res(self, res):
|
||||
"""Save publish result to queue"""
|
||||
if self.__post_result_wait_queue.size() >= 16:
|
||||
self.__post_result_wait_queue.get()
|
||||
self.__post_result_wait_queue.put(res)
|
||||
|
||||
def __sota_download_info(self, size, md5_value):
|
||||
self.__file_size = size
|
||||
self.__md5_value = md5_value
|
||||
|
||||
def __sota_upgrade_start(self, start_addr, need_download_size):
|
||||
download_size = 0
|
||||
sota_mode = SOTA()
|
||||
while need_download_size != 0:
|
||||
readsize = 4096
|
||||
if (readsize > need_download_size):
|
||||
readsize = need_download_size
|
||||
updateFile = quecIot.mcuFWDataRead(start_addr, readsize)
|
||||
sota_mode.write_update_data(updateFile)
|
||||
log.debug("Download File Size: %s" % readsize)
|
||||
need_download_size -= readsize
|
||||
start_addr += readsize
|
||||
download_size += readsize
|
||||
if (download_size == self.__file_size):
|
||||
log.debug("File Download Success, Update Start.")
|
||||
self.ota_action(3)
|
||||
if sota_mode.check_md5(self.__md5_value):
|
||||
if sota_mode.file_update():
|
||||
sota_mode.sota_set_flag()
|
||||
log.debug("File Update Success, Power Restart.")
|
||||
else:
|
||||
log.debug("File Update Failed, Power Restart.")
|
||||
break
|
||||
else:
|
||||
self.ota_action(2)
|
||||
|
||||
res_data = ("object_model", [("power_restart", 1)])
|
||||
self.notifyObservers(self, *res_data)
|
||||
|
||||
def __data_format(self, k, v):
|
||||
"""Publish data format by AliObjectModel
|
||||
|
||||
Parameter:
|
||||
k: object model name
|
||||
v: object model value
|
||||
|
||||
return:
|
||||
{
|
||||
"object_model_id": object_model_value
|
||||
}
|
||||
|
||||
e.g.:
|
||||
k:
|
||||
"sos_alert"
|
||||
|
||||
v:
|
||||
{"local_time": 1649995898000}
|
||||
|
||||
return data:
|
||||
{
|
||||
6: {
|
||||
19: 1649995898000
|
||||
}
|
||||
}
|
||||
"""
|
||||
# log.debug("k: %s, v: %s" % (k, v))
|
||||
k_id = None
|
||||
struct_info = {}
|
||||
if self.__object_model.items["events"].get(k):
|
||||
k_id = self.__object_model.items["events"][k]["id"]
|
||||
if isinstance(self.__object_model.items["events"][k]["struct_info"], dict):
|
||||
struct_info = self.__object_model.items["events"][k]["struct_info"]
|
||||
elif self.__object_model.items["properties"].get(k):
|
||||
k_id = self.__object_model.items["properties"][k]["id"]
|
||||
if isinstance(self.__object_model.items["properties"][k]["struct_info"], dict):
|
||||
struct_info = self.__object_model.items["properties"][k]["struct_info"]
|
||||
else:
|
||||
return False
|
||||
|
||||
if isinstance(v, dict):
|
||||
nv = {}
|
||||
for ik, iv in v.items():
|
||||
if struct_info.get(ik):
|
||||
nv[struct_info[ik]["id"]] = iv
|
||||
else:
|
||||
nv[ik] = iv
|
||||
v = nv
|
||||
|
||||
return {k_id: v}
|
||||
|
||||
def __event_cb(self, data):
|
||||
"""Queccloud downlink message callback
|
||||
|
||||
Parameter:
|
||||
data: response dictionary info, all event info see `EVENT_CODE`
|
||||
data format: (`event_code`, `errcode`, `event_data`)
|
||||
- `event_code`: event code
|
||||
- `errcode`: detail code
|
||||
- `event_data`: event data info, data type: bytes or dict
|
||||
"""
|
||||
res_data = ()
|
||||
event = data[0]
|
||||
errcode = data[1]
|
||||
eventdata = b""
|
||||
if len(data) > 2:
|
||||
eventdata = data[2]
|
||||
log.info("Event[%s] ErrCode[%s] Msg[%s] EventData[%s]" % (event, errcode, EVENT_CODE.get(event, {}).get(errcode, ""), eventdata))
|
||||
|
||||
if event == 3:
|
||||
if errcode == 10200:
|
||||
if eventdata:
|
||||
file_info = eval(eventdata)
|
||||
log.info("OTA File Info: componentNo: %s, sourceVersion: %s, targetVersion: %s, "
|
||||
"batteryLimit: %s, minSignalIntensity: %s, minSignalIntensity: %s" % file_info)
|
||||
elif event == 4:
|
||||
if errcode == 10200:
|
||||
self.__put_post_res(True)
|
||||
elif errcode == 10210:
|
||||
self.__put_post_res(True)
|
||||
elif errcode == 10220:
|
||||
self.__put_post_res(True)
|
||||
elif errcode == 10300:
|
||||
self.__put_post_res(False)
|
||||
elif errcode == 10310:
|
||||
self.__put_post_res(False)
|
||||
elif errcode == 10320:
|
||||
self.__put_post_res(False)
|
||||
elif event == 5:
|
||||
if errcode == 10200:
|
||||
# TODO: Data Type Passthrough (Not Support Now).
|
||||
res_data = ("raw_data", eventdata)
|
||||
elif errcode == 10210:
|
||||
dl_data = [(self.__object_model.items_id[k], v.decode() if isinstance(v, bytes) else v) for k, v in eventdata.items()]
|
||||
res_data = ("object_model", dl_data)
|
||||
elif errcode == 10211:
|
||||
# eventdata[0] is pkgId.
|
||||
object_model_ids = eventdata[1]
|
||||
object_model_val = [self.__object_model.items_id[i] for i in object_model_ids if self.__object_model.items_id.get(i)]
|
||||
res_data = ("query", object_model_val)
|
||||
pass
|
||||
elif event == 7:
|
||||
if errcode == 10700:
|
||||
if eventdata:
|
||||
file_info = eval(eventdata)
|
||||
log.info("OTA File Info: componentNo: %s, sourceVersion: %s, targetVersion: %s, "
|
||||
"batteryLimit: %s, minSignalIntensity: %s, useSpace: %s" % file_info)
|
||||
res_data = ("object_model", [("ota_status", (file_info[0], 1, file_info[2]))])
|
||||
elif errcode == 10701:
|
||||
res_data = ("object_model", [("ota_status", (None, 2, None))])
|
||||
elif errcode == 10702:
|
||||
res_data = ("object_model", [("ota_status", (None, 2, None))])
|
||||
elif errcode == 10703:
|
||||
res_data = ("object_model", [("ota_status", (None, 2, None))])
|
||||
elif errcode == 10704:
|
||||
res_data = ("object_model", [("ota_status", (None, 2, None))])
|
||||
elif errcode == 10705:
|
||||
res_data = ("object_model", [("ota_status", (None, 3, None))])
|
||||
elif errcode == 10706:
|
||||
res_data = ("object_model", [("ota_status", (None, 4, None))])
|
||||
|
||||
if res_data:
|
||||
self.notifyObservers(self, *res_data)
|
||||
|
||||
if event == 7 and errcode == 10701 and eventdata:
|
||||
file_info = eval(eventdata)
|
||||
self.__sota_download_info(int(file_info[1]), file_info[2])
|
||||
if event == 7 and errcode == 10703 and eventdata:
|
||||
file_info = eval(eventdata)
|
||||
log.info("OTA File Info: componentNo: %s, length: %s, md5: %s, crc: %s" % file_info)
|
||||
self.__sota_upgrade_start(int(file_info[2]), int(file_info[3]))
|
||||
|
||||
def set_object_model(self, object_model):
|
||||
"""Register QuecObjectModel to this class"""
|
||||
if object_model and isinstance(object_model, QuecObjectModel):
|
||||
self.__object_model = object_model
|
||||
return True
|
||||
return False
|
||||
|
||||
def init(self, enforce=False):
|
||||
"""queccloud connect
|
||||
|
||||
Parameter:
|
||||
enforce:
|
||||
True: enfore cloud connect
|
||||
False: check connect status, return True if cloud connected
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
log.debug(
|
||||
"[init start] enforce: %s QuecThing Work State: %s, quecIot.getConnmode(): %s"
|
||||
% (enforce, quecIot.getWorkState(), quecIot.getConnmode())
|
||||
)
|
||||
log.debug("[init start] PK: %s, PS: %s, DK: %s, DS: %s, SERVER: %s" % (self.__pk, self.__ps, self.__dk, self.__ds, self.__server))
|
||||
if enforce is False:
|
||||
if quecIot.getWorkState() == 8 and quecIot.getConnmode() == 1:
|
||||
return True
|
||||
|
||||
quecIot.init()
|
||||
quecIot.setEventCB(self.__event_cb)
|
||||
quecIot.setProductinfo(self.__pk, self.__ps)
|
||||
if self.__dk or self.__ds:
|
||||
quecIot.setDkDs(self.__dk, self.__ds)
|
||||
quecIot.setServer(1, self.__server)
|
||||
quecIot.setLifetime(self.__life_time)
|
||||
quecIot.setMcuVersion(self.__mcu_name, self.__mcu_version)
|
||||
quecIot.setConnmode(1)
|
||||
|
||||
count = 0
|
||||
while quecIot.getWorkState() != 8 and count < 10:
|
||||
utime.sleep_ms(200)
|
||||
count += 1
|
||||
|
||||
if not self.__ds and self.__dk:
|
||||
count = 0
|
||||
while count < 3:
|
||||
dkds = quecIot.getDkDs()
|
||||
if dkds:
|
||||
self.__dk, self.__ds = dkds
|
||||
log.debug("dk: %s, ds: %s" % dkds)
|
||||
break
|
||||
count += 1
|
||||
utime.sleep(count)
|
||||
|
||||
log.debug("[init over] QuecThing Work State: %s, quecIot.getConnmode(): %s" % (quecIot.getWorkState(), quecIot.getConnmode()))
|
||||
if quecIot.getWorkState() == 8 and quecIot.getConnmode() == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""queccloud disconnect"""
|
||||
return quecIot.setConnmode(0)
|
||||
|
||||
def post_data(self, data):
|
||||
"""Publish object model property, event
|
||||
|
||||
Parameter:
|
||||
data format:
|
||||
{
|
||||
"phone_num": "123456789",
|
||||
"energy": 100,
|
||||
"gps": [
|
||||
"$GNGGA,XXX"
|
||||
"$GNVTG,XXX"
|
||||
"$GNRMC,XXX"
|
||||
],
|
||||
}
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
res = True
|
||||
# log.debug("post_data: %s" % str(data))
|
||||
for k, v in data.items():
|
||||
om_data = self.__data_format(k, v)
|
||||
if om_data is not False:
|
||||
if v is not None:
|
||||
phymodelReport_res = quecIot.phymodelReport(1, om_data)
|
||||
if not phymodelReport_res:
|
||||
res = False
|
||||
break
|
||||
else:
|
||||
continue
|
||||
elif k == "gps":
|
||||
locReportOutside_res = quecIot.locReportOutside(v)
|
||||
if not locReportOutside_res:
|
||||
res = False
|
||||
break
|
||||
elif k == "non_gps":
|
||||
locReportInside_res = quecIot.locReportInside(v)
|
||||
if not locReportInside_res:
|
||||
res = False
|
||||
break
|
||||
else:
|
||||
v = {}
|
||||
continue
|
||||
|
||||
res = self.__get_post_res()
|
||||
if res:
|
||||
v = {}
|
||||
else:
|
||||
res = False
|
||||
break
|
||||
|
||||
self.__rm_empty_data(data)
|
||||
return res
|
||||
|
||||
def ota_request(self, mp_mode=0):
|
||||
"""Publish mcu and firmware ota plain request
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
return quecIot.otaRequest(mp_mode) if mp_mode in (0, 1) else False
|
||||
|
||||
def ota_action(self, action=1, module=None):
|
||||
"""Publish ota upgrade start or cancel ota upgrade
|
||||
|
||||
Parameter:
|
||||
action: confirm or cancel upgrade
|
||||
- 0: cancel upgrade
|
||||
- 1: confirm upgrade
|
||||
|
||||
module: useless
|
||||
|
||||
Return:
|
||||
Ture: Success
|
||||
False: Failed
|
||||
"""
|
||||
return quecIot.otaAction(action) if action in (0, 1, 2, 3) else False
|
135
code/remote.py
135
code/remote.py
@ -1,135 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from usr.logging import getLogger
|
||||
from usr.common import Observable, CloudObserver
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class RemoteSubscribe(CloudObserver):
|
||||
def __init__(self):
|
||||
self.__executor = None
|
||||
|
||||
def get_executor(self):
|
||||
return self.__executor
|
||||
|
||||
def add_executor(self, executor):
|
||||
if executor:
|
||||
self.__executor = executor
|
||||
return True
|
||||
return False
|
||||
|
||||
def raw_data(self, *args, **kwargs):
|
||||
return self.__executor.event_option(*args, **kwargs) if self.__executor else False
|
||||
|
||||
def object_model(self, *args, **kwargs):
|
||||
return self.__executor.event_done(*args, **kwargs) if self.__executor else False
|
||||
|
||||
def query(self, *args, **kwargs):
|
||||
return self.__executor.event_query(*args, **kwargs) if self.__executor else False
|
||||
|
||||
def ota_plain(self, *args, **kwargs):
|
||||
return self.__executor.event_ota_plain(*args, **kwargs) if self.__executor else False
|
||||
|
||||
def ota_file_download(self, *args, **kwargs):
|
||||
# TODO: To Download OTA File For MQTT Association (Not Support Now.)
|
||||
log.debug("ota_file_download: %s" % str(args))
|
||||
if self.__executor and hasattr(self.__executor, "ota_file_download"):
|
||||
return self.__executor.event_ota_file_download(*args, **kwargs)
|
||||
else:
|
||||
return False
|
||||
|
||||
def execute(self, observable, *args, **kwargs):
|
||||
"""
|
||||
1. observable: Cloud Iot Object.
|
||||
2. args[1]: Cloud DownLink Data Type.
|
||||
2.1 object_model: Set Cloud Object Model.
|
||||
2.2 query: Query Cloud Object Model.
|
||||
2.3 ota_plain: OTA Plain Info.
|
||||
2.4 raw_data: Passthrough Data (Not Support Now).
|
||||
2.5 ota_file_download: Download OTA File For MQTT Association (Not Support Now).
|
||||
3. args[2]: Cloud DownLink Data(List Or Dict).
|
||||
"""
|
||||
opt_attr = args[1]
|
||||
opt_args = args[2] if not isinstance(args[2], dict) else ()
|
||||
opt_kwargs = args[2] if isinstance(args[2], dict) else {}
|
||||
if hasattr(self, opt_attr):
|
||||
option_fun = getattr(self, opt_attr)
|
||||
return option_fun(*opt_args, **opt_kwargs)
|
||||
else:
|
||||
log.error("RemoteSubscribe Has No Attribute [%s]." % opt_attr)
|
||||
return False
|
||||
|
||||
|
||||
class RemotePublish(Observable):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
cloud:
|
||||
CloudIot Object
|
||||
"""
|
||||
super().__init__()
|
||||
self.__cloud = None
|
||||
|
||||
def __cloud_conn(self, enforce=False):
|
||||
return self.__cloud.init(enforce=enforce) if self.__cloud else False
|
||||
|
||||
def __cloud_post(self, data):
|
||||
return self.__cloud.post_data(data) if self.__cloud else False
|
||||
|
||||
def add_cloud(self, cloud):
|
||||
if hasattr(cloud, "init") and \
|
||||
hasattr(cloud, "post_data") and \
|
||||
hasattr(cloud, "ota_request") and \
|
||||
hasattr(cloud, "ota_action"):
|
||||
self.__cloud = cloud
|
||||
return True
|
||||
return False
|
||||
|
||||
def cloud_ota_check(self):
|
||||
return self.__cloud.ota_request() if self.__cloud else False
|
||||
|
||||
def cloud_ota_action(self, action=1, module=None):
|
||||
return self.__cloud.ota_action(action, module) if self.__cloud else False
|
||||
|
||||
def post_data(self, data):
|
||||
"""
|
||||
Data format to post:
|
||||
|
||||
{
|
||||
"switch": True,
|
||||
"energy": 100,
|
||||
"non_gps": [],
|
||||
"gps": []
|
||||
}
|
||||
"""
|
||||
res = True
|
||||
if self.__cloud_conn():
|
||||
if not self.__cloud_post(data):
|
||||
if self.__cloud_conn(enforce=True):
|
||||
if not self.__cloud_post(data):
|
||||
res = False
|
||||
else:
|
||||
log.error("Cloud Connect Failed.")
|
||||
res = False
|
||||
else:
|
||||
log.error("Cloud Connect Failed.")
|
||||
res = False
|
||||
|
||||
if res is False:
|
||||
# This Observer Is History
|
||||
self.notifyObservers(self, *[data])
|
||||
|
||||
return res
|
@ -1,61 +0,0 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import _thread
|
||||
|
||||
from queue import Queue
|
||||
from usr.common import Singleton
|
||||
from usr.logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
def sensor_process(args):
|
||||
self = args
|
||||
while True:
|
||||
sensor_read = self.sensor_queue.get()
|
||||
if sensor_read:
|
||||
sensor_data = {}
|
||||
sensor_data["temperature"] = self.temperature()
|
||||
sensor_data["light"] = self.light()
|
||||
sensor_data["driving_behavior_code"] = self.driving_behavior()
|
||||
if self.sensor_read_cb:
|
||||
self.sensor_read_cb(**sensor_data)
|
||||
else:
|
||||
log.warn("Sensor read callback is not defined.")
|
||||
|
||||
|
||||
class Sensor(Singleton):
|
||||
def __init__(self, sensor_read_cb=None):
|
||||
self.sensor_read_cb = sensor_read_cb
|
||||
self.sensor_queue = Queue(maxsize=64)
|
||||
_thread.start_new_thread(sensor_process, (self,))
|
||||
|
||||
def temperature(self):
|
||||
# TODO: Get temperature value
|
||||
temperature_values = None
|
||||
return temperature_values
|
||||
|
||||
def light(self):
|
||||
# TODO: Get temperature value
|
||||
light_values = None
|
||||
return light_values
|
||||
|
||||
def driving_behavior(self):
|
||||
# TODO: Get driving behavior code
|
||||
driving_behavior_code = None
|
||||
return driving_behavior_code
|
||||
|
||||
def post_data(self, sensor_type, sensor_value):
|
||||
self.sensor_queue.put(True)
|
@ -19,8 +19,8 @@ import ujson
|
||||
import modem
|
||||
import _thread
|
||||
|
||||
from usr.common import Singleton
|
||||
from usr.common import option_lock
|
||||
from usr.moudles.common import Singleton
|
||||
from usr.moudles.common import option_lock
|
||||
from usr.settings_sys import SYSConfig
|
||||
from usr.settings_loc import LocConfig
|
||||
from usr.settings_alicloud import AliCloudConfig
|
||||
|
@ -12,63 +12,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import modem
|
||||
import utime
|
||||
import osTimer
|
||||
|
||||
from usr.logging import Logger
|
||||
from usr.tracker import tracker
|
||||
from usr.battery import Battery
|
||||
from usr.history import History
|
||||
from usr.location import Location, _loc_method, GPSMatch, GPSParse
|
||||
from usr.quecthing import QuecThing, QuecObjectModel
|
||||
from usr.aliyunIot import AliYunIot, AliObjectModel
|
||||
from usr.mpower import LowEnergyManage
|
||||
from usr.common import Observable, Observer
|
||||
from usr.remote import RemoteSubscribe, RemotePublish
|
||||
from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, \
|
||||
DEVICE_FIRMWARE_NAME, DEVICE_FIRMWARE_VERSION, LocConfig, \
|
||||
AliCloudConfig, QuecCloudConfig
|
||||
|
||||
log = Logger(__name__)
|
||||
|
||||
|
||||
def test_led():
|
||||
pass
|
||||
|
||||
|
||||
def test_logger():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
log = Logger("test_logger")
|
||||
log.debug("debug Level Log.")
|
||||
log.info("info Level Log.")
|
||||
log.warn("warn Level Log.")
|
||||
log.error("error Level Log.")
|
||||
log.critical("critical Level Log.")
|
||||
|
||||
assert log.get_debug() is True, "[test_logger] FAILED: log.get_debug() is not True."
|
||||
print("[test_logger] SUCCESS: log.get_debug() is True.")
|
||||
res["success"] += 1
|
||||
|
||||
assert log.set_debug(True) is True, "[test_logger] FAILED: log.set_debug(True)."
|
||||
print("[test_logger] SUCCESS: log.set_debug(True).")
|
||||
res["success"] += 1
|
||||
assert log.set_debug(False) is True, "[test_logger] FAILED: log.set_debug(False)."
|
||||
print("[test_logger] SUCCESS: log.set_debug(False).")
|
||||
res["success"] += 1
|
||||
|
||||
assert log.get_level() == "debug", "[test_logger] FAILED: log.get_level() is not debug."
|
||||
print("[test_logger] SUCCESS: log.get_level() is debug.")
|
||||
res["success"] += 1
|
||||
|
||||
for level in ("debug", "info", "warn", "error", "critical"):
|
||||
assert log.set_level(level) is True and log.get_level() == level, "[test_logger] FAILED: log.set_level(%s)." % level
|
||||
print("[test_logger] SUCCESS: log.set_level(%s)." % level)
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_logger] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
from usr.settings import Settings
|
||||
|
||||
|
||||
def test_settings():
|
||||
@ -111,451 +56,12 @@ def test_settings():
|
||||
print("[test_settings] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
run_time = 0
|
||||
|
||||
|
||||
def get_voltage_cb(args):
|
||||
global run_time
|
||||
run_time += 5
|
||||
|
||||
|
||||
def test_battery():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
battery = Battery()
|
||||
|
||||
temp = 30
|
||||
msg = "[test_battery] %s: battery.set_temp(30)."
|
||||
assert battery.set_temp(temp) and battery.__temp == temp, msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
timer = osTimer()
|
||||
timer.start(5, 1, get_voltage_cb)
|
||||
voltage = battery.get_voltage()
|
||||
timer.stop()
|
||||
global run_time
|
||||
print("[test_battery] battery.get_voltage() run_time: %sms" % run_time)
|
||||
msg = "[test_battery] %s: battery.get_voltage() %s."
|
||||
assert isinstance(voltage, int) and voltage > 0, msg % ("FAILED", voltage)
|
||||
print(msg % ("SUCCESS", voltage))
|
||||
res["success"] += 1
|
||||
|
||||
energy = battery.get_energy()
|
||||
assert isinstance(energy, int) and energy >= 0, "[test_battery] FAILED: battery.get_energy() %s." % energy
|
||||
print("[test_battery] SUCCESS: battery.get_energy() is %s." % energy)
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_battery] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
class TestHistObservable(Observable):
|
||||
|
||||
def produce_hist_data(self, local_time):
|
||||
hist_data = [{"local_time": local_time}]
|
||||
self.notifyObservers(self, *hist_data)
|
||||
|
||||
|
||||
def test_history():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
history = History()
|
||||
test_hist_obs = TestHistObservable()
|
||||
test_hist_obs.addObserver(history)
|
||||
|
||||
hist_data = [{"test": "test"}]
|
||||
assert history.write(hist_data), "[test_history] FAILED: history.write()."
|
||||
print("[test_history] SUCCESS: history.write(%s)." % str(hist_data))
|
||||
res["success"] += 1
|
||||
|
||||
hist = history.read()
|
||||
assert hist.get("data") is not None and isinstance(hist["data"], list), "[test_history] FAILED: history.read() %s." % hist
|
||||
print("[test_history] SUCCESS: history.read() is %s." % hist)
|
||||
res["success"] += 1
|
||||
|
||||
local_time = utime.mktime(utime.localtime())
|
||||
test_hist_obs.produce_hist_data(local_time)
|
||||
hist = history.read()
|
||||
obs_res = False
|
||||
for i in hist.get("data", []):
|
||||
if i.get("local_time") == local_time:
|
||||
obs_res = True
|
||||
break
|
||||
assert obs_res, "[test_history] FAILED: history.update() %s." % str(hist)
|
||||
print("[test_history] SUCCESS: history.update() %s." % str(hist))
|
||||
res["success"] += 1
|
||||
|
||||
assert history.clean(), "[test_history] FAILED: history.clean()."
|
||||
print("[test_history] SUCCESS: history.clean().")
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_history] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
def test_location():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
settings = Settings()
|
||||
current_settings = settings.get()
|
||||
gps_mode = 0x2
|
||||
locator_init_params = current_settings["LocConfig"]["locator_init_params"]
|
||||
|
||||
locator = Location(gps_mode, locator_init_params)
|
||||
for loc_method in range(1, 8):
|
||||
loc_data = locator.read(loc_method)
|
||||
if loc_method & 0x1:
|
||||
assert loc_data.get(0x1) not in ("", (), None), "[test_location] FAILED: locator.read(%s) loc_data: %s." % (loc_method, loc_data)
|
||||
if loc_method & 0x2:
|
||||
assert loc_data.get(0x2) not in ("", (), None), "[test_location] FAILED: locator.read(%s) loc_data: %s." % (loc_method, loc_data)
|
||||
if loc_method & 0x4:
|
||||
assert loc_data.get(0x4) not in ("", (), None), "[test_location] FAILED: locator.read(%s) loc_data: %s." % (loc_method, loc_data)
|
||||
print("[test_location] SUCCESS: locator.read(%s) loc_data: %s." % (loc_method, loc_data))
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
|
||||
print("[test_location] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
def get_quec_loc_data(loc_method, loc_data):
|
||||
__gps_match = GPSMatch()
|
||||
|
||||
if loc_method == 0x1:
|
||||
res = {"gps": []}
|
||||
r = __gps_match.GxRMC(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = __gps_match.GxGGA(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = __gps_match.GxVTG(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
return res
|
||||
elif loc_method == 0x2:
|
||||
return {"non_gps": ["LBS"]}
|
||||
elif loc_method == 0x4:
|
||||
return {"non_gps": []}
|
||||
|
||||
|
||||
def test_quecthing():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
settings = Settings()
|
||||
current_settings = settings.get()
|
||||
|
||||
cloud_init_params = QuecCloudConfig.__dict__
|
||||
cloud = QuecThing(
|
||||
cloud_init_params["PK"],
|
||||
cloud_init_params["PS"],
|
||||
cloud_init_params["DK"],
|
||||
cloud_init_params["DS"],
|
||||
cloud_init_params["SERVER"],
|
||||
mcu_name=PROJECT_NAME,
|
||||
mcu_version=PROJECT_VERSION
|
||||
)
|
||||
remote_sub = RemoteSubscribe()
|
||||
cloud.addObserver(remote_sub)
|
||||
|
||||
quec_om = QuecObjectModel()
|
||||
msg = "[test_quecthing] %s: cloud.set_object_model(%s)."
|
||||
assert cloud.set_object_model(quec_om), msg % ("FAILED", quec_om)
|
||||
print(msg % ("SUCCESS", quec_om))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_quecthing] %s: cloud.init()."
|
||||
assert cloud.init(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_quecthing] %s: get_quec_loc_data(%s, %s) %s."
|
||||
loc_method = _loc_method.gps
|
||||
gps_mode = LocConfig._gps_mode.external
|
||||
locator_init_params = current_settings["LocConfig"]["locator_init_params"]
|
||||
|
||||
locator = Location(gps_mode, locator_init_params)
|
||||
loc_data = locator.read(loc_method)
|
||||
quec_loc_data = get_quec_loc_data(loc_method, loc_data.get(loc_method))
|
||||
assert quec_loc_data != "", msg % ("FAILED", loc_method, loc_data, quec_loc_data)
|
||||
print(msg % ("SUCCESS", loc_method, loc_data, quec_loc_data))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_quecthing] %s: cloud.post_data(%s)."
|
||||
assert cloud.post_data(quec_loc_data), msg % ("FAILED", str(quec_loc_data))
|
||||
print(msg % ("SUCCESS", str(quec_loc_data)))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_quecthing] %s: cloud.ota_request()."
|
||||
assert cloud.ota_request(), msg % ("FAILED",)
|
||||
print(msg % ("SUCCESS",))
|
||||
res["success"] += 1
|
||||
|
||||
# # PASS: No OTA Plain, ota_action Return False
|
||||
# msg = "[test_quecthing] %s: cloud.ota_action()."
|
||||
# assert cloud.ota_action() is True, msg % ("FAILED",)
|
||||
# print(msg % ("SUCCESS",))
|
||||
|
||||
msg = "[test_quecthing] %s: cloud.close()."
|
||||
assert cloud.close(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_quecthing] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
def get_ali_loc_data(loc_method, loc_data):
|
||||
res = {"GeoLocation": {}}
|
||||
|
||||
__gps_match = GPSMatch()
|
||||
__gps_parse = GPSParse()
|
||||
|
||||
if loc_method == 0x1:
|
||||
gga_data = __gps_match.GxGGA(loc_data)
|
||||
data = {}
|
||||
if gga_data:
|
||||
Latitude = __gps_parse.GxGGA_latitude(gga_data)
|
||||
if Latitude:
|
||||
data["Latitude"] = float("%.2f" % float(Latitude))
|
||||
Longtitude = __gps_parse.GxGGA_longtitude(gga_data)
|
||||
if Longtitude:
|
||||
data["Longtitude"] = float("%.2f" % float(Longtitude))
|
||||
Altitude = __gps_parse.GxGGA_altitude(gga_data)
|
||||
if Altitude:
|
||||
data["Altitude"] = float("%.2f" % float(Altitude))
|
||||
if data:
|
||||
data["CoordinateSystem"] = 1
|
||||
res = {"GeoLocation": data}
|
||||
elif loc_method in (0x2, 0x4):
|
||||
if loc_data:
|
||||
res["GeoLocation"] = {
|
||||
"Longtitude": round(loc_data[0], 2),
|
||||
"Latitude": round(loc_data[1], 2),
|
||||
# "Altitude": 0.0,
|
||||
"CoordinateSystem": 1
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def test_aliyuniot():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
settings = Settings()
|
||||
current_settings = settings.get()
|
||||
|
||||
cloud_init_params = AliCloudConfig.__dict__
|
||||
client_id = cloud_init_params["client_id"] if cloud_init_params.get("client_id") else modem.getDevImei()
|
||||
cloud = AliYunIot(
|
||||
cloud_init_params["PK"],
|
||||
cloud_init_params["PS"],
|
||||
cloud_init_params["DK"],
|
||||
cloud_init_params["DS"],
|
||||
cloud_init_params["SERVER"],
|
||||
client_id,
|
||||
burning_method=cloud_init_params["burning_method"],
|
||||
mcu_name=PROJECT_NAME,
|
||||
mcu_version=PROJECT_VERSION,
|
||||
firmware_name=DEVICE_FIRMWARE_NAME,
|
||||
firmware_version=DEVICE_FIRMWARE_VERSION
|
||||
)
|
||||
remote_sub = RemoteSubscribe()
|
||||
cloud.addObserver(remote_sub)
|
||||
|
||||
ali_om = AliObjectModel()
|
||||
msg = "[test_aliyuniot] %s: cloud.set_object_model(%s)."
|
||||
assert cloud.set_object_model(ali_om), msg % ("FAILED", ali_om)
|
||||
print(msg % ("SUCCESS", ali_om))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_aliyuniot] %s: cloud.init()."
|
||||
assert cloud.init(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_aliyuniot] %s: get_ali_loc_data(%s, %s) %s."
|
||||
loc_method = _loc_method.gps
|
||||
gps_mode = LocConfig._gps_mode.external
|
||||
locator_init_params = current_settings["LocConfig"]["locator_init_params"]
|
||||
|
||||
locator = Location(gps_mode, locator_init_params)
|
||||
loc_data = locator.read(loc_method)
|
||||
ali_loc_data = get_ali_loc_data(loc_method, loc_data.get(loc_method))
|
||||
assert ali_loc_data["GeoLocation"] != {}, msg % ("FAILED", loc_method, loc_data, ali_loc_data)
|
||||
print(msg % ("SUCCESS", loc_method, loc_data, ali_loc_data))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_aliyuniot] %s: cloud.post_data(%s)."
|
||||
assert cloud.post_data(ali_loc_data), msg % ("FAILED", str(ali_loc_data))
|
||||
print(msg % ("SUCCESS", str(ali_loc_data)))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_aliyuniot] %s: cloud.ota_request()."
|
||||
assert cloud.ota_request(), msg % ("FAILED",)
|
||||
print(msg % ("SUCCESS",))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_aliyuniot] %s: cloud.device_report()."
|
||||
assert cloud.device_report(), msg % ("FAILED",)
|
||||
print(msg % ("SUCCESS",))
|
||||
res["success"] += 1
|
||||
|
||||
# # PASS: No OTA Plain, ota_action Return False
|
||||
# msg = "[test_aliyuniot] %s: cloud.ota_action()."
|
||||
# assert cloud.ota_action() is True, msg % ("FAILED",)
|
||||
# print(msg % ("SUCCESS",))
|
||||
|
||||
msg = "[test_aliyuniot] %s: cloud.close()."
|
||||
assert cloud.close() and cloud.__ali.getAliyunSta() != 0, msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_aliyuniot] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
def test_remote():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
settings = Settings()
|
||||
current_settings = settings.get()
|
||||
cloud_init_params = current_settings["cloud"]
|
||||
|
||||
cloud = QuecThing(
|
||||
cloud_init_params["PK"],
|
||||
cloud_init_params["PS"],
|
||||
cloud_init_params["DK"],
|
||||
cloud_init_params["DS"],
|
||||
cloud_init_params["SERVER"],
|
||||
mcu_name=PROJECT_NAME,
|
||||
mcu_version=PROJECT_VERSION
|
||||
)
|
||||
remote_sub = RemoteSubscribe()
|
||||
cloud.addObserver(remote_sub)
|
||||
remote_pub = RemotePublish()
|
||||
|
||||
msg = "[test_remote] %s: cloud.cloud_init()."
|
||||
assert cloud.cloud_init(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
|
||||
msg = "[test_remote] %s: remote_pub.set_cloud(cloud)."
|
||||
assert remote_pub.set_cloud(cloud), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_remote] %s: remote_pub.get_cloud()."
|
||||
assert isinstance(remote_pub.get_cloud(), QuecThing), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_remote] %s: remote_pub.cloud_ota_check()."
|
||||
assert remote_pub.cloud_ota_check(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
# # PASS: No OTA Plain, ota_action Return False
|
||||
# msg = "[test_remote] %s: remote_pub.ota_request()."
|
||||
# assert remote_pub.ota_request(), msg % "FAILED"
|
||||
# print(msg % "SUCCESS")
|
||||
|
||||
gps_mode = 0x2
|
||||
locator_init_params = current_settings["user_cfg"]["locator_init_params"]
|
||||
locator = Location(gps_mode, locator_init_params)
|
||||
|
||||
loc_method = 0x1
|
||||
loc_data = locator.read(loc_method)
|
||||
quec_loc_data = cloud.get_loc_data(loc_method, loc_data.get(loc_method))
|
||||
|
||||
msg = "[test_remote] %s: remote_pub.post_data(%s)."
|
||||
assert remote_pub.post_data(quec_loc_data), msg % ("FAILED", str(quec_loc_data))
|
||||
print(msg % ("SUCCESS", str(quec_loc_data)))
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_remote] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
class TestLEMObserver(Observer):
|
||||
|
||||
def update(self, observable, *args, **kwargs):
|
||||
log.debug("observable: %s" % observable)
|
||||
log.debug("args: %s" % str(args))
|
||||
log.debug("kwargs: %s" % str(kwargs))
|
||||
observable.start()
|
||||
return True
|
||||
|
||||
|
||||
def test_low_energy_manage():
|
||||
res = {"all": 0, "success": 0, "failed": 0}
|
||||
|
||||
low_energy_manage = LowEnergyManage()
|
||||
test_lem_obs = TestLEMObserver()
|
||||
low_energy_manage.addObserver(test_lem_obs)
|
||||
|
||||
period = 5
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.set_period(%s)."
|
||||
assert low_energy_manage.set_period(period), msg % ("FAILED", period)
|
||||
print(msg % ("SUCCESS", period))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.get_period()."
|
||||
assert low_energy_manage.get_period() == period, msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
low_energy_method = "PM"
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.set_low_energy_method(%s)."
|
||||
assert low_energy_manage.set_low_energy_method(low_energy_method), msg % ("FAILED", low_energy_method)
|
||||
print(msg % ("SUCCESS", low_energy_method))
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.get_low_energy_method()."
|
||||
assert low_energy_manage.get_low_energy_method() == low_energy_method, msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.low_energy_init()."
|
||||
assert low_energy_manage.low_energy_init(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.get_lpm_fd()."
|
||||
assert low_energy_manage.get_lpm_fd() is not None, msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.start()."
|
||||
assert low_energy_manage.start(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
utime.sleep(period * 3 + 1)
|
||||
msg = "[test_low_energy_manage] %s: low_energy_manage.stop()."
|
||||
assert low_energy_manage.stop(), msg % "FAILED"
|
||||
print(msg % "SUCCESS")
|
||||
res["success"] += 1
|
||||
|
||||
res["all"] = res["success"] + res["failed"]
|
||||
print("[test_low_energy_manage] ALL: %s SUCCESS: %s, FAILED: %s." % (res["all"], res["success"], res["failed"]))
|
||||
|
||||
|
||||
def test_tracker():
|
||||
tracker()
|
||||
|
||||
|
||||
def main():
|
||||
# test_logger()
|
||||
# test_settings()
|
||||
# test_battery()
|
||||
# test_history()
|
||||
# test_location()
|
||||
# test_quecthing()
|
||||
# test_aliyuniot()
|
||||
# test_remote()
|
||||
# test_low_energy_manage()
|
||||
test_tracker()
|
||||
|
||||
|
||||
|
845
code/tracker.py
845
code/tracker.py
@ -13,28 +13,24 @@
|
||||
# limitations under the License.
|
||||
|
||||
import sim
|
||||
import utime
|
||||
import modem
|
||||
import checkNet
|
||||
import dataCall
|
||||
|
||||
from misc import Power
|
||||
|
||||
from usr.led import LED
|
||||
from usr.sensor import Sensor
|
||||
from usr.battery import Battery
|
||||
from usr.ota import OTAFileClear
|
||||
from usr.history import History
|
||||
from usr.logging import getLogger
|
||||
from usr.mpower import LowEnergyManage
|
||||
from usr.remote import RemotePublish, RemoteSubscribe
|
||||
from usr.aliyunIot import AliYunIot, AliObjectModel
|
||||
from usr.quecthing import QuecThing, QuecObjectModel
|
||||
from usr.common import Singleton, LOWENERGYMAP
|
||||
from usr.location import Location, GPSMatch, GPSParse, _loc_method
|
||||
from usr.modules.sensor import Sensor
|
||||
from usr.modules.battery import Battery
|
||||
from usr.modules.ota import OTAFileClear
|
||||
from usr.modules.history import History
|
||||
from usr.modules.logging import getLogger
|
||||
from usr.modules.mpower import LowEnergyManage
|
||||
from usr.modules.remote import RemotePublish, RemoteSubscribe
|
||||
from usr.modules.aliyunIot import AliYunIot, AliObjectModel
|
||||
from usr.modules.quecthing import QuecThing, QuecObjectModel
|
||||
from usr.modules.location import Location
|
||||
from usr.settings import PROJECT_NAME, PROJECT_VERSION, \
|
||||
DEVICE_FIRMWARE_NAME, DEVICE_FIRMWARE_VERSION, settings, UserConfig, \
|
||||
SYSConfig, Settings
|
||||
DEVICE_FIRMWARE_NAME, DEVICE_FIRMWARE_VERSION, settings, SYSConfig
|
||||
from usr.tracker_collector import Collector
|
||||
from usr.tracker_controller import Controller
|
||||
from usr.tracker_devicecheck import DeviceCheck
|
||||
|
||||
try:
|
||||
from misc import USB
|
||||
@ -50,16 +46,6 @@ log = getLogger(__name__)
|
||||
|
||||
sim.setSimDet(1, 0)
|
||||
|
||||
ALERTCODE = {
|
||||
20000: "fault_alert",
|
||||
30002: "low_power_alert",
|
||||
30003: "over_speed_alert",
|
||||
30004: "sim_abnormal_alert",
|
||||
30005: "disassemble_alert",
|
||||
40000: "drive_behavior_alert",
|
||||
50001: "sos_alert",
|
||||
}
|
||||
|
||||
|
||||
def pwk_callback(status):
|
||||
if status == 0:
|
||||
@ -93,809 +79,6 @@ def nw_callback(args):
|
||||
pass
|
||||
|
||||
|
||||
class Collector(Singleton):
|
||||
def __init__(self):
|
||||
self.__controller = None
|
||||
self.__devicecheck = None
|
||||
self.__battery = None
|
||||
self.__sensor = None
|
||||
self.__locator = None
|
||||
self.__history = None
|
||||
self.__gps_match = GPSMatch()
|
||||
self.__gps_parse = GPSParse()
|
||||
|
||||
def __format_loc_method(self, data):
|
||||
loc_method = "%04d" % int(bin(data)[2:])
|
||||
gps = bool(int(loc_method[-1]))
|
||||
cell = bool(int(loc_method[-2]))
|
||||
wifi = bool(int(loc_method[-3]))
|
||||
|
||||
loc_method = {
|
||||
"gps": gps,
|
||||
"cell": cell,
|
||||
"wifi": wifi,
|
||||
}
|
||||
return loc_method
|
||||
|
||||
def __device_speed_check(self):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
alert_data = {
|
||||
"current_speed": 0.00
|
||||
}
|
||||
if current_settings["user_cfg"]["sw_over_speed_alert"] is True:
|
||||
if self.__locator.gps:
|
||||
gps_data = self.__locator.gps.read()[1]
|
||||
vtg_data = self.__gps_match.GxVTG(gps_data)
|
||||
speed = self.__gps_parse.GxVTG_speed(vtg_data)
|
||||
if speed and float(speed) >= current_settings["user_cfg"]["over_speed_threshold"]:
|
||||
alert_code = 30003
|
||||
alert_info = {"local_time": self.__get_local_time()}
|
||||
alert_data = self.__get_alert_data(alert_code, alert_info)
|
||||
if speed:
|
||||
alert_data["current_speed"] = float(speed)
|
||||
|
||||
log.debug("__device_speed_check: %s" % str(alert_data))
|
||||
return alert_data
|
||||
|
||||
def __get_local_time(self):
|
||||
return str(utime.mktime(utime.localtime()) * 1000)
|
||||
|
||||
def __get_alert_data(self, alert_code, alert_info):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
alert_data = {}
|
||||
if ALERTCODE.get(alert_code):
|
||||
alert_status = current_settings.get("user_cfg", {}).get("sw_" + ALERTCODE.get(alert_code))
|
||||
if alert_status:
|
||||
alert_data = {ALERTCODE.get(alert_code): alert_info}
|
||||
else:
|
||||
log.warn("%s switch is %s" % (ALERTCODE.get(alert_code), alert_status))
|
||||
else:
|
||||
log.error("altercode (%s) is not exists. alert info: %s" % (alert_code, alert_info))
|
||||
|
||||
return alert_data
|
||||
|
||||
def __init_low_energy_method(self, period):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
device_model = modem.getDevModel()
|
||||
support_methds = LOWENERGYMAP.get(device_model, [])
|
||||
method = "NULL"
|
||||
if support_methds:
|
||||
if period >= current_settings["user_cfg"]["work_mode_timeline"]:
|
||||
if "PSM" in support_methds:
|
||||
method = "PSM"
|
||||
elif "POWERDOWN" in support_methds:
|
||||
method = "POWERDOWN"
|
||||
elif "PM" in support_methds:
|
||||
method = "PM"
|
||||
else:
|
||||
if "PM" in support_methds:
|
||||
method = "PM"
|
||||
log.debug("__init_low_energy_method: %s" % method)
|
||||
return method
|
||||
|
||||
def __get_ali_loc_data(self, loc_method, loc_data):
|
||||
res = {"GeoLocation": {}}
|
||||
|
||||
if loc_method == 0x1:
|
||||
gga_data = self.__gps_match.GxGGA(loc_data)
|
||||
data = {}
|
||||
if gga_data:
|
||||
Latitude = self.__gps_parse.GxGGA_latitude(gga_data)
|
||||
if Latitude:
|
||||
data["Latitude"] = float("%.2f" % float(Latitude))
|
||||
Longtitude = self.__gps_parse.GxGGA_longtitude(gga_data)
|
||||
if Longtitude:
|
||||
data["Longtitude"] = float("%.2f" % float(Longtitude))
|
||||
Altitude = self.__gps_parse.GxGGA_altitude(gga_data)
|
||||
if Altitude:
|
||||
data["Altitude"] = float("%.2f" % float(Altitude))
|
||||
if data:
|
||||
data["CoordinateSystem"] = 1
|
||||
res = {"GeoLocation": data}
|
||||
elif loc_method in (0x2, 0x4):
|
||||
if loc_data:
|
||||
res["GeoLocation"] = {
|
||||
"Longtitude": round(loc_data[0], 2),
|
||||
"Latitude": round(loc_data[1], 2),
|
||||
# "Altitude": 0.0,
|
||||
"CoordinateSystem": 1
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
def __get_quec_loc_data(self, loc_method, loc_data):
|
||||
if loc_method == 0x1:
|
||||
res = {"gps": []}
|
||||
r = self.__gps_match.GxRMC(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = self.__gps_match.GxGGA(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = self.__gps_match.GxVTG(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
return res
|
||||
elif loc_method == 0x2:
|
||||
return {"non_gps": ["LBS"]}
|
||||
elif loc_method == 0x4:
|
||||
return {"non_gps": []}
|
||||
|
||||
def __get_loc_data(self, loc_method, loc_data):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["sys"]["cloud"] & SYSConfig._cloud.quecIot:
|
||||
return self.__get_quec_loc_data(loc_method, loc_data)
|
||||
elif current_settings["sys"]["cloud"] & SYSConfig._cloud.AliYun:
|
||||
return self.__get_ali_loc_data(loc_method, loc_data)
|
||||
return {}
|
||||
|
||||
def __read_battery(self):
|
||||
if not self.__battery:
|
||||
raise TypeError("self.__battery is not registered.")
|
||||
|
||||
res = {}
|
||||
self.__battery.set_temp(20)
|
||||
energy = self.__battery.get_energy()
|
||||
res = {
|
||||
"energy": energy,
|
||||
"voltage": self.__battery.get_voltage(),
|
||||
}
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if energy <= current_settings["user_cfg"]["low_power_alert_threshold"]:
|
||||
alert_data = self.__get_alert_data(30002, {"local_time": self.__get_local_time()})
|
||||
res.update(alert_data)
|
||||
|
||||
return res
|
||||
|
||||
def __read_sensor(self):
|
||||
return {}
|
||||
|
||||
def __read_location(self):
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered.")
|
||||
|
||||
res = {}
|
||||
current_settings = self.__controller.settings_get()
|
||||
# Get cloud location data
|
||||
if current_settings["user_cfg"].get("loc_method"):
|
||||
cfg_loc_method = current_settings["user_cfg"].get("loc_method")
|
||||
elif current_settings["sys"]["base_cfg"]["LocConfig"]:
|
||||
cfg_loc_method = current_settings["LocConfig"]["loc_method"]
|
||||
else:
|
||||
cfg_loc_method = 7
|
||||
loc_info = self.__locator.read(cfg_loc_method)
|
||||
if loc_info:
|
||||
loc_method_dict = {v: k for k, v in _loc_method.__dict__.items()}
|
||||
loc_data = None
|
||||
for loc_method in loc_method_dict.keys():
|
||||
if loc_info.get(loc_method):
|
||||
log.debug("Location Data loc_method: %s" % loc_method_dict[loc_method])
|
||||
loc_data = loc_info[loc_method]
|
||||
|
||||
if loc_method == _loc_method.gps:
|
||||
gga_satellite = self.__gps_parse.GxGGA_satellite_num(self.__gps_match.GxGGA(loc_data))
|
||||
log.debug("GxGGA Satellite Num %s" % gga_satellite)
|
||||
gsv_satellite = self.__gps_parse.GxGSV_satellite_num(self.__gps_match.GxGSV(loc_data))
|
||||
log.debug("GxGSV Satellite Num %s" % gsv_satellite)
|
||||
break
|
||||
if loc_data:
|
||||
res = self.__get_loc_data(loc_method, loc_data)
|
||||
|
||||
return res
|
||||
|
||||
def add_module(self, module):
|
||||
if isinstance(module, Controller):
|
||||
self.__controller = module
|
||||
return True
|
||||
elif isinstance(module, DeviceCheck):
|
||||
self.__devicecheck = module
|
||||
return True
|
||||
elif isinstance(module, Battery):
|
||||
self.__battery = module
|
||||
return True
|
||||
elif isinstance(module, Sensor):
|
||||
self.__sensor = module
|
||||
return True
|
||||
elif isinstance(module, Location):
|
||||
self.__locator = module
|
||||
return True
|
||||
elif isinstance(module, History):
|
||||
self.__history = module
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def read_module_data(self, module):
|
||||
if module == "Battery":
|
||||
return self.__read_battery()
|
||||
elif module == "Sensor":
|
||||
return self.__read_sensor()
|
||||
elif module == "Location":
|
||||
return self.__read_location()
|
||||
elif module == "History":
|
||||
return self.__read_history()
|
||||
|
||||
def device_status_get(self):
|
||||
if not self.__devicecheck:
|
||||
raise TypeError("self.__devicecheck is not registered.")
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
device_status_data = {}
|
||||
device_module_status = {}
|
||||
alert_code = 20000
|
||||
|
||||
net_status = self.__devicecheck.net()
|
||||
location_status = self.__devicecheck.location()
|
||||
temp_status = self.__devicecheck.temp()
|
||||
light_status = self.__devicecheck.light()
|
||||
triaxial_status = self.__devicecheck.triaxial()
|
||||
mike_status = self.__devicecheck.mike()
|
||||
|
||||
device_module_status["net"] = 1 if net_status == (3, 1) else 0
|
||||
device_module_status["location"] = 1 if location_status else 0
|
||||
|
||||
# TODO: Check Sensor.
|
||||
if temp_status is not None:
|
||||
device_module_status["temp_sensor"] = 1 if temp_status else 0
|
||||
if light_status is not None:
|
||||
device_module_status["light_sensor"] = 1 if temp_status else 0
|
||||
if triaxial_status is not None:
|
||||
device_module_status["move_sensor"] = 1 if temp_status else 0
|
||||
if mike_status is not None:
|
||||
device_module_status["mike"] = 1 if temp_status else 0
|
||||
|
||||
device_status = True
|
||||
# TODO: Led Show
|
||||
if net_status == (3, 1) and location_status is True and \
|
||||
(temp_status is True or temp_status is None) and \
|
||||
(light_status is True or light_status is None) and \
|
||||
(triaxial_status is True or triaxial_status is None) and \
|
||||
(mike_status is True or mike_status is None):
|
||||
# self.__controller.running_led_show(0.5)
|
||||
device_status = True
|
||||
else:
|
||||
# self.__controller.running_led_show(2)
|
||||
device_status = False
|
||||
|
||||
if device_status is False:
|
||||
device_status_data = self.__get_alert_data(alert_code, {"local_time": self.__get_local_time()})
|
||||
|
||||
device_status_data.update({"device_module_status": device_module_status})
|
||||
|
||||
return device_status_data
|
||||
|
||||
def device_status_check(self):
|
||||
device_status_check_res = self.device_status_get()
|
||||
self.device_data_report(event_data=device_status_check_res)
|
||||
|
||||
def device_data_get(self, power_switch=True):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
|
||||
device_data = {
|
||||
"power_switch": power_switch,
|
||||
"local_time": self.__get_local_time(),
|
||||
}
|
||||
|
||||
# Get ota status & drive behiver code
|
||||
device_data.update({
|
||||
"ota_status": current_settings["user_cfg"]["ota_status"],
|
||||
"drive_behavior_code": current_settings["user_cfg"]["drive_behavior_code"],
|
||||
})
|
||||
|
||||
# Get user settings info
|
||||
device_data.update(current_settings["user_cfg"])
|
||||
|
||||
# Format loc method
|
||||
device_data.update({"loc_method": self.__format_loc_method(current_settings["user_cfg"]["loc_method"])})
|
||||
|
||||
# Get cloud location data
|
||||
device_data.update(self.__read_location())
|
||||
|
||||
# Get gps speed
|
||||
device_data.update(self.__device_speed_check())
|
||||
|
||||
# Get battery energy
|
||||
device_data.update(self.__read_battery())
|
||||
|
||||
# TODO: Add other machine info.
|
||||
|
||||
return device_data
|
||||
|
||||
def device_data_report(self, power_switch=True, event_data={}, msg=""):
|
||||
# TODO: msg to mark post data source
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
device_data = self.device_data_get(power_switch)
|
||||
if event_data:
|
||||
device_data.update(event_data)
|
||||
|
||||
post_res = self.__controller.remote_post_data(device_data)
|
||||
|
||||
# OTA status rst
|
||||
current_settings = self.__controller.settings_get() if self.__controller else {}
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["upgrade_status"] in (3, 4):
|
||||
self.ota_status_reset()
|
||||
|
||||
return post_res
|
||||
|
||||
def ota_status_reset(self):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
ota_info = {}
|
||||
ota_info["sys_target_version"] = "--"
|
||||
ota_info["app_target_version"] = "--"
|
||||
ota_info["upgrade_module"] = 0
|
||||
ota_info["upgrade_status"] = 0
|
||||
ota_status_info.update(ota_info)
|
||||
self.__controller.settings_set("ota_status", ota_status_info)
|
||||
|
||||
if current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
self.__controller.settings_set("user_ota_action", -1)
|
||||
|
||||
def report_history(self):
|
||||
if not self.__history:
|
||||
raise TypeError("self.__history is not registered.")
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
res = True
|
||||
hist = self.__history.read()
|
||||
if hist["data"]:
|
||||
pt_count = 0
|
||||
for i, data in enumerate(hist["data"]):
|
||||
pt_count += 1
|
||||
if not self.__controller.remote_post_data(data):
|
||||
res = False
|
||||
break
|
||||
|
||||
hist["data"] = hist["data"][pt_count:]
|
||||
if hist["data"]:
|
||||
# Flush data in hist-dictionary to tracker_data.hist file.
|
||||
self.__history.write(hist["data"])
|
||||
|
||||
return res
|
||||
|
||||
# Do cloud event downlink option by controller
|
||||
def event_option(self, *args, **kwargs):
|
||||
# TODO: Data Type Passthrough (Not Support Now).
|
||||
return False
|
||||
|
||||
def event_done(self, *args, **kwargs):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
try:
|
||||
setting_flag = 0
|
||||
|
||||
for arg in args:
|
||||
if hasattr(UserConfig, arg[0]):
|
||||
set_res = self.__controller.settings_set(arg[0], arg[1])
|
||||
if set_res and setting_flag == 0:
|
||||
setting_flag = 1
|
||||
if hasattr(self, arg[0]):
|
||||
getattr(self, arg[0])(arg[1])
|
||||
|
||||
if setting_flag:
|
||||
self.__controller.settings_save()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def event_query(self, *args, **kwargs):
|
||||
return self.device_data_report()
|
||||
|
||||
def event_ota_plain(self, *args, **kwargs):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = settings.get()
|
||||
if current_settings["user_cfg"]["sw_ota"]:
|
||||
if current_settings["user_cfg"]["sw_ota_auto_upgrade"] or current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
if current_settings["user_cfg"]["sw_ota_auto_upgrade"]:
|
||||
ota_action_val = 1
|
||||
else:
|
||||
if current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
ota_action_val = current_settings["user_cfg"]["user_ota_action"]
|
||||
else:
|
||||
return
|
||||
|
||||
if current_settings["sys"]["cloud"] == SYSConfig._cloud.quecIot or \
|
||||
current_settings["sys"]["cloud"] == SYSConfig._cloud.AliYun:
|
||||
log.debug("ota_plain args: %s, kwargs: %s" % (str(args), str(kwargs)))
|
||||
self.__controller.remote_ota_action(action=ota_action_val, module=kwargs.get("module"))
|
||||
else:
|
||||
log.error("Current Cloud (0x%X) Not Supported!" % current_settings["sys"]["cloud"])
|
||||
|
||||
def event_ota_file_download(self, *args, **kwargs):
|
||||
# OAT MQTT File Download Is Not Supported Yet.
|
||||
return False
|
||||
|
||||
def power_switch(self, flag=None):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.event_query(power_switch=flag)
|
||||
if flag is False:
|
||||
self.__controller.power_down()
|
||||
|
||||
def user_ota_action(self, action):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["user_cfg"]["sw_ota"] and current_settings["user_cfg"]["sw_ota_auto_upgrade"] is False:
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["upgrade_status"] == 1 and current_settings["user_cfg"]["user_ota_action"] == -1:
|
||||
self.__controller.settings_set("user_ota_action", action)
|
||||
self.__controller.settings_save()
|
||||
self.__controller.remote_ota_check()
|
||||
|
||||
def ota_status(self, upgrade_info=None):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if upgrade_info and current_settings["user_cfg"]["sw_ota"]:
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["sys_target_version"] == "--" and ota_status_info["app_target_version"] == "--":
|
||||
ota_info = {}
|
||||
if upgrade_info[0] == DEVICE_FIRMWARE_NAME:
|
||||
ota_info["upgrade_module"] = 1
|
||||
ota_info["sys_target_version"] = upgrade_info[2]
|
||||
elif upgrade_info[0] == PROJECT_NAME:
|
||||
ota_info["upgrade_module"] = 2
|
||||
ota_info["app_target_version"] = upgrade_info[2]
|
||||
ota_info["upgrade_status"] = upgrade_info[1]
|
||||
ota_status_info.update(ota_info)
|
||||
self.__controller.settings_set("ota_status", ota_status_info)
|
||||
self.__controller.settings_save()
|
||||
|
||||
def power_restart(self, flag):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.event_query(power_switch=False)
|
||||
self.__controller.power_restart()
|
||||
|
||||
def work_cycle_period(self, period):
|
||||
# Reset work_cycle_period & Reset RTC
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.__controller.low_energy_stop()
|
||||
|
||||
self.__controller.low_energy_set_period(period)
|
||||
method = self.__init_low_energy_method(period)
|
||||
self.__controller.low_energy_set_method(method)
|
||||
|
||||
self.__controller.low_energy_init()
|
||||
self.__controller.low_energy_start()
|
||||
|
||||
def cloud_init_params(self, params):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.__controller.settings_set("cloud", params)
|
||||
self.__controller.settings_save()
|
||||
|
||||
def low_engery_option(self, low_energy_method):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.report_history()
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["user_cfg"]["work_mode"] == UserConfig._work_mode.intelligent:
|
||||
speed_info = self.__device_speed_check()
|
||||
if speed_info.get("current_speed") > 0:
|
||||
self.device_data_report()
|
||||
else:
|
||||
self.device_data_report()
|
||||
|
||||
self.__controller.low_energy_start()
|
||||
|
||||
if low_energy_method == "PSM":
|
||||
# TODO: PSM option.
|
||||
pass
|
||||
elif low_energy_method == "POWERDOWN":
|
||||
self.__controller.power_down()
|
||||
|
||||
def update(self, observable, *args, **kwargs):
|
||||
if isinstance(observable, LowEnergyManage):
|
||||
log.debug("Low Energy RTC Method: %s" % args[1])
|
||||
self.low_engery_option(args[1])
|
||||
|
||||
|
||||
class DeviceCheck(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__locator = None
|
||||
self.__sensor = None
|
||||
|
||||
def add_module(self, module):
|
||||
if isinstance(module, Location):
|
||||
self.__locator = module
|
||||
return True
|
||||
elif isinstance(module, Sensor):
|
||||
self.__sensor = module
|
||||
return True
|
||||
return False
|
||||
|
||||
def net(self):
|
||||
current_settings = settings.get()
|
||||
checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION)
|
||||
timeout = current_settings.get("sys", {}).get("checknet_timeout", 60)
|
||||
check_res = checknet.wait_network_connected(timeout)
|
||||
log.debug("DeviceCheck.net res: %s" % str(check_res))
|
||||
return check_res
|
||||
|
||||
def location(self):
|
||||
# return True if OK
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered")
|
||||
|
||||
current_settings = settings.get()
|
||||
retry = 0
|
||||
gps_data = None
|
||||
sleep_time = 1
|
||||
|
||||
while retry < 5:
|
||||
if current_settings["user_cfg"].get("loc_method"):
|
||||
loc_method = current_settings["user_cfg"].get("loc_method")
|
||||
elif current_settings["sys"]["base_cfg"]["LocConfig"]:
|
||||
loc_method = current_settings["LocConfig"].get("loc_method")
|
||||
else:
|
||||
loc_method = 7
|
||||
|
||||
gps_data = self.__locator.read(loc_method)
|
||||
if gps_data:
|
||||
break
|
||||
else:
|
||||
retry += 1
|
||||
utime.sleep(sleep_time)
|
||||
sleep_time *= 2
|
||||
|
||||
if gps_data:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def temp(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def light(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def triaxial(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def mike(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
|
||||
class Controller(Singleton):
|
||||
def __init__(self):
|
||||
self.__remote_pub = None
|
||||
self.__settings = None
|
||||
self.__low_energy = None
|
||||
self.__energy_led = None
|
||||
self.__running_led = None
|
||||
self.__power_key = None
|
||||
self.__usb = None
|
||||
self.__data_call = None
|
||||
self.__ota_file_clear = None
|
||||
|
||||
def add_module(self, module, led_type=None, callback=None):
|
||||
if isinstance(module, RemotePublish):
|
||||
self.__remote_pub = module
|
||||
return True
|
||||
elif isinstance(module, Settings):
|
||||
self.__settings = module
|
||||
return True
|
||||
elif isinstance(module, LowEnergyManage):
|
||||
self.__low_energy = module
|
||||
return True
|
||||
elif isinstance(module, OTAFileClear):
|
||||
self.__ota_file_clear = module
|
||||
return True
|
||||
elif isinstance(module, LED):
|
||||
if led_type == "energy":
|
||||
self.__energy_led = module
|
||||
return True
|
||||
elif led_type == "running":
|
||||
self.running_led = module
|
||||
return True
|
||||
elif isinstance(module, PowerKey):
|
||||
self.__power_key = module
|
||||
if callback:
|
||||
self.__power_key.powerKeyEventRegister(callback)
|
||||
return True
|
||||
elif isinstance(module, USB):
|
||||
self.__usb = module
|
||||
if callback:
|
||||
self.__usb.setCallback(callback)
|
||||
return True
|
||||
elif module is dataCall:
|
||||
self.__data_call = module
|
||||
if callback:
|
||||
self.__data_call.setCallback(callback)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def set_remote_pub(self, remote_pub):
|
||||
if isinstance(remote_pub, RemotePublish):
|
||||
self.__remote_pub = remote_pub
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_settings(self, settings):
|
||||
if isinstance(settings, Settings):
|
||||
self.__settings = settings
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_low_energy(self, low_energy_manage):
|
||||
if isinstance(low_energy_manage, LowEnergyManage):
|
||||
self.__low_energy = low_energy_manage
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_energy_led(self, energy_led):
|
||||
if isinstance(energy_led, LED):
|
||||
self.__energy_led = energy_led
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_running_led(self, running_led):
|
||||
if isinstance(running_led, LED):
|
||||
self.__running_led = running_led
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_power_key(self, power_key, power_key_cb):
|
||||
if isinstance(power_key, PowerKey):
|
||||
self.__power_key = power_key
|
||||
if power_key_cb:
|
||||
self.__power_key.powerKeyEventRegister(power_key_cb)
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_usb(self, usb, usb_cb):
|
||||
if isinstance(usb, USB):
|
||||
self.__usb = usb
|
||||
if usb_cb:
|
||||
self.__usb.setCallback(usb_cb)
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_data_call(self, data_call, data_call_cb):
|
||||
if data_call is dataCall:
|
||||
self.__data_call = data_call
|
||||
if data_call_cb:
|
||||
self.__data_call.setCallback(data_call_cb)
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_ota_file_clear(self, ota_file_clear):
|
||||
if isinstance(ota_file_clear, OTAFileClear):
|
||||
self.__ota_file_clear = ota_file_clear
|
||||
return True
|
||||
return False
|
||||
|
||||
def settings_get(self):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
return self.__settings.get()
|
||||
|
||||
def settings_set(self, key, value):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
if key == "loc_method":
|
||||
v = "0b"
|
||||
v += str(int(value.get(3, 0)))
|
||||
v += str(int(value.get(2, 0)))
|
||||
v += str(int(value.get(1, 0)))
|
||||
value = int(v, 2)
|
||||
set_res = self.__settings.set(key, value)
|
||||
log.debug("__settings_set key: %s, val: %s, set_res: %s" % (key, value, set_res))
|
||||
return set_res
|
||||
|
||||
def settings_save(self):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
return self.__settings.save()
|
||||
|
||||
def power_restart(self):
|
||||
Power.powerRestart()
|
||||
|
||||
def power_down(self):
|
||||
Power.powerDown()
|
||||
|
||||
def remote_post_data(self, data):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.post_data(data)
|
||||
|
||||
def remote_ota_check(self):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.cloud_ota_check()
|
||||
|
||||
def remote_ota_action(self, action, module):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.cloud_ota_action(action, module)
|
||||
|
||||
def low_energy_set_period(self, period):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.set_period(period)
|
||||
|
||||
def low_energy_set_method(self, method):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.set_low_energy_method(method)
|
||||
|
||||
def low_energy_init(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.low_energy_init()
|
||||
|
||||
def low_energy_start(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.start()
|
||||
|
||||
def low_energy_stop(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.stop()
|
||||
|
||||
def ota_file_clean(self):
|
||||
if not self.__ota_file_clear:
|
||||
raise TypeError("self.__ota_file_clear is not registered.")
|
||||
self.__ota_file_clear.file_clear()
|
||||
|
||||
def running_led_show(self, period):
|
||||
if not self.__running_led:
|
||||
raise TypeError("self.__running_led is not registered.")
|
||||
self.__running_led.set_period(period)
|
||||
return self.__running_led.led_timer_start()
|
||||
|
||||
def energy_led_show(self, period):
|
||||
if not self.energy_led_show:
|
||||
raise TypeError("self.energy_led_show is not registered.")
|
||||
self.__energy_led.set_period(period)
|
||||
return self.__energy_led.led_timer_start()
|
||||
|
||||
|
||||
def tracker():
|
||||
current_settings = settings.get()
|
||||
|
||||
|
575
code/tracker_collector.py
Normal file
575
code/tracker_collector.py
Normal file
@ -0,0 +1,575 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import utime
|
||||
import modem
|
||||
|
||||
from usr.moudles.sensor import Sensor
|
||||
from usr.moudles.battery import Battery
|
||||
from usr.moudles.history import History
|
||||
from usr.moudles.logging import getLogger
|
||||
from usr.moudles.mpower import LowEnergyManage
|
||||
from usr.moudles.common import Singleton, LOWENERGYMAP
|
||||
from usr.moudles.location import Location, GPSMatch, GPSParse, _loc_method
|
||||
from usr.settings import PROJECT_NAME, DEVICE_FIRMWARE_NAME, settings, UserConfig, SYSConfig
|
||||
from usr.tracker_controller import Controller
|
||||
from usr.tracker_devicecheck import DeviceCheck
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
ALERTCODE = {
|
||||
20000: "fault_alert",
|
||||
30002: "low_power_alert",
|
||||
30003: "over_speed_alert",
|
||||
30004: "sim_abnormal_alert",
|
||||
30005: "disassemble_alert",
|
||||
40000: "drive_behavior_alert",
|
||||
50001: "sos_alert",
|
||||
}
|
||||
|
||||
|
||||
class Collector(Singleton):
|
||||
def __init__(self):
|
||||
self.__controller = None
|
||||
self.__devicecheck = None
|
||||
self.__battery = None
|
||||
self.__sensor = None
|
||||
self.__locator = None
|
||||
self.__history = None
|
||||
self.__gps_match = GPSMatch()
|
||||
self.__gps_parse = GPSParse()
|
||||
|
||||
def __format_loc_method(self, data):
|
||||
loc_method = "%04d" % int(bin(data)[2:])
|
||||
gps = bool(int(loc_method[-1]))
|
||||
cell = bool(int(loc_method[-2]))
|
||||
wifi = bool(int(loc_method[-3]))
|
||||
|
||||
loc_method = {
|
||||
"gps": gps,
|
||||
"cell": cell,
|
||||
"wifi": wifi,
|
||||
}
|
||||
return loc_method
|
||||
|
||||
def __device_speed_check(self):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
alert_data = {
|
||||
"current_speed": 0.00
|
||||
}
|
||||
if current_settings["user_cfg"]["sw_over_speed_alert"] is True:
|
||||
if self.__locator.gps:
|
||||
gps_data = self.__locator.gps.read()[1]
|
||||
vtg_data = self.__gps_match.GxVTG(gps_data)
|
||||
speed = self.__gps_parse.GxVTG_speed(vtg_data)
|
||||
if speed and float(speed) >= current_settings["user_cfg"]["over_speed_threshold"]:
|
||||
alert_code = 30003
|
||||
alert_info = {"local_time": self.__get_local_time()}
|
||||
alert_data = self.__get_alert_data(alert_code, alert_info)
|
||||
if speed:
|
||||
alert_data["current_speed"] = float(speed)
|
||||
|
||||
log.debug("__device_speed_check: %s" % str(alert_data))
|
||||
return alert_data
|
||||
|
||||
def __get_local_time(self):
|
||||
return str(utime.mktime(utime.localtime()) * 1000)
|
||||
|
||||
def __get_alert_data(self, alert_code, alert_info):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
alert_data = {}
|
||||
if ALERTCODE.get(alert_code):
|
||||
alert_status = current_settings.get("user_cfg", {}).get("sw_" + ALERTCODE.get(alert_code))
|
||||
if alert_status:
|
||||
alert_data = {ALERTCODE.get(alert_code): alert_info}
|
||||
else:
|
||||
log.warn("%s switch is %s" % (ALERTCODE.get(alert_code), alert_status))
|
||||
else:
|
||||
log.error("altercode (%s) is not exists. alert info: %s" % (alert_code, alert_info))
|
||||
|
||||
return alert_data
|
||||
|
||||
def __init_low_energy_method(self, period):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
device_model = modem.getDevModel()
|
||||
support_methds = LOWENERGYMAP.get(device_model, [])
|
||||
method = "NULL"
|
||||
if support_methds:
|
||||
if period >= current_settings["user_cfg"]["work_mode_timeline"]:
|
||||
if "PSM" in support_methds:
|
||||
method = "PSM"
|
||||
elif "POWERDOWN" in support_methds:
|
||||
method = "POWERDOWN"
|
||||
elif "PM" in support_methds:
|
||||
method = "PM"
|
||||
else:
|
||||
if "PM" in support_methds:
|
||||
method = "PM"
|
||||
log.debug("__init_low_energy_method: %s" % method)
|
||||
return method
|
||||
|
||||
def __get_ali_loc_data(self, loc_method, loc_data):
|
||||
res = {"GeoLocation": {}}
|
||||
|
||||
if loc_method == 0x1:
|
||||
gga_data = self.__gps_match.GxGGA(loc_data)
|
||||
data = {}
|
||||
if gga_data:
|
||||
Latitude = self.__gps_parse.GxGGA_latitude(gga_data)
|
||||
if Latitude:
|
||||
data["Latitude"] = float("%.2f" % float(Latitude))
|
||||
Longtitude = self.__gps_parse.GxGGA_longtitude(gga_data)
|
||||
if Longtitude:
|
||||
data["Longtitude"] = float("%.2f" % float(Longtitude))
|
||||
Altitude = self.__gps_parse.GxGGA_altitude(gga_data)
|
||||
if Altitude:
|
||||
data["Altitude"] = float("%.2f" % float(Altitude))
|
||||
if data:
|
||||
data["CoordinateSystem"] = 1
|
||||
res = {"GeoLocation": data}
|
||||
elif loc_method in (0x2, 0x4):
|
||||
if loc_data:
|
||||
res["GeoLocation"] = {
|
||||
"Longtitude": round(loc_data[0], 2),
|
||||
"Latitude": round(loc_data[1], 2),
|
||||
# "Altitude": 0.0,
|
||||
"CoordinateSystem": 1
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
def __get_quec_loc_data(self, loc_method, loc_data):
|
||||
if loc_method == 0x1:
|
||||
res = {"gps": []}
|
||||
r = self.__gps_match.GxRMC(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = self.__gps_match.GxGGA(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
|
||||
r = self.__gps_match.GxVTG(loc_data)
|
||||
if r:
|
||||
res["gps"].append(r)
|
||||
return res
|
||||
elif loc_method == 0x2:
|
||||
return {"non_gps": ["LBS"]}
|
||||
elif loc_method == 0x4:
|
||||
return {"non_gps": []}
|
||||
|
||||
def __get_loc_data(self, loc_method, loc_data):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["sys"]["cloud"] & SYSConfig._cloud.quecIot:
|
||||
return self.__get_quec_loc_data(loc_method, loc_data)
|
||||
elif current_settings["sys"]["cloud"] & SYSConfig._cloud.AliYun:
|
||||
return self.__get_ali_loc_data(loc_method, loc_data)
|
||||
return {}
|
||||
|
||||
def __read_battery(self):
|
||||
if not self.__battery:
|
||||
raise TypeError("self.__battery is not registered.")
|
||||
|
||||
res = {}
|
||||
self.__battery.set_temp(20)
|
||||
energy = self.__battery.get_energy()
|
||||
res = {
|
||||
"energy": energy,
|
||||
"voltage": self.__battery.get_voltage(),
|
||||
}
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if energy <= current_settings["user_cfg"]["low_power_alert_threshold"]:
|
||||
alert_data = self.__get_alert_data(30002, {"local_time": self.__get_local_time()})
|
||||
res.update(alert_data)
|
||||
|
||||
return res
|
||||
|
||||
def __read_sensor(self):
|
||||
return {}
|
||||
|
||||
def __read_location(self):
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered.")
|
||||
|
||||
res = {}
|
||||
current_settings = self.__controller.settings_get()
|
||||
# Get cloud location data
|
||||
if current_settings["user_cfg"].get("loc_method"):
|
||||
cfg_loc_method = current_settings["user_cfg"].get("loc_method")
|
||||
elif current_settings["sys"]["base_cfg"]["LocConfig"]:
|
||||
cfg_loc_method = current_settings["LocConfig"]["loc_method"]
|
||||
else:
|
||||
cfg_loc_method = 7
|
||||
loc_info = self.__locator.read(cfg_loc_method)
|
||||
if loc_info:
|
||||
loc_method_dict = {v: k for k, v in _loc_method.__dict__.items()}
|
||||
loc_data = None
|
||||
for loc_method in loc_method_dict.keys():
|
||||
if loc_info.get(loc_method):
|
||||
log.debug("Location Data loc_method: %s" % loc_method_dict[loc_method])
|
||||
loc_data = loc_info[loc_method]
|
||||
|
||||
if loc_method == _loc_method.gps:
|
||||
gga_satellite = self.__gps_parse.GxGGA_satellite_num(self.__gps_match.GxGGA(loc_data))
|
||||
log.debug("GxGGA Satellite Num %s" % gga_satellite)
|
||||
gsv_satellite = self.__gps_parse.GxGSV_satellite_num(self.__gps_match.GxGSV(loc_data))
|
||||
log.debug("GxGSV Satellite Num %s" % gsv_satellite)
|
||||
break
|
||||
if loc_data:
|
||||
res = self.__get_loc_data(loc_method, loc_data)
|
||||
|
||||
return res
|
||||
|
||||
def add_module(self, module):
|
||||
if isinstance(module, Controller):
|
||||
self.__controller = module
|
||||
return True
|
||||
elif isinstance(module, DeviceCheck):
|
||||
self.__devicecheck = module
|
||||
return True
|
||||
elif isinstance(module, Battery):
|
||||
self.__battery = module
|
||||
return True
|
||||
elif isinstance(module, Sensor):
|
||||
self.__sensor = module
|
||||
return True
|
||||
elif isinstance(module, Location):
|
||||
self.__locator = module
|
||||
return True
|
||||
elif isinstance(module, History):
|
||||
self.__history = module
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def read_module_data(self, module):
|
||||
if module == "Battery":
|
||||
return self.__read_battery()
|
||||
elif module == "Sensor":
|
||||
return self.__read_sensor()
|
||||
elif module == "Location":
|
||||
return self.__read_location()
|
||||
elif module == "History":
|
||||
return self.__read_history()
|
||||
|
||||
def device_status_get(self):
|
||||
if not self.__devicecheck:
|
||||
raise TypeError("self.__devicecheck is not registered.")
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
device_status_data = {}
|
||||
device_module_status = {}
|
||||
alert_code = 20000
|
||||
|
||||
net_status = self.__devicecheck.net()
|
||||
location_status = self.__devicecheck.location()
|
||||
temp_status = self.__devicecheck.temp()
|
||||
light_status = self.__devicecheck.light()
|
||||
triaxial_status = self.__devicecheck.triaxial()
|
||||
mike_status = self.__devicecheck.mike()
|
||||
|
||||
device_module_status["net"] = 1 if net_status == (3, 1) else 0
|
||||
device_module_status["location"] = 1 if location_status else 0
|
||||
|
||||
# TODO: Check Sensor.
|
||||
if temp_status is not None:
|
||||
device_module_status["temp_sensor"] = 1 if temp_status else 0
|
||||
if light_status is not None:
|
||||
device_module_status["light_sensor"] = 1 if temp_status else 0
|
||||
if triaxial_status is not None:
|
||||
device_module_status["move_sensor"] = 1 if temp_status else 0
|
||||
if mike_status is not None:
|
||||
device_module_status["mike"] = 1 if temp_status else 0
|
||||
|
||||
device_status = True
|
||||
# TODO: Led Show
|
||||
if net_status == (3, 1) and location_status is True and \
|
||||
(temp_status is True or temp_status is None) and \
|
||||
(light_status is True or light_status is None) and \
|
||||
(triaxial_status is True or triaxial_status is None) and \
|
||||
(mike_status is True or mike_status is None):
|
||||
# self.__controller.running_led_show(0.5)
|
||||
device_status = True
|
||||
else:
|
||||
# self.__controller.running_led_show(2)
|
||||
device_status = False
|
||||
|
||||
if device_status is False:
|
||||
device_status_data = self.__get_alert_data(alert_code, {"local_time": self.__get_local_time()})
|
||||
|
||||
device_status_data.update({"device_module_status": device_module_status})
|
||||
|
||||
return device_status_data
|
||||
|
||||
def device_status_check(self):
|
||||
device_status_check_res = self.device_status_get()
|
||||
self.device_data_report(event_data=device_status_check_res)
|
||||
|
||||
def device_data_get(self, power_switch=True):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
|
||||
device_data = {
|
||||
"power_switch": power_switch,
|
||||
"local_time": self.__get_local_time(),
|
||||
}
|
||||
|
||||
# Get ota status & drive behiver code
|
||||
device_data.update({
|
||||
"ota_status": current_settings["user_cfg"]["ota_status"],
|
||||
"drive_behavior_code": current_settings["user_cfg"]["drive_behavior_code"],
|
||||
})
|
||||
|
||||
# Get user settings info
|
||||
device_data.update(current_settings["user_cfg"])
|
||||
|
||||
# Format loc method
|
||||
device_data.update({"loc_method": self.__format_loc_method(current_settings["user_cfg"]["loc_method"])})
|
||||
|
||||
# Get cloud location data
|
||||
device_data.update(self.__read_location())
|
||||
|
||||
# Get gps speed
|
||||
device_data.update(self.__device_speed_check())
|
||||
|
||||
# Get battery energy
|
||||
device_data.update(self.__read_battery())
|
||||
|
||||
# TODO: Add other machine info.
|
||||
|
||||
return device_data
|
||||
|
||||
def device_data_report(self, power_switch=True, event_data={}, msg=""):
|
||||
# TODO: msg to mark post data source
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
device_data = self.device_data_get(power_switch)
|
||||
if event_data:
|
||||
device_data.update(event_data)
|
||||
|
||||
post_res = self.__controller.remote_post_data(device_data)
|
||||
|
||||
# OTA status rst
|
||||
current_settings = self.__controller.settings_get() if self.__controller else {}
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["upgrade_status"] in (3, 4):
|
||||
self.ota_status_reset()
|
||||
|
||||
return post_res
|
||||
|
||||
def ota_status_reset(self):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
ota_info = {}
|
||||
ota_info["sys_target_version"] = "--"
|
||||
ota_info["app_target_version"] = "--"
|
||||
ota_info["upgrade_module"] = 0
|
||||
ota_info["upgrade_status"] = 0
|
||||
ota_status_info.update(ota_info)
|
||||
self.__controller.settings_set("ota_status", ota_status_info)
|
||||
|
||||
if current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
self.__controller.settings_set("user_ota_action", -1)
|
||||
|
||||
def report_history(self):
|
||||
if not self.__history:
|
||||
raise TypeError("self.__history is not registered.")
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
res = True
|
||||
hist = self.__history.read()
|
||||
if hist["data"]:
|
||||
pt_count = 0
|
||||
for i, data in enumerate(hist["data"]):
|
||||
pt_count += 1
|
||||
if not self.__controller.remote_post_data(data):
|
||||
res = False
|
||||
break
|
||||
|
||||
hist["data"] = hist["data"][pt_count:]
|
||||
if hist["data"]:
|
||||
# Flush data in hist-dictionary to tracker_data.hist file.
|
||||
self.__history.write(hist["data"])
|
||||
|
||||
return res
|
||||
|
||||
# Do cloud event downlink option by controller
|
||||
def event_option(self, *args, **kwargs):
|
||||
# TODO: Data Type Passthrough (Not Support Now).
|
||||
return False
|
||||
|
||||
def event_done(self, *args, **kwargs):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
try:
|
||||
setting_flag = 0
|
||||
|
||||
for arg in args:
|
||||
if hasattr(UserConfig, arg[0]):
|
||||
set_res = self.__controller.settings_set(arg[0], arg[1])
|
||||
if set_res and setting_flag == 0:
|
||||
setting_flag = 1
|
||||
if hasattr(self, arg[0]):
|
||||
getattr(self, arg[0])(arg[1])
|
||||
|
||||
if setting_flag:
|
||||
self.__controller.settings_save()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def event_query(self, *args, **kwargs):
|
||||
return self.device_data_report()
|
||||
|
||||
def event_ota_plain(self, *args, **kwargs):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = settings.get()
|
||||
if current_settings["user_cfg"]["sw_ota"]:
|
||||
if current_settings["user_cfg"]["sw_ota_auto_upgrade"] or current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
if current_settings["user_cfg"]["sw_ota_auto_upgrade"]:
|
||||
ota_action_val = 1
|
||||
else:
|
||||
if current_settings["user_cfg"]["user_ota_action"] != -1:
|
||||
ota_action_val = current_settings["user_cfg"]["user_ota_action"]
|
||||
else:
|
||||
return
|
||||
|
||||
if current_settings["sys"]["cloud"] == SYSConfig._cloud.quecIot or \
|
||||
current_settings["sys"]["cloud"] == SYSConfig._cloud.AliYun:
|
||||
log.debug("ota_plain args: %s, kwargs: %s" % (str(args), str(kwargs)))
|
||||
self.__controller.remote_ota_action(action=ota_action_val, module=kwargs.get("module"))
|
||||
else:
|
||||
log.error("Current Cloud (0x%X) Not Supported!" % current_settings["sys"]["cloud"])
|
||||
|
||||
def event_ota_file_download(self, *args, **kwargs):
|
||||
# OAT MQTT File Download Is Not Supported Yet.
|
||||
return False
|
||||
|
||||
def power_switch(self, flag=None):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.event_query(power_switch=flag)
|
||||
if flag is False:
|
||||
self.__controller.power_down()
|
||||
|
||||
def user_ota_action(self, action):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["user_cfg"]["sw_ota"] and current_settings["user_cfg"]["sw_ota_auto_upgrade"] is False:
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["upgrade_status"] == 1 and current_settings["user_cfg"]["user_ota_action"] == -1:
|
||||
self.__controller.settings_set("user_ota_action", action)
|
||||
self.__controller.settings_save()
|
||||
self.__controller.remote_ota_check()
|
||||
|
||||
def ota_status(self, upgrade_info=None):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
current_settings = self.__controller.settings_get()
|
||||
if upgrade_info and current_settings["user_cfg"]["sw_ota"]:
|
||||
ota_status_info = current_settings["user_cfg"]["ota_status"]
|
||||
if ota_status_info["sys_target_version"] == "--" and ota_status_info["app_target_version"] == "--":
|
||||
ota_info = {}
|
||||
if upgrade_info[0] == DEVICE_FIRMWARE_NAME:
|
||||
ota_info["upgrade_module"] = 1
|
||||
ota_info["sys_target_version"] = upgrade_info[2]
|
||||
elif upgrade_info[0] == PROJECT_NAME:
|
||||
ota_info["upgrade_module"] = 2
|
||||
ota_info["app_target_version"] = upgrade_info[2]
|
||||
ota_info["upgrade_status"] = upgrade_info[1]
|
||||
ota_status_info.update(ota_info)
|
||||
self.__controller.settings_set("ota_status", ota_status_info)
|
||||
self.__controller.settings_save()
|
||||
|
||||
def power_restart(self, flag):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.event_query(power_switch=False)
|
||||
self.__controller.power_restart()
|
||||
|
||||
def work_cycle_period(self, period):
|
||||
# Reset work_cycle_period & Reset RTC
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.__controller.low_energy_stop()
|
||||
|
||||
self.__controller.low_energy_set_period(period)
|
||||
method = self.__init_low_energy_method(period)
|
||||
self.__controller.low_energy_set_method(method)
|
||||
|
||||
self.__controller.low_energy_init()
|
||||
self.__controller.low_energy_start()
|
||||
|
||||
def cloud_init_params(self, params):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.__controller.settings_set("cloud", params)
|
||||
self.__controller.settings_save()
|
||||
|
||||
def low_engery_option(self, low_energy_method):
|
||||
if not self.__controller:
|
||||
raise TypeError("self.__controller is not registered.")
|
||||
|
||||
self.report_history()
|
||||
current_settings = self.__controller.settings_get()
|
||||
if current_settings["user_cfg"]["work_mode"] == UserConfig._work_mode.intelligent:
|
||||
speed_info = self.__device_speed_check()
|
||||
if speed_info.get("current_speed") > 0:
|
||||
self.device_data_report()
|
||||
else:
|
||||
self.device_data_report()
|
||||
|
||||
self.__controller.low_energy_start()
|
||||
|
||||
if low_energy_method == "PSM":
|
||||
# TODO: PSM option.
|
||||
pass
|
||||
elif low_energy_method == "POWERDOWN":
|
||||
self.__controller.power_down()
|
||||
|
||||
def update(self, observable, *args, **kwargs):
|
||||
if isinstance(observable, LowEnergyManage):
|
||||
log.debug("Low Energy RTC Method: %s" % args[1])
|
||||
self.low_engery_option(args[1])
|
173
code/tracker_controller.py
Normal file
173
code/tracker_controller.py
Normal file
@ -0,0 +1,173 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import dataCall
|
||||
|
||||
from misc import Power
|
||||
|
||||
from usr.moudles.led import LED
|
||||
from usr.moudles.ota import OTAFileClear
|
||||
from usr.moudles.logging import getLogger
|
||||
from usr.moudles.mpower import LowEnergyManage
|
||||
from usr.moudles.remote import RemotePublish
|
||||
from usr.moudles.common import Singleton
|
||||
from usr.settings import Settings
|
||||
|
||||
try:
|
||||
from misc import USB
|
||||
except ImportError:
|
||||
USB = None
|
||||
try:
|
||||
from misc import PowerKey
|
||||
except ImportError:
|
||||
PowerKey = None
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Controller(Singleton):
|
||||
def __init__(self):
|
||||
self.__remote_pub = None
|
||||
self.__settings = None
|
||||
self.__low_energy = None
|
||||
self.__energy_led = None
|
||||
self.__running_led = None
|
||||
self.__power_key = None
|
||||
self.__usb = None
|
||||
self.__data_call = None
|
||||
self.__ota_file_clear = None
|
||||
|
||||
def add_module(self, module, led_type=None, callback=None):
|
||||
if isinstance(module, RemotePublish):
|
||||
self.__remote_pub = module
|
||||
return True
|
||||
elif isinstance(module, Settings):
|
||||
self.__settings = module
|
||||
return True
|
||||
elif isinstance(module, LowEnergyManage):
|
||||
self.__low_energy = module
|
||||
return True
|
||||
elif isinstance(module, OTAFileClear):
|
||||
self.__ota_file_clear = module
|
||||
return True
|
||||
elif isinstance(module, LED):
|
||||
if led_type == "energy":
|
||||
self.__energy_led = module
|
||||
return True
|
||||
elif led_type == "running":
|
||||
self.running_led = module
|
||||
return True
|
||||
elif isinstance(module, PowerKey):
|
||||
self.__power_key = module
|
||||
if callback:
|
||||
self.__power_key.powerKeyEventRegister(callback)
|
||||
return True
|
||||
elif isinstance(module, USB):
|
||||
self.__usb = module
|
||||
if callback:
|
||||
self.__usb.setCallback(callback)
|
||||
return True
|
||||
elif module is dataCall:
|
||||
self.__data_call = module
|
||||
if callback:
|
||||
self.__data_call.setCallback(callback)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def settings_get(self):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
return self.__settings.get()
|
||||
|
||||
def settings_set(self, key, value):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
if key == "loc_method":
|
||||
v = "0b"
|
||||
v += str(int(value.get(3, 0)))
|
||||
v += str(int(value.get(2, 0)))
|
||||
v += str(int(value.get(1, 0)))
|
||||
value = int(v, 2)
|
||||
set_res = self.__settings.set(key, value)
|
||||
log.debug("__settings_set key: %s, val: %s, set_res: %s" % (key, value, set_res))
|
||||
return set_res
|
||||
|
||||
def settings_save(self):
|
||||
if not self.__settings:
|
||||
raise TypeError("self.__settings is not registered.")
|
||||
return self.__settings.save()
|
||||
|
||||
def power_restart(self):
|
||||
Power.powerRestart()
|
||||
|
||||
def power_down(self):
|
||||
Power.powerDown()
|
||||
|
||||
def remote_post_data(self, data):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.post_data(data)
|
||||
|
||||
def remote_ota_check(self):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.cloud_ota_check()
|
||||
|
||||
def remote_ota_action(self, action, module):
|
||||
if not self.__remote_pub:
|
||||
raise TypeError("self.__remote_pub is not registered.")
|
||||
return self.__remote_pub.cloud_ota_action(action, module)
|
||||
|
||||
def low_energy_set_period(self, period):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.set_period(period)
|
||||
|
||||
def low_energy_set_method(self, method):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.set_low_energy_method(method)
|
||||
|
||||
def low_energy_init(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.low_energy_init()
|
||||
|
||||
def low_energy_start(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.start()
|
||||
|
||||
def low_energy_stop(self):
|
||||
if not self.__low_energy:
|
||||
raise TypeError("self.__low_energy is not registered.")
|
||||
return self.__low_energy.stop()
|
||||
|
||||
def ota_file_clean(self):
|
||||
if not self.__ota_file_clear:
|
||||
raise TypeError("self.__ota_file_clear is not registered.")
|
||||
self.__ota_file_clear.file_clear()
|
||||
|
||||
def running_led_show(self, period):
|
||||
if not self.__running_led:
|
||||
raise TypeError("self.__running_led is not registered.")
|
||||
self.__running_led.set_period(period)
|
||||
return self.__running_led.led_timer_start()
|
||||
|
||||
def energy_led_show(self, period):
|
||||
if not self.energy_led_show:
|
||||
raise TypeError("self.energy_led_show is not registered.")
|
||||
self.__energy_led.set_period(period)
|
||||
return self.__energy_led.led_timer_start()
|
94
code/tracker_devicecheck.py
Normal file
94
code/tracker_devicecheck.py
Normal file
@ -0,0 +1,94 @@
|
||||
# Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import utime
|
||||
import checkNet
|
||||
|
||||
from usr.moudules.sensor import Sensor
|
||||
from usr.moudules.logging import getLogger
|
||||
from usr.moudules.location import Location
|
||||
from usr.settings import PROJECT_NAME, PROJECT_VERSION, settings
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class DeviceCheck(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__locator = None
|
||||
self.__sensor = None
|
||||
|
||||
def add_module(self, module):
|
||||
if isinstance(module, Location):
|
||||
self.__locator = module
|
||||
return True
|
||||
elif isinstance(module, Sensor):
|
||||
self.__sensor = module
|
||||
return True
|
||||
return False
|
||||
|
||||
def net(self):
|
||||
current_settings = settings.get()
|
||||
checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION)
|
||||
timeout = current_settings.get("sys", {}).get("checknet_timeout", 60)
|
||||
check_res = checknet.wait_network_connected(timeout)
|
||||
log.debug("DeviceCheck.net res: %s" % str(check_res))
|
||||
return check_res
|
||||
|
||||
def location(self):
|
||||
# return True if OK
|
||||
if not self.__locator:
|
||||
raise TypeError("self.__locator is not registered")
|
||||
|
||||
current_settings = settings.get()
|
||||
retry = 0
|
||||
gps_data = None
|
||||
sleep_time = 1
|
||||
|
||||
while retry < 5:
|
||||
if current_settings["user_cfg"].get("loc_method"):
|
||||
loc_method = current_settings["user_cfg"].get("loc_method")
|
||||
elif current_settings["sys"]["base_cfg"]["LocConfig"]:
|
||||
loc_method = current_settings["LocConfig"].get("loc_method")
|
||||
else:
|
||||
loc_method = 7
|
||||
|
||||
gps_data = self.__locator.read(loc_method)
|
||||
if gps_data:
|
||||
break
|
||||
else:
|
||||
retry += 1
|
||||
utime.sleep(sleep_time)
|
||||
sleep_time *= 2
|
||||
|
||||
if gps_data:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def temp(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def light(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def triaxial(self):
|
||||
# return True if OK
|
||||
return None
|
||||
|
||||
def mike(self):
|
||||
# return True if OK
|
||||
return None
|
Loading…
x
Reference in New Issue
Block a user