mirror of
https://gitee.com/qpy-solutions/tracker-v2.git
synced 2025-05-19 02:58:25 +08:00
initial commit
This commit is contained in:
commit
967dc50e24
6
code/alert.py
Normal file
6
code/alert.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
class AlertMonitor(object):
|
||||||
|
'''
|
||||||
|
Recv alert signals and process them
|
||||||
|
'''
|
||||||
|
pass
|
12
code/battery.py
Normal file
12
code/battery.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
class Battery(object):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def indicate(self, low_power_threshold, low_power_cb):
|
||||||
|
self.low_power_threshold = low_power_threshold
|
||||||
|
self.low_power_cb = low_power_cb
|
||||||
|
pass
|
||||||
|
|
||||||
|
def charge(self):
|
||||||
|
pass
|
7
code/dev_info.py
Normal file
7
code/dev_info.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
version = '1.0.0'
|
||||||
|
|
||||||
|
quecIot = {
|
||||||
|
'PK': 'p1122c',
|
||||||
|
'PS': 'UG9wMGxwS2t1UE5x'
|
||||||
|
}
|
4
code/led.py
Normal file
4
code/led.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
class LED():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
157
code/location.py
Normal file
157
code/location.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
|
||||||
|
import usr.settings as settings
|
||||||
|
from machine import UART
|
||||||
|
import cellLocator
|
||||||
|
import wifilocator
|
||||||
|
import ure
|
||||||
|
import _thread
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
gps_data_retrieve_queue = None
|
||||||
|
|
||||||
|
'''
|
||||||
|
GPS data retrieve callback from UART
|
||||||
|
When data comes, send a message to queue of data length
|
||||||
|
'''
|
||||||
|
def gps_data_retrieve_cb(para_list):
|
||||||
|
global gps_data_retrieve_queue
|
||||||
|
toRead = para_list[2]
|
||||||
|
if toRead:
|
||||||
|
gps_data_retrieve_queue.put(toRead)
|
||||||
|
|
||||||
|
'''
|
||||||
|
GPS data retrieve thread
|
||||||
|
Receive a message from queue of data length.
|
||||||
|
Then read the corresponding length of data from UART into self.gps_data.
|
||||||
|
So self.gps_data will be updated immediately once the data comes to UART that
|
||||||
|
the self.gps_data could keep the latest data.
|
||||||
|
'''
|
||||||
|
def gps_data_retrieve_thread(argv):
|
||||||
|
global gps_data_retrieve_queue
|
||||||
|
self = argv
|
||||||
|
|
||||||
|
while True:
|
||||||
|
toRead = gps_data_retrieve_queue.get()
|
||||||
|
if toRead:
|
||||||
|
self.gps_data = self.uart_read(toRead).decode()
|
||||||
|
|
||||||
|
class GPS(UART):
|
||||||
|
def __init__(self, gps_cfg):
|
||||||
|
global gps_data_retrieve_queue
|
||||||
|
super(GPS, self).__init__(gps_cfg['UARTn'], gps_cfg['buadrate'], gps_cfg['databits'], gps_cfg['parity'], gps_cfg['stopbits'], gps_cfg['flowctl'])
|
||||||
|
self.set_callback(gps_data_retrieve_cb)
|
||||||
|
self.gps_data = ''
|
||||||
|
gps_data_retrieve_queue = Queue(maxsize=8)
|
||||||
|
_thread.start_new_thread(gps_data_retrieve_thread, (self,))
|
||||||
|
|
||||||
|
def uart_read(self, nread):
|
||||||
|
return super(GPS, self).read(nread).decode()
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
return self.gps_data
|
||||||
|
|
||||||
|
def read_location_GxRMC(self):
|
||||||
|
gps_data = self.read()
|
||||||
|
rmc_re = ure.search(
|
||||||
|
r"\$G[NP]RMC,[0-9]+\.[0-9]+,A,[0-9]+\.[0-9]+,[NS],[0-9]+\.[0-9]+,[EW],[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+,,,[ADE],[SCUV]\*[0-9]+",
|
||||||
|
gps_data)
|
||||||
|
if rmc_re:
|
||||||
|
return rmc_re.group(0)
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_location_GxGGA(self):
|
||||||
|
gps_data = self.read()
|
||||||
|
gga_re = ure.search(
|
||||||
|
r"\$G[BLPN]GGA,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[NS],[0-9]+\.[0-9]+,[EW],[126],[0-9]+,[0-9]+\.[0-9]+,-*[0-9]+\.[0-9]+,M,-*[0-9]+\.[0-9]+,M,,\*[0-9]+",
|
||||||
|
gps_data)
|
||||||
|
if gga_re:
|
||||||
|
return gga_re.group(0)
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
class CellLocator(cellLocator):
|
||||||
|
def __init__(self, cellLocator_cfg):
|
||||||
|
self.cellLocator_cfg = cellLocator_cfg
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
return super(CellLocator, self).getLocation(self.cellLocator_cfg['serverAddr'], self.cellLocator_cfg['port'], self.cellLocator_cfg['token'], self.cellLocator_cfg['timeout'], self.cellLocator_cfg['profileIdx'])
|
||||||
|
|
||||||
|
class WiFiLocator(wifilocator):
|
||||||
|
def __init__(self, wifiLocator_cfg):
|
||||||
|
super(WiFiLocator, self).__init__(wifiLocator_cfg['token'])
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
return super(WiFiLocator, self).getwifilocator()
|
||||||
|
|
||||||
|
def loc_worker(argv):
|
||||||
|
self = argv
|
||||||
|
while True:
|
||||||
|
trigger = self.trigger_queue.get()
|
||||||
|
if trigger:
|
||||||
|
data = self.read()
|
||||||
|
if data and self.read_cb:
|
||||||
|
self.read_cb(data)
|
||||||
|
|
||||||
|
class Location(GPS, CellLocator, WiFiLocator):
|
||||||
|
gps_enabled = False
|
||||||
|
cellLoc_enabled = False
|
||||||
|
wifiLoc_enabled = False
|
||||||
|
|
||||||
|
def __init__(self, read_cb, **kw):
|
||||||
|
current_settings = settings.get()
|
||||||
|
|
||||||
|
self.read_cb = read_cb
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.gps:
|
||||||
|
if 'gps_cfg' in kw:
|
||||||
|
super(Location, self).__init__(kw['gps_cfg'])
|
||||||
|
self.gps_enabled = True
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid gps init parameters.')
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.cell:
|
||||||
|
if 'cellLocator_cfg' in kw:
|
||||||
|
super(GPS, self).__init__(kw['cellLocator_cfg'])
|
||||||
|
self.cellLoc_enabled = True
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid cell-locator init parameters.')
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.wifi:
|
||||||
|
if 'wifiLocator_cfg' in kw:
|
||||||
|
super(CellLocator, self).__init__(kw['wifiLocator_cfg'])
|
||||||
|
self.wifiLoc_enabled = True
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid wifi-locator init parameters.')
|
||||||
|
|
||||||
|
self.trigger_queue = Queue(maxsize=64)
|
||||||
|
_thread.start_new_thread(loc_worker, (self,))
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
if self.gps_enabled:
|
||||||
|
data = []
|
||||||
|
r = super(Location, self).read_location_GxRMC()
|
||||||
|
if r:
|
||||||
|
data.append(r)
|
||||||
|
|
||||||
|
r = super(Location, self).read_location_GxGGA()
|
||||||
|
if r:
|
||||||
|
data.append(r)
|
||||||
|
|
||||||
|
if len(data):
|
||||||
|
return (settings.default_values_app._loc_method.gps, data)
|
||||||
|
|
||||||
|
if self.cellLoc_enabled:
|
||||||
|
data = super(GPS, self).read()
|
||||||
|
if data:
|
||||||
|
return (settings.default_values_app._loc_method.cell, data)
|
||||||
|
|
||||||
|
if self.wifiLoc_enabled:
|
||||||
|
data = super(CellLocator, self).read()
|
||||||
|
if data:
|
||||||
|
return (settings.default_values_app._loc_method.wifi, data)
|
||||||
|
|
||||||
|
return ()
|
||||||
|
|
||||||
|
def trigger(self):
|
||||||
|
self.trigger_queue.put(True)
|
56
code/logging.py
Normal file
56
code/logging.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
import utime
|
||||||
|
|
||||||
|
def asyncLog(name, level, *message, timeout=None, await_connection=True):
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
#
|
||||||
|
# yield config.getMQTT().publish(base_topic.format(level), message, qos=1, timeout=timeout,
|
||||||
|
# await_connection=await_connection)
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log(name, level, *message, local_only=False, return_only=False, timeout=None):
|
||||||
|
|
||||||
|
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)
|
||||||
|
if return_only:
|
||||||
|
return
|
||||||
|
if not local_only:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def critical(self, *message, local_only=True):
|
||||||
|
log(self.name, "critical", *message, local_only=local_only, timeout=None)
|
||||||
|
|
||||||
|
def error(self, *message, local_only=True):
|
||||||
|
log(self.name, "error", *message, local_only=local_only, timeout=None)
|
||||||
|
|
||||||
|
def warn(self, *message, local_only=True):
|
||||||
|
log(self.name, "warn", *message, local_only=local_only, timeout=None)
|
||||||
|
|
||||||
|
def info(self, *message, local_only=True):
|
||||||
|
log(self.name, "info", *message, local_only=local_only, timeout=20)
|
||||||
|
|
||||||
|
def debug(self, *message, local_only=True):
|
||||||
|
log(self.name, "debug", *message, local_only=local_only, timeout=5)
|
||||||
|
|
||||||
|
def asyncLog(self, level, *message, timeout=True):
|
||||||
|
log(self.name, level, *message, return_only=True)
|
||||||
|
if timeout == 0:
|
||||||
|
return
|
||||||
|
asyncLog(self.name, level, *message, timeout=timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def getLogger(name):
|
||||||
|
return Logger(name)
|
62
code/main.py
Normal file
62
code/main.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
import usr.settings as settings
|
||||||
|
from usr.tracker import Tracker
|
||||||
|
from usr.logging import getLogger
|
||||||
|
import UART
|
||||||
|
import osTimer
|
||||||
|
|
||||||
|
tracker = None
|
||||||
|
|
||||||
|
log = getLogger('tracker')
|
||||||
|
|
||||||
|
PROFILE_IDX = 0
|
||||||
|
|
||||||
|
settings.init()
|
||||||
|
current_settings = settings.get()
|
||||||
|
|
||||||
|
locator_init_params = {}
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.gps:
|
||||||
|
locator_init_params['gps_cfg'] = {
|
||||||
|
'UARTn': UART.UART0,
|
||||||
|
'buadrate': 115200,
|
||||||
|
'databits': 8,
|
||||||
|
'parity': 0,
|
||||||
|
'stopbits': 1,
|
||||||
|
'flowctl': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.cell:
|
||||||
|
locator_init_params['cellLocator_cfg'] = {
|
||||||
|
'serverAddr': 'www.queclocator.com',
|
||||||
|
'port': 80,
|
||||||
|
'token': 'xGP77d2z0i91s67n',
|
||||||
|
'timeout': 3,
|
||||||
|
'profileIdx': PROFILE_IDX
|
||||||
|
}
|
||||||
|
|
||||||
|
if current_settings['app']['loc_method'] & settings.default_values_app._loc_method.wifi:
|
||||||
|
locator_init_params['wifiLocator_cfg'] = {
|
||||||
|
'token': 'xGP77d2z0i91s67n'
|
||||||
|
}
|
||||||
|
|
||||||
|
def loc_read_cb(data):
|
||||||
|
if data:
|
||||||
|
loc_method = data[0]
|
||||||
|
loc_data = data[1]
|
||||||
|
log.info("loc_method:", loc_method)
|
||||||
|
log.info("loc_data:", loc_data)
|
||||||
|
if loc_method == settings.default_values_app._loc_method.gps:
|
||||||
|
data_type = tracker.remote.DATA_LOCA_GPS
|
||||||
|
else:
|
||||||
|
data_type = tracker.remote.DATA_LOCA_NON_GPS
|
||||||
|
tracker.remote.post_data(data_type, loc_data)
|
||||||
|
|
||||||
|
tracker = Tracker(loc_read_cb, **locator_init_params)
|
||||||
|
|
||||||
|
def loc_timer_cb(argv):
|
||||||
|
tracker.trigger()
|
||||||
|
|
||||||
|
if (current_settings['app']['loc_mode'] & settings.default_values_app._loc_mode.cycle) and current_settings['app']['loc_cycle_period']:
|
||||||
|
loc_timer = osTimer()
|
||||||
|
loc_timer.start(current_settings['app']['loc_cycle_period'] * 1000, 1, loc_timer_cb)
|
0
code/ota.py
Normal file
0
code/ota.py
Normal file
80
code/quecthing.py
Normal file
80
code/quecthing.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
import quecIot
|
||||||
|
from usr.logging import getLogger
|
||||||
|
|
||||||
|
DATA_NON_LOCA = 0x0
|
||||||
|
DATA_LOCA_NON_GPS = 0x1
|
||||||
|
DATA_LOCA_GPS = 0x2
|
||||||
|
|
||||||
|
log = getLogger('QuecThing')
|
||||||
|
|
||||||
|
class QuecThing(object):
|
||||||
|
def __init__(self, pk, ps, downlink_queue):
|
||||||
|
self.downlink_queue = downlink_queue
|
||||||
|
quecIot.init()
|
||||||
|
quecIot.setEventCB(self.eventCB)
|
||||||
|
quecIot.setProductinfo(pk, ps)
|
||||||
|
quecIot.setServer(1, "iot-south.quectel.com:2883")
|
||||||
|
quecIot.setConnmode(1)
|
||||||
|
|
||||||
|
def post_data(self, data_type, data):
|
||||||
|
if data_type == DATA_NON_LOCA:
|
||||||
|
quecIot.passTransSend(1, data)
|
||||||
|
elif data_type == DATA_LOCA_GPS:
|
||||||
|
quecIot.locReportOutside(data)
|
||||||
|
elif data_type == DATA_LOCA_NON_GPS:
|
||||||
|
quecIot.locReportInside(data)
|
||||||
|
else:
|
||||||
|
raise ValueError('No such locator (0x%X).' % data_type)
|
||||||
|
|
||||||
|
def eventCB(self, data):
|
||||||
|
log.info("event:", data)
|
||||||
|
event = data[0]
|
||||||
|
errcode = data[1]
|
||||||
|
if len(data) > 2:
|
||||||
|
data = data[2]
|
||||||
|
|
||||||
|
if event == 1:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Device authentication succeeded.')
|
||||||
|
elif errcode == 10422:
|
||||||
|
log.info('Device has been authenticated (connect failed).')
|
||||||
|
elif event == 2:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Access succeeded.')
|
||||||
|
elif event == 3:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Subscription succeeded.')
|
||||||
|
elif event == 4:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Data sending succeeded.')
|
||||||
|
elif errcode == 10210:
|
||||||
|
log.info('Object model data sending succeeded.')
|
||||||
|
elif errcode == 10220:
|
||||||
|
log.info('Location data sending succeeded.')
|
||||||
|
elif errcode == 10300:
|
||||||
|
log.info('Data sending failed.')
|
||||||
|
elif errcode == 10310:
|
||||||
|
log.info('Object model data sending failed.')
|
||||||
|
elif errcode == 10320:
|
||||||
|
log.info('Location data sending failed.')
|
||||||
|
elif event == 5:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Recving raw data.')
|
||||||
|
log.info(data)
|
||||||
|
'''
|
||||||
|
self.downlink_queue.put(data)
|
||||||
|
'''
|
||||||
|
if errcode == 10210:
|
||||||
|
log.info('Recving object model data.')
|
||||||
|
'''
|
||||||
|
self.downlink_queue.put(data)
|
||||||
|
'''
|
||||||
|
elif errcode == 10211:
|
||||||
|
log.info('Recving object model query command.')
|
||||||
|
elif event == 6:
|
||||||
|
if errcode == 10200:
|
||||||
|
log.info('Logout succeeded.')
|
||||||
|
elif event == 7:
|
||||||
|
if errcode == 10700:
|
||||||
|
log.info('New OTA plain.')
|
210
code/remote.py
Normal file
210
code/remote.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
|
||||||
|
from logging import exception
|
||||||
|
import utime
|
||||||
|
import ql_fs
|
||||||
|
import ujson
|
||||||
|
import uos
|
||||||
|
import _thread
|
||||||
|
from queue import Queue
|
||||||
|
import usr.settings as settings
|
||||||
|
import usr.dev_info as dev_info
|
||||||
|
|
||||||
|
current_settings = settings.get()
|
||||||
|
|
||||||
|
if current_settings['sys']['cloud'] == settings.default_values_sys._cloud.quecIot:
|
||||||
|
from usr.quecthing import QuecThing
|
||||||
|
|
||||||
|
class RemoteError(Exception):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self.value)
|
||||||
|
|
||||||
|
def downlink_process(argv):
|
||||||
|
self = argv
|
||||||
|
while True:
|
||||||
|
'''
|
||||||
|
Recv data from quecIot or AliYun or other server.
|
||||||
|
Data format should be unified at the process module file of its own before put to downlink_queue.
|
||||||
|
|
||||||
|
Data format:
|
||||||
|
TODO: =====================
|
||||||
|
'''
|
||||||
|
msg = self.downlink_queue.get()
|
||||||
|
if msg:
|
||||||
|
pass
|
||||||
|
'''
|
||||||
|
TODO: processing for settings or control commands from downlink channel
|
||||||
|
'''
|
||||||
|
|
||||||
|
def uplink_process(argv):
|
||||||
|
self = argv
|
||||||
|
ret = False
|
||||||
|
while True:
|
||||||
|
|
||||||
|
'''
|
||||||
|
We need to post data in tracker_data.hist file to server firstly every time.
|
||||||
|
If still can't post all data to server, stop posting, but to append all data in uplink_queue to tracker_data.hist.
|
||||||
|
When data in tracker_data.hist and in uplink_queue is processed, wait for new data coming into uplink_queue.
|
||||||
|
If get new data, try to post data again, if fail, add data to tracker_data.hist file.
|
||||||
|
Otherwise, keep waiting untill new data coming, then process could go to the start of loopwhile, and data in tracker_data.hist could be processed again.
|
||||||
|
'''
|
||||||
|
|
||||||
|
need_refresh = False
|
||||||
|
|
||||||
|
# Read history data that didn't send to server intime to hist-dictionary.
|
||||||
|
hist = self.read_history()
|
||||||
|
try:
|
||||||
|
for key, value in hist.items():
|
||||||
|
# Check if non_loca data (sensor or device info data) or location gps data or location non-gps data (cell/wifi-locator data)
|
||||||
|
if key == 'non_loca' or key == 'loca_non_gps' or key == 'loca_gps':
|
||||||
|
if key == 'non_loca':
|
||||||
|
data_type = self.DATA_NON_LOCA
|
||||||
|
elif key == 'loca_non_gps':
|
||||||
|
data_type = self.DATA_LOCA_NON_GPS
|
||||||
|
else:
|
||||||
|
data_type = self.DATA_LOCA_GPS
|
||||||
|
for i, data in enumerate(value):
|
||||||
|
ntry = 0
|
||||||
|
# Try at most 3 times to post data to server.
|
||||||
|
while not self.cloud.post_data(data_type, data):
|
||||||
|
ntry += 1
|
||||||
|
if ntry >= 3: # Data post failed after 3 times, maybe network error?
|
||||||
|
raise RemoteError('Data post failed.') # Stop posting more data, go to exception handler.
|
||||||
|
utime.sleep(1)
|
||||||
|
else:
|
||||||
|
value.pop(i) # Pop data from data-list after posting sueecss.
|
||||||
|
need_refresh = True # Data in hist-dictionary changed, need to refresh history file.
|
||||||
|
except Exception:
|
||||||
|
while True: # Put all data in uplink_queue to hist-dictionary.
|
||||||
|
if self.uplink_queue.size():
|
||||||
|
msg = self.uplink_queue.get()
|
||||||
|
if msg:
|
||||||
|
if msg[0] == self.DATA_NON_LOCA:
|
||||||
|
key = 'non_loca'
|
||||||
|
elif msg[0] == self.DATA_LOCA_NON_GPS:
|
||||||
|
key = 'loca_non_gps'
|
||||||
|
elif msg[0] == self.DATA_LOCA_GPS:
|
||||||
|
key = 'loca_gps'
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
hist[key].append(msg[1])
|
||||||
|
need_refresh = True
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
if need_refresh:
|
||||||
|
# Flush data in hist-dictionary to tracker_data.hist file.
|
||||||
|
self.refresh_history(hist)
|
||||||
|
need_refresh = False
|
||||||
|
|
||||||
|
'''
|
||||||
|
If history data exists, put a empty msg to uplink_queue to trriger the return of self.uplink_queue.get() API below.
|
||||||
|
So that history data could be processed again immediately.
|
||||||
|
Without this, history data could only be processed after new data being put into uplink_queue.
|
||||||
|
But is this necessary ???
|
||||||
|
'''
|
||||||
|
if len(hist['non_loca']) + len(hist['loca_non_gps']) + len(hist['loca_gps']):
|
||||||
|
self.uplink_queue.put(())
|
||||||
|
|
||||||
|
# When comes to this, wait for new data coming into uplink_queue.
|
||||||
|
msg = self.uplink_queue.get()
|
||||||
|
if msg:
|
||||||
|
if msg[0] == self.DATA_NON_LOCA or msg[0] == self.DATA_LOCA_NON_GPS or msg[0] == self.DATA_LOCA_GPS:
|
||||||
|
if not self.cloud.post_data(msg[0], msg[1]):
|
||||||
|
self.add_history(msg[0], msg[1])
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
class Remote(object):
|
||||||
|
_history = '/usr/tracker_data.hist'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.downlink_queue = Queue(maxsize=64)
|
||||||
|
self.uplink_queue = Queue(maxsize=64)
|
||||||
|
if current_settings['sys']['cloud'] == settings.default_values_sys._cloud.quecIot:
|
||||||
|
self.cloud = QuecThing(dev_info.quecIot['PK'], dev_info.quecIot['PS'], self.downlink_queue)
|
||||||
|
self.DATA_NON_LOCA = QuecThing.DATA_NON_LOCA
|
||||||
|
self.DATA_LOCA_NON_GPS = QuecThing.DATA_LOCA_NON_GPS
|
||||||
|
self.DATA_LOCA_GPS = QuecThing.DATA_LOCA_GPS
|
||||||
|
else:
|
||||||
|
raise settings.Error('Current cloud (0x%X) not supported!' % current_settings['sys']['cloud'])
|
||||||
|
|
||||||
|
_thread.start_new_thread(downlink_process, (self,))
|
||||||
|
_thread.start_new_thread(uplink_process, (self,))
|
||||||
|
|
||||||
|
def read_history(self):
|
||||||
|
'''
|
||||||
|
{
|
||||||
|
"non_loca": [
|
||||||
|
{xxx},
|
||||||
|
{xxx}
|
||||||
|
],
|
||||||
|
|
||||||
|
"loca_non_gps": [
|
||||||
|
{xxx},
|
||||||
|
{xxx}
|
||||||
|
],
|
||||||
|
|
||||||
|
"loca_gps": [
|
||||||
|
{xxx},
|
||||||
|
{xxx}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
if ql_fs.path_exists(self._history):
|
||||||
|
with open(self._history, 'r') as f:
|
||||||
|
try:
|
||||||
|
res = ujson.load(f)
|
||||||
|
if isinstance(res, dict):
|
||||||
|
return res
|
||||||
|
return {}
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def add_history(self, data_type, data):
|
||||||
|
try:
|
||||||
|
with open(self._history, 'r') as f:
|
||||||
|
res = ujson.load(f)
|
||||||
|
except Exception:
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
if not isinstance(res, dict):
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
if data_type == self.DATA_NON_LOCA:
|
||||||
|
key = 'non_loca'
|
||||||
|
elif data_type == self.DATA_LOCA_NON_GPS:
|
||||||
|
key = 'loca_non_gps'
|
||||||
|
elif data_type == self.DATA_LOCA_GPS:
|
||||||
|
key = 'loca_gps'
|
||||||
|
|
||||||
|
if key not in res:
|
||||||
|
res[key] = []
|
||||||
|
|
||||||
|
res[key].append(data)
|
||||||
|
|
||||||
|
return self.refresh_history(res)
|
||||||
|
|
||||||
|
def refresh_history(self, hist_dict):
|
||||||
|
try:
|
||||||
|
with open(self._history, 'w') as f:
|
||||||
|
ujson.dump(hist_dict, f, indent = 4)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def clean_history(self):
|
||||||
|
uos.remove(self._history)
|
||||||
|
|
||||||
|
def post_data(self, data_type, data):
|
||||||
|
self.uplink_queue.put((data_type, data))
|
17
code/selfcheck.py
Normal file
17
code/selfcheck.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
'''
|
||||||
|
check if network, gps, and all the sensors work normally
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def netcheck():
|
||||||
|
# return True if OK
|
||||||
|
pass
|
||||||
|
|
||||||
|
def gps_check():
|
||||||
|
# return True if OK
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sensor_check():
|
||||||
|
# return True if OK
|
||||||
|
pass
|
4
code/sensor.py
Normal file
4
code/sensor.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
class Sensor():
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
171
code/settings.py
Normal file
171
code/settings.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
import ql_fs
|
||||||
|
import ujson
|
||||||
|
import uos
|
||||||
|
import ure
|
||||||
|
|
||||||
|
tracker_settings_file = '/usr/tracker_settings.json'
|
||||||
|
|
||||||
|
class default_values_app(object):
|
||||||
|
'''
|
||||||
|
App default settings
|
||||||
|
'''
|
||||||
|
|
||||||
|
class _loc_method(object):
|
||||||
|
none = 0x0
|
||||||
|
gps = 0x1
|
||||||
|
cell = 0x2
|
||||||
|
wifi = 0x4
|
||||||
|
all = 0x7
|
||||||
|
|
||||||
|
class _loc_mode(object):
|
||||||
|
none = 0x0
|
||||||
|
cycle = 0x1
|
||||||
|
onAlert = 0x2
|
||||||
|
onPhoneCall = 0x4
|
||||||
|
onVoiceRecord = 0x8
|
||||||
|
all = 0xF
|
||||||
|
|
||||||
|
'''
|
||||||
|
variables of App default settings below MUST NOT start with '_'
|
||||||
|
'''
|
||||||
|
|
||||||
|
phone_num = ''
|
||||||
|
|
||||||
|
loc_method = _loc_method.gps
|
||||||
|
|
||||||
|
loc_mode = _loc_mode.cycle
|
||||||
|
|
||||||
|
loc_cycle_period = 1
|
||||||
|
|
||||||
|
sw_ota = True
|
||||||
|
|
||||||
|
sw_auto_upgrade = True
|
||||||
|
|
||||||
|
sw_electric_fence = True
|
||||||
|
|
||||||
|
sw_phone_call = False
|
||||||
|
|
||||||
|
sw_voice_record = False
|
||||||
|
|
||||||
|
sw_jtt808 = True
|
||||||
|
|
||||||
|
sw_fault_alert = True
|
||||||
|
|
||||||
|
sw_low_power_alert = True
|
||||||
|
|
||||||
|
sw_over_speed_alert = True
|
||||||
|
|
||||||
|
sw_sim_out_alert = True
|
||||||
|
|
||||||
|
sw_disassemble_alert = True
|
||||||
|
|
||||||
|
sw_vibrate_alert = True
|
||||||
|
|
||||||
|
sw_drive_behavior_alert = True
|
||||||
|
|
||||||
|
|
||||||
|
class default_values_sys(object):
|
||||||
|
'''
|
||||||
|
System default settings
|
||||||
|
'''
|
||||||
|
|
||||||
|
class _cloud(object):
|
||||||
|
none = 0x0
|
||||||
|
quecIot = 0x1
|
||||||
|
AliYun = 0x2
|
||||||
|
JTT808 = 0x4
|
||||||
|
customization = 0x8
|
||||||
|
|
||||||
|
'''
|
||||||
|
variables of system default settings below MUST NOT start with '_'
|
||||||
|
'''
|
||||||
|
|
||||||
|
cloud = _cloud.quecIot
|
||||||
|
|
||||||
|
|
||||||
|
default_settings_app = {k:v for k,v in default_values_app.__dict__.items() if not k.startswith('_')}
|
||||||
|
current_settings_app = {}
|
||||||
|
|
||||||
|
default_settings_sys = {k:v for k,v in default_values_sys.__dict__.items() if not k.startswith('_')}
|
||||||
|
current_settings_sys = {}
|
||||||
|
|
||||||
|
default_settings = {'app':default_settings_app, 'sys':default_settings_sys}
|
||||||
|
current_settings = {}
|
||||||
|
|
||||||
|
def init():
|
||||||
|
global current_settings
|
||||||
|
if not ql_fs.path_exists(tracker_settings_file):
|
||||||
|
with open(tracker_settings_file, 'w') as f:
|
||||||
|
ujson.dump(default_settings, f, indent = 4)
|
||||||
|
current_settings = dict(default_settings)
|
||||||
|
else:
|
||||||
|
with open(tracker_settings_file, 'r') as f:
|
||||||
|
current_settings = ujson.load(f)
|
||||||
|
|
||||||
|
def get():
|
||||||
|
global current_settings
|
||||||
|
return current_settings
|
||||||
|
|
||||||
|
def set(opt, val):
|
||||||
|
if opt in current_settings['app']:
|
||||||
|
if opt == 'phone_num':
|
||||||
|
if not isinstance(val, str):
|
||||||
|
return False
|
||||||
|
pattern = ure.compile(r'^(?:(?:\+)86)?1[3-9]\d{9}$')
|
||||||
|
if pattern.search(val):
|
||||||
|
current_settings['app'][opt] = val
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif opt == 'loc_method':
|
||||||
|
if not isinstance(val, int):
|
||||||
|
return False
|
||||||
|
if val > default_values_app._loc_method.all:
|
||||||
|
return False
|
||||||
|
current_settings['app'][opt] = val
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif opt == 'loc_mode':
|
||||||
|
if not isinstance(val, int):
|
||||||
|
return False
|
||||||
|
if val > default_values_app._loc_mode.all:
|
||||||
|
return False
|
||||||
|
current_settings['app'][opt] = val
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif opt == 'loc_cycle_period':
|
||||||
|
if not isinstance(val, int):
|
||||||
|
return False
|
||||||
|
if val < 1:
|
||||||
|
return False
|
||||||
|
current_settings['app'][opt] = val
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif opt == 'sw_ota' or opt == 'sw_auto_upgrade' or opt == 'sw_electric_fence' or opt == 'sw_phone_call' or opt == 'sw_voice_record' \
|
||||||
|
or opt == 'sw_jtt808' or opt == 'sw_fault_alert' or opt == 'sw_low_power_alert' or opt == 'sw_over_speed_alert' or opt == 'sw_sim_out_alert' \
|
||||||
|
or opt == 'sw_disassemble_alert' or opt == 'sw_vibrate_alert' or opt == 'sw_drive_behavior_alert':
|
||||||
|
if not isinstance(val, bool):
|
||||||
|
return False
|
||||||
|
current_settings['app'][opt] = val
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def save():
|
||||||
|
with open(tracker_settings_file, 'w') as f:
|
||||||
|
ujson.dump(current_settings, f, indent = 4)
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
uos.remove(tracker_settings_file)
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self.value)
|
12
code/tracker.py
Normal file
12
code/tracker.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
from usr.location import Location
|
||||||
|
from usr.location import Remote
|
||||||
|
from usr.sensor import Sensor
|
||||||
|
from usr.led import LED
|
||||||
|
|
||||||
|
class Tracker():
|
||||||
|
def __init__(self, loc_read_cb, **kw):
|
||||||
|
self.locator = Location(loc_read_cb, **kw)
|
||||||
|
self.remote = Remote()
|
||||||
|
self.sensor = Sensor()
|
||||||
|
self.led = LED()
|
BIN
docs/tracker功能定义.xlsx
Normal file
BIN
docs/tracker功能定义.xlsx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user