diff --git a/QPY_OCPU_BETA0001_EC200U_EUAA_FW/QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac new file mode 100644 index 0000000..059780f Binary files /dev/null and b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac differ diff --git a/QPY_OCPU_BETA0001_EC200U_EUAA_FW/Quectel_Disclaimer_for_Software_BETA_Version.pdf b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/Quectel_Disclaimer_for_Software_BETA_Version.pdf new file mode 100644 index 0000000..d1b1b0c Binary files /dev/null and b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/Quectel_Disclaimer_for_Software_BETA_Version.pdf differ diff --git a/QPY_OCPU_BETA0001_EC200U_EUAA_FW/changelog - EC200UEU_AA_BETA.md b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/changelog - EC200UEU_AA_BETA.md new file mode 100644 index 0000000..9eaa002 --- /dev/null +++ b/QPY_OCPU_BETA0001_EC200U_EUAA_FW/changelog - EC200UEU_AA_BETA.md @@ -0,0 +1,88 @@ +## Release History +**[QPY_OCPU_EC200UEU_AA_BETA] 2024-04-18** +* ZH +* 支持功能list +1. app_fota +2. PWM +3. dataCall +4. fota +5. log +6. net +7. ntptime +8. pm +9. queue +10. sim +11. sys_bus +12. uio +13. ujson +14. BLE +15. usocket +16. utime +17. _thread +18. Timer +19. RTC +20. WDT +21. Pin +22. ExtInt +23. UART +24. SPI +25. IIC +26. Key +27. Power +28. ADC +29. PowerKey +30. TencentYun +31. voicecall +32. wifiscan +33. wifilocator +34. SMS +35. Audio +36. Ethernet +37. AliYun +38. GNSS +39. USSD + + + + +* EN +* Support function list +1. app_fota +2. PWM +3. dataCall +4. fota +5. log +6. net +7. ntptime +8. pm +9. queue +10. sim +11. sys_bus +12. uio +13. ujson +14. BLE +15. usocket +16. utime +17. _thread +18. Timer +19. RTC +20. WDT +21. Pin +22. ExtInt +23. UART +24. SPI +25. IIC +26. Key +27. Power +28. ADC +29. PowerKey +30. TencentYun +31. voicecall +32. wifiscan +33. wifilocator +34. SMS +35. Audio +36. Ethernet +37. AliYun +38. GNSS +39. USSD \ No newline at end of file diff --git a/code/_main.py b/code/_main.py new file mode 100644 index 0000000..bd63a9d --- /dev/null +++ b/code/_main.py @@ -0,0 +1,120 @@ +# 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. + +""" +@file :_main.py +@author :Jack Sun (jack.sun@quectel.com) +@brief :Project start. +@version :2.2.0 +@date :2022-10-31 14:42:25 +@copyright :Copyright (c) 2022 +""" + +import _thread +try: + from modules.battery import Battery + from modules.history import History + from modules.logging import getLogger + from modules.net_manage import NetManager + from modules.thingsboard import TBDeviceMQTTClient + from modules.power_manage import PowerManage + from modules.aliIot import AliIot, AliIotOTA + from modules.location import GNSS, CellLocator, WiFiLocator, CoordinateSystemConvert + from settings_user import UserConfig + from tracker_tb import Tracker as TBTracker + from tracker_ali import Tracker as AliTracker + from settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION +except ImportError: + from usr.modules.battery import Battery + from usr.modules.history import History + from usr.modules.logging import getLogger + from usr.modules.net_manage import NetManager + from usr.modules.thingsboard import TBDeviceMQTTClient + from usr.modules.power_manage import PowerManage + from usr.modules.aliIot import AliIot, AliIotOTA + from usr.modules.location import GNSS, CellLocator, WiFiLocator, CoordinateSystemConvert + from usr.settings_user import UserConfig + from usr.tracker_tb import Tracker as TBTracker + from usr.tracker_ali import Tracker as AliTracker + from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION + +log = getLogger(__name__) + +def main(): + log.debug("[x] Main start.") + log.info("PROJECT_NAME: %s, PROJECT_VERSION: %s" % (PROJECT_NAME, PROJECT_VERSION)) + log.info("DEVICE_FIRMWARE_NAME: %s, DEVICE_FIRMWARE_VERSION: %s" % (FIRMWARE_NAME, FIRMWARE_VERSION)) + + # Init settings. + settings = Settings() + # Init battery. + battery = Battery() + # Init history + history = History() + # Init power manage and set device low energy. + power_manage = PowerManage() + power_manage.autosleep(1) + # Init net modules and start net connect. + net_manager = NetManager() + _thread.stack_size(0x1000) + _thread.start_new_thread(net_manager.net_connect, ()) + # Init GNSS modules and start reading and parsing gnss data. + loc_cfg = settings.read("loc") + gnss = GNSS(**loc_cfg["gps_cfg"]) + gnss.set_trans(0) + gnss.start() + # Init cell and wifi location modules. + cell = CellLocator(**loc_cfg["cell_cfg"]) + wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) + cyc = CoordinateSystemConvert() + # Init tracker business modules. + user_cfg = settings.read("user") + server_cfg = settings.read("server") + # Init coordinate system convert modules. + if user_cfg["server"] == UserConfig._server.AliIot: + server = AliIot(**server_cfg) + server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) + server_ota.set_server(server) + tracker = AliTracker() + elif user_cfg["server"] == UserConfig._server.ThingsBoard: + # Init server modules. + server = TBDeviceMQTTClient(**server_cfg) + tracker = TBTracker() + else: + raise ValueError("User config server is not compared.") + tracker.add_module(settings) + tracker.add_module(battery) + tracker.add_module(history) + tracker.add_module(net_manager) + tracker.add_module(server) + tracker.add_module(server_ota) + tracker.add_module(gnss) + tracker.add_module(cell) + tracker.add_module(wifi) + tracker.add_module(cyc) + server.add_event("over_speed_alert") + server.add_event("sim_abnormal_alert") + server.add_event("low_power_alert") + server.add_event("fault_alert") + # Set net modules callback. + net_manager.set_callback(tracker.net_callback) + # Set server modules callback. + server.set_callback(tracker.server_callback) + # Start tracker business. + tracker.running() + + log.debug("[x] Main over.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/code/main.py b/code/main.py deleted file mode 100644 index ef312f7..0000000 --- a/code/main.py +++ /dev/null @@ -1,97 +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. - -""" -@file :_main.py -@author :Jack Sun (jack.sun@quectel.com) -@brief :Project start. -@version :2.2.0 -@date :2022-10-31 14:42:25 -@copyright :Copyright (c) 2022 -""" - -import _thread - -from usr.modules.battery import Battery -from usr.modules.history import History -from usr.modules.logging import getLogger -from usr.modules.net_manage import NetManager -from usr.modules.thingsboard import TBDeviceMQTTClient -from usr.modules.power_manage import PowerManage -from usr.modules.aliIot import AliIot, AliIotOTA -from usr.modules.location import GNSS, CellLocator, WiFiLocator, CoordinateSystemConvert - -from usr.settings_user import UserConfig -from usr.tracker_tb import Tracker as TBTracker -from usr.tracker_ali import Tracker as AliTracker -from usr.settings import Settings, PROJECT_NAME, FIRMWARE_NAME - -log = getLogger(__name__) - -log.debug("[x] Main start.") - -# Init settings. -settings = Settings() -# Init battery. -battery = Battery() -# Init history -history = History() -# Init power manage and set device low energy. -power_manage = PowerManage() -power_manage.autosleep(1) -# Init net modules and start net connect. -net_manager = NetManager() -_thread.stack_size(0x1000) -_thread.start_new_thread(net_manager.net_connect, ()) -# Init GNSS modules and start reading and parsing gnss data. -loc_cfg = settings.read("loc") -gnss = GNSS(**loc_cfg["gps_cfg"]) -gnss.set_trans(0) -gnss.start() -# Init cell and wifi location modules. -cell = CellLocator(**loc_cfg["cell_cfg"]) -wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) -cyc = CoordinateSystemConvert() -# Init tracker business modules. -user_cfg = settings.read("user") -server_cfg = settings.read("server") -# Init coordinate system convert modules. -if user_cfg["server"] == UserConfig._server.AliIot: - server = AliIot(**server_cfg) - server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) - server_ota.set_server(server) - tracker = AliTracker() -elif user_cfg["server"] == UserConfig._server.ThingsBoard: - # Init server modules. - server = TBDeviceMQTTClient(**server_cfg) - tracker = TBTracker() -else: - raise ValueError("User config server is not compared.") -tracker.add_module(settings) -tracker.add_module(battery) -tracker.add_module(history) -tracker.add_module(net_manager) -tracker.add_module(server) -tracker.add_module(gnss) -tracker.add_module(cell) -tracker.add_module(wifi) -tracker.add_module(cyc) -# Set net modules callback. -net_manager.set_callback(tracker.net_callback) -# Set server modules callback. -server.set_callback(tracker.server_callback) -# Start tracker business. -tracker.running() - -log.debug("[x] Main over.") diff --git a/code/settings.py b/code/settings.py index 0a8bb21..bd31426 100644 --- a/code/settings.py +++ b/code/settings.py @@ -28,14 +28,13 @@ import usys as sys try: - from usr.dev_settings_server import AliIotConfig, ThingsBoardConfig + from settings_server import AliIotConfig, ThingsBoardConfig + from settings_loc import LocConfig + from settings_user import UserConfig except ImportError: from usr.settings_server import AliIotConfig, ThingsBoardConfig -try: - from usr.dev_settings_loc import LocConfig -except ImportError: from usr.settings_loc import LocConfig -from usr.settings_user import UserConfig + from usr.settings_user import UserConfig PROJECT_NAME = "QuecPython-Tracker" @@ -45,7 +44,6 @@ FIRMWARE_VERSION = modem.getDevFwVersion() - class Settings: def __init__(self, config_file="/usr/tracker_config.json"): @@ -56,24 +54,24 @@ def __init__(self, config_file="/usr/tracker_config.json"): def __init_config(self): try: - if not ql_fs.path_exists(self.__file): - # UserConfig init - self.__data["user"] = {k: v for k, v in UserConfig.__dict__.items() if not k.startswith("_")} - self.__data["user"]["ota_status"]["sys_current_version"] = FIRMWARE_VERSION - self.__data["user"]["ota_status"]["app_current_version"] = PROJECT_VERSION + if ql_fs.path_exists(self.__file): + ql_fs.touch(self.__file, {}) + + # UserConfig init + self.__data["user"] = {k: v for k, v in UserConfig.__dict__.items() if not k.startswith("_")} + self.__data["user"]["ota_status"]["sys_current_version"] = FIRMWARE_VERSION + self.__data["user"]["ota_status"]["app_current_version"] = PROJECT_VERSION - # CloudConfig init - self.__data["server"] = {} - if self.__data["user"]["server"] == UserConfig._server.AliIot: - self.__data["server"] = {k: v for k, v in AliIotConfig.__dict__.items() if not k.startswith("_")} - elif self.__data["user"]["server"] == UserConfig._server.ThingsBoard: - self.__data["server"] = {k: v for k, v in ThingsBoardConfig.__dict__.items() if not k.startswith("_")} + # CloudConfig init + self.__data["server"] = {} + if self.__data["user"]["server"] == UserConfig._server.AliIot: + self.__data["server"] = {k: v for k, v in AliIotConfig.__dict__.items() if not k.startswith("_")} + elif self.__data["user"]["server"] == UserConfig._server.ThingsBoard: + self.__data["server"] = {k: v for k, v in ThingsBoardConfig.__dict__.items() if not k.startswith("_")} - # LocConfig init - self.__data["loc"] = {k: v for k, v in LocConfig.__dict__.items() if not k.startswith("_")} - ql_fs.touch(self.__file, self.__data) - else: - self.__data = ql_fs.read_json(self.__file) + # LocConfig init + self.__data["loc"] = {k: v for k, v in LocConfig.__dict__.items() if not k.startswith("_")} + ql_fs.touch(self.__file, self.__data) except Exception as e: sys.print_exception(e) diff --git a/code/settings_loc.py b/code/settings_loc.py index 853b88d..ced84be 100644 --- a/code/settings_loc.py +++ b/code/settings_loc.py @@ -13,11 +13,11 @@ # limitations under the License. """ -@file :settings_loc.py +@file :dev_settings_loc.py @author :Jack Sun (jack.sun@quectel.com) @brief :Loction config. @version :2.2.0 -@date :2023-04-11 11:26:16 +@date :2022-10-31 14:42:25 @copyright :Copyright (c) 2022 """ @@ -43,18 +43,18 @@ class _gps_sleep_mode: profile_idx = 1 - map_coordinate_system = _map_coordinate_system.WGS84 + map_coordinate_system = _map_coordinate_system.GCJ02 gps_sleep_mode = _gps_sleep_mode.none gps_cfg = { - "UARTn": UART.UART1, + "gps_mode": _gps_mode.internal, + "UARTn": UART.UART2, "buadrate": 115200, "databits": 8, "parity": 0, "stopbits": 1, "flowctl": 0, - "gps_mode": _gps_mode.external_uart, "PowerPin": None, "StandbyPin": None, "BackupPin": None, diff --git a/code/settings_server.py b/code/settings_server.py index 545bd08..251644d 100644 --- a/code/settings_server.py +++ b/code/settings_server.py @@ -13,11 +13,11 @@ # limitations under the License. """ -@file :settings_server.py +@file :dev_settings_server.py @author :Jack Sun (jack.sun@quectel.com) @brief :Server config. @version :2.2.0 -@date :2023-04-11 11:25:09 +@date :2022-10-31 14:42:25 @copyright :Copyright (c) 2022 """ @@ -25,13 +25,14 @@ class AliIotConfig: product_key = "" - product_secret = "" device_name = "" device_secret = "" + product_secret = None server = "iot-as-mqtt.cn-shanghai.aliyuncs.com" qos = 1 + class ThingsBoardConfig: host = "" diff --git a/code/tracker_ali.py b/code/tracker_ali.py index 4982883..3edad60 100644 --- a/code/tracker_ali.py +++ b/code/tracker_ali.py @@ -29,15 +29,26 @@ from queue import Queue from machine import RTC -from usr.settings_user import UserConfig -from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION -from usr.modules.battery import Battery -from usr.modules.history import History -from usr.modules.logging import getLogger -from usr.modules.net_manage import NetManager -from usr.modules.aliIot import AliIot, AliIotOTA -from usr.modules.power_manage import PowerManage, PMLock -from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert +try: + from settings_user import UserConfig + from settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION + from modules.battery import Battery + from modules.history import History + from modules.logging import getLogger + from modules.net_manage import NetManager + from modules.aliIot import AliIot, AliIotOTA + from modules.power_manage import PowerManage, PMLock + from modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert +except ImportError: + from usr.settings_user import UserConfig + from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION + from usr.modules.battery import Battery + from usr.modules.history import History + from usr.modules.logging import getLogger + from usr.modules.net_manage import NetManager + from usr.modules.aliIot import AliIot, AliIotOTA + from usr.modules.power_manage import PowerManage, PMLock + from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert log = getLogger(__name__) @@ -260,7 +271,7 @@ def __set_rtc(self, period, callback): def __server_connect(self): if self.__net_manager.net_status(): - self.__server.disconnect() + # self.__server.disconnect() self.__server.connect() if not self.__server.status: self.__server_reconn_timer.stop() @@ -445,51 +456,3 @@ def server_connect(self, args): if self.__server_conn_tag == 0: self.__server_conn_tag = 1 self.__business_queue.put((0, "server_connect")) - - -if __name__ == "__main__": - # Init settings. - settings = Settings() - # Init battery. - battery = Battery() - # Init history - history = History() - # Init power manage and set device low energy. - power_manage = PowerManage() - power_manage.autosleep(1) - # Init net modules and start net connect. - net_manager = NetManager() - _thread.stack_size(0x1000) - _thread.start_new_thread(net_manager.net_connect, ()) - # Init GNSS modules and start reading and parsing gnss data. - loc_cfg = settings.read("loc") - gnss = GNSS(**loc_cfg["gps_cfg"]) - gnss.set_trans(0) - gnss.start() - # Init cell and wifi location modules. - cell = CellLocator(**loc_cfg["cell_cfg"]) - wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) - # Init coordinate system convert modules. - csc = CoordinateSystemConvert() - # Init server modules. - server_cfg = settings.read("server") - server = AliIot(**server_cfg) - server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) - server_ota.set_server(server) - # Initialize tracker business modules. - tracker = Tracker() - tracker.add_module(settings) - tracker.add_module(battery) - tracker.add_module(history) - tracker.add_module(net_manager) - tracker.add_module(server) - tracker.add_module(server_ota) - tracker.add_module(gnss) - tracker.add_module(cell) - tracker.add_module(wifi) - tracker.add_module(csc) - # Set net and server callback. - net_manager.set_callback(tracker.net_callback) - server.set_callback(tracker.server_callback) - # Tracker start. - tracker.running() diff --git a/code/tracker_tb.py b/code/tracker_tb.py index 2e0a149..522ec43 100644 --- a/code/tracker_tb.py +++ b/code/tracker_tb.py @@ -28,15 +28,26 @@ from queue import Queue from machine import RTC -from usr.settings import Settings -from usr.settings_user import UserConfig -from usr.modules.battery import Battery -from usr.modules.history import History -from usr.modules.logging import getLogger -from usr.modules.net_manage import NetManager -from usr.modules.thingsboard import TBDeviceMQTTClient -from usr.modules.power_manage import PowerManage, PMLock -from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert +try: + from settings import Settings + from settings_user import UserConfig + from modules.battery import Battery + from modules.history import History + from modules.logging import getLogger + from modules.net_manage import NetManager + from modules.thingsboard import TBDeviceMQTTClient + from modules.power_manage import PowerManage, PMLock + from modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert +except ImportError: + from usr.settings import Settings + from usr.settings_user import UserConfig + from usr.modules.battery import Battery + from usr.modules.history import History + from usr.modules.logging import getLogger + from usr.modules.net_manage import NetManager + from usr.modules.thingsboard import TBDeviceMQTTClient + from usr.modules.power_manage import PowerManage, PMLock + from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert log = getLogger(__name__) diff --git a/docs/common/EC800G_Tracker_hardware_materials.zip b/docs/common/EC800G_Tracker_hardware_materials.zip deleted file mode 100644 index f07c938..0000000 Binary files a/docs/common/EC800G_Tracker_hardware_materials.zip and /dev/null differ diff --git a/docs/en/Tracker solution design guide.md b/docs/en/Tracker solution design guide.md deleted file mode 100644 index 92f616b..0000000 --- a/docs/en/Tracker solution design guide.md +++ /dev/null @@ -1,831 +0,0 @@ -[中文](../zh/定位器方案设计指导.md) | **English** | - -# Tracker Solution Design Guide - -## Introduction - -This document describes the design framework of Quecel smart tracker in the QuecPython solution, including the software and hardware system framework, description of key components, introduction and functional examples of system initialization process and business process, to help you quickly understand the overall architecture and functions of Quectel smart tracker. - -## Function Overview - -The software functions of smart tracker solution are demonstrated in the diagram below. The solution is divided into functions based on the actual business of the tracker and developed in a modular way. - -![solution-tracker-101](./media/solution-tracker-101.png) - -- Transmission Protocol Parsing - + Connection and data interaction with Alibaba IoT Platform - + Connection and data interaction with ThingsBoard - + GT06 protocol - + JT/T808 protocol -- Network Management - + MQTT protocol (Alibaba IoT/ThingsBoard/other platforms) - + TCP/UDP protocol (GT06/JTT808 protocol) - + APN settings (network registration and data call) - + LTE NET (4G network registration and data call) -- Peripheral Management - + GNSS: Turn on/off the GNSS module, read positioning data from the GNSS module, and inject AGPS data. - + G-sensor: Read data of sensors - + Charge IC: Charging management, obtaining device charging status - + Battery: Battery management, reading battery voltage and calculating battery level - + LED: LED indicator -- Data Storage - + Storage of system configuration parameters - + Storage of location data backup - + AGPS download storage - + Log information storage -- Device Upgrade - + OTA upgrade -- Business Function Management - + Connection and reconnection of network and IoT platforms - + Device data acquisition and reporting - + Alarm detection and reporting - + Processing of IoT platform downlink commands - + Device low power consumption - -## Data Interaction Process - -The data interaction process between the module and the IoT platform is described in the following diagram. - -![solution-tracker-102](./media/solution-tracker-102.png) - -Process description: - -1. The mobile APP sends commands to the IoT platform. The server issues commands to the module through TCP/UDP/MQTT protocols, and the module parses the command data. -2. The module reports data to the IoT platform through TCP/UDP/MQTT protocols. The IoT platform processes the data and synchronously displays it on the mobile APP. - -## Software Framework - -### Design Philosophy and Patterns - -- This system is designed as a listener pattern, that is, transmit messages and listen for events through callback functions. -- The software functions are split according to the tracker's business requirements, which are implemented based on functional modules. Each part is independently developed to reduce dependencies and can be debugged and run independently, thus achieving decoupling effects. -- Interactions between functions are realized through callback functions. All business function processing, such as downlink command processing, alarm detection, data acquisition and reporting, and device control, is done in the `Tracker` class. - -![solution-tracker-104](./media/solution-tracker-104.png) - -1. All functional modules are registered in the `Tracker` class through `Tracker.add_module`. -2. The Server module (IoT platform interaction module) transmits service downlink data to `Tracker.server_callback()` for processing through callback functions. -3. The NetManage module transmits network disconnection events to `Tracker.net_callback` for processing through callback functions. - -### Software Architecture Diagram - -The software system framework is described as follows: - -- Display layer, connection with different IoT platforms -- Transport layer, data interaction over different protocols -- Business layer, mainly used for device data acquisition, device control, downlink commands receiving and processing of IoT platforms, and data integration and reporting. -- Device layer, functions including obtaining and parsing location data, reading sensor data, battery management and historical data storage, and device information acquisition and device functions setting, such as device version, IMEI number, APN settings, network data call and device low power consumption. - -![solution-tracker-107](./media/solution-tracker-107.png) - -## Component Introduction - -### Core Business Module (Tracker) - -1. Function Description - -Implement core business logic, interact with the server and parse the data, and control device modules. All functions are passed and processed in the sub-thread of the business event message queue as events. - -2. Implementation Principle - -- Register functional modules to obtain data from various functional modules, such as location information, battery information, and sensor information. - -```python -class Tracker: - ... - - def add_module(self, module): - # Register various functional modules to the Tracker class for control in the Tracker class - if isinstance(module, AliIot): - self.__server = module - elif isinstance(module, AliIotOTA): - self.__server_ota = module - elif isinstance(module, Battery): - self.__battery = module - elif isinstance(module, History): - self.__history = module - elif isinstance(module, GNSS): - self.__gnss = module - elif isinstance(module, CellLocator): - self.__cell = module - elif isinstance(module, WiFiLocator): - self.__wifi = module - elif isinstance(module, NMEAParse): - self.__nmea_parse = module - elif isinstance(module, CoordinateSystemConvert): - self.__csc = module - elif isinstance(module, NetManage): - self.__net_manage = module - elif isinstance(module, PowerManage): - self.__pm = module - elif isinstance(module, TempHumiditySensor): - self.__temp_sensor = module - elif isinstance(module, Settings): - self.__settings = module - else: - return False - return True - - def running(self, args=None): - if self.__running_tag == 1: - return - self.__running_tag = 1 - # Disable device sleep - self.__pm.autosleep(0) - self.__pm.set_psm(mode=0) - # Start the sub-thread of listening for business event message queues - self.__business_start() - # Send version OTA upgrade command to the event queue for execution - self.__business_queue.put((0, "ota_refresh")) - # Send location data reporting event (including network connection, device data acquisition and device data reporting) - self.__business_queue.put((0, "loc_report")) - # Send the event of querying OTA upgrade - self.__business_queue.put((0, "check_ota")) - # Send the device sleep event - self.__business_queue.put((0, "into_sleep")) - self.__running_tag = 0 -``` - -- Listen for the commands issued by the server through callback functions and perform business processing. - -```python -class Tracker: - ... - - def server_callback(self, args): - # Pass the server's downlink message to the business event message queue for processing - self.__business_queue.put((1, args)) -``` - -```python -class Tracker: - ... - - def __business_running(self): - while True: - data = self.__business_queue.get() - with self.__business_lock: - self.__business_tag = 1 - ... - # Process IoT platform downlink commands - if data[0] == 1: - self.__server_option(*data[1]) - self.__business_tag = 0 -``` - -```python -class Tracker: - ... - - def __server_option(self, topic, data): - if topic.endswith("/property/set"): - # Process the downlink message of setting properties - self.__server_property_set(data) - elif topic.find("/rrpc/request/") != -1: - # Process the downlink message of transparent transmission data - msg_id = topic.split("/")[-1] - self.__server_rrpc_response(msg_id, data) - elif topic.find("/thing/service/") != -1: - # Process the downlink message of service data - service = topic.split("/")[-1] - self.__server_service_response(service, data) - elif topic.startswith("/ota/device/upgrade/") or topic.endswith("/ota/firmware/get_reply"): - # Process the downlink message of OTA upgrades - user_cfg = self.__settings.read("user") - if self.__server_ota_flag == 0: - if user_cfg["sw_ota"] == 1: - self.__server_ota_flag = 1 - if user_cfg["sw_ota_auto_upgrade"] == 1 or user_cfg["user_ota_action"] == 1: - # Perform the OTA upgrade after the conditions for the OTA upgrade have been met - self.__server_ota_process(data) - else: - self.__server_ota_flag = 0 - self.__server_ota.set_ota_data(data["data"]) - ota_info = self.__server_ota.get_ota_info() - ota_info["ota_status"] = 1 - self.__server_ota_state_save(**ota_info) - else: - module = data.get("data", {}).get("module") - self.__server.ota_device_progress(-1, "Device is not alowed ota.", module) -``` - -- Wake up the device from sleep through the RTC callback function and report business data. - -```python -class Tracker: - ... - - def __into_sleep(self): - while True: - if self.__business_queue.size() == 0 and self.__business_tag == 0: - break - utime.sleep_ms(500) - user_cfg = self.__settings.read("user") - # Automatically adjust the sleep mode (auto-sleep or PSM) based on the sleep duration - if user_cfg["work_cycle_period"] < user_cfg["work_mode_timeline"]: - self.__pm.autosleep(1) - else: - self.__pm.set_psm(mode=1, tau=user_cfg["work_cycle_period"], act=5) - # Enable RTC to wake up the device at a specified time - self.__set_rtc(user_cfg["work_cycle_period"], self.running) - - def __set_rtc(self, period, callback): - # Set the RTC to wake up the device - self.__business_rtc.enable_alarm(0) - if callback and callable(callback): - self.__business_rtc.register_callback(callback) - atime = utime.localtime(utime.mktime(utime.localtime()) + period) - alarm_time = (atime[0], atime[1], atime[2], atime[6], atime[3], atime[4], atime[5], 0) - _res = self.__business_rtc.set_alarm(alarm_time) - log.debug("alarm_time: %s, set_alarm res %s." % (str(alarm_time), _res)) - return self.__business_rtc.enable_alarm(1) if _res == 0 else -1 -``` - -3. Registration of functional modules and callback function configuration - -```python -def main(): - # Initialize the network management module - net_manage = NetManage(PROJECT_NAME, PROJECT_VERSION) - # Initialize the configuration parameter module - settings = Settings() - # Initialize the battery detection module - battery = Battery() - # Initialize the historical data module - history = History() - # Initialize the IoT platform (AliIot) module - server_cfg = settings.read("server") - server = AliIot(**server_cfg) - # Initialize the IoT platform (AliIot) OTA module - server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) - server_ota.set_server(server) - # Initialize the low power consumption module - power_manage = PowerManage() - # Initialize the temperature and humidity sensor module - temp_sensor = TempHumiditySensor(i2cn=I2C.I2C1, mode=I2C.FAST_MODE) - loc_cfg = settings.read("loc") - # Initialize the GNSS positioning module - gnss = GNSS(**loc_cfg["gps_cfg"]) - # Initialize the LBS positioning module - cell = CellLocator(**loc_cfg["cell_cfg"]) - # Initialize the Wi-Fi positioning module - wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) - # Initialize the GNSS positioning data parsing module - nmea_parse = NMEAParse() - # Initialize the WGS84 to GCJ02 coordinate system conversion module - cyc = CoordinateSystemConvert() - - # Initialize the Tracker business module - tracker = Tracker() - # Register the basic objects to the Tracker class for control - tracker.add_module(settings) - tracker.add_module(battery) - tracker.add_module(history) - tracker.add_module(net_manage) - tracker.add_module(server) - tracker.add_module(server_ota) - tracker.add_module(power_manage) - tracker.add_module(temp_sensor) - tracker.add_module(gnss) - tracker.add_module(cell) - tracker.add_module(wifi) - tracker.add_module(nmea_parse) - tracker.add_module(cyc) - - # Set the callback function for the network module, which processes business when the network is disconnected - net_manage.set_callback(tracker.net_callback) - # Set the callback function for receiving downlink data from the server, which processes business when the server issues commands - server.set_callback(tracker.server_callback) - - # Start the Tracker project business functions - tracker.running() - - -if __name__ == "__main__": - # Run the main file - main() -``` - -### location - -1. Function Description - -Obtain the current device location information through built-in or external GNSS, LBS, and Wi-Fi. - -2. Implementation Principle - -- Turn on the GNSS module to read the location data from the built-in GNSS through *quecgnss.read()*. - -```python -class GNSS: - ... - - def __internal_read(self): - log.debug("__internal_read start.") - # Turn on GNSS - self.__internal_open() - - # Clear the historical GNSS data cached in the serial port - while self.__break == 0: - gnss_data = quecgnss.read(1024) - if gnss_data[0] == 0: - self.__break = 1 - self.__break = 0 - - self.__gps_nmea_data_clean() - self.__gps_data_check_timer.start(2000, 1, self.__gps_data_check_callback) - cycle = 0 - # Read raw GNSS data - while self.__break == 0: - gnss_data = quecgnss.read(1024) - if gnss_data and gnss_data[1]: - this_gps_data = gnss_data[1].decode() if len(gnss_data) > 1 and gnss_data[1] else "" - self.__reverse_gps_data(this_gps_data) - if self.__check_gps_valid(): - self.__break = 1 - cycle += 1 - if cycle >= self.__retry: - if self.__break != 1: - self.__break = 1 - if self.__break != 1: - utime.sleep(1) - self.__gps_data_check_timer.stop() - self.__break = 0 - -self.__gps_data_check_callback(None) - # Turn off GNSS - self.__internal_close() - log.debug("__internal_read %s." % ("success" if self.__get_gps_data() else "failed")) - return self.__get_gps_data() -``` - -- Read the location data from the external GNSS module through the UART. - -```python -class GNSS: - ... - - def __external_read(self): - # Open the UART for the external GNSS module - self.__external_open() - log.debug("__external_read start") - - # Clear the historical GNSS data cached in the UART - while self.__break == 0: - self.__gps_timer.start(50, 0, self.__gps_timer_callback) - signal = self.__external_retrieve_queue.get() - log.debug("[first] signal: %s" % signal) - if signal: - to_read = self.__external_obj.any() - log.debug("[first] to_read: %s" % to_read) - if to_read > 0: - self.__set_gps_data(self.__external_obj.read(to_read).decode()) - self.__gps_timer.stop() - self.__break = 0 - - self.__gps_nmea_data_clean() - self.__gps_data_check_timer.start(2000, 1, self.__gps_data_check_callback) - cycle = 0 - # Read raw GNSS data - while self.__break == 0: - self.__gps_timer.start(1500, 0, self.__gps_timer_callback) - signal = self.__external_retrieve_queue.get() - log.debug("[second] signal: %s" % signal) - if signal: - to_read = self.__external_obj.any() - log.debug("[second] to_read: %s" % to_read) - if to_read > 0: - self.__reverse_gps_data(self.__external_obj.read(to_read).decode()) - if self.__check_gps_valid(): - self.__break = 1 - - self.__gps_timer.stop() - cycle += 1 - if cycle >= self.__retry: - self.__break = 1 - if self.__break != 1: - utime.sleep(1) - self.__gps_data_check_timer.stop() - self.__break = 0 - - # Check if GPS data is usable or not - self.__gps_data_check_callback(None) - # Close the UART for the external GNSS module - self.__external_close() - log.debug("__external_read %s." % ("success" if self.__get_gps_data() else "failed")) - return self.__get_gps_data() -``` - -- Read the location data, including the latitude, longitude and accuracy, from the LBS through *cellLocator.getLocation()*. - -```python -class CellLocator: - ... - - def __read_thread(self): - loc_data = () - try: - # Read LBS-positioning data - loc_data = cellLocator.getLocation( - self.__serverAddr, - self.__port, - self.__token, - self.__timeout, - self.__profileIdx - ) - loc_data = loc_data if isinstance(loc_data, tuple) and loc_data[0] and loc_data[1] else () - except Exception as e: - sys.print_exception(e) - self.__queue.put(loc_data) -``` - -- Read the location data, including the latitude, longitude, accuracy and MAC address, from the Wi-Fi through *wifilocator(token).getwifilocator()*. - -```python -class WiFiLocator: - - def __init__(self, token): - self.__wifilocator = wifilocator(token) if wifilocator else None - - def read(self): - loc_data = -1 - try: - return self.__wifilocator.getwifilocator() if self.__wifilocator else -1 - except Exception as e: - sys.print_exception(e) - return loc_data -``` - -### battery - -1. Function Description - -Read the battery level and voltage. Get the charging status of the battery and notify you of the status changes through callback functions. - -2. Implementation Principles - -- There are two ways to read the battery voltage - + Get voltage through *Power.getVbatt()* - + Calculate the voltage obtained through ADC - -```python -class Battery(object): - ... - - def __get_power_vbatt(self): - """Get vbatt from power""" - # Get voltage through Power.getVbatt() - return int(sum([Power.getVbatt() for i in range(100)]) / 100) - - def __get_adc_vbatt(self): - """Get vbatt from adc""" - # Calculate the voltage obtained through ADC - self.__adc.open() - utime.sleep_ms(self.__adc_period) - adc_list = list() - for i in range(self.__adc_period): - adc_list.append(self.__adc.read(self.__adc_num)) - utime.sleep_ms(self.__adc_period) - adc_list.remove(min(adc_list)) - adc_list.remove(max(adc_list)) - adc_value = int(sum(adc_list) / len(adc_list)) - self.__adc.close() - vbatt_value = adc_value * (self.__factor + 1) - return vbatt_value -``` - -- The calculation of battery level is only an analog currently. You can get the fuzzy value based on the following table of data relationships between voltage, temperature, and battery level. - -```python -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, - }, - }, -} -``` - -```python -class Battery: - ... - - def __get_soc_from_dict(self, key, volt_arg): - """Get battery energy from map""" - if BATTERY_OCV_TABLE[self.__battery_ocv].get(key): - volts = sorted(BATTERY_OCV_TABLE[self.__battery_ocv][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[self.__battery_ocv][key].get(volt, 0) - soc2 = BATTERY_OCV_TABLE[self.__battery_ocv][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): - """Get battery energy by temperature and voltage""" - 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) -``` - -- The battery\'s state of charge is determined by interrupting the pin and obtaining the high and low levels of the pin. - -```python -class Battery: - ... - - def __update_charge_status(self): - """Update Charge status by gpio status""" - if not self.__usb: - chrg_level = self.__chrg_gpio.read() - stdby_level = self.__stdby_gpio.read() - if chrg_level == 1 and stdby_level == 1: - # Not charge. - self.__charge_status = 0 - elif chrg_level == 0 and stdby_level == 1: - # Charging. - self.__charge_status = 1 - elif chrg_level == 1 and stdby_level == 0: - # Charge over. - self.__charge_status = 2 - else: - raise TypeError("CHRG and STDBY cannot be 0 at the same time!") - else: - self.__usb_charge() - - @property - def charge_status(self): - """Get charge status - Returns: - 0 - Not charged - 1 - Charging - 2 - Finished charging - """ - self.__update_charge_status() - return self.__charge_status - -``` - -### power_manage - -1. Function Description - -Wake up the device periodically and process business logic. After the business processing is completed, the device enters sleep mode. - -Two sleep modes are supported currently. - -- auto-sleepauto-sleep -- PSM - -2. Implementation Principle - -Set the corresponding sleep mode to make the device enter sleep mode, and wake up the device by RTC. - -```python -class PowerManage: - ... - - def autosleep(self, val): - """Set device autosleep. - - Args: - val (int): 0 - disable, 1 - enable. - - Returns: - bool: True - success. False - failed. - """ - return True if hasattr(pm, "autosleep") and val in (0, 1) and pm.autosleep(val) == 0 else False - - def set_psm(self, mode=1, tau=None, act=None): - """Set device psm. - - Args: - mode (int): 0 - disable psm, 1 - enable psm. - tau (int/None): tau seconds. When mode is 0, this value is None. (default: `None`) - act (int/None): act seconds. When mode is 0, this value is None. (default: `None`) - - Returns: - bool: True - success. False - failed. - """ - if not hasattr(pm, "set_psm_time") or not hasattr(pm, "get_psm_time"): - return False - if mode == 0: - return pm.set_psm_time(0) - else: - self.__init_tau(tau) - self.__init_act(act) - res = pm.set_psm_time(self.__tau_unit, self.__tau_time, self.__act_unit, self.__act_time) - log.info("set_psm_time: %s" % res) - if res: - get_psm_res = pm.get_psm_time() - log.debug("get_psm_res: %s" % str(get_psm_res)) - if get_psm_res[0] == 1 and get_psm_res[1:] == [self.__tau_unit, self.__tau_time, self.__act_unit, self.__act_time]: - log.debug("PSM time equal set time.") - return res -``` - -### aliyunIot - -1. Function Description - -Interact with Alibaba IoT Platform over the MQTT protocol. - -- Connect and log in to the platform -- Send TSL model data to the server -- Receive commands from the server -- Perform OTA upgrade - -> Alibaba IoT Platform over MQTT protocol is taken as an example here. The actual application should be developed according to the actual IoT platform and protocol and the basic logic is similar. - -2. Implementation Principle - -Log in to Alibaba IoT Platform and interact with it according to the communication rules over the MQTT protocol. - -- Register an account and log in - -```python -class AliIot: - ... - - def connect(self): - res = -1 - self.__server = "%s.%s" % (self.__product_key, self.__domain) - log.debug("self.__product_key: %s" % self.__product_key) - log.debug("self.__product_secret: %s" % self.__product_secret) - log.debug("self.__device_name: %s" % self.__device_name) - log.debug("self.__device_secret: %s" % self.__device_secret) - log.debug("self.__server: %s" % self.__server) - self.__server = aLiYun(self.__product_key, self.__product_secret, self.__device_name, self.__device_secret, self.__server) - res = self.__server.setMqtt(self.__device_name) - if res == 0: - self.__server.setCallback(self.__subscribe_callback) - res = self.__subscribe_topics() - if res == 0: - self.__server.start() - return res -``` - -- Report data - -```python -class AliIot: - ... - - def properties_report(self, data):. - # Report properties - _timestamp = self.__timestamp - _id = self.__id - params = {key: {"value": val, "time": _timestamp} for key, val in data.items()} - properties = { - "id": _id, - "version": "1.0", - "sys": { - "ack": 1 - }, - "params": params, - "method": "thing.event.property.post", - } - pub_res = self.__server.publish(self.ica_topic_property_post, ujson.dumps(properties), qos=self.__qos) if self.__server else -1 - return self.__get_post_res(_id) if pub_res is True else False - - def event_report(self, event, data): - # Report events - _timestamp = self.__timestamp - _id = self.__id - params = {"value": data, "time": _timestamp} - properties = { - "id": _id, - "version": "1.0", - "sys": { - "ack": 1 - }, - "params": params, - "method": "thing.event.%s.post" % event, - } - pub_res = self.__server.publish(self.ica_topic_event_post.format(event), ujson.dumps(properties), qos=self.__qos) if self.__server else -1 - return self.__get_post_res(_id) if pub_res is True else False -``` - -- Respond to the downlink data - -```python -class AliIot: - ... - - def __subscribe_callback(self, topic, data): - topic = topic.decode() - try: - data = ujson.loads(data) - except: - pass - log.debug("topic: %s, data: %s" % (topic, str(data))) - - if topic.endswith("/post_reply"): - self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False) - return - elif topic.endswith("/thing/ota/firmware/get_reply"): - self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False) - - if self.__callback and callable(self.__callback): - # Pass the data to Tracker.server_callback() for processing - self.__callback((topic, data)) -``` - -- OTA Upgrade - -```python -class AliIotOTA: - ... - - def start(self): - # Start an OTA upgrade - if self.__module == self.__project_name: - self.__start_sota() - elif self.__module == self.__firmware_name: - self.__start_fota() - else: - return False - return True - - def __start_fota(self): - log.debug("__start_fota") - fota_obj = fota() - url1 = self.__files[0]["url"] - url2 = self.__files[1]["url"] if len(self.__files) > 1 else "" - log.debug("start httpDownload") - if url2: - res = fota_obj.httpDownload(url1=url1, url2=url2, callback=self.__fota_callback) if fota_obj else -1 - else: - res = fota_obj.httpDownload(url1=url1, callback=self.__fota_callback) if fota_obj else -1 - log.debug("httpDownload res: %s" % res) - if res == 0: - self.__ota_timer.start(600 * 1000, 0, self.__ota_timer_callback) - fota_res = self.__fota_queue.get() - self.__ota_timer.stop() - return fota_res - else: - self.__server.ota_device_progress(-2, "Download File Failed.", module=self.__module) - return False -``` - -### UML Class Diagram - -The following is a UML class figure depicting the dependencies and inheritance relationships of all component objects in the project software codes. "Tracker" is the top-level object and is associated with the dependent component objects. - -![solution-tracker-104](./media/solution-tracker-104.png) - -## Event Flow Description - -### Business Process - -![solution-tracker-105](media/solution-tracker-105.png) - -Business Process Description: - -1. Power on the device. -2. Configure APN and connect to the network (network registration and data call); Configure IoT platform and establish a connection, with retry on failure. -3. Detect the boot of objects and acquire data. - - Power on the GNSS object and wait for positioning data. - - Power on the G-Sensor and detect the calibration. - - Turn on LED indicators (network status/positioning status/charging status, etc.). - - Acquire battery level and detect charging status. - - Detect alarms (overspeed/vibration/geo-fence/low battery level, etc.). -4. After connecting to the IoT platform, check if there is any historical data that needs to be reported and proceed with reporting. -5. Upon successful connection to the IoT platform, report current device information (location/alarms). -6. If the connection to the IoT platform fails, store the current device information (location/alarms). -7. When the device has no tasks, enter low power mode and wake up the device periodically to detect device information and report it. -8. After connecting to the IoT platform, wait for commands to be issued by the IoT platform -9. Parse commands - - Device control commands, such as modifying device business parameters and controlling device shutdown or reboot. - - OTA upgrade commands for OTA upgrades - - Device information query commands, which should be responded with device information - -### System Initialization Process - -![solution-tracker-106](media/solution-tracker-106.png) - -1. Initialize basic functional objects, such as low power management, configuration parameters, battery, historical files, positioning, and sensors. -2. Initialize IoT platform server object, such as Alibaba IoT Platform, ThingsBoard, or other private service platform (GT06, JT/T808, etc.). -3. Initialize the core business object (Tracker), and add various functional objects to the Tracker object through *tracker.add_module()*, then register *Tracker.server_callback()* to the Server object for receiving downlink messages and commands from the server. diff --git a/docs/en/Tracker solution implementation guide.md b/docs/en/Tracker solution implementation guide.md deleted file mode 100644 index b20a8b1..0000000 --- a/docs/en/Tracker solution implementation guide.md +++ /dev/null @@ -1,237 +0,0 @@ -[中文](../zh/定位器方案应用指导.md) | **English** | - -# Tracker Solution Application Note - -## Introduction - -This document introduces how to run the tracker solution program we provided on modules or devices. The operations demonstrated in this document are based on Quectel EG915U series module. - -## Get Solution Resource - -Tracker solution resources can be downloaded from [https://github.com/QuecPython/solution-tracker](https://github.com/QuecPython/solution-tracker) - -> The solution project has a sub-project named `modules`. Do not forget to download the sub-project together. -> -> The command for downloading the sub-project synchronously: `git clone --recursive https://github.com/QuecPython/solution-tracker.git` - -Resource package directory: - -![solution-tracker-001](./media/solution-tracker-001.png) - -- *code* - -This directory contains the software solution code. - -![solution-tracker-002](./media/solution-tracker-002.png) - -- *docs* - -This directory contains project documents such as user guides and functional interface specifications. - -![solution-tracker-003](./media/solution-tracker-003.png) - -- *object_model_demo* - -This directory contains a TSL model file of the Alibaba IoT Platform, which can be directly imported into the Alibaba IoT Platform for debugging. - -## Solution Overview - -This is a public version of the tracker solution, which does not include all functions. The solution provides the functional implementation of the core components of the tracker and functions such as data interaction, and event forwarding with the server. You can continue to develop business functions based on this framework. The current software framework has the following features: - -- Data interaction over MQTT (Alibaba IoT Platform and ThingsBoard are supported currently.) -- Read and write configuration file -- OTA upgrade -- LED indicator -- Device network management -- Device information management -- Battery level and charging management -- Backup data storage -- GNSS positioning/LBS positioning/Wi-Fi positioning -- Low power management -- Log storage and recording - -## Set up Environment - -### Install USB Driver - -Please download and install the driver according to the platform of the module to be debugged. [Click here to download USB Drivers](https://python.quectel.com/download) - -![solution-tracker-004](./media/solution-tracker-004.png) - -### Download Development and Debugging Tool - -It is recommended to use QPYcom for development and debugging. The processes described in this document are under the premise that QPYcom is used and USB driver installation is successful. - -[Click here to download QPYcom](https://python.quectel.com/download) - -![solution-tracker-005](./media/solution-tracker-005.png) - -[Click here to view QPYcom User Guide](https://python.quectel.com/doc/Application_guide/en/dev-tools/QPYcom/qpycom-gui.html) - -### Modify Code Configuration Parameters - -The configuration parameters used in the current solution code are not configured. Please modify configurations according to the instructions below. - -Find the configuration files starting with `settings_` in the *code* folder and modify the configuration based on actual parameters, as shown below. - -- `settings_server.py` is used to configure the IoT platform connection information. - -```python -class AliIotConfig: - - product_key = "" - product_secret = "" - device_name = "" - device_secret = "" - server = "iot-as-mqtt.cn-shanghai.aliyuncs.com" - qos = 1 - - -class ThingsBoardConfig: - - host = "" - port = 1883 - username = "" - qos = 0 - client_id = "" -``` - -- `settings_loc.py` is used to configure the information of the module used for positioning (UART port of the external GNSS communication, authentication information for LBS/Wi-Fi positioning). - -```python -gps_cfg = { - "UARTn": UART.UART1, - "buadrate": 115200, - "databits": 8, - "parity": 0, - "stopbits": 1, - "flowctl": 0, - "gps_mode": _gps_mode.external, - "nmea": 0b010111, - "PowerPin": None, - "StandbyPin": None, - "BackupPin": None, -} - -cell_cfg = { - "serverAddr": "www.queclocator.com", - "port": 80, - "token": "xxxxxxxxxx", - "timeout": 3, - "profileIdx": profile_idx, -} - -wifi_cfg = { - "token": "xxxxxxxxxx" -} -``` - -- `settings_user.py` is used to configure parameters related to user business functions (e.g., alarm switch, low battery level threshold). - -```python -class _server: - none = 0x0 - AliIot = 0x1 - ThingsBoard = 0x2 - -class _drive_behavior_code: - none = 0x0 - sharply_start = 0x1 - sharply_stop = 0x2 - sharply_turn_left = 0x3 - sharply_turn_right = 0x4 - -class _ota_upgrade_module: - none = 0x0 - sys = 0x1 - app = 0x2```markdown -debug = 1 -log_level = "DEBUG" -checknet_timeout = 60 -server = _server.AliIot -phone_num = "" -low_power_alert_threshold = 20 -low_power_shutdown_threshold = 5 -over_speed_threshold = 50 -sw_ota = 1 -sw_ota_auto_upgrade = 1 -sw_voice_listen = 0 -sw_voice_record = 0 -sw_fault_alert = 1 -sw_low_power_alert = 1 -sw_over_speed_alert = 1 -sw_sim_abnormal_alert = 1 -sw_disassemble_alert = 1 -sw_drive_behavior_alert = 1 -drive_behavior_code = _drive_behavior_code.none -loc_method = _loc_method.all -loc_gps_read_timeout = 300 -work_mode = _work_mode.cycle -work_mode_timeline = 3600 -work_cycle_period = 30 -user_ota_action = -1 -ota_status = { - "sys_current_version": "", - "sys_target_version": "--", - "app_current_version": "", - "app_target_version": "--", - "upgrade_module": _ota_upgrade_module.none, - "upgrade_status": _ota_upgrade_status.none, -} -``` - -### Download Firmware - -Download the corresponding QuecPython firmware according to the current debugging module model from the QuecPython official website, and download the firmware into the module with QPYcom. - -[Click here to download firmware](https://python.quectel.com/download) - -![solution-tracker-006](./media/solution-tracker-006.png) - -Use QPYcom to download firmware. - -1. Select firmware - -![solution-tracker-007](./media/solution-tracker-007.png) - -2. Download firmware - -![solution-tracker-008](./media/solution-tracker-008.png) - -3. Wait for the completion of firmware download - -![solution-tracker-009](./media/solution-tracker-009.png) - -4. Successful download - -![solution-tracker-010](./media/solution-tracker-010.png) - -5. Connect to the interactive port - -![solution-tracker-011](./media/solution-tracker-011.png) - -6. View the download information - -![solution-tracker-012](./media/solution-tracker-012.png) - -### Download Code - -- It is recommended to rename the *`main.py`* file to *`_main.py`* before downloading the code because the *`main.py`* file will run automatically when the module is powered on, which is not convenient for debugging. During the test, we can manually run the *`_main.py`* file for easier debugging. - -- When downloading the code via USB, you need to reserve a USB port or test point for the device. Or you can use an EVB for debugging, and install the driver in advance. - -1. Select "**`Quectel USB NMEA PORT`**". This serial port is for interaction, and QPYcom logs will also be output through this serial port. - -![solution-tracker-013](./media/solution-tracker-013.png) - -2. Download the business functional code to the device in batches. Click "**Download script**" and wait for the download to complete. After the download is complete, view the result on the "File" page. - -![solution-tracker-014](./media/solution-tracker-014.png) - -3. After successful download, it is recommended to reboot the device and run the function (If the *`main.py`* file was downloaded, the function will run automatically after the device is rebooted; if the *`main.py`* file was renamed to *`_main.py`* before downloading, you need to manually run the *`_main.py`* file to start the function). - -![solution-tracker-015](./media/solution-tracker-015.png) - -4. View the running result - -![solution-tracker-016](./media/solution-tracker-016.png) diff --git a/docs/en/media/C2Py.png b/docs/en/media/C2Py.png deleted file mode 100644 index b432d58..0000000 Binary files a/docs/en/media/C2Py.png and /dev/null differ diff --git a/docs/en/media/QPYCom_V3.3.0.png b/docs/en/media/QPYCom_V3.3.0.png deleted file mode 100644 index a29207e..0000000 Binary files a/docs/en/media/QPYCom_V3.3.0.png and /dev/null differ diff --git a/docs/en/media/connect.png b/docs/en/media/connect.png new file mode 100644 index 0000000..d41ac89 Binary files /dev/null and b/docs/en/media/connect.png differ diff --git a/docs/en/media/solution-tracker-001.png b/docs/en/media/solution-tracker-001.png deleted file mode 100644 index 66ac56a..0000000 Binary files a/docs/en/media/solution-tracker-001.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-002.png b/docs/en/media/solution-tracker-002.png deleted file mode 100644 index 460123a..0000000 Binary files a/docs/en/media/solution-tracker-002.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-003.png b/docs/en/media/solution-tracker-003.png deleted file mode 100644 index 4806307..0000000 Binary files a/docs/en/media/solution-tracker-003.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-004.png b/docs/en/media/solution-tracker-004.png deleted file mode 100644 index ffcfab5..0000000 Binary files a/docs/en/media/solution-tracker-004.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-005.png b/docs/en/media/solution-tracker-005.png deleted file mode 100644 index 967ab29..0000000 Binary files a/docs/en/media/solution-tracker-005.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-006.png b/docs/en/media/solution-tracker-006.png deleted file mode 100644 index b2caa51..0000000 Binary files a/docs/en/media/solution-tracker-006.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-007.png b/docs/en/media/solution-tracker-007.png deleted file mode 100644 index b0a55f1..0000000 Binary files a/docs/en/media/solution-tracker-007.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-008.png b/docs/en/media/solution-tracker-008.png deleted file mode 100644 index f93609d..0000000 Binary files a/docs/en/media/solution-tracker-008.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-009.png b/docs/en/media/solution-tracker-009.png deleted file mode 100644 index 88e83b9..0000000 Binary files a/docs/en/media/solution-tracker-009.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-010.png b/docs/en/media/solution-tracker-010.png deleted file mode 100644 index 2a9d813..0000000 Binary files a/docs/en/media/solution-tracker-010.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-011.png b/docs/en/media/solution-tracker-011.png deleted file mode 100644 index 7ac88c4..0000000 Binary files a/docs/en/media/solution-tracker-011.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-012.png b/docs/en/media/solution-tracker-012.png deleted file mode 100644 index 0797bc0..0000000 Binary files a/docs/en/media/solution-tracker-012.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-013.png b/docs/en/media/solution-tracker-013.png deleted file mode 100644 index 98b0a5b..0000000 Binary files a/docs/en/media/solution-tracker-013.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-014.png b/docs/en/media/solution-tracker-014.png deleted file mode 100644 index d683421..0000000 Binary files a/docs/en/media/solution-tracker-014.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-015.png b/docs/en/media/solution-tracker-015.png deleted file mode 100644 index b480370..0000000 Binary files a/docs/en/media/solution-tracker-015.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-016.png b/docs/en/media/solution-tracker-016.png deleted file mode 100644 index 4724a67..0000000 Binary files a/docs/en/media/solution-tracker-016.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-101.png b/docs/en/media/solution-tracker-101.png deleted file mode 100644 index 7a44231..0000000 Binary files a/docs/en/media/solution-tracker-101.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-102.png b/docs/en/media/solution-tracker-102.png deleted file mode 100644 index 9485afe..0000000 Binary files a/docs/en/media/solution-tracker-102.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-104.png b/docs/en/media/solution-tracker-104.png deleted file mode 100644 index f6aab3b..0000000 Binary files a/docs/en/media/solution-tracker-104.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-105.png b/docs/en/media/solution-tracker-105.png deleted file mode 100644 index d4ac95d..0000000 Binary files a/docs/en/media/solution-tracker-105.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-106.png b/docs/en/media/solution-tracker-106.png deleted file mode 100644 index 5ac9736..0000000 Binary files a/docs/en/media/solution-tracker-106.png and /dev/null differ diff --git a/docs/en/media/solution-tracker-107.png b/docs/en/media/solution-tracker-107.png deleted file mode 100644 index 98a27e6..0000000 Binary files a/docs/en/media/solution-tracker-107.png and /dev/null differ diff --git a/docs/en/media/tracker_alert.png b/docs/en/media/tracker_alert.png deleted file mode 100644 index 7767e83..0000000 Binary files a/docs/en/media/tracker_alert.png and /dev/null differ diff --git a/docs/en/media/tracker_application.png b/docs/en/media/tracker_application.png index 328259d..8309e6d 100644 Binary files a/docs/en/media/tracker_application.png and b/docs/en/media/tracker_application.png differ diff --git a/docs/en/media/tracker_funcion.png b/docs/en/media/tracker_funcion.png index 049b410..a7cbc61 100644 Binary files a/docs/en/media/tracker_funcion.png and b/docs/en/media/tracker_funcion.png differ diff --git a/docs/zh/media/C2Py.png b/docs/zh/media/C2Py.png deleted file mode 100644 index b432d58..0000000 Binary files a/docs/zh/media/C2Py.png and /dev/null differ diff --git a/docs/zh/media/QPYCom_V2.1.png b/docs/zh/media/QPYCom_V2.1.png deleted file mode 100644 index 00726aa..0000000 Binary files a/docs/zh/media/QPYCom_V2.1.png and /dev/null differ diff --git a/docs/zh/media/QPYCom_V3.3.0.png b/docs/zh/media/QPYCom_V3.3.0.png deleted file mode 100644 index 5f62a0f..0000000 Binary files a/docs/zh/media/QPYCom_V3.3.0.png and /dev/null differ diff --git a/docs/zh/media/aliyun_create_device.png b/docs/zh/media/aliyun_create_device.png deleted file mode 100644 index 88f9181..0000000 Binary files a/docs/zh/media/aliyun_create_device.png and /dev/null differ diff --git a/docs/zh/media/aliyun_create_object_model.png b/docs/zh/media/aliyun_create_object_model.png deleted file mode 100644 index 84bcae4..0000000 Binary files a/docs/zh/media/aliyun_create_object_model.png and /dev/null differ diff --git a/docs/zh/media/aliyun_create_product.png b/docs/zh/media/aliyun_create_product.png deleted file mode 100644 index 751d596..0000000 Binary files a/docs/zh/media/aliyun_create_product.png and /dev/null differ diff --git a/docs/zh/media/aliyun_create_product_detail.png b/docs/zh/media/aliyun_create_product_detail.png deleted file mode 100644 index 77fe65c..0000000 Binary files a/docs/zh/media/aliyun_create_product_detail.png and /dev/null differ diff --git a/docs/zh/media/aliyun_export_lite_mode_object_model.png b/docs/zh/media/aliyun_export_lite_mode_object_model.png deleted file mode 100644 index 073cd76..0000000 Binary files a/docs/zh/media/aliyun_export_lite_mode_object_model.png and /dev/null differ diff --git a/docs/zh/media/aliyun_import_object_model.png b/docs/zh/media/aliyun_import_object_model.png deleted file mode 100644 index bab8480..0000000 Binary files a/docs/zh/media/aliyun_import_object_model.png and /dev/null differ diff --git a/docs/zh/media/aliyun_online_send_message.png b/docs/zh/media/aliyun_online_send_message.png deleted file mode 100644 index a74c18c..0000000 Binary files a/docs/zh/media/aliyun_online_send_message.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_fota_module.png b/docs/zh/media/aliyun_ota_fota_module.png deleted file mode 100644 index 16c4ea3..0000000 Binary files a/docs/zh/media/aliyun_ota_fota_module.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_fota_plain.png b/docs/zh/media/aliyun_ota_fota_plain.png deleted file mode 100644 index 1e3e689..0000000 Binary files a/docs/zh/media/aliyun_ota_fota_plain.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_fota_upgrade_package.png b/docs/zh/media/aliyun_ota_fota_upgrade_package.png deleted file mode 100644 index fdfb1c0..0000000 Binary files a/docs/zh/media/aliyun_ota_fota_upgrade_package.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_fota_upgrade_process.png b/docs/zh/media/aliyun_ota_fota_upgrade_process.png deleted file mode 100644 index 110e20b..0000000 Binary files a/docs/zh/media/aliyun_ota_fota_upgrade_process.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_sota_module.png b/docs/zh/media/aliyun_ota_sota_module.png deleted file mode 100644 index b330880..0000000 Binary files a/docs/zh/media/aliyun_ota_sota_module.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_sota_plain.png b/docs/zh/media/aliyun_ota_sota_plain.png deleted file mode 100644 index 6444cd7..0000000 Binary files a/docs/zh/media/aliyun_ota_sota_plain.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_sota_upgrade_package.png b/docs/zh/media/aliyun_ota_sota_upgrade_package.png deleted file mode 100644 index e7090ed..0000000 Binary files a/docs/zh/media/aliyun_ota_sota_upgrade_package.png and /dev/null differ diff --git a/docs/zh/media/aliyun_ota_sota_upgrade_process.png b/docs/zh/media/aliyun_ota_sota_upgrade_process.png deleted file mode 100644 index 559053a..0000000 Binary files a/docs/zh/media/aliyun_ota_sota_upgrade_process.png and /dev/null differ diff --git a/docs/zh/media/aliyun_tracker_running_saas_view.png b/docs/zh/media/aliyun_tracker_running_saas_view.png deleted file mode 100644 index efa4897..0000000 Binary files a/docs/zh/media/aliyun_tracker_running_saas_view.png and /dev/null differ diff --git a/docs/zh/media/qpycom_download.png b/docs/zh/media/qpycom_download.png deleted file mode 100644 index b60dccb..0000000 Binary files a/docs/zh/media/qpycom_download.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-001.png b/docs/zh/media/solution-tracker-001.png deleted file mode 100644 index 66ac56a..0000000 Binary files a/docs/zh/media/solution-tracker-001.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-002.png b/docs/zh/media/solution-tracker-002.png deleted file mode 100644 index 460123a..0000000 Binary files a/docs/zh/media/solution-tracker-002.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-003.png b/docs/zh/media/solution-tracker-003.png deleted file mode 100644 index 045d9bf..0000000 Binary files a/docs/zh/media/solution-tracker-003.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-004.png b/docs/zh/media/solution-tracker-004.png deleted file mode 100644 index d52a88c..0000000 Binary files a/docs/zh/media/solution-tracker-004.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-005.png b/docs/zh/media/solution-tracker-005.png deleted file mode 100644 index 9b1dbb0..0000000 Binary files a/docs/zh/media/solution-tracker-005.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-006.png b/docs/zh/media/solution-tracker-006.png deleted file mode 100644 index b8dd5fb..0000000 Binary files a/docs/zh/media/solution-tracker-006.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-007.png b/docs/zh/media/solution-tracker-007.png deleted file mode 100644 index 1952d0a..0000000 Binary files a/docs/zh/media/solution-tracker-007.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-008.png b/docs/zh/media/solution-tracker-008.png deleted file mode 100644 index 5105547..0000000 Binary files a/docs/zh/media/solution-tracker-008.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-009.png b/docs/zh/media/solution-tracker-009.png deleted file mode 100644 index 52e3a88..0000000 Binary files a/docs/zh/media/solution-tracker-009.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-010.png b/docs/zh/media/solution-tracker-010.png deleted file mode 100644 index dc51f07..0000000 Binary files a/docs/zh/media/solution-tracker-010.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-011.png b/docs/zh/media/solution-tracker-011.png deleted file mode 100644 index cc4b964..0000000 Binary files a/docs/zh/media/solution-tracker-011.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-012.png b/docs/zh/media/solution-tracker-012.png deleted file mode 100644 index 0052db0..0000000 Binary files a/docs/zh/media/solution-tracker-012.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-013.png b/docs/zh/media/solution-tracker-013.png deleted file mode 100644 index fd7f354..0000000 Binary files a/docs/zh/media/solution-tracker-013.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-014.png b/docs/zh/media/solution-tracker-014.png deleted file mode 100644 index 0d0845b..0000000 Binary files a/docs/zh/media/solution-tracker-014.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-015.png b/docs/zh/media/solution-tracker-015.png deleted file mode 100644 index b1b07d3..0000000 Binary files a/docs/zh/media/solution-tracker-015.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-016.png b/docs/zh/media/solution-tracker-016.png deleted file mode 100644 index 7e18beb..0000000 Binary files a/docs/zh/media/solution-tracker-016.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-101.png b/docs/zh/media/solution-tracker-101.png deleted file mode 100644 index 3e8afed..0000000 Binary files a/docs/zh/media/solution-tracker-101.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-102.png b/docs/zh/media/solution-tracker-102.png deleted file mode 100644 index 4c29c47..0000000 Binary files a/docs/zh/media/solution-tracker-102.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-103.png b/docs/zh/media/solution-tracker-103.png deleted file mode 100644 index cdb9a66..0000000 Binary files a/docs/zh/media/solution-tracker-103.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-104.png b/docs/zh/media/solution-tracker-104.png deleted file mode 100644 index f6aab3b..0000000 Binary files a/docs/zh/media/solution-tracker-104.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-105.png b/docs/zh/media/solution-tracker-105.png deleted file mode 100644 index c82d4f9..0000000 Binary files a/docs/zh/media/solution-tracker-105.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-106.png b/docs/zh/media/solution-tracker-106.png deleted file mode 100644 index a024c88..0000000 Binary files a/docs/zh/media/solution-tracker-106.png and /dev/null differ diff --git a/docs/zh/media/solution-tracker-107.png b/docs/zh/media/solution-tracker-107.png deleted file mode 100644 index e0ac68d..0000000 Binary files a/docs/zh/media/solution-tracker-107.png and /dev/null differ diff --git a/docs/zh/media/tracker_alert.png b/docs/zh/media/tracker_alert.png deleted file mode 100644 index c829d6e..0000000 Binary files a/docs/zh/media/tracker_alert.png and /dev/null differ diff --git a/docs/zh/media/tracker_code_import.png b/docs/zh/media/tracker_code_import.png deleted file mode 100644 index 07a9477..0000000 Binary files a/docs/zh/media/tracker_code_import.png and /dev/null differ diff --git a/docs/zh/media/tracker_modules_registration_process.png b/docs/zh/media/tracker_modules_registration_process.png deleted file mode 100644 index 9949cbe..0000000 Binary files a/docs/zh/media/tracker_modules_registration_process.png and /dev/null differ diff --git a/docs/zh/media/tracker_running.png b/docs/zh/media/tracker_running.png deleted file mode 100644 index 98207cf..0000000 Binary files a/docs/zh/media/tracker_running.png and /dev/null differ diff --git "a/docs/zh/media/\350\277\236\347\272\277.png" "b/docs/zh/media/\350\277\236\347\272\277.png" new file mode 100644 index 0000000..d41ac89 Binary files /dev/null and "b/docs/zh/media/\350\277\236\347\272\277.png" differ diff --git "a/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\345\272\224\347\224\250\346\214\207\345\257\274.md" "b/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\345\272\224\347\224\250\346\214\207\345\257\274.md" deleted file mode 100644 index fd13c01..0000000 --- "a/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\345\272\224\347\224\250\346\214\207\345\257\274.md" +++ /dev/null @@ -1,238 +0,0 @@ -**中文** | [English](../en/Tracker%20solution%20implementation%20guide.md) | - -# 定位器方案应用指导 - -## 引言 - -本文档用于介绍如何在模组或设备上运行我们提供的定位器方案程序, 当前文档操作基于EG915U型号模组进行展示。 - -## 方案资源获取 - -定位器解决方案资源下载地址: https://github.com/QuecPython/solution-tracker - -> 该方案项目有一个`modules`子仓库, 在下载时需要注意同步下载 -> -> 子仓库同步下载指令`git clone --recursive https://github.com/QuecPython/solution-tracker.git` - -资源包目录展示: - -![solution-tracker-001](./media/solution-tracker-001.png) - -- code 文件夹: - -该目录下包含软件方案代码 - -![solution-tracker-002](./media/solution-tracker-002.png) - -- docs 文件夹: - -该目录下包含用户指导手册与功能接口说明的项目文档 - -![solution-tracker-003](./media/solution-tracker-003.png) - -- object_model_demo 文件夹: - -该目录下提供了一个阿里Iot平台的物模型文件, 可以直接导入阿里Iot平台, 方便调试 - -## 方案说明 - -此方案为定位器公版方案, 不包含全部业务功能, 方案提供定位器业务核心组件的功能实现以及与服务端完成数据交互, 事件转发等功能, 使用者应基于此框架继续开发业务功能, 当前软件框架完成功能如下: - -- MQTT协议通讯(当前方案支持阿里Iot平台/ThingsBoard平台) -- 配置文件读写 -- OTA远程升级 -- LED指示灯 -- 设备网络管理 -- 设备信息管理 -- 电池电量与充电管理 -- 备份信息存储 -- GNSS定位/基站定位/Wifi定位 -- 低功耗管理 -- 日志存储记录 - -## 环境搭建 - -### USB驱动安装 - -请根据调试模组平台进行驱动下载安装, [点击此处下载](https://python.quectel.com/download) - -![solution-tracker-004](./media/solution-tracker-004.png) - -### 开发调试工具 - -推荐使用QPYcom进行开发调试, 此文档中的流程介绍均使用该工具进行, 且成功安装USB驱动 - -工具下载链接: [点击此处下载](https://python.quectel.com/download) - -![solution-tracker-005](./media/solution-tracker-005.png) - -工具使用说明: [点击此处访问](https://python.quectel.com/doc/Application_guide/en/dev-tools/QPYcom/qpycom-gui.html) - -### 代码配置参数修改 - -目前方案代码使用的配置参数未进行配置, 请按照下面说明进行更改。 - -找到code中的以`settings_`开头的配置文件进行配置, 根据实际参数进行调整, 如下图: - -- `settings_server.py` 用于配置连接的 IoT 平台连接信息 - -```python -class AliIotConfig: - - product_key = "" - product_secret = "" - device_name = "" - device_secret = "" - server = "iot-as-mqtt.cn-shanghai.aliyuncs.com" - qos = 1 - - -class ThingsBoardConfig: - - host = "" - port = 1883 - username = "" - qos = 0 - client_id = "" -``` - -- `settings_loc.py` 用于配置定位模块的配置信息(外挂GNSS串口, 基站/Wifi定位的认证信息) - -```python -gps_cfg = { - "UARTn": UART.UART1, - "buadrate": 115200, - "databits": 8, - "parity": 0, - "stopbits": 1, - "flowctl": 0, - "gps_mode": _gps_mode.external, - "nmea": 0b010111, - "PowerPin": None, - "StandbyPin": None, - "BackupPin": None, -} - -cell_cfg = { - "serverAddr": "www.queclocator.com", - "port": 80, - "token": "xxxxxxxxxx", - "timeout": 3, - "profileIdx": profile_idx, -} - -wifi_cfg = { - "token": "xxxxxxxxxx" -} -``` - -- `settings_user.py` 用于配置用户业务功能的相关配置参数(如报警开关, 低电阈值等) - -```python -class _server: - none = 0x0 - AliIot = 0x1 - ThingsBoard = 0x2 - -class _drive_behavior_code: - none = 0x0 - sharply_start = 0x1 - sharply_stop = 0x2 - sharply_turn_left = 0x3 - sharply_turn_right = 0x4 - -class _ota_upgrade_module: - none = 0x0 - sys = 0x1 - app = 0x2 - -debug = 1 -log_level = "DEBUG" -checknet_timeout = 60 -server = _server.AliIot -phone_num = "" -low_power_alert_threshold = 20 -low_power_shutdown_threshold = 5 -over_speed_threshold = 50 -sw_ota = 1 -sw_ota_auto_upgrade = 1 -sw_voice_listen = 0 -sw_voice_record = 0 -sw_fault_alert = 1 -sw_low_power_alert = 1 -sw_over_speed_alert = 1 -sw_sim_abnormal_alert = 1 -sw_disassemble_alert = 1 -sw_drive_behavior_alert = 1 -drive_behavior_code = _drive_behavior_code.none -loc_method = _loc_method.all -loc_gps_read_timeout = 300 -work_mode = _work_mode.cycle -work_mode_timeline = 3600 -work_cycle_period = 30 -user_ota_action = -1 -ota_status = { - "sys_current_version": "", - "sys_target_version": "--", - "app_current_version": "", - "app_target_version": "--", - "upgrade_module": _ota_upgrade_module.none, - "upgrade_status": _ota_upgrade_status.none, -} -``` - -### 烧录固件 - -根据当前调试模组型号下载对应QuecPython固件, 并使用Qpycom工具进行烧录 - -固件下载地址: [点击此处访问](https://python.quectel.com/download) - -![solution-tracker-006](./media/solution-tracker-006.png) - -使用QPYcom工具下载固件 - -1. 选择固件 - -![solution-tracker-007](./media/solution-tracker-007.png) - -2. 下载固件 - -![solution-tracker-008](./media/solution-tracker-008.png) - -3. 等待固件烧录 - -![solution-tracker-009](./media/solution-tracker-009.png) - -4. 烧录成功 - -![solution-tracker-010](./media/solution-tracker-010.png) - -5. 连接交互口 - -![solution-tracker-011](./media/solution-tracker-011.png) - -6. 查看烧录信息 - -![solution-tracker-012](./media/solution-tracker-012.png) - -### 烧录代码 - -- 建议在下载代码前将文件中的`main.py`重命名为`_main.py`, 因为`main.py`会上电自运行, 不方便调试, 我们测试阶段可以手动执行`_main.py`来运行, 方便调试问题 - -- 通过USB下载代码需要设备预留USB接口或测试点, 或使用开发板进行调试, 并提前安装好驱动 - -1. 选择`Quectel USB NMEA PORT`, 该串口为交互口, 程序LOG也会通过该串口输出 - -![solution-tracker-013](./media/solution-tracker-013.png) - -2. 将业务功能代码批量烧录设备, 点击下载脚本后等待下载完成, 下载完成后在文件中查看 - -![solution-tracker-014](./media/solution-tracker-014.png) - -3. 烧录成功后建议重启设备, 然后运行功能(如烧录了`main.py`, 则重启设备后, 功能会自动运行, 如已将`main.py`重命名后烧录, 则需手动运行`_main.py`启动功能) - -![solution-tracker-015](./media/solution-tracker-015.png) - -4. 运行结果展示 - -![solution-tracker-016](./media/solution-tracker-016.png) diff --git "a/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\350\256\276\350\256\241\346\214\207\345\257\274.md" "b/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\350\256\276\350\256\241\346\214\207\345\257\274.md" deleted file mode 100644 index 3dedbc3..0000000 --- "a/docs/zh/\345\256\232\344\275\215\345\231\250\346\226\271\346\241\210\350\256\276\350\256\241\346\214\207\345\257\274.md" +++ /dev/null @@ -1,833 +0,0 @@ -**中文** | [English](../en/Tracker%20solution%20design%20guide.md) | - -# 定位器方案设计指导 - -## 引言 - -本文档主要描述移远通信QuecPython定位器的设计框架, 包含软硬件系统框架、关键组件功能描述、系统初始化流程和业务流程的介绍以及功能示例, 方便用户快速了解QuecPython定位器的整体架构与功能。 - -## 功能简介 - -智能定位器方案中的软件功能介绍如下图所示, 方案根据定位器实际业务进行功能拆分, 模块化开发实现。 - -![solution-tracker-101](./media/solution-tracker-101.png) - -- 传输协议解析 - + 阿里Iot平台连接与数据交互 - + ThingsBoard平台连接与数据交互 - + GT06协议 - + JT/T808协议 -- 网络管理 - + MQTT协议(阿里Iot/ThingsBoard/其他平台) - + TCP/UDP协议(GT06/JTT808协议) - + APN设置(用于注网拨号) - + LTE NET(4G注网拨号) -- 外设管理 - + GNSS定位数据的读取, 使能, AGPS注入等 - + G-Sensor传感器数据读取 - + Charge IC充电管理, 获取设备充电状态 - + Battery电池管理, 读取电池电压, 换算电量 - + LED指示灯 -- 数据存储 - + 系统配置参数存储 - + 定位数据补传存储 - + AGPS下载存储 - + 日志信息存储 -- 设备升级 - + OTA升级 -- 业务功能管理 - + 网络与IoT 平台的连接与重连 - + 设备数据采集与上报 - + 报警检测与上报 - + IoT 平台下行指令处理 - + 设备低功耗休眠 - -## 数据交互流程 - -模组、IoT 平台之间数据交互流程如下图介绍: - -![solution-tracker-102](./media/solution-tracker-102.png) - -流程描述: - -1. 手机APP发送指令到IoT 平台, 服务端通过TCP/UDP/MQTT协议下发指令数据到模组端接收, 模组进行解析处理; -2. 模组通过TCP/UDP/MQTT协议上报数据到IoT 平台, IoT 平台进行处理, 同步显示到手机端 - -## 软件框架 - -### 设计思想与模式 - -- 本系统采用监听者模式设计,通过回调函数进行消息的传递事件的监听 -- 软件根据定位器业务需求对其功能进行拆分, 主要分模块来实现, 每个部分独立开发实现, 相互之间减少依赖, 可独立调试运行, 达到解耦合的效果; -- 功能之间的事件交互都通过回调函数来完成, 所有的业务功能处理全部在`Tracker`类中进行处理, 如下行的指令处理, 报警检测, 数据采集与上报, 设备的控制等。 - -![solution-tracker-104](./media/solution-tracker-104.png) - -1. 所有的功能模块通过`Tracker.add_module`注册到`Tracker`类中进行控制 -2. Server模块(IoT 平台交互模块)通过回调将服务型下行的数据传递到`Tracker.server_callback`中进行处理 -3. NetManage模块通过回调将网络断开连接事件传递到`Tracker.net_callback`中进行处理 - -### 软件架构图 - -软件系统框架介绍描述如下: - -- 展现层, 对接不同的 IoT 平台 -- 传输层, 使用不同的协议进行交互 -- 业务层, 主要用于采集设备数据, 控制设备模块, 接收处理IoT 平台下行指令, 数据的整合上报 -- 设备层, 主要是定位数据的获取与解析, 传感器数据的读取, 电池管理, 历史数据存储等功能, 设备数据的信息的采集与设备功能设置, 如设备的版本信息, IMEI号, APN设置, 网络拨号, 设备低功耗等 - -![solution-tracker-107](./media/solution-tracker-107.png) - -## 功能组件介绍 - -### 核心业务模块(Tracker) - -1. 功能描述: - -实现核心业务逻辑, 与服务端的数据交互解析, 设备模块的控制, 所有功能以事件的形式, 传入业务事件消息队列子线程中处理。 - -2. 实现原理: - -- 通过注册功能模块, 获取各个功能模块的数据, 如定位信息, 电池信息, 传感器信息等; - -```python -class Tracker: - ... - - def add_module(self, module): - # 将各个功能模块注册到Tracker类中,在Tracker类中进行控制 - if isinstance(module, AliIot): - self.__server = module - elif isinstance(module, AliIotOTA): - self.__server_ota = module - elif isinstance(module, Battery): - self.__battery = module - elif isinstance(module, History): - self.__history = module - elif isinstance(module, GNSS): - self.__gnss = module - elif isinstance(module, CellLocator): - self.__cell = module - elif isinstance(module, WiFiLocator): - self.__wifi = module - elif isinstance(module, NMEAParse): - self.__nmea_parse = module - elif isinstance(module, CoordinateSystemConvert): - self.__csc = module - elif isinstance(module, NetManage): - self.__net_manage = module - elif isinstance(module, PowerManage): - self.__pm = module - elif isinstance(module, TempHumiditySensor): - self.__temp_sensor = module - elif isinstance(module, Settings): - self.__settings = module - else: - return False - return True - - def running(self, args=None): - if self.__running_tag == 1: - return - self.__running_tag = 1 - # 禁用设备休眠 - self.__pm.autosleep(0) - self.__pm.set_psm(mode=0) - # 启动业务事件消息队列监听子线程 - self.__business_start() - # 发送OTA版本刷新指令到事件队列中进行执行 - self.__business_queue.put((0, "ota_refresh")) - # 发送上报定位数据事件(包含网络的连接,设备数据的采集,设备数据的上报) - self.__business_queue.put((0, "loc_report")) - # 发送OTA升级查询指令事件 - self.__business_queue.put((0, "check_ota")) - # 发送设备休眠事件 - self.__business_queue.put((0, "into_sleep")) - self.__running_tag = 0 -``` - -- 通过回调监听服务端下发的指令消息, 进行业务处理; - -```python -class Tracker: - ... - - def server_callback(self, args): - # 服务端下行消息传入业务事件消息队列中进行处理 - self.__business_queue.put((1, args)) -``` - -```python -class Tracker: - ... - - def __business_running(self): - while True: - data = self.__business_queue.get() - with self.__business_lock: - self.__business_tag = 1 - ... - # 处理IoT 平台下行指令功能 - if data[0] == 1: - self.__server_option(*data[1]) - self.__business_tag = 0 -``` - -```python -class Tracker: - ... - - def __server_option(self, topic, data): - if topic.endswith("/property/set"): - # 处理属性设置的下行消息 - self.__server_property_set(data) - elif topic.find("/rrpc/request/") != -1: - # 处理透传数据的下行消息 - msg_id = topic.split("/")[-1] - self.__server_rrpc_response(msg_id, data) - elif topic.find("/thing/service/") != -1: - # 处理服务数据的下行消息 - service = topic.split("/")[-1] - self.__server_service_response(service, data) - elif topic.startswith("/ota/device/upgrade/") or topic.endswith("/ota/firmware/get_reply"): - # 处理OTA升级的下行消息 - user_cfg = self.__settings.read("user") - if self.__server_ota_flag == 0: - if user_cfg["sw_ota"] == 1: - self.__server_ota_flag = 1 - if user_cfg["sw_ota_auto_upgrade"] == 1 or user_cfg["user_ota_action"] == 1: - # 满足OTA升级条件,执行OTA升级流程 - self.__server_ota_process(data) - else: - self.__server_ota_flag = 0 - self.__server_ota.set_ota_data(data["data"]) - ota_info = self.__server_ota.get_ota_info() - ota_info["ota_status"] = 1 - self.__server_ota_state_save(**ota_info) - else: - module = data.get("data", {}).get("module") - self.__server.ota_device_progress(-1, "Device is not alowed ota.", module) -``` - -- 通过RTC回调唤醒操作, 唤醒设备休眠, 进行业务数据上报. - -```python -class Tracker: - ... - - def __into_sleep(self): - while True: - if self.__business_queue.size() == 0 and self.__business_tag == 0: - break - utime.sleep_ms(500) - user_cfg = self.__settings.read("user") - # 根据休眠时长自动调整休眠模式,autosleep或者psm - if user_cfg["work_cycle_period"] < user_cfg["work_mode_timeline"]: - self.__pm.autosleep(1) - else: - self.__pm.set_psm(mode=1, tau=user_cfg["work_cycle_period"], act=5) - # 启动RTC定时唤醒设备 - self.__set_rtc(user_cfg["work_cycle_period"], self.running) - - def __set_rtc(self, period, callback): - # 设置RTC唤醒时钟,唤醒设备 - self.__business_rtc.enable_alarm(0) - if callback and callable(callback): - self.__business_rtc.register_callback(callback) - atime = utime.localtime(utime.mktime(utime.localtime()) + period) - alarm_time = (atime[0], atime[1], atime[2], atime[6], atime[3], atime[4], atime[5], 0) - _res = self.__business_rtc.set_alarm(alarm_time) - log.debug("alarm_time: %s, set_alarm res %s." % (str(alarm_time), _res)) - return self.__business_rtc.enable_alarm(1) if _res == 0 else -1 -``` - -3. 注册功能模块与回调函数配置 - -```python -def main(): - # 初始化网络功能模块 - net_manage = NetManage(PROJECT_NAME, PROJECT_VERSION) - # 初始化配置参数功能模块 - settings = Settings() - # 初始化电池检测功能模块 - battery = Battery() - # 初始化历史数据功能模块 - history = History() - # 初始化IoT 平台(阿里Iot)功能模块 - server_cfg = settings.read("server") - server = AliIot(**server_cfg) - # 初始化IoT 平台(阿里Iot)OTA功能模块 - server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) - server_ota.set_server(server) - # 初始化低功耗功能模块 - power_manage = PowerManage() - # 初始化温湿度传感器功能模块 - temp_sensor = TempHumiditySensor(i2cn=I2C.I2C1, mode=I2C.FAST_MODE) - loc_cfg = settings.read("loc") - # 初始化GNSS定位功能模块 - gnss = GNSS(**loc_cfg["gps_cfg"]) - # 初始化基站定位功能模块 - cell = CellLocator(**loc_cfg["cell_cfg"]) - # 初始化Wifi定位功能模块 - wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) - # 初始化GNSS定位数据解析功能模块 - nmea_parse = NMEAParse() - # 初始化WGS84与GCJ02坐标系转换功能模块 - cyc = CoordinateSystemConvert() - - # 初始化Tracker业务功能模块 - tracker = Tracker() - # 将基础功能模块注册到Tracker类中进行控制 - tracker.add_module(settings) - tracker.add_module(battery) - tracker.add_module(history) - tracker.add_module(net_manage) - tracker.add_module(server) - tracker.add_module(server_ota) - tracker.add_module(power_manage) - tracker.add_module(temp_sensor) - tracker.add_module(gnss) - tracker.add_module(cell) - tracker.add_module(wifi) - tracker.add_module(nmea_parse) - tracker.add_module(cyc) - - # 设置网络模块的回调, 当网络断开,进行业务处理 - net_manage.set_callback(tracker.net_callback) - # 设置服务端下行数据接收的回调,当服务端下发指令时,进行业务处理 - server.set_callback(tracker.server_callback) - - # 启动Tracker项目业务功能. - tracker.running() - - -if __name__ == "__main__": - # 主文件启动 - main() -``` - -### 定位模块(loction) - -1. 功能描述: - -通过内置或外挂GNSS, 基站, Wifi获取当前设备定位信息。 - -2. 实现原理: - -- 内置GNSS通过quecgnss接口开启与读取GNSS数据; - -```python -class GNSS: - ... - - def __internal_read(self): - log.debug("__internal_read start.") - # 开启GNSS - self.__internal_open() - - # 清除串口缓存的GNSS历史数据 - while self.__break == 0: - gnss_data = quecgnss.read(1024) - if gnss_data[0] == 0: - self.__break = 1 - self.__break = 0 - - self.__gps_nmea_data_clean() - self.__gps_data_check_timer.start(2000, 1, self.__gps_data_check_callback) - cycle = 0 - # 读取GNSS原始数据 - while self.__break == 0: - gnss_data = quecgnss.read(1024) - if gnss_data and gnss_data[1]: - this_gps_data = gnss_data[1].decode() if len(gnss_data) > 1 and gnss_data[1] else "" - self.__reverse_gps_data(this_gps_data) - if self.__check_gps_valid(): - self.__break = 1 - cycle += 1 - if cycle >= self.__retry: - if self.__break != 1: - self.__break = 1 - if self.__break != 1: - utime.sleep(1) - self.__gps_data_check_timer.stop() - self.__break = 0 - - self.__gps_data_check_callback(None) - # 关闭GNSS - self.__internal_close() - log.debug("__internal_read %s." % ("success" if self.__get_gps_data() else "failed")) - return self.__get_gps_data() -``` - -- 外挂GNSS通过UART串口读取GNSS数据; - -```python -class GNSS: - ... - - def __external_read(self): - # 开启GNSS UART串口 - self.__external_open() - log.debug("__external_read start") - - # 清除串口缓存的GNSS历史数据 - while self.__break == 0: - self.__gps_timer.start(50, 0, self.__gps_timer_callback) - signal = self.__external_retrieve_queue.get() - log.debug("[first] signal: %s" % signal) - if signal: - to_read = self.__external_obj.any() - log.debug("[first] to_read: %s" % to_read) - if to_read > 0: - self.__set_gps_data(self.__external_obj.read(to_read).decode()) - self.__gps_timer.stop() - self.__break = 0 - - self.__gps_nmea_data_clean() - self.__gps_data_check_timer.start(2000, 1, self.__gps_data_check_callback) - cycle = 0 - # 读取GNSS原始数据 - while self.__break == 0: - self.__gps_timer.start(1500, 0, self.__gps_timer_callback) - signal = self.__external_retrieve_queue.get() - log.debug("[second] signal: %s" % signal) - if signal: - to_read = self.__external_obj.any() - log.debug("[second] to_read: %s" % to_read) - if to_read > 0: - self.__reverse_gps_data(self.__external_obj.read(to_read).decode()) - if self.__check_gps_valid(): - self.__break = 1 - - self.__gps_timer.stop() - cycle += 1 - if cycle >= self.__retry: - self.__break = 1 - if self.__break != 1: - utime.sleep(1) - self.__gps_data_check_timer.stop() - self.__break = 0 - - # To check GPS data is usable or not. - self.__gps_data_check_callback(None) - # 关闭GNSS串口 - self.__external_close() - log.debug("__external_read %s." % ("success" if self.__get_gps_data() else "failed")) - return self.__get_gps_data() -``` - -- 基站定位通过cellLocator基站定位接口获取基站定位经纬度, 精度等信息; - -```python -class CellLocator: - ... - - def __read_thread(self): - loc_data = () - try: - # 读取基站定位信息 - loc_data = cellLocator.getLocation( - self.__serverAddr, - self.__port, - self.__token, - self.__timeout, - self.__profileIdx - ) - loc_data = loc_data if isinstance(loc_data, tuple) and loc_data[0] and loc_data[1] else () - except Exception as e: - sys.print_exception(e) - self.__queue.put(loc_data) -``` - -- Wifi定位通过wifilocator和wifiScan接口获取定位经纬度, 精度, mac地址等信息。 - -```python -class WiFiLocator: - - def __init__(self, token): - self.__wifilocator = wifilocator(token) if wifilocator else None - - def __read_thread(self): - loc_data = () - try: - # 读取Wifi定位信息 - loc_data = self.__wifilocator_obj.getwifilocator() - loc_data = loc_data if isinstance(loc_data, tuple) and loc_data[0] and loc_data[1] else () - except Exception as e: - sys.print_exception(e) - self.__queue.put(loc_data) -``` - -### 电池模块(battery) - -1. 功能描述 - -读取电池的电量, 电压, 获取电池的充电状态, 通过回调函数通知用户电池充电状态变化。 - -2. 实现原理: - -- 电池电压的获取方式有两种 - + 通过Power模块获取电源电压 - + 通过ADC获取电压进行计算 - -```python -class Battery(object): - ... - - def __get_power_vbatt(self): - """Get vbatt from power""" - # 通过Power模块获取电源电压 - return int(sum([Power.getVbatt() for i in range(100)]) / 100) - - def __get_adc_vbatt(self): - """Get vbatt from adc""" - # 通过ADC获取电压进行计算 - self.__adc.open() - utime.sleep_ms(self.__adc_period) - adc_list = list() - for i in range(self.__adc_period): - adc_list.append(self.__adc.read(self.__adc_num)) - utime.sleep_ms(self.__adc_period) - adc_list.remove(min(adc_list)) - adc_list.remove(max(adc_list)) - adc_value = int(sum(adc_list) / len(adc_list)) - self.__adc.close() - vbatt_value = adc_value * (self.__factor + 1) - return vbatt_value -``` - -- 电池电量目前只提供模拟计算, 录入了一个电压, 温度对应电池电量的数据关系表进行模糊计算 - -```python -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, - }, - }, -} -``` - -```python -class Battery: - ... - - def __get_soc_from_dict(self, key, volt_arg): - """Get battery energy from map""" - if BATTERY_OCV_TABLE[self.__battery_ocv].get(key): - volts = sorted(BATTERY_OCV_TABLE[self.__battery_ocv][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[self.__battery_ocv][key].get(volt, 0) - soc2 = BATTERY_OCV_TABLE[self.__battery_ocv][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): - """Get battery energy by temperature and voltage""" - 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) -``` - -- 电池的充电状态是通过引脚中断与获取引脚的电平高低判断当前设备的充电状态 - -```python -class Battery: - ... - - def __update_charge_status(self): - """Update Charge status by gpio status""" - if not self.__usb: - chrg_level = self.__chrg_gpio.read() - stdby_level = self.__stdby_gpio.read() - if chrg_level == 1 and stdby_level == 1: - # Not charge. - self.__charge_status = 0 - elif chrg_level == 0 and stdby_level == 1: - # Charging. - self.__charge_status = 1 - elif chrg_level == 1 and stdby_level == 0: - # Charge over. - self.__charge_status = 2 - else: - raise TypeError("CHRG and STDBY cannot be 0 at the same time!") - else: - self.__usb_charge() - - @property - def charge_status(self): - """Get charge status - Returns: - 0 - Not charged - 1 - Charging - 2 - Finished charging - """ - self.__update_charge_status() - return self.__charge_status - -``` - -### 低功耗模块(power_manage) - -1. 功能描述: - -周期性唤醒设备并进行业务处理, 业务处理完成后, 设备进入休眠模式 - -当前支持的休眠模式有: - -- autosleep -- psm - -2. 实现原理: - -设置对应的休眠模式, 使设备进入休眠, 通过RTC定时器进行设备唤醒 - -```python -class PowerManage: - ... - - def autosleep(self, val): - """Set device autosleep. - - Args: - val (int): 0 - disable, 1 - enable. - - Returns: - bool: True - success. False - failed. - """ - return True if hasattr(pm, "autosleep") and val in (0, 1) and pm.autosleep(val) == 0 else False - - def set_psm(self, mode=1, tau=None, act=None): - """Set device psm. - - Args: - mode (int): 0 - disable psm, 1 - enable psm. - tau (int/None): tau seconds. When mode is 0, this value is None. (default: `None`) - act (int/None): act seconds. When mode is 0, this value is None. (default: `None`) - - Returns: - bool: True - success. False - failed. - """ - if not hasattr(pm, "set_psm_time") or not hasattr(pm, "get_psm_time"): - return False - if mode == 0: - return pm.set_psm_time(0) - else: - self.__init_tau(tau) - self.__init_act(act) - res = pm.set_psm_time(self.__tau_unit, self.__tau_time, self.__act_unit, self.__act_time) - log.info("set_psm_time: %s" % res) - if res: - get_psm_res = pm.get_psm_time() - log.debug("get_psm_res: %s" % str(get_psm_res)) - if get_psm_res[0] == 1 and get_psm_res[1:] == [self.__tau_unit, self.__tau_time, self.__act_unit, self.__act_time]: - log.debug("PSM time equal set time.") - return res -``` - -### 阿里Iot(aliyunIot) - -1. 功能描述: - -通过MQTT协议与阿里Iot物联网模块进行交互 - -- 设备连接登录平台 -- 发送物模型数据到服务端 -- 接收服务端下发的指令 -- OTA升级 - -> 此处以阿里Iot MQTT协议为例, 实际应用以实际对接的IoT 平台与协议进行开发, 基本逻辑模式一致。 - -2. 实现原理: - -通过MQTT协议, 按照阿里Iot物联网模块的通信规则进行登录与数据交互。 - -- 注册登录 - -```python -class AliIot: - ... - - def connect(self): - res = -1 - self.__server = "%s.%s" % (self.__product_key, self.__domain) - log.debug("self.__product_key: %s" % self.__product_key) - log.debug("self.__product_secret: %s" % self.__product_secret) - log.debug("self.__device_name: %s" % self.__device_name) - log.debug("self.__device_secret: %s" % self.__device_secret) - log.debug("self.__server: %s" % self.__server) - self.__server = aLiYun(self.__product_key, self.__product_secret, self.__device_name, self.__device_secret, self.__server) - res = self.__server.setMqtt(self.__device_name) - if res == 0: - self.__server.setCallback(self.__subscribe_callback) - res = self.__subscribe_topics() - if res == 0: - self.__server.start() - return res -``` - -- 数据上传 - -```python -class AliIot: - ... - - def properties_report(self, data):. - # 属性上报 - _timestamp = self.__timestamp - _id = self.__id - params = {key: {"value": val, "time": _timestamp} for key, val in data.items()} - properties = { - "id": _id, - "version": "1.0", - "sys": { - "ack": 1 - }, - "params": params, - "method": "thing.event.property.post", - } - pub_res = self.__server.publish(self.ica_topic_property_post, ujson.dumps(properties), qos=self.__qos) if self.__server else -1 - return self.__get_post_res(_id) if pub_res is True else False - - def event_report(self, event, data): - # 事件上报 - _timestamp = self.__timestamp - _id = self.__id - params = {"value": data, "time": _timestamp} - properties = { - "id": _id, - "version": "1.0", - "sys": { - "ack": 1 - }, - "params": params, - "method": "thing.event.%s.post" % event, - } - pub_res = self.__server.publish(self.ica_topic_event_post.format(event), ujson.dumps(properties), qos=self.__qos) if self.__server else -1 - return self.__get_post_res(_id) if pub_res is True else False -``` - -- 下行数据回传 - -```python -class AliIot: - ... - - def __subscribe_callback(self, topic, data): - topic = topic.decode() - try: - data = ujson.loads(data) - except: - pass - log.debug("topic: %s, data: %s" % (topic, str(data))) - - if topic.endswith("/post_reply"): - self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False) - return - elif topic.endswith("/thing/ota/firmware/get_reply"): - self.__put_post_res(data["id"], True if int(data["code"]) == 200 else False) - - if self.__callback and callable(self.__callback): - # 传入Tracker.server_callback中进行处理 - self.__callback((topic, data)) -``` - -- OTA升级 - -```python -class AliIotOTA: - ... - - def start(self): - # 开始OTA升级 - if self.__module == self.__project_name: - self.__start_sota() - elif self.__module == self.__firmware_name: - self.__start_fota() - else: - return False - return True - - def __start_fota(self): - log.debug("__start_fota") - fota_obj = fota() - url1 = self.__files[0]["url"] - url2 = self.__files[1]["url"] if len(self.__files) > 1 else "" - log.debug("start httpDownload") - if url2: - res = fota_obj.httpDownload(url1=url1, url2=url2, callback=self.__fota_callback) if fota_obj else -1 - else: - res = fota_obj.httpDownload(url1=url1, callback=self.__fota_callback) if fota_obj else -1 - log.debug("httpDownload res: %s" % res) - if res == 0: - self.__ota_timer.start(600 * 1000, 0, self.__ota_timer_callback) - fota_res = self.__fota_queue.get() - self.__ota_timer.stop() - return fota_res - else: - self.__server.ota_device_progress(-2, "Download File Failed.", module=self.__module) - return False -``` - -### UML类图 - -项目软件代码中各组件对象之间存在依赖关系与继承关系, 我们可以将定位器这个产品作为顶层对象, 它由若干个对应的功能所组成, 本章节通过UML类图将其与所依赖的组件对象建立了关联, 具体如下图所示。 - -![solution-tracker-104](./media/solution-tracker-104.png) - -## 事件流程描述 - -### 业务流程 - -![solution-tracker-105](media/solution-tracker-105.png) - -业务流程说明: - -1. 设备上电启动 -2. 网络(APN)配置与(注网拨号)连接,IoT 平台配置与连接,失败重试 -3. 设备模块启动检测与数据采集 - - GNSS定位模块启动,等待定位数据 - - G-Sensor三轴加速传感器模块启动与校准检测 - - LED指示灯(网络状态/定位状态/充电状态等)启动 - - 电池电量采集与充电状态检测 - - 报警检测(超速检测/震动检测/围栏检测/低电检测等) -4. IoT 平台连接成功后,检测是否有历史数据需要上报进行上报 -5. IoT 平台连接成功,上报当前设备信息(定位/告警) -6. IoT 平台连接失败则存储当前设备信息(定位/告警) -7. 设备无任务,进入低功耗模式,定时唤醒设备进行设备信息检测与上报 -8. IoT 平台连接成功后,等待IoT 平台下发指令信息 -9. 指令信息的解析 - - 设备控制指令,如修改设备业务参数,控制设备关机重启等 - - 下发OTA升级指令,进行OTA升级 - - 设备信息查询指令,应答设备信息 - -### 系统初始化流程 - -![solution-tracker-106](media/solution-tracker-106.png) - -1. 基础功能模块初始化, 低功耗管理, 配置参数, 电池, 历史文件, 定位, 传感器。 -2. 初始化IoT 平台客户端模块, 阿里Iot或ThingsBoard平台或私有服务平台(GT06、JT/T808等) -3. 初始化核心业务模块(Tracker), 将各个功能模块通过add_module接口添加到Tracker对象中, 再将Tracker.server_callback注册到Server对象中, 用于接收服务端下行的消息指令。 diff --git a/readme.md b/readme.md index 023811d..efd05c6 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,22 @@ [中文](readme_zh.md) | English -## Introduction to Smart Tracker +Welcome to the QuecPython Tracker Solution repository! This repository provides a comprehensive solution for developing Tracker device applications using QuecPython. + +## Table of Contents + +- [Introduction](#introduction) +- [Functions](#Functions) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Installation](#installation) + - [Running the Application](#running-the-application) +- [Directory Structure](#directory-structure) +- [Contributing](#contributing) +- [License](#license) +- [Support](#support) + +## Introduction ### Overview @@ -12,18 +27,6 @@ ![](./docs/en/media/tracker_process.png) -### Functions - -- Multi-technology positioning, geo-fence alarm, danger alarm, SOS alarm reporting, audio monitoring, recording, historical track playback, remote control, etc. -- Smart positioning - - The system utilizes 4G communication/multi-technology positioning/distributed services to provide a one-stop solution from end to service for the smart tracker industry. -- All-platform support - - The device operation platform and mobile APP have all-round functions, enabling terminal device manufacturers to quickly manage devices and end users without the need to build your own service platforms. -- Reliable and stable - - The terminal device has high positioning accuracy, high sensitivity to danger perception, low power consumption, and stable operation. Terminal device manufacturers can develop customized solutions directly based on the public version, greatly shortening the hardware development cycle. - -![](./docs/en/media/tracker_funcion.png) - ### Features - Intelligent perception, recognition, and reporting of location information and danger alarms. @@ -42,103 +45,158 @@ ![](./docs/en/media/tracker_application.png) -## Quectel Smart Tracker and Capabilities - -### Capabilities - -- **Support multiple platforms such as Alibaba IoT Platform, ThingsBoard, and private service platforms (Only Alibaba IoT Platform and ThingsBoard are supported currently, while others are under development)** -- **Support local and remote parameter configuration** -- **Support OTA upgrades** -- **Support offline data storage** - - For unstable network connections, data that fails to be sent will be temporarily stored locally and prioritized for transmission to the server when the network is restored. - - The amount of data stored offline can be configured through a configuration file. -- **Support common sensors and input devices** - - Sensors - - Ambient light sensor - - Three-axis acceleration sensor - - Temperature and humidity sensor - - ... - - Input devices - - Microphone - - ... -- **Support QuecPython, enabling rapid secondary development with Python** - -### Supporting Component - -#### QPYcom - -QPYcom is a powerful tool that integrates **QuecPython REPL interaction, file transfer between PC and module, file system image making and packaging into the firmware, and firmware downloading**. - -If you want to conduct secondary development, QPYcom will greatly improve your development efficiency. - -[Click here to download QPYCom](https://python.quectel.com/download) - -For the QPYCom user guide, refer to the `docs` folder in the installation directory. - -![](./docs/en/media/QPYCom_V3.3.0.png) - -### Advantages - -- **Multi-technology Positioning** - - Support multiple technologies such as GPS, BDS, GLONASS, Galileo, Wi-Fi and LBS to realize an accurate positioning in any corner of the world. -- **1000 mAh** - - Ultra-low power consumption to realize ultra-long standby time (theoretical standby time longer than 8000 days). -- **Sensors** - - Acceleration sensors, temperature and humidity sensors, and ambient light sensors greatly expand usage scenarios, including cold-chain transportation and logistics monitoring. -- **Wide-range Voltage Support** - - Support voltage from 9 V to 108 V, covering cars, large trucks, new energy vehicles and electric scooters. -- **Fast Positioning** - - Support fast positioning with the help of AGPS. -- **Concealed Installation** - - Magnetic, adhesive, fixed, and movable. The hidden tracker provides effective positioning. -- **Low-cost Development** - - Secondary development with Python reduces software development costs. - ![C2Py.png](./docs/en/media/C2Py.png) - - Applicable to multiple Quectel module models. Through Python development, you can quickly switch to different module models without modifying the code. -- **Strong Customer Service and Technical Support Capabilities** - -## Workflow of Quectel Smart Tracker - -### Danger Alarm and SOS Alarm Reporting +## Functions -![](./docs/en/media/tracker_alert.png) - -### Remote Control - -![](./docs/en/media/solution-tracker-102.png) - -## Download Complete Code Project - -### Description - -This project includes a sub-project named `modules`. When downloading the code, make sure to download the sub-project together. - -### Download Steps - -1. Download the main project code - -- `git clone https://github.com/QuecPython/solution-tracker.git` - -2. Enter the project root directory - -- `cd solution-tracker/` - -3. Switch to the corresponding main project branch - -- `git checkout master` - -4. Initialize the sub-project - -- `git submodule init` - -5. Download the sub-project code - -- `git submodule update` - -6. Enter the sub-project directory - -- `cd code/modules/` +- Multi-technology positioning, geo-fence alarm, danger alarm, SOS alarm reporting, audio monitoring, recording, historical track playback, remote control, etc. +- Smart positioning + - The system utilizes 4G communication/multi-technology positioning/distributed services to provide a one-stop solution from end to service for the smart tracker industry. +- All-platform support + - The device operation platform and mobile APP have all-round functions, enabling terminal device manufacturers to quickly manage devices and end users without the need to build your own service platforms. +- Reliable and stable + - The terminal device has high positioning accuracy, high sensitivity to danger perception, low power consumption, and stable operation. Terminal device manufacturers can develop customized solutions directly based on the public version, greatly shortening the hardware development cycle. -7. Switch to the corresponding sub-project branch +![](./docs/en/media/tracker_funcion.png) -- `git checkout master` +## Getting Started + +### Prerequisites + +Before you begin, ensure you have the following prerequisites: + +- **Hardware**: + + - A set of EC200UEUAA QuecPython standard development board with LTE antenna Type-C data cable, etc + + > Click for Tracker EVB's [schematic](https://python.quectel.com/en/wp-content/uploads/sites/2/2024/11/EC200U_A_C4-P01-Series-EVB_SCH.pdf) and [silk screen](https://python.quectel.com/en/wp-content/uploads/sites/2/2024/11/EC200U_A_C4-P01-Series-EVB_Silkscreen.pdf) documents. + + - PC (Windows 7, Windows 10, or Windows 11) + + - One GNSS antenna + + - A jumper cap + + - A functional Nano SIM card + +- **Software**: + - USB driver for the QuecPython module: [QuecPython_USB_Driver_Win10_U_G](https://python.quectel.com/wp-content/uploads/2024/09/Quectel_Windows_USB_DriverU_V1.0.19.zip) + - debugging tool: [QPYcom](https://python.quectel.com/en/wp-content/uploads/sites/2/2024/11/QPYcom_V3.6.0.zip) + - QuecPython firmware and related software resources. + - Python text editor (e.g., [VSCode](https://code.visualstudio.com/), [Pycharm](https://www.jetbrains.com/pycharm/download/)). + +### Installation + +1. **Clone the Repository**: + + ```bash + # 1.Pull the main project code + git clone https://github.com/QuecPython/solution-tracker.git + + # 2.Enter the project + cd solution-tracker/ + + # 3.Checkout to master + git checkout master + + # 4.Sub project init + git submodule init + + # 5.Sub project code pull + git submodule update + + # 6.Enter the sub project + cd code/modules/ + + # 7.checkout to master + git checkout master + ``` + +2. **Flash the Firmware**: + Follow the [instructions](https://python.quectel.com/doc/Application_guide/en/dev-tools/QPYcom/qpycom-dw.html#Download-Firmware) to flash the firmware to the development board. + +### Running the Application + +1. **Connect the Hardware**: + Connect the hardware according to the following diagram: + ![](./docs/en/media/connect.png) + 1. Connect the antenna to the antenna connector marked with the word `LTE`. + 2. Connect the GNSS antenna to the antenna connector labeled with the word `GNSS`. + 3. Insert a usable Nano SIM card into the back of the development board at the position shown in the diagram. + 4. Use jumper caps to short circuit the two pins labeled with the word `GNSS-EN`, enabling the development board to have built-in GNSS functionality. + 5. Connect the development board and computer using a Type-C data cable. + +2. **Download Code to the Device**: + - Launch the QPYcom debugging tool. + - Connect the data cable to the computer. + - Follow the [instructions](https://python.quectel.com/doc/Application_guide/en/dev-tools/QPYcom/qpycom-dw.html#Download-Script) to import all files within the `code` folder into the module's file system, preserving the directory structure. + +3. **Run the Application**: + - Select the `File` tab. + - Select the `_main.py` script. + - Right-click and select `Run` or use the run shortcut button to execute the script. + +## Directory Structure + +``` +solution-tracker/ +├── code/ +│   ├── modules/ +│   │   ├── docs/ +│   │   │   ├── en/ +│   │   │   └── zh/ +│   │   ├── aliIot.py +│   │   ├── battery.py +│   │   ├── battery.py +│   │   ├── buzzer.py +│   │   ├── common.py +│   │   ├── history.py +│   │   ├── led.py +│   │   ├── location.py +│   │   ├── logging.py +│   │   ├── net_manage.py +│   │   ├── player.py +│   │   ├── power_manage.py +│   │   ├── serial.py +│   │   ├── temp_humidity_sensor.py +│   │   ├── thingsboard.py +│   │   └── thingsboard.py +│   ├── _main.py +│   ├── settings.py +│   ├── settings_loc.py.py +│   ├── settings_server.py +│   ├── settings_user.py +│   ├── tracker_ali.py +│   └── tracker_tb.py +├── docs/ +│   ├── en/ +│   │   └── media/ +│   └── zh/ +│   └── media/ +├── object_model_demo/ +│   └── ali_cloud_object_model.json +├── QPY_OCPU_BETA0001_EC200U_EUAA_FW/ +│   └── QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac +├── .gitignore +├── .gitmodules +├── CHANGELOG.md +├── LICENSE +├── readme.md +└── readme_zh.md +``` + +## Contributing + +We welcome contributions to improve this project! Please follow these steps to contribute: + +1. Fork the repository. +2. Create a new branch (`git checkout -b feature/your-feature`). +3. Commit your changes (`git commit -m 'Add your feature'`). +4. Push to the branch (`git push origin feature/your-feature`). +5. Open a Pull Request. + +## License + +This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for details. + +## Support + +If you have any questions or need support, please refer to the [QuecPython documentation](https://python.quectel.com/doc/en) or open an issue in this repository. diff --git a/readme_zh.md b/readme_zh.md index dd5f7f4..dae2569 100644 --- a/readme_zh.md +++ b/readme_zh.md @@ -2,34 +2,37 @@ 中文 | [English](readme.md) -## Tracker 介绍 +欢迎来到 QuecPython Tracker 解决方案仓库!本仓库提供了一个全面的解决方案,用于使用 QuecPython Tracker 设备应用程序。 -### 产品概述 +## 目录 -- Tracker智能定位器。 -- 终端设备功能涵盖绝大部分定位器应用场景 -- 可视化运营平台+手机APP, 设备管理和数据查看更方便 +- [介绍](#介绍) +- [功能](#功能) +- [快速开始](#快速开始) + - [先决条件](#先决条件) + - [安装](#安装) + - [运行应用程序](#运行应用程序) +- [目录结构](#目录结构) +- [贡献](#贡献) +- [许可证](#许可证) +- [支持](#支持) -![](./docs/zh/media/tracker_process.png) +## 介绍 -### 产品功能 +### 产品概述 -- 多重定位、安全围栏、危险报警、紧急求救、语音监听、录音、轨迹回放、远程控制等 -- 智能定位 - - 系统利用4G通信/多重定位/分布式服务等技术, 为智能定位器行业提供从端到服务的一站式解决方案 -- 全平台支持 - - 设备运营平台和手机APP功能齐全, 终端设备厂商无需自行搭建服务平台即可快速实现对设备和终端用户的管理 -- 可靠稳定 - - 终端设备定位精度高、危险感知灵敏度高、功耗低、运行稳定, 终端设备厂商可套壳即用, 极大缩短硬件开发周期 +- Tracker 智能定位器 +- 终端设备功能涵盖绝大部分定位器应用场景 +- 可视化运营平台+手机 APP,设备管理和数据查看更方便 -![](./docs/zh/media/tracker_funcion.png) +![](./docs/zh/media/tracker_process.png) ### 产品特点 - 位置信息、危险警情智能感知、识别和上报 -- 支持阿里Iot平台、ThingsBoard、私有服务等多种Iot平台对接 -- QuecPython二次开发, 模块化、定制化、缩短开发周期 -- 可视化运营平台、手机APP控制终端 +- 支持阿里 IoT 平台、ThingsBoard、私有服务等多种 IoT 平台对接 +- QuecPython 二次开发,模块化、定制化、缩短开发周期 +- 可视化运营平台、手机 APP 控制终端 ### 应用行业 @@ -42,103 +45,161 @@ ![](./docs/zh/media/tracker_application.png) -## 移远Tracker智能定位器及其能力 - -### 产品能力 - -- **通道支持阿里Iot平台、ThingsBoard、私有服务平台等多种平台(目前暂只支持阿里Iot平台和ThingsBoard平台, 其他平台正在开发中)** -- **支持本地和远程参数配置** -- **支持OTA升级** -- **支持数据离线存储** - - 在网络连接不稳定情况下, 将发送失败的数据暂存至本地, 在网络恢复后优先将本地数据发送至服务端 - - 离线存储的数据量可通过配置文件配置 -- **支持常用的传感器和输入设备** - - 传感器: - - 照度传感器 - - 三轴加速度传感器 - - 温湿度传感器 - - ... - - 输入设备 - - 麦克风 - - ... -- **支持QuecPython, 可以使用Python代码快速实现二次开发** - -### 产品配套组件 - -#### QPYcom工具 - -QPYcom工具是一个集**QuecPython repl交互、PC和模组间文件传输、文件系统镜像制作并打包到固件包、及固件烧录等各种功能**于一体的强大利器。 - -用户如需进行二次开发, 使用QPYcom将会大大提高开发的效率。 - -[点此下载QPYCom工具。](https://python.quectel.com/download) - -QPYCom的使用文档, 参见安装目录下的`docs`文件夹。 - -![](./docs/zh/media/QPYCom_V3.3.0.png) - -### 产品优势 - -- **多重定位** - - 支持GPS、BDS、GLONASS、Galileo, 支持Wi-Fi、基站定位, 世界任意角落, 都能精准定位 -- **1000mah** - - 超低功耗, 超长待机, 理论待机>8000天 -- **传感器** - - 加速传感器、温湿度传感器、光照传感器, 极大扩展使用场景, 冷链运输、物流监控, 不在话下 -- **宽电压支持** - - 最低9v, 最高108v, 不论是小轿车、大货车、新能源汽车, 还是两轮电动车, 统统支持 -- **疾速定位** - - AGPS加持, 疾速定位, 急脾气?别着急。定位器比你更“疾” -- **隐蔽安装** - - 可磁吸、可粘扣、可固定、可移动, 定位效果无所遁形, 定位器杳无踪迹 -- **低成本开发** - - 可使用Python进行二次开发, 降低软件开发成本 - ![C2Py.png](./docs/zh/media/C2Py.png) - - 我司多平台模组适用, 使用Python开发, 无需修改代码即可快速切换至不同模组 -- **强大的客户服务和技术支持能力** - -## 移远Tracker智能定位器的工作流程 - -### 危险报警、紧急求救 +## 功能 -![](./docs/zh/media/tracker_alert.png) - -### 远程控制 - -![](./docs/zh/media/solution-tracker-102.png) - -## 拉取完整代码工程 - -### 说明 - -本项目包含有一个`modules`子项目, 拉取代码时需将子项目一并拉去下来进行使用。 - -### 拉取步骤 - -1 拉取主项目代码 - -- `git clone https://github.com/QuecPython/solution-tracker.git` - -2 进入项目根目录 - -- `cd solution-tracker/` - -3 切换对应的主项目分支 - -- `git checkout master` - -4 子项目初始化 - -- `git submodule init` - -5 子项目代码拉取 - -- `git submodule update` - -6 进入子项目目录 - -- `cd code/modules/` +- 多重定位、安全围栏、危险报警、紧急求救、语音监听、录音、轨迹回放、远程控制等 +- 智能定位 + - 系统利用 4G 通信/多重定位/分布式服务等技术,为智能定位器行业提供从端到服务的一站式解决方案 +- 全平台支持 + - 设备运营平台和手机 APP 功能齐全,终端设备厂商无需自行搭建服务平台即可快速实现对设备和终端用户的管理 +- 可靠稳定 + - 终端设备定位精度高、危险感知灵敏度高、功耗低、运行稳定,终端设备厂商可套壳即用,极大缩短硬件开发周期 -7 切换对应的子项目分支 +![](./docs/zh/media/tracker_funcion.png) -- `git checkout master` +## 快速开始 + +### 先决条件 + +在开始之前,请确保您具备以下先决条件: + +- **硬件:** + + - Windows 电脑一台,建议 `Win10` 系统 + + - 一套 [EC200UEUAA QuecPython 标准开发板](https://python.quectel.com/doc/Getting_started/zh/evb/ec200x-evb.html)(含 LTE 天线、 Type-C 数据线等) + + > 点击查看 Tracker 定位器开发板的[原理图](https://python.quectel.com/wp-content/uploads/2024/09/EC200UA_C4-P01%E7%B3%BB%E5%88%97%E5%BC%80%E5%8F%91%E6%9D%BF%E5%8E%9F%E7%90%86%E5%9B%BE.pdf)和[丝印图](https://python.quectel.com/wp-content/uploads/2024/09/EC200UA_C4-P01%E7%B3%BB%E5%88%97%E5%BC%80%E5%8F%91%E6%9D%BF%E4%B8%9D%E5%8D%B0.pdf)文档。 + + - 一根 [GNSS天线](https://e.tb.cn/h.TpAFyEz02BnCHRD?tk=fznae6ITVEX) + + - 一个排针跳线帽 + + - 一张可正常使用的 Nano SIM 卡 + +- **软件:** + + - QuecPython 模块的 USB 驱动:[QuecPython_USB_Driver_Win10_U_G](https://python.quectel.com/wp-content/uploads/2024/09/Quectel_Windows_USB_DriverU_V1.0.19.zip) + - 调试工具 [QPYcom](https://images.quectel.com/python/2022/12/QPYcom_V3.6.0.zip) + - QuecPython 固件及相关软件资源 + - Python 文本编辑器(例如,[VSCode](https://code.visualstudio.com/)、[Pycharm](https://www.jetbrains.com/pycharm/download/)) + +### 安装 + +1. **克隆仓库**: + + ```bash + # 1.拉取主项目代码 + git clone https://github.com/QuecPython/solution-tracker.git + + # 2.进入项目根目录 + cd solution-tracker/ + + # 3.切换对应的主项目分支 + git checkout master + + # 4.子项目初始化 + git submodule init + + # 5.子项目代码拉取 + git submodule update + + # 6.进入子项目目录 + cd code/modules/ + + # 7.切换对应的子项目分支 + git checkout master + ``` + +2. **烧录固件:** + 按照[说明](https://python.quectel.com/doc/Application_guide/zh/dev-tools/QPYcom/qpycom-dw.html#%E4%B8%8B%E8%BD%BD%E5%9B%BA%E4%BB%B6)将固件烧录到开发板上。 + +### 运行应用程序 + +1. **连接硬件:** + 按照下图进行硬件连接: + + ![](./docs/zh/media/连线.png) + + 1. 将 LTE 天线连接至标识有 `LTE` 字样的天线连接座上 + 2. 将 GNSS 天线连接至标识有 `GNSS` 字样的天线连接座上 + 3. 在图示位置开发板背面插入可用的 Nano SIM 卡 + 4. 使用跳线帽将标识有 `GNSS_EN` 字样的两根排针短接,使能开发板内置 GNSS 功能 + 5. 使用 Type-C 数据线连接开发板和电脑 + +2. **将代码下载到设备:** + - 启动 QPYcom 调试工具。 + - 将数据线连接到计算机。 + - 按照[说明](https://python.quectel.com/doc/Application_guide/zh/dev-tools/QPYcom/qpycom-dw.html#%E4%B8%8B%E8%BD%BD%E8%84%9A%E6%9C%AC)将 `code` 文件夹中的所有文件导入到模块的文件系统中,保留目录结构。 + +3. **运行应用程序:** + - 选择 `File` 选项卡。 + - 选择 `_main.py` 脚本。 + - 右键单击并选择 `Run` 或使用`运行`快捷按钮执行脚本。 + +## 目录结构 + +```plaintext +solution-tracker/ +├── code/ +│   ├── modules/ +│   │   ├── docs/ +│   │   │   ├── en/ +│   │   │   └── zh/ +│   │   ├── aliIot.py +│   │   ├── battery.py +│   │   ├── battery.py +│   │   ├── buzzer.py +│   │   ├── common.py +│   │   ├── history.py +│   │   ├── led.py +│   │   ├── location.py +│   │   ├── logging.py +│   │   ├── net_manage.py +│   │   ├── player.py +│   │   ├── power_manage.py +│   │   ├── serial.py +│   │   ├── temp_humidity_sensor.py +│   │   ├── thingsboard.py +│   │   └── thingsboard.py +│   ├── _main.py +│   ├── settings.py +│   ├── settings_loc.py.py +│   ├── settings_server.py +│   ├── settings_user.py +│   ├── tracker_ali.py +│   └── tracker_tb.py +├── docs/ +│   ├── en/ +│   │   └── media/ +│   └── zh/ +│   └── media/ +├── object_model_demo/ +│   └── ali_cloud_object_model.json +├── QPY_OCPU_BETA0001_EC200U_EUAA_FW/ +│   └── QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac +├── .gitignore +├── .gitmodules +├── CHANGELOG.md +├── LICENSE +├── readme.md +└── readme_zh.md +``` + +## 贡献 + +我们欢迎对本项目的改进做出贡献!请按照以下步骤进行贡献: + +1. Fork 此仓库。 +2. 创建一个新分支(`git checkout -b feature/your-feature`)。 +3. 提交您的更改(`git commit -m 'Add your feature'`)。 +4. 推送到分支(`git push origin feature/your-feature`)。 +5. 打开一个 Pull Request。 + +## 许可证 + +本项目使用 Apache 许可证。详细信息请参阅 [LICENSE](LICENSE) 文件。 + +## 支持 + +如果您有任何问题或需要支持,请参阅 [QuecPython 文档](https://python.quectel.com/doc)或在本仓库中打开一个 issue。