├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── QPY_OCPU_BETA0001_EC200U_EUAA_FW ├── QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac ├── Quectel_Disclaimer_for_Software_BETA_Version.pdf └── changelog - EC200UEU_AA_BETA.md ├── README.md ├── README.zh.md ├── code ├── _main.py ├── settings.py ├── settings_loc.py ├── settings_server.py ├── settings_user.py ├── tracker_ali.py └── tracker_tb.py ├── docs ├── en │ └── media │ │ ├── connect.png │ │ ├── tracker_application.png │ │ ├── tracker_funcion.png │ │ └── tracker_process.png └── zh │ └── media │ ├── tracker_application.png │ ├── tracker_funcion.png │ ├── tracker_process.png │ └── 连线.png └── object_model_demo └── ali_cloud_object_model.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Specify filepatterns you want git to ignore. 2 | 3 | .vscode 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | .idea/ 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | workspace.xml 85 | # SageMath parsed files 86 | *.sage.py 87 | .idea/workspace.xml 88 | # Environments 89 | .env 90 | .venv 91 | env/ 92 | venv/ 93 | ENV/ 94 | env.bak/ 95 | venv.bak/ 96 | 97 | # Spyder project settings 98 | .spyderproject 99 | .spyproject 100 | 101 | # Rope project settings 102 | .ropeproject 103 | 104 | # mkdocs documentation 105 | /site 106 | 107 | # mypy 108 | .mypy_cache/ 109 | 110 | tracker_settings.json 111 | 112 | dev_settings_*.py 113 | .test/ 114 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "code/modules"] 2 | path = code/modules 3 | url = https://github.com/QuecPython/modules.git 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog 2 | 3 | All significant changes to this project will be documented in this file. 4 | 5 | ## [v2.0.0] - 2024-06-04 6 | 7 | ### Added 8 | 9 | - Restructured the entire Tracker's business functions, adding three new modules: `tracker_collector` (collector), `tracker_controller` (controller), and `tracker_devicecheck` (device status checker). 10 | - Extracted non-business functionalities into separate, independent modules housed within the standalone `modules` project. 11 | - Included sample JSON files for Aliyun and QuecCloud IoT device models. 12 | - **net_manage.py**: Introduced a network management module; 13 | - **power_manage.py**: Added a low-power management module, replacing the previous `mpower.py`; 14 | - **thingsboard.py**: Incorporated MQTT client code for connecting to the ThingsBoard platform; 15 | 16 | ### Changed 17 | 18 | - Refined the overall project architecture, dedicating individual modules to specific platform functionalities (e.g., `tracker_ali.py` for Aliyun, `tracker_tb.py` for ThingsBoard). 19 | - Optimized code within several modules, including: 20 | + **aliyunIot.py** 21 | + **battery.py** 22 | + **buzzer.py** 23 | + **common.py** 24 | + **led.py** 25 | + **location.py** 26 | + **logging.py** 27 | 28 | ### Removed 29 | 30 | - Removed the ota module as OTA upgrade capabilities are now integrated into respective cloud functionality modules. 31 | - Discontinued the timer module; LED blinking functionality previously in the timer module has been moved to the LED module. 32 | - Decommissioned the Tracker class in the tracker module, redistributing its functionalities among `tracker_collector`, `tracker_controller`, and `tracker_devicecheck`. 33 | - Refactored the SelfCheck function into `tracker_devicecheck`. 34 | - Migrated Aliyun, QuecCloud IoT, battery, common, history, LED, location, logging, and cloud interaction middleware modules into the `modules` directory. 35 | - Retired the QuecCloud module. 36 | - Eliminated the `remote` middleware module. 37 | 38 | ## [v1.0.0] - 2024-06-04 39 | 40 | ### Initial Release 41 | 42 | - Initial release for this project. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /QPY_OCPU_BETA0001_EC200U_EUAA_FW/QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/QPY_OCPU_BETA0001_EC200U_EUAA_FW/QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac -------------------------------------------------------------------------------- /QPY_OCPU_BETA0001_EC200U_EUAA_FW/Quectel_Disclaimer_for_Software_BETA_Version.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/QPY_OCPU_BETA0001_EC200U_EUAA_FW/Quectel_Disclaimer_for_Software_BETA_Version.pdf -------------------------------------------------------------------------------- /QPY_OCPU_BETA0001_EC200U_EUAA_FW/changelog - EC200UEU_AA_BETA.md: -------------------------------------------------------------------------------- 1 | ## Release History 2 | **[QPY_OCPU_EC200UEU_AA_BETA] 2024-04-18** 3 | * ZH 4 | * 支持功能list 5 | 1. app_fota 6 | 2. PWM 7 | 3. dataCall 8 | 4. fota 9 | 5. log 10 | 6. net 11 | 7. ntptime 12 | 8. pm 13 | 9. queue 14 | 10. sim 15 | 11. sys_bus 16 | 12. uio 17 | 13. ujson 18 | 14. BLE 19 | 15. usocket 20 | 16. utime 21 | 17. _thread 22 | 18. Timer 23 | 19. RTC 24 | 20. WDT 25 | 21. Pin 26 | 22. ExtInt 27 | 23. UART 28 | 24. SPI 29 | 25. IIC 30 | 26. Key 31 | 27. Power 32 | 28. ADC 33 | 29. PowerKey 34 | 30. TencentYun 35 | 31. voicecall 36 | 32. wifiscan 37 | 33. wifilocator 38 | 34. SMS 39 | 35. Audio 40 | 36. Ethernet 41 | 37. AliYun 42 | 38. GNSS 43 | 39. USSD 44 | 45 | 46 | 47 | 48 | * EN 49 | * Support function list 50 | 1. app_fota 51 | 2. PWM 52 | 3. dataCall 53 | 4. fota 54 | 5. log 55 | 6. net 56 | 7. ntptime 57 | 8. pm 58 | 9. queue 59 | 10. sim 60 | 11. sys_bus 61 | 12. uio 62 | 13. ujson 63 | 14. BLE 64 | 15. usocket 65 | 16. utime 66 | 17. _thread 67 | 18. Timer 68 | 19. RTC 69 | 20. WDT 70 | 21. Pin 71 | 22. ExtInt 72 | 23. UART 73 | 24. SPI 74 | 25. IIC 75 | 26. Key 76 | 27. Power 77 | 28. ADC 78 | 29. PowerKey 79 | 30. TencentYun 80 | 31. voicecall 81 | 32. wifiscan 82 | 33. wifilocator 83 | 34. SMS 84 | 35. Audio 85 | 36. Ethernet 86 | 37. AliYun 87 | 38. GNSS 88 | 39. USSD -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smart Tracker Solution for QuecPython 2 | 3 | [中文](README.zh.md) | English 4 | 5 | Welcome to the QuecPython Tracker Solution repository! This repository provides a comprehensive solution for developing Tracker device applications using QuecPython. 6 | 7 | ## Table of Contents 8 | 9 | - [Introduction](#introduction) 10 | - [Functions](#Functions) 11 | - [Getting Started](#getting-started) 12 | - [Prerequisites](#prerequisites) 13 | - [Installation](#installation) 14 | - [Running the Application](#running-the-application) 15 | - [Directory Structure](#directory-structure) 16 | - [Contributing](#contributing) 17 | - [License](#license) 18 | - [Support](#support) 19 | 20 | ## Introduction 21 | 22 | ### Overview 23 | 24 | - Smart tracker 25 | - Terminal device functions meet the majority of requirements in tracker application scenarios 26 | - The visual operation platform and the mobile APP make device management and data viewing more convenient. 27 | 28 | ![](./docs/en/media/tracker_process.png) 29 | 30 | ### Features 31 | 32 | - Intelligent perception, recognition, and reporting of location information and danger alarms. 33 | - Support integration with various IoT platforms such as Alibaba IoT Platform, ThingsBoard, and other private services. 34 | - Secondary development with QuecPython to formulate modular and customizable solutions, thus shortening development cycles. 35 | - Visual operation platform and mobile APP to control terminal devices. 36 | 37 | ### Applications 38 | 39 | - Vehicle tracking 40 | - Logistics and transportation 41 | - People tracking 42 | - Electronic student ID card 43 | - Pet tracking 44 | - Special industries (agricultural irrigation, rare species monitoring, etc.) 45 | 46 | ![](./docs/en/media/tracker_application.png) 47 | 48 | ## Functions 49 | 50 | - Multi-technology positioning, geo-fence alarm, danger alarm, SOS alarm reporting, audio monitoring, recording, historical track playback, remote control, etc. 51 | - Smart positioning 52 | - 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. 53 | - All-platform support 54 | - 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. 55 | - Reliable and stable 56 | - 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. 57 | 58 | ![](./docs/en/media/tracker_funcion.png) 59 | 60 | ## Getting Started 61 | 62 | ### Prerequisites 63 | 64 | Before you begin, ensure you have the following prerequisites: 65 | 66 | - **Hardware**: 67 | 68 | - A set of EC200UEUAA QuecPython standard development board with LTE antenna Type-C data cable, etc 69 | 70 | > 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. 71 | 72 | - PC (Windows 7, Windows 10, or Windows 11) 73 | 74 | - One GNSS antenna 75 | 76 | - A jumper cap 77 | 78 | - A functional Nano SIM card 79 | 80 | - **Software**: 81 | - 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) 82 | - debugging tool: [QPYcom](https://python.quectel.com/en/wp-content/uploads/sites/2/2024/11/QPYcom_V3.6.0.zip) 83 | - QuecPython firmware and related software resources. 84 | - Python text editor (e.g., [VSCode](https://code.visualstudio.com/), [Pycharm](https://www.jetbrains.com/pycharm/download/)). 85 | 86 | ### Installation 87 | 88 | 1. **Clone the Repository**: 89 | 90 | ```bash 91 | # 1.Pull the main project code 92 | git clone https://github.com/QuecPython/solution-tracker.git 93 | 94 | # 2.Enter the project 95 | cd solution-tracker/ 96 | 97 | # 3.Checkout to master 98 | git checkout master 99 | 100 | # 4.Sub project init 101 | git submodule init 102 | 103 | # 5.Sub project code pull 104 | git submodule update 105 | 106 | # 6.Enter the sub project 107 | cd code/modules/ 108 | 109 | # 7.checkout to master 110 | git checkout master 111 | ``` 112 | 113 | 2. **Flash the Firmware**: 114 | 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. 115 | 116 | ### Running the Application 117 | 118 | 1. **Connect the Hardware**: 119 | Connect the hardware according to the following diagram: 120 | ![](./docs/en/media/connect.png) 121 | 1. Connect the antenna to the antenna connector marked with the word `LTE`. 122 | 2. Connect the GNSS antenna to the antenna connector labeled with the word `GNSS`. 123 | 3. Insert a usable Nano SIM card into the back of the development board at the position shown in the diagram. 124 | 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. 125 | 5. Connect the development board and computer using a Type-C data cable. 126 | 127 | 2. **Download Code to the Device**: 128 | - Launch the QPYcom debugging tool. 129 | - Connect the data cable to the computer. 130 | - 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. 131 | 132 | 3. **Run the Application**: 133 | - Select the `File` tab. 134 | - Select the `_main.py` script. 135 | - Right-click and select `Run` or use the run shortcut button to execute the script. 136 | 137 | ## Directory Structure 138 | 139 | ```plaintext 140 | solution-tracker/ 141 | ├── code/ 142 | │   ├── modules/ 143 | │   │   ├── docs/ 144 | │   │   │   ├── en/ 145 | │   │   │   └── zh/ 146 | │   │   ├── aliIot.py 147 | │   │   ├── battery.py 148 | │   │   ├── battery.py 149 | │   │   ├── buzzer.py 150 | │   │   ├── common.py 151 | │   │   ├── history.py 152 | │   │   ├── led.py 153 | │   │   ├── location.py 154 | │   │   ├── logging.py 155 | │   │   ├── net_manage.py 156 | │   │   ├── player.py 157 | │   │   ├── power_manage.py 158 | │   │   ├── serial.py 159 | │   │   ├── temp_humidity_sensor.py 160 | │   │   ├── thingsboard.py 161 | │   │   └── thingsboard.py 162 | │   ├── _main.py 163 | │   ├── settings.py 164 | │   ├── settings_loc.py.py 165 | │   ├── settings_server.py 166 | │   ├── settings_user.py 167 | │   ├── tracker_ali.py 168 | │   └── tracker_tb.py 169 | ├── docs/ 170 | │   ├── en/ 171 | │   │   └── media/ 172 | │   └── zh/ 173 | │   └── media/ 174 | ├── object_model_demo/ 175 | │   └── ali_cloud_object_model.json 176 | ├── QPY_OCPU_BETA0001_EC200U_EUAA_FW/ 177 | │   └── QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac 178 | ├── .gitignore 179 | ├── .gitmodules 180 | ├── CHANGELOG.md 181 | ├── LICENSE 182 | ├── readme.md 183 | └── readme_zh.md 184 | ``` 185 | 186 | ## Contributing 187 | 188 | We welcome contributions to improve this project! Please follow these steps to contribute: 189 | 190 | 1. Fork the repository. 191 | 2. Create a new branch (`git checkout -b feature/your-feature`). 192 | 3. Commit your changes (`git commit -m 'Add your feature'`). 193 | 4. Push to the branch (`git push origin feature/your-feature`). 194 | 5. Open a Pull Request. 195 | 196 | ## License 197 | 198 | This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for details. 199 | 200 | ## Support 201 | 202 | 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. 203 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # QuecPython 智能定位器解决方案 2 | 3 | 中文 | [English](README.md) 4 | 5 | 欢迎来到 QuecPython Tracker 解决方案仓库!本仓库提供了一个全面的解决方案,用于使用 QuecPython Tracker 设备应用程序。 6 | 7 | ## 目录 8 | 9 | - [介绍](#介绍) 10 | - [功能](#功能) 11 | - [快速开始](#快速开始) 12 | - [先决条件](#先决条件) 13 | - [安装](#安装) 14 | - [运行应用程序](#运行应用程序) 15 | - [目录结构](#目录结构) 16 | - [贡献](#贡献) 17 | - [许可证](#许可证) 18 | - [支持](#支持) 19 | 20 | ## 介绍 21 | 22 | ### 产品概述 23 | 24 | - Tracker 智能定位器 25 | - 终端设备功能涵盖绝大部分定位器应用场景 26 | - 可视化运营平台+手机 APP,设备管理和数据查看更方便 27 | 28 | ![](./docs/zh/media/tracker_process.png) 29 | 30 | ### 产品特点 31 | 32 | - 位置信息、危险警情智能感知、识别和上报 33 | - 支持阿里 IoT 平台、ThingsBoard、私有服务等多种 IoT 平台对接 34 | - QuecPython 二次开发,模块化、定制化、缩短开发周期 35 | - 可视化运营平台、手机 APP 控制终端 36 | 37 | ### 应用行业 38 | 39 | - 车载定位 40 | - 物流货运 41 | - 人员定位 42 | - 电子学生证 43 | - 宠物定位 44 | - 特殊行业(农业灌溉, 稀有物种监控等) 45 | 46 | ![](./docs/zh/media/tracker_application.png) 47 | 48 | ## 功能 49 | 50 | - 多重定位、安全围栏、危险报警、紧急求救、语音监听、录音、轨迹回放、远程控制等 51 | - 智能定位 52 | - 系统利用 4G 通信/多重定位/分布式服务等技术,为智能定位器行业提供从端到服务的一站式解决方案 53 | - 全平台支持 54 | - 设备运营平台和手机 APP 功能齐全,终端设备厂商无需自行搭建服务平台即可快速实现对设备和终端用户的管理 55 | - 可靠稳定 56 | - 终端设备定位精度高、危险感知灵敏度高、功耗低、运行稳定,终端设备厂商可套壳即用,极大缩短硬件开发周期 57 | 58 | ![](./docs/zh/media/tracker_funcion.png) 59 | 60 | ## 快速开始 61 | 62 | ### 先决条件 63 | 64 | 在开始之前,请确保您具备以下先决条件: 65 | 66 | - **硬件:** 67 | 68 | - Windows 电脑一台,建议 `Win10` 系统 69 | 70 | - 一套 [EC200UEUAA QuecPython 标准开发板](https://python.quectel.com/doc/Getting_started/zh/evb/ec200x-evb.html)(含 LTE 天线、 Type-C 数据线等) 71 | 72 | > 点击查看 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)文档。 73 | 74 | - 一根 [GNSS天线](https://e.tb.cn/h.TpAFyEz02BnCHRD?tk=fznae6ITVEX) 75 | 76 | - 一个排针跳线帽 77 | 78 | - 一张可正常使用的 Nano SIM 卡 79 | 80 | - **软件:** 81 | 82 | - 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) 83 | - 调试工具 [QPYcom](https://images.quectel.com/python/2022/12/QPYcom_V3.6.0.zip) 84 | - QuecPython 固件及相关软件资源 85 | - Python 文本编辑器(例如,[VSCode](https://code.visualstudio.com/)、[Pycharm](https://www.jetbrains.com/pycharm/download/)) 86 | 87 | ### 安装 88 | 89 | 1. **克隆仓库**: 90 | 91 | ```bash 92 | # 1.拉取主项目代码 93 | git clone https://github.com/QuecPython/solution-tracker.git 94 | 95 | # 2.进入项目根目录 96 | cd solution-tracker/ 97 | 98 | # 3.切换对应的主项目分支 99 | git checkout master 100 | 101 | # 4.子项目初始化 102 | git submodule init 103 | 104 | # 5.子项目代码拉取 105 | git submodule update 106 | 107 | # 6.进入子项目目录 108 | cd code/modules/ 109 | 110 | # 7.切换对应的子项目分支 111 | git checkout master 112 | ``` 113 | 114 | 2. **烧录固件:** 115 | 按照[说明](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)将固件烧录到开发板上。 116 | 117 | ### 运行应用程序 118 | 119 | 1. **连接硬件:** 120 | 按照下图进行硬件连接: 121 | 122 | ![](./docs/zh/media/连线.png) 123 | 124 | 1. 将 LTE 天线连接至标识有 `LTE` 字样的天线连接座上 125 | 2. 将 GNSS 天线连接至标识有 `GNSS` 字样的天线连接座上 126 | 3. 在图示位置开发板背面插入可用的 Nano SIM 卡 127 | 4. 使用跳线帽将标识有 `GNSS_EN` 字样的两根排针短接,使能开发板内置 GNSS 功能 128 | 5. 使用 Type-C 数据线连接开发板和电脑 129 | 130 | 2. **将代码下载到设备:** 131 | - 启动 QPYcom 调试工具。 132 | - 将数据线连接到计算机。 133 | - 按照[说明](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` 文件夹中的所有文件导入到模块的文件系统中,保留目录结构。 134 | 135 | 3. **运行应用程序:** 136 | - 选择 `File` 选项卡。 137 | - 选择 `_main.py` 脚本。 138 | - 右键单击并选择 `Run` 或使用`运行`快捷按钮执行脚本。 139 | 140 | ## 目录结构 141 | 142 | ```plaintext 143 | solution-tracker/ 144 | ├── code/ 145 | │   ├── modules/ 146 | │   │   ├── docs/ 147 | │   │   │   ├── en/ 148 | │   │   │   └── zh/ 149 | │   │   ├── aliIot.py 150 | │   │   ├── battery.py 151 | │   │   ├── battery.py 152 | │   │   ├── buzzer.py 153 | │   │   ├── common.py 154 | │   │   ├── history.py 155 | │   │   ├── led.py 156 | │   │   ├── location.py 157 | │   │   ├── logging.py 158 | │   │   ├── net_manage.py 159 | │   │   ├── player.py 160 | │   │   ├── power_manage.py 161 | │   │   ├── serial.py 162 | │   │   ├── temp_humidity_sensor.py 163 | │   │   ├── thingsboard.py 164 | │   │   └── thingsboard.py 165 | │   ├── _main.py 166 | │   ├── settings.py 167 | │   ├── settings_loc.py.py 168 | │   ├── settings_server.py 169 | │   ├── settings_user.py 170 | │   ├── tracker_ali.py 171 | │   └── tracker_tb.py 172 | ├── docs/ 173 | │   ├── en/ 174 | │   │   └── media/ 175 | │   └── zh/ 176 | │   └── media/ 177 | ├── object_model_demo/ 178 | │   └── ali_cloud_object_model.json 179 | ├── QPY_OCPU_BETA0001_EC200U_EUAA_FW/ 180 | │   └── QPY_OCPU_BETA0001_EC200U_EUAA_FW.pac 181 | ├── .gitignore 182 | ├── .gitmodules 183 | ├── CHANGELOG.md 184 | ├── LICENSE 185 | ├── readme.md 186 | └── readme_zh.md 187 | ``` 188 | 189 | ## 贡献 190 | 191 | 我们欢迎对本项目的改进做出贡献!请按照以下步骤进行贡献: 192 | 193 | 1. Fork 此仓库。 194 | 2. 创建一个新分支(`git checkout -b feature/your-feature`)。 195 | 3. 提交您的更改(`git commit -m 'Add your feature'`)。 196 | 4. 推送到分支(`git push origin feature/your-feature`)。 197 | 5. 打开一个 Pull Request。 198 | 199 | ## 许可证 200 | 201 | 本项目使用 Apache 许可证。详细信息请参阅 [LICENSE](LICENSE) 文件。 202 | 203 | ## 支持 204 | 205 | 如果您有任何问题或需要支持,请参阅 [QuecPython 文档](https://python.quectel.com/doc)或在本仓库中打开一个 issue。 206 | -------------------------------------------------------------------------------- /code/_main.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :_main.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Project start. 19 | @version :2.2.0 20 | @date :2022-10-31 14:42:25 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | import _thread 25 | try: 26 | from modules.battery import Battery 27 | from modules.history import History 28 | from modules.logging import getLogger 29 | from modules.net_manage import NetManager 30 | from modules.thingsboard import TBDeviceMQTTClient 31 | from modules.power_manage import PowerManage 32 | from modules.aliIot import AliIot, AliIotOTA 33 | from modules.location import GNSS, CellLocator, WiFiLocator, CoordinateSystemConvert 34 | from settings_user import UserConfig 35 | from tracker_tb import Tracker as TBTracker 36 | from tracker_ali import Tracker as AliTracker 37 | from settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION 38 | except ImportError: 39 | from usr.modules.battery import Battery 40 | from usr.modules.history import History 41 | from usr.modules.logging import getLogger 42 | from usr.modules.net_manage import NetManager 43 | from usr.modules.thingsboard import TBDeviceMQTTClient 44 | from usr.modules.power_manage import PowerManage 45 | from usr.modules.aliIot import AliIot, AliIotOTA 46 | from usr.modules.location import GNSS, CellLocator, WiFiLocator, CoordinateSystemConvert 47 | from usr.settings_user import UserConfig 48 | from usr.tracker_tb import Tracker as TBTracker 49 | from usr.tracker_ali import Tracker as AliTracker 50 | from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION 51 | 52 | log = getLogger(__name__) 53 | 54 | def main(): 55 | log.debug("[x] Main start.") 56 | log.info("PROJECT_NAME: %s, PROJECT_VERSION: %s" % (PROJECT_NAME, PROJECT_VERSION)) 57 | log.info("DEVICE_FIRMWARE_NAME: %s, DEVICE_FIRMWARE_VERSION: %s" % (FIRMWARE_NAME, FIRMWARE_VERSION)) 58 | 59 | # Init settings. 60 | settings = Settings() 61 | # Init battery. 62 | battery = Battery() 63 | # Init history 64 | history = History() 65 | # Init power manage and set device low energy. 66 | power_manage = PowerManage() 67 | power_manage.autosleep(1) 68 | # Init net modules and start net connect. 69 | net_manager = NetManager() 70 | _thread.stack_size(0x1000) 71 | _thread.start_new_thread(net_manager.net_connect, ()) 72 | # Init GNSS modules and start reading and parsing gnss data. 73 | loc_cfg = settings.read("loc") 74 | gnss = GNSS(**loc_cfg["gps_cfg"]) 75 | gnss.set_trans(0) 76 | gnss.start() 77 | # Init cell and wifi location modules. 78 | cell = CellLocator(**loc_cfg["cell_cfg"]) 79 | wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) 80 | cyc = CoordinateSystemConvert() 81 | # Init tracker business modules. 82 | user_cfg = settings.read("user") 83 | server_cfg = settings.read("server") 84 | # Init coordinate system convert modules. 85 | if user_cfg["server"] == UserConfig._server.AliIot: 86 | server = AliIot(**server_cfg) 87 | server_ota = AliIotOTA(PROJECT_NAME, FIRMWARE_NAME) 88 | server_ota.set_server(server) 89 | tracker = AliTracker() 90 | elif user_cfg["server"] == UserConfig._server.ThingsBoard: 91 | # Init server modules. 92 | server = TBDeviceMQTTClient(**server_cfg) 93 | tracker = TBTracker() 94 | else: 95 | raise ValueError("User config server is not compared.") 96 | tracker.add_module(settings) 97 | tracker.add_module(battery) 98 | tracker.add_module(history) 99 | tracker.add_module(net_manager) 100 | tracker.add_module(server) 101 | tracker.add_module(server_ota) 102 | tracker.add_module(gnss) 103 | tracker.add_module(cell) 104 | tracker.add_module(wifi) 105 | tracker.add_module(cyc) 106 | server.add_event("over_speed_alert") 107 | server.add_event("sim_abnormal_alert") 108 | server.add_event("low_power_alert") 109 | server.add_event("fault_alert") 110 | # Set net modules callback. 111 | net_manager.set_callback(tracker.net_callback) 112 | # Set server modules callback. 113 | server.set_callback(tracker.server_callback) 114 | # Start tracker business. 115 | tracker.running() 116 | 117 | log.debug("[x] Main over.") 118 | 119 | if __name__ == "__main__": 120 | main() -------------------------------------------------------------------------------- /code/settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :settings.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Project settings. 19 | @version :2.2.0 20 | @date :2022-10-31 14:42:25 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | import uos 25 | import ql_fs 26 | import modem 27 | import _thread 28 | import usys as sys 29 | 30 | try: 31 | from settings_server import AliIotConfig, ThingsBoardConfig 32 | from settings_loc import LocConfig 33 | from settings_user import UserConfig 34 | except ImportError: 35 | from usr.settings_server import AliIotConfig, ThingsBoardConfig 36 | from usr.settings_loc import LocConfig 37 | from usr.settings_user import UserConfig 38 | 39 | PROJECT_NAME = "QuecPython-Tracker" 40 | 41 | PROJECT_VERSION = "2.2.0" 42 | 43 | FIRMWARE_NAME = uos.uname()[0].split("=")[1] 44 | 45 | FIRMWARE_VERSION = modem.getDevFwVersion() 46 | 47 | class Settings: 48 | 49 | def __init__(self, config_file="/usr/tracker_config.json"): 50 | self.__file = config_file 51 | self.__lock = _thread.allocate_lock() 52 | self.__data = {} 53 | self.__init_config() 54 | 55 | def __init_config(self): 56 | try: 57 | if ql_fs.path_exists(self.__file): 58 | ql_fs.touch(self.__file, {}) 59 | 60 | # UserConfig init 61 | self.__data["user"] = {k: v for k, v in UserConfig.__dict__.items() if not k.startswith("_")} 62 | self.__data["user"]["ota_status"]["sys_current_version"] = FIRMWARE_VERSION 63 | self.__data["user"]["ota_status"]["app_current_version"] = PROJECT_VERSION 64 | 65 | # CloudConfig init 66 | self.__data["server"] = {} 67 | if self.__data["user"]["server"] == UserConfig._server.AliIot: 68 | self.__data["server"] = {k: v for k, v in AliIotConfig.__dict__.items() if not k.startswith("_")} 69 | elif self.__data["user"]["server"] == UserConfig._server.ThingsBoard: 70 | self.__data["server"] = {k: v for k, v in ThingsBoardConfig.__dict__.items() if not k.startswith("_")} 71 | 72 | # LocConfig init 73 | self.__data["loc"] = {k: v for k, v in LocConfig.__dict__.items() if not k.startswith("_")} 74 | ql_fs.touch(self.__file, self.__data) 75 | except Exception as e: 76 | sys.print_exception(e) 77 | 78 | def read(self, key=None): 79 | with self.__lock: 80 | try: 81 | return self.__data if key is None else self.__data.get(key) 82 | except Exception as e: 83 | sys.print_exception(e) 84 | 85 | def save(self, data): 86 | with self.__lock: 87 | res = -1 88 | if isinstance(data, dict): 89 | self.__data.update(data) 90 | res = ql_fs.touch(self.__file, self.__data) 91 | return True if res == 0 else False 92 | -------------------------------------------------------------------------------- /code/settings_loc.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :dev_settings_loc.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Loction config. 19 | @version :2.2.0 20 | @date :2022-10-31 14:42:25 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | from machine import UART 25 | 26 | 27 | class LocConfig: 28 | 29 | class _gps_mode: 30 | internal = 0x1 31 | external_uart = 0x2 32 | external_i2c = 0x3 33 | 34 | class _map_coordinate_system: 35 | WGS84 = "WGS84" 36 | GCJ02 = "GCJ02" 37 | 38 | class _gps_sleep_mode: 39 | none = 0x0 40 | pull_off = 0x1 41 | backup = 0x2 42 | standby = 0x3 43 | 44 | profile_idx = 1 45 | 46 | map_coordinate_system = _map_coordinate_system.GCJ02 47 | 48 | gps_sleep_mode = _gps_sleep_mode.none 49 | 50 | gps_cfg = { 51 | "gps_mode": _gps_mode.internal, 52 | "UARTn": UART.UART2, 53 | "buadrate": 115200, 54 | "databits": 8, 55 | "parity": 0, 56 | "stopbits": 1, 57 | "flowctl": 0, 58 | "PowerPin": None, 59 | "StandbyPin": None, 60 | "BackupPin": None, 61 | } 62 | 63 | cell_cfg = { 64 | "serverAddr": "www.queclocator.com", 65 | "port": 80, 66 | "token": "xxxxxxxxxx", 67 | "timeout": 3, 68 | "profileIdx": profile_idx, 69 | } 70 | 71 | wifi_cfg = { 72 | "token": "xxxxxxxxxx" 73 | } 74 | -------------------------------------------------------------------------------- /code/settings_server.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :dev_settings_server.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Server config. 19 | @version :2.2.0 20 | @date :2022-10-31 14:42:25 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | 25 | class AliIotConfig: 26 | 27 | product_key = "" 28 | device_name = "" 29 | device_secret = "" 30 | product_secret = None 31 | server = "iot-as-mqtt.cn-shanghai.aliyuncs.com" 32 | qos = 1 33 | 34 | 35 | 36 | class ThingsBoardConfig: 37 | 38 | host = "" 39 | port = 1883 40 | username = "" 41 | qos = 0 42 | client_id = "" 43 | -------------------------------------------------------------------------------- /code/settings_user.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :settings_user.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :User setting config. 19 | @version :2.2.0 20 | @date :2023-04-11 11:43:11 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | 25 | class UserConfig: 26 | 27 | class _server: 28 | none = 0x0 29 | AliIot = 0x1 30 | ThingsBoard = 0x2 31 | 32 | class _loc_method: 33 | none = 0x0 34 | gps = 0x1 35 | cell = 0x2 36 | wifi = 0x4 37 | all = 0x7 38 | 39 | class _work_mode: 40 | cycle = 0x1 41 | intelligent = 0x2 42 | 43 | class _drive_behavior_code: 44 | none = 0x0 45 | sharply_start = 0x1 46 | sharply_stop = 0x2 47 | sharply_turn_left = 0x3 48 | sharply_turn_right = 0x4 49 | 50 | class _ota_upgrade_status: 51 | none = 0x0 52 | to_be_updated = 0x1 53 | updating = 0x2 54 | update_successed = 0x3 55 | update_failed = 0x4 56 | 57 | class _ota_upgrade_module: 58 | none = 0x0 59 | sys = 0x1 60 | app = 0x2 61 | 62 | debug = 1 63 | 64 | log_level = "DEBUG" 65 | 66 | checknet_timeout = 60 67 | 68 | server = _server.AliIot 69 | 70 | phone_num = "" 71 | 72 | low_power_alert_threshold = 20 73 | 74 | low_power_shutdown_threshold = 5 75 | 76 | over_speed_threshold = 50 77 | 78 | sw_ota = 1 79 | 80 | sw_ota_auto_upgrade = 1 81 | 82 | sw_voice_listen = 0 83 | 84 | sw_voice_record = 0 85 | 86 | sw_fault_alert = 1 87 | 88 | sw_low_power_alert = 1 89 | 90 | sw_over_speed_alert = 1 91 | 92 | sw_sim_abnormal_alert = 1 93 | 94 | sw_disassemble_alert = 1 95 | 96 | sw_drive_behavior_alert = 1 97 | 98 | drive_behavior_code = _drive_behavior_code.none 99 | 100 | loc_method = _loc_method.gps 101 | 102 | loc_gps_read_timeout = 300 103 | 104 | work_mode = _work_mode.cycle 105 | 106 | work_mode_timeline = 3600 107 | 108 | work_cycle_period = 10 109 | 110 | user_ota_action = -1 111 | 112 | ota_status = { 113 | "sys_current_version": "", 114 | "sys_target_version": "--", 115 | "app_current_version": "", 116 | "app_target_version": "--", 117 | "upgrade_module": _ota_upgrade_module.none, 118 | "upgrade_status": _ota_upgrade_status.none, 119 | } 120 | -------------------------------------------------------------------------------- /code/tracker_ali.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :tracker_ali.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Tracker by aliyun. 19 | @version :2.2.0 20 | @date :2023-04-11 11:43:11 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | import sys 25 | import utime 26 | import _thread 27 | import osTimer 28 | from misc import Power 29 | from queue import Queue 30 | from machine import RTC 31 | 32 | try: 33 | from settings_user import UserConfig 34 | from settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION 35 | from modules.battery import Battery 36 | from modules.history import History 37 | from modules.logging import getLogger 38 | from modules.net_manage import NetManager 39 | from modules.aliIot import AliIot, AliIotOTA 40 | from modules.power_manage import PowerManage, PMLock 41 | from modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert 42 | except ImportError: 43 | from usr.settings_user import UserConfig 44 | from usr.settings import Settings, PROJECT_NAME, PROJECT_VERSION, FIRMWARE_NAME, FIRMWARE_VERSION 45 | from usr.modules.battery import Battery 46 | from usr.modules.history import History 47 | from usr.modules.logging import getLogger 48 | from usr.modules.net_manage import NetManager 49 | from usr.modules.aliIot import AliIot, AliIotOTA 50 | from usr.modules.power_manage import PowerManage, PMLock 51 | from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert 52 | 53 | log = getLogger(__name__) 54 | 55 | 56 | class Tracker: 57 | 58 | def __init__(self): 59 | self.__server = None 60 | self.__server_ota = None 61 | self.__battery = None 62 | self.__history = None 63 | self.__gnss = None 64 | self.__cell = None 65 | self.__wifi = None 66 | self.__csc = None 67 | self.__net_manager = None 68 | self.__pm = None 69 | self.__settings = None 70 | 71 | self.__business_lock = PMLock("block") 72 | self.__business_tid = None 73 | self.__business_rtc = RTC() 74 | self.__business_queue = Queue() 75 | self.__business_tag = 0 76 | self.__running_tag = 0 77 | self.__server_ota_flag = 0 78 | self.__server_reconn_timer = osTimer() 79 | self.__server_conn_tag = 0 80 | self.__server_reconn_count = 0 81 | self.__reset_tag = 0 82 | 83 | def __business_start(self): 84 | if not self.__business_tid: 85 | _thread.stack_size(0x2000) 86 | self.__business_tid = _thread.start_new_thread(self.__business_running, ()) 87 | 88 | def __business_stop(self): 89 | if self.__business_tid and _thread.threadIsRunning(self.__business_tid): 90 | try: 91 | _thread.stop_thread(self.__business_tid) 92 | except Exception as e: 93 | sys.print_exception(e) 94 | self.__business_tid = None 95 | 96 | def __business_running(self): 97 | while True: 98 | data = self.__business_queue.get() 99 | with self.__business_lock: 100 | self.__business_tag = 1 101 | if data[0] == 0: 102 | if data[1] == "loc_report": 103 | self.__loc_report() 104 | elif data[1] == "server_connect": 105 | self.__server_connect() 106 | elif data[1] == "check_ota": 107 | self.__server_check_ota() 108 | elif data[1] == "ota_refresh": 109 | self.__ota_cfg_refresh() 110 | if data[0] == 1: 111 | self.__server_option(*data[1]) 112 | self.__business_tag = 0 113 | 114 | def __loc_report(self): 115 | his_data = {"properties": {}, "events": []} 116 | loc_state, properties = self.__get_device_infos() 117 | alarms = self.__get_alarms(properties) 118 | res = False 119 | if self.__server.status: 120 | res = self.__server.properties_report(properties) 121 | if not res: 122 | his_data["properties"] = properties 123 | for alarm in alarms: 124 | res = self.__server.event_report(alarm, {}) 125 | if not res: 126 | his_data["events"].append(alarm) 127 | 128 | if loc_state and not self.__server.status: 129 | his_data["properties"] = properties 130 | his_data["events"] = alarms 131 | 132 | if his_data["properties"] or his_data["events"]: 133 | self.__history.write([his_data]) 134 | 135 | self.__history_report() 136 | 137 | user_cfg = self.__settings.read("user") 138 | self.__set_rtc(user_cfg["work_cycle_period"], self.loc_report) 139 | 140 | def __history_report(self): 141 | failed_datas = [] 142 | his_datas = self.__history.read() 143 | if his_datas["data"]: 144 | for item in his_datas["data"]: 145 | faile_data = {"properties": {}, "events": []} 146 | res = self.__server.properties_report(item["properties"]) 147 | if not res: 148 | faile_data["properties"] = item["properties"] 149 | for alarm in item["events"]: 150 | res = self.__server.event_report(alarm, {}) 151 | if not res: 152 | faile_data["events"].append(alarm) 153 | if faile_data["properties"] or faile_data["events"]: 154 | failed_datas.append(faile_data) 155 | if failed_datas: 156 | self.__history.write(failed_datas) 157 | 158 | def __get_device_infos(self): 159 | user_cfg = self.__settings.read("user") 160 | loc_cfg = self.__settings.read("loc") 161 | properties = { 162 | "power_switch": 1, 163 | "energy": self.__battery.energy, 164 | "voltage": self.__battery.voltage, 165 | "local_time": str(utime.mktime(utime.localtime()) * 1000), 166 | "loc_method": { 167 | "gps": int((user_cfg["loc_method"] & UserConfig._loc_method.gps) / UserConfig._loc_method.gps), 168 | "cell": int((user_cfg["loc_method"] & UserConfig._loc_method.cell) / UserConfig._loc_method.cell), 169 | "wifi": int((user_cfg["loc_method"] & UserConfig._loc_method.wifi) / UserConfig._loc_method.wifi), 170 | }, 171 | "phone_num": user_cfg["phone_num"], 172 | "work_mode": user_cfg["work_mode"], 173 | "work_cycle_period": user_cfg["work_cycle_period"], 174 | "low_power_alert_threshold": user_cfg["low_power_alert_threshold"], 175 | "low_power_shutdown_threshold": user_cfg["low_power_shutdown_threshold"], 176 | "sw_ota": user_cfg["sw_ota"], 177 | "sw_ota_auto_upgrade": user_cfg["sw_ota_auto_upgrade"], 178 | "sw_voice_listen": user_cfg["sw_voice_listen"], 179 | "sw_voice_record": user_cfg["sw_voice_record"], 180 | "sw_fault_alert": user_cfg["sw_fault_alert"], 181 | "sw_low_power_alert": user_cfg["sw_low_power_alert"], 182 | "sw_over_speed_alert": user_cfg["sw_over_speed_alert"], 183 | "sw_sim_abnormal_alert": user_cfg["sw_sim_abnormal_alert"], 184 | "sw_disassemble_alert": user_cfg["sw_disassemble_alert"], 185 | "sw_drive_behavior_alert": user_cfg["sw_drive_behavior_alert"], 186 | "drive_behavior_code": user_cfg["drive_behavior_code"], 187 | "over_speed_threshold": user_cfg["over_speed_threshold"], 188 | "user_ota_action": user_cfg["user_ota_action"], 189 | "ota_status": user_cfg["ota_status"], 190 | "work_mode_timeline": user_cfg["work_mode_timeline"], 191 | "loc_gps_read_timeout": user_cfg["loc_gps_read_timeout"], 192 | "gps_mode": loc_cfg["gps_cfg"]["gps_mode"], 193 | "device_module_status": { 194 | # "net": 0, 195 | # "location": 0, 196 | # "temp_sensor": 0, 197 | # "light_sensor": 0, 198 | # "move_sensor": 0, 199 | # "mike": 0, 200 | }, 201 | } 202 | loc_state, loc_data = self.__get_loc_data() 203 | properties.update(loc_data) 204 | properties["device_module_status"]["location"] = 1 if properties["GeoLocation"]["Longitude"] else 0 205 | properties["device_module_status"]["temp_sensor"] = 1 if properties.get("temperature") is not None or properties.get("humidity") is not None else 0 206 | properties["device_module_status"]["net"] = int(self.__net_manager.net_status()) 207 | return (loc_state, properties) 208 | 209 | def __get_loc_data(self): 210 | loc_state = 0 211 | loc_data = { 212 | "GeoLocation": { 213 | "Longitude": 0.0, 214 | "Latitude": 0.0, 215 | "Altitude": 0.0, 216 | "CoordinateSystem": 1, 217 | }, 218 | "current_speed": 0, 219 | } 220 | loc_cfg = self.__settings.read("loc") 221 | loc_data["GeoLocation"]["CoordinateSystem"] = 1 if loc_cfg["map_coordinate_system"] == "WGS84" else 2 222 | user_cfg = self.__settings.read("user") 223 | if user_cfg["loc_method"] & UserConfig._loc_method.gps: 224 | res = self.__gnss.read() 225 | if res["state"] == "A": 226 | loc_data["GeoLocation"]["Latitude"] = float(res["lat"]) * (1 if res["lat_dir"] == "N" else -1) 227 | loc_data["GeoLocation"]["Longitude"] = float(res["lng"]) * (1 if res["lng_dir"] == "E" else -1) 228 | loc_data["GeoLocation"]["Altitude"] = res["altitude"] 229 | loc_data["current_speed"] = float(res["speed"]) 230 | loc_state = 1 231 | if loc_state == 0 and user_cfg["loc_method"] & UserConfig._loc_method.cell: 232 | res = self.__cell.read() 233 | if res: 234 | loc_data["GeoLocation"]["Longitude"] = res[0] 235 | loc_data["GeoLocation"]["Latitude"] = res[1] 236 | loc_state = 1 237 | if loc_state == 0 and user_cfg["loc_method"] & UserConfig._loc_method.wifi: 238 | res = self.__wifi.read() 239 | if res: 240 | loc_data["GeoLocation"]["Longitude"] = res[0] 241 | loc_data["GeoLocation"]["Latitude"] = res[1] 242 | loc_state = 1 243 | if loc_state == 1 and loc_cfg["map_coordinate_system"] == "GCJ02": 244 | lng, lat = self.__csc.wgs84_to_gcj02(loc_data["GeoLocation"]["Longitude"], loc_data["GeoLocation"]["Latitude"]) 245 | loc_data["GeoLocation"]["Longitude"] = lng 246 | loc_data["GeoLocation"]["Latitude"] = lat 247 | return (loc_state, loc_data) 248 | 249 | def __get_alarms(self, properties): 250 | alarms = [] 251 | user_cfg = self.__settings.read("user") 252 | if user_cfg["sw_over_speed_alert"] and properties["current_speed"] >= user_cfg["over_speed_threshold"]: 253 | alarms.append("over_speed_alert") 254 | if user_cfg["sw_sim_abnormal_alert"] and self.__net_manager.sim_status() != 1: 255 | alarms.append("sim_abnormal_alert") 256 | if user_cfg["sw_low_power_alert"] and properties["energy"] < user_cfg["low_power_alert_threshold"]: 257 | alarms.append("low_power_alert") 258 | if user_cfg["sw_fault_alert"] and 0 in properties["device_module_status"].values(): 259 | alarms.append("fault_alert") 260 | return alarms 261 | 262 | def __set_rtc(self, period, callback): 263 | self.__business_rtc.enable_alarm(0) 264 | if callback and callable(callback): 265 | self.__business_rtc.register_callback(callback) 266 | atime = utime.localtime(utime.mktime(utime.localtime()) + period) 267 | alarm_time = (atime[0], atime[1], atime[2], atime[6], atime[3], atime[4], atime[5], 0) 268 | _res = self.__business_rtc.set_alarm(alarm_time) 269 | log.debug("alarm_time: %s, set_alarm res %s." % (str(alarm_time), _res)) 270 | return self.__business_rtc.enable_alarm(1) if _res == 0 else -1 271 | 272 | def __server_connect(self): 273 | if self.__net_manager.net_status(): 274 | # self.__server.disconnect() 275 | self.__server.connect() 276 | if not self.__server.status: 277 | self.__server_reconn_timer.stop() 278 | self.__server_reconn_timer.start(60 * 1000, 0, self.server_connect) 279 | self.__server_reconn_count += 1 280 | else: 281 | self.__server_reconn_count = 0 282 | 283 | # When server not connect success after 20 miuntes, to reset device. 284 | if self.__server_reconn_count >= 20: 285 | _thread.stack_size(0x1000) 286 | _thread.start_new_thread(self.__power_restart, ()) 287 | self.__server_conn_tag = 0 288 | 289 | def __server_cfg_save(self, data): 290 | save_tag = 0 291 | server_cfg = self.__settings.read("server") 292 | if server_cfg["product_key"] != data["product_key"]: 293 | server_cfg["product_key"] = data["product_key"] 294 | save_tag = 1 295 | if server_cfg["product_secret"] != data["product_secret"]: 296 | server_cfg["product_secret"] = data["product_secret"] 297 | save_tag = 1 298 | if server_cfg["device_name"] != data["device_name"]: 299 | server_cfg["device_name"] = data["device_name"] 300 | save_tag = 1 301 | if server_cfg["device_secret"] != data["device_secret"]: 302 | server_cfg["device_secret"] = data["device_secret"] 303 | save_tag = 1 304 | if save_tag == 1: 305 | self.__settings.save({"server": server_cfg}) 306 | 307 | def __server_option(self, topic, data): 308 | if topic.endswith("/property/set"): 309 | self.__server_property_set(data) 310 | elif topic.find("/rrpc/request/") != -1: 311 | msg_id = topic.split("/")[-1] 312 | self.__server_rrpc_response(msg_id, data) 313 | elif topic.find("/thing/service/") != -1: 314 | service = topic.split("/")[-1] 315 | self.__server_service_response(service, data) 316 | elif topic.startswith("/ota/device/upgrade/") or topic.endswith("/ota/firmware/get_reply"): 317 | user_cfg = self.__settings.read("user") 318 | if self.__server_ota_flag == 0: 319 | if user_cfg["sw_ota"] == 1: 320 | self.__server_ota_flag = 1 321 | if user_cfg["sw_ota_auto_upgrade"] == 1 or user_cfg["user_ota_action"] == 1: 322 | self.__server_ota_process(data) 323 | else: 324 | self.__server_ota_flag = 0 325 | self.__server_ota.set_ota_data(data["data"]) 326 | ota_info = self.__server_ota.get_ota_info() 327 | ota_info["ota_status"] = 1 328 | self.__server_ota_state_save(**ota_info) 329 | else: 330 | module = data.get("data", {}).get("module") 331 | self.__server.ota_device_progress(-1, "Device is not alowed ota.", module) 332 | 333 | def __server_property_set(self, data): 334 | set_properties = data.get("params", {}) 335 | user_cfg = self.__settings.read("user") 336 | user_cfg.update(set_properties) 337 | if self.__settings.save({"user": user_cfg}): 338 | self.__server.property_set_reply(data.get("id"), 200, "success") 339 | self.__business_queue.put((0, "loc_report")) 340 | else: 341 | self.__server.property_set_reply(data.get("id"), 9201, "save properties failed") 342 | 343 | def __server_ota_process(self, data): 344 | code = data.get("code") 345 | module = data.get("data", {}).get("module") 346 | if code in ("1000", 200) and module: 347 | self.__server.ota_device_progress(1, "", module) 348 | self.__server_ota.set_ota_data(data["data"]) 349 | ota_info = self.__server_ota.get_ota_info() 350 | ota_info["ota_status"] = 2 351 | self.__server_ota_state_save(**ota_info) 352 | if self.__server_ota.start(): 353 | ota_info["ota_status"] = 3 354 | self.__server_ota_state_save(**ota_info) 355 | self.__power_restart() 356 | else: 357 | ota_info["ota_status"] = 4 358 | self.__server_ota_state_save(**ota_info) 359 | self.__server_ota_flag = 0 360 | 361 | def __server_ota_state_save(self, ota_module, ota_version, ota_status): 362 | user_cfg = self.__settings.read("user") 363 | if ota_module == PROJECT_NAME: 364 | user_cfg["ota_status"]["upgrade_module"] = 2 365 | user_cfg["ota_status"]["upgrade_status"] = ota_status 366 | user_cfg["ota_status"]["app_target_version"] = ota_version 367 | if ota_module == FIRMWARE_NAME: 368 | user_cfg["ota_status"]["upgrade_module"] = 1 369 | user_cfg["ota_status"]["upgrade_status"] = ota_status 370 | user_cfg["ota_status"]["sys_target_version"] = ota_version 371 | self.__settings.save({"user": user_cfg}) 372 | 373 | def __server_check_ota(self): 374 | if self.__server_ota_flag == 0 and self.__server.status: 375 | res = self.__server.ota_device_inform(PROJECT_VERSION, PROJECT_NAME) 376 | log.debug("ota_device_inform report project %s" % res) 377 | res = self.__server.ota_device_inform(FIRMWARE_VERSION, FIRMWARE_NAME) 378 | log.debug("ota_device_inform report firmware %s" % res) 379 | res = self.__server.ota_firmware_get(PROJECT_NAME) 380 | log.debug("ota_firmware_get project %s" % res) 381 | res = self.__server.ota_firmware_get(FIRMWARE_NAME) 382 | log.debug("ota_firmware_get firmware %s" % res) 383 | 384 | def __server_rrpc_response(self, msg_id, data): 385 | self.__server.rrpc_response(msg_id, data) 386 | 387 | def __server_service_response(self, service, data): 388 | msg_id = data.get("id") 389 | self.__server.service_response(service, 200, {}, msg_id, "success") 390 | 391 | def __power_restart(self): 392 | log.debug("__power_restart") 393 | Power.powerRestart() 394 | 395 | def __ota_cfg_refresh(self): 396 | user_cfg = self.__settings.read("user") 397 | if user_cfg["ota_status"]["upgrade_status"] in (3, 4): 398 | user_cfg["ota_status"]["upgrade_status"] = 0 399 | if user_cfg["ota_status"]["upgrade_module"] == 1: 400 | user_cfg["ota_status"]["sys_target_version"] = "--" 401 | if user_cfg["ota_status"]["upgrade_module"] == 2: 402 | user_cfg["ota_status"]["app_target_version"] = "--" 403 | user_cfg["ota_status"]["upgrade_module"] = 0 404 | user_cfg["user_ota_action"] = -1 405 | self.__settings.save({"user": user_cfg}) 406 | 407 | def add_module(self, module): 408 | if isinstance(module, AliIot): 409 | self.__server = module 410 | elif isinstance(module, AliIotOTA): 411 | self.__server_ota = module 412 | elif isinstance(module, Battery): 413 | self.__battery = module 414 | elif isinstance(module, History): 415 | self.__history = module 416 | elif isinstance(module, GNSSBase): 417 | self.__gnss = module 418 | elif isinstance(module, CellLocator): 419 | self.__cell = module 420 | elif isinstance(module, WiFiLocator): 421 | self.__wifi = module 422 | elif isinstance(module, CoordinateSystemConvert): 423 | self.__csc = module 424 | elif isinstance(module, NetManager): 425 | self.__net_manager = module 426 | elif isinstance(module, Settings): 427 | self.__settings = module 428 | else: 429 | return False 430 | return True 431 | 432 | def running(self, args=None): 433 | self.__business_start() 434 | self.server_connect(None) 435 | self.__business_queue.put((0, "ota_refresh")) 436 | self.loc_report(None) 437 | self.__business_queue.put((0, "check_ota")) 438 | 439 | def server_callback(self, args): 440 | self.__business_queue.put((1, args)) 441 | 442 | def net_callback(self, args): 443 | log.debug("net_callback args: %s" % str(args)) 444 | if args[1] == 0: 445 | self.__server.disconnect() 446 | self.__server_reconn_timer.stop() 447 | self.__server_reconn_timer.start(30 * 1000, 0, self.server_connect) 448 | else: 449 | self.__server_reconn_timer.stop() 450 | self.server_connect(None) 451 | 452 | def loc_report(self, args): 453 | self.__business_queue.put((0, "loc_report")) 454 | 455 | def server_connect(self, args): 456 | if self.__server_conn_tag == 0: 457 | self.__server_conn_tag = 1 458 | self.__business_queue.put((0, "server_connect")) 459 | -------------------------------------------------------------------------------- /code/tracker_tb.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | @file :tracker_tb.py 17 | @author :Jack Sun (jack.sun@quectel.com) 18 | @brief :Tracker by ThingsBoard. 19 | @version :2.2.0 20 | @date :2023-04-14 14:30:13 21 | @copyright :Copyright (c) 2022 22 | """ 23 | 24 | import utime 25 | import _thread 26 | import osTimer 27 | from misc import Power 28 | from queue import Queue 29 | from machine import RTC 30 | 31 | try: 32 | from settings import Settings 33 | from settings_user import UserConfig 34 | from modules.battery import Battery 35 | from modules.history import History 36 | from modules.logging import getLogger 37 | from modules.net_manage import NetManager 38 | from modules.thingsboard import TBDeviceMQTTClient 39 | from modules.power_manage import PowerManage, PMLock 40 | from modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert 41 | except ImportError: 42 | from usr.settings import Settings 43 | from usr.settings_user import UserConfig 44 | from usr.modules.battery import Battery 45 | from usr.modules.history import History 46 | from usr.modules.logging import getLogger 47 | from usr.modules.net_manage import NetManager 48 | from usr.modules.thingsboard import TBDeviceMQTTClient 49 | from usr.modules.power_manage import PowerManage, PMLock 50 | from usr.modules.location import GNSS, GNSSBase, CellLocator, WiFiLocator, CoordinateSystemConvert 51 | 52 | log = getLogger(__name__) 53 | 54 | 55 | class Tracker: 56 | 57 | def __init__(self): 58 | self.__server = None 59 | self.__server_ota = None 60 | self.__battery = None 61 | self.__history = None 62 | self.__gnss = None 63 | self.__cell = None 64 | self.__wifi = None 65 | self.__csc = None 66 | self.__net_manager = None 67 | self.__settings = None 68 | 69 | self.__business_lock = PMLock("block") 70 | self.__business_tid = None 71 | self.__business_rtc = RTC() 72 | self.__business_queue = Queue() 73 | self.__business_tag = 0 74 | self.__server_ota_flag = 0 75 | self.__server_reconn_timer = osTimer() 76 | self.__server_conn_tag = 0 77 | self.__server_reconn_count = 0 78 | self.__reset_tag = 0 79 | 80 | def __business_start(self): 81 | if not self.__business_tid or (self.__business_tid and not _thread.threadIsRunning(self.__business_tid)): 82 | _thread.stack_size(0x2000) 83 | self.__business_tid = _thread.start_new_thread(self.__business_running, ()) 84 | 85 | def __business_stop(self): 86 | self.__business_tid = None 87 | 88 | def __business_running(self): 89 | while self.__business_tid is not None or self.__business_queue.size() > 0: 90 | data = self.__business_queue.get() 91 | with self.__business_lock: 92 | self.__business_tag = 1 93 | if data[0] == 0: 94 | if data[1] == "loc_report": 95 | self.__loc_report() 96 | if data[1] == "server_connect": 97 | self.__server_connect() 98 | if data[0] == 1: 99 | self.__server_option(data[1]) 100 | self.__business_tag = 0 101 | 102 | def __loc_report(self): 103 | # Report current location. 104 | loc_state, properties = self.__get_loc_data() 105 | if loc_state == 1: 106 | res = False 107 | if self.__server.status: 108 | res = self.__server.send_telemetry(properties) 109 | if not res: 110 | self.__history.write([properties]) 111 | 112 | # Report history location. 113 | if self.__server.status: 114 | self.__history_report() 115 | 116 | # Start report again timer. 117 | user_cfg = self.__settings.read("user") 118 | self.__set_rtc(user_cfg["work_cycle_period"], self.loc_report) 119 | 120 | def __history_report(self): 121 | failed_datas = [] 122 | his_datas = self.__history.read() 123 | if his_datas["data"]: 124 | for item in his_datas["data"]: 125 | res = self.__server.send_telemetry(item) 126 | if not res: 127 | failed_datas.append(item) 128 | if failed_datas: 129 | self.__history.write(failed_datas) 130 | 131 | def __get_loc_data(self): 132 | loc_state = 0 133 | loc_data = { 134 | "Longitude": 0.0, 135 | "Latitude": 0.0, 136 | "Altitude": 0.0, 137 | "Speed": 0.0, 138 | } 139 | loc_cfg = self.__settings.read("loc") 140 | user_cfg = self.__settings.read("user") 141 | if user_cfg["loc_method"] & UserConfig._loc_method.gps: 142 | res = self.__gnss.read() 143 | log.debug("gnss read %s" % str(res)) 144 | if res["state"] == "A": 145 | loc_data["Latitude"] = float(res["lat"]) * (1 if res["lat_dir"] == "N" else -1) 146 | loc_data["Longitude"] = float(res["lng"]) * (1 if res["lng_dir"] == "E" else -1) 147 | loc_data["Altitude"] = res["altitude"] 148 | loc_data["Speed"] = res["speed"] 149 | loc_state = 1 150 | if loc_state == 0 and user_cfg["loc_method"] & UserConfig._loc_method.cell: 151 | res = self.__cell.read() 152 | if isinstance(res, tuple): 153 | loc_data["Longitude"] = res[0] 154 | loc_data["Latitude"] = res[1] 155 | loc_state = 1 156 | if loc_state == 0 and user_cfg["loc_method"] & UserConfig._loc_method.wifi: 157 | res = self.__wifi.read() 158 | if isinstance(res, tuple): 159 | loc_data["Longitude"] = res[0] 160 | loc_data["Latitude"] = res[1] 161 | loc_state = 1 162 | if loc_state == 1 and loc_cfg["map_coordinate_system"] == "GCJ02": 163 | lng, lat = self.__csc.wgs84_to_gcj02(loc_data["Longitude"], loc_data["Latitude"]) 164 | loc_data["Longitude"] = lng 165 | loc_data["Latitude"] = lat 166 | return (loc_state, loc_data) 167 | 168 | def __set_rtc(self, period, callback): 169 | self.__business_rtc.enable_alarm(0) 170 | if callback and callable(callback): 171 | self.__business_rtc.register_callback(callback) 172 | atime = utime.localtime(utime.mktime(utime.localtime()) + period) 173 | alarm_time = (atime[0], atime[1], atime[2], atime[6], atime[3], atime[4], atime[5], 0) 174 | _res = self.__business_rtc.set_alarm(alarm_time) 175 | log.debug("alarm_time: %s, set_alarm res %s." % (str(alarm_time), _res)) 176 | return self.__business_rtc.enable_alarm(1) if _res == 0 else -1 177 | 178 | def __server_connect(self): 179 | if self.__net_manager.net_status(): 180 | self.__server.disconnect() 181 | self.__server.connect() 182 | if not self.__server.status: 183 | self.__server_reconn_timer.stop() 184 | self.__server_reconn_timer.start(60 * 1000, 0, self.server_connect) 185 | self.__server_reconn_count += 1 186 | else: 187 | self.__server_reconn_count = 0 188 | 189 | # When server not connect success after 20 miuntes, to reset device. 190 | if self.__server_reconn_count >= 20: 191 | _thread.stack_size(0x1000) 192 | _thread.start_new_thread(self.__power_restart, ()) 193 | self.__server_conn_tag = 0 194 | 195 | def __server_option(self, args): 196 | topic, data = args 197 | log.debug("topic[%s]data[%s]" % args) 198 | # TODO: Handle server data. 199 | 200 | def __power_restart(self): 201 | if self.__reset_tag == 1: 202 | return 203 | self.__reset_tag = 1 204 | count = 0 205 | while (self.__business_queue.size() > 0 or self.__business_tag == 1) and count < 30: 206 | count += 1 207 | utime.sleep(1) 208 | log.debug("__power_restart") 209 | Power.powerRestart() 210 | 211 | def add_module(self, module): 212 | if isinstance(module, TBDeviceMQTTClient): 213 | self.__server = module 214 | elif isinstance(module, Battery): 215 | self.__battery = module 216 | elif isinstance(module, History): 217 | self.__history = module 218 | elif isinstance(module, GNSSBase): 219 | self.__gnss = module 220 | elif isinstance(module, CellLocator): 221 | self.__cell = module 222 | elif isinstance(module, WiFiLocator): 223 | self.__wifi = module 224 | elif isinstance(module, CoordinateSystemConvert): 225 | self.__csc = module 226 | elif isinstance(module, NetManager): 227 | self.__net_manager = module 228 | elif isinstance(module, Settings): 229 | self.__settings = module 230 | else: 231 | return False 232 | return True 233 | 234 | def running(self): 235 | self.__business_start() 236 | self.server_connect(None) 237 | self.loc_report(None) 238 | 239 | def server_callback(self, topic, data): 240 | self.__business_queue.put((1, (topic, data))) 241 | 242 | def net_callback(self, args): 243 | log.debug("net_callback args: %s" % str(args)) 244 | if args[1] == 0: 245 | self.__server.disconnect() 246 | self.__server_reconn_timer.stop() 247 | self.__server_reconn_timer.start(30 * 1000, 0, self.server_connect) 248 | else: 249 | self.__server_reconn_timer.stop() 250 | self.server_connect(None) 251 | 252 | def loc_report(self, args): 253 | self.__business_queue.put((0, "loc_report")) 254 | 255 | def server_connect(self, args): 256 | if self.__server_conn_tag == 0: 257 | self.__server_conn_tag = 1 258 | self.__business_queue.put((0, "server_connect")) 259 | 260 | 261 | if __name__ == "__main__": 262 | # Init settings. 263 | settings = Settings() 264 | # Init battery. 265 | battery = Battery() 266 | # Init history 267 | history = History() 268 | # Init power manage and set device low energy. 269 | power_manage = PowerManage() 270 | power_manage.autosleep(1) 271 | # Init net modules and start net connect. 272 | net_manager = NetManager() 273 | _thread.stack_size(0x1000) 274 | _thread.start_new_thread(net_manager.net_connect, ()) 275 | # Init GNSS modules and start reading and parsing gnss data. 276 | loc_cfg = settings.read("loc") 277 | gnss = GNSS(**loc_cfg["gps_cfg"]) 278 | gnss.set_trans(0) 279 | gnss.start() 280 | # Init cell and wifi location modules. 281 | cell = CellLocator(**loc_cfg["cell_cfg"]) 282 | wifi = WiFiLocator(**loc_cfg["wifi_cfg"]) 283 | # Init coordinate system convert modules. 284 | cyc = CoordinateSystemConvert() 285 | # Init server modules. 286 | server_cfg = settings.read("server") 287 | server = TBDeviceMQTTClient(**server_cfg) 288 | # Init tracker business modules. 289 | tracker = Tracker() 290 | tracker.add_module(settings) 291 | tracker.add_module(battery) 292 | tracker.add_module(history) 293 | tracker.add_module(net_manager) 294 | tracker.add_module(server) 295 | tracker.add_module(gnss) 296 | tracker.add_module(cell) 297 | tracker.add_module(wifi) 298 | tracker.add_module(cyc) 299 | # Set net modules callback. 300 | net_manager.set_callback(tracker.net_callback) 301 | # Set server modules callback. 302 | server.set_callback(tracker.server_callback) 303 | # Start tracker business. 304 | tracker.running() 305 | -------------------------------------------------------------------------------- /docs/en/media/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/en/media/connect.png -------------------------------------------------------------------------------- /docs/en/media/tracker_application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/en/media/tracker_application.png -------------------------------------------------------------------------------- /docs/en/media/tracker_funcion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/en/media/tracker_funcion.png -------------------------------------------------------------------------------- /docs/en/media/tracker_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/en/media/tracker_process.png -------------------------------------------------------------------------------- /docs/zh/media/tracker_application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/zh/media/tracker_application.png -------------------------------------------------------------------------------- /docs/zh/media/tracker_funcion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/zh/media/tracker_funcion.png -------------------------------------------------------------------------------- /docs/zh/media/tracker_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/zh/media/tracker_process.png -------------------------------------------------------------------------------- /docs/zh/media/连线.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuecPython/solution-tracker/9b4b6438728fe4de2ca73cd3610db52535a0d804/docs/zh/media/连线.png -------------------------------------------------------------------------------- /object_model_demo/ali_cloud_object_model.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": "https://iotx-tsl.oss-ap-southeast-1.aliyuncs.com/schema.json", 3 | "profile": { 4 | "version": "1.0", 5 | "productKey": "h3nqn03lil0" 6 | }, 7 | "properties": [ 8 | { 9 | "identifier": "GeoLocation", 10 | "name": "地理位置", 11 | "accessMode": "r", 12 | "required": true, 13 | "dataType": { 14 | "type": "struct", 15 | "specs": [ 16 | { 17 | "identifier": "Longitude", 18 | "name": "经度", 19 | "dataType": { 20 | "type": "double", 21 | "specs": { 22 | "min": "-180", 23 | "max": "180", 24 | "unit": "°", 25 | "unitName": "度", 26 | "step": "0.01" 27 | } 28 | } 29 | }, 30 | { 31 | "identifier": "Latitude", 32 | "name": "纬度", 33 | "dataType": { 34 | "type": "double", 35 | "specs": { 36 | "min": "-90", 37 | "max": "90", 38 | "unit": "°", 39 | "unitName": "度", 40 | "step": "0.01" 41 | } 42 | } 43 | }, 44 | { 45 | "identifier": "Altitude", 46 | "name": "海拔", 47 | "dataType": { 48 | "type": "double", 49 | "specs": { 50 | "min": "0", 51 | "max": "9999", 52 | "unit": "m", 53 | "unitName": "米", 54 | "step": "0.01" 55 | } 56 | } 57 | }, 58 | { 59 | "identifier": "CoordinateSystem", 60 | "name": "坐标系统", 61 | "dataType": { 62 | "type": "enum", 63 | "specs": { 64 | "1": "WGS_84", 65 | "2": "GCJ_02" 66 | } 67 | } 68 | } 69 | ] 70 | } 71 | }, 72 | { 73 | "identifier": "power_switch", 74 | "name": "开关机", 75 | "accessMode": "rw", 76 | "required": false, 77 | "dataType": { 78 | "type": "bool", 79 | "specs": { 80 | "0": "关", 81 | "1": "开" 82 | } 83 | } 84 | }, 85 | { 86 | "identifier": "energy", 87 | "name": "电量", 88 | "accessMode": "r", 89 | "required": false, 90 | "dataType": { 91 | "type": "int", 92 | "specs": { 93 | "min": "0", 94 | "max": "100", 95 | "unit": "%", 96 | "unitName": "百分比", 97 | "step": "1" 98 | } 99 | } 100 | }, 101 | { 102 | "identifier": "phone_num", 103 | "name": "电话号码", 104 | "accessMode": "rw", 105 | "required": false, 106 | "dataType": { 107 | "type": "text", 108 | "specs": { 109 | "length": "11" 110 | } 111 | } 112 | }, 113 | { 114 | "identifier": "loc_method", 115 | "name": "定位方式", 116 | "accessMode": "rw", 117 | "required": false, 118 | "dataType": { 119 | "type": "struct", 120 | "specs": [ 121 | { 122 | "identifier": "gps", 123 | "name": "GPS", 124 | "dataType": { 125 | "type": "bool", 126 | "specs": { 127 | "0": "禁用", 128 | "1": "启用" 129 | } 130 | } 131 | }, 132 | { 133 | "identifier": "cell", 134 | "name": "基站", 135 | "dataType": { 136 | "type": "bool", 137 | "specs": { 138 | "0": "禁用", 139 | "1": "启用" 140 | } 141 | } 142 | }, 143 | { 144 | "identifier": "wifi", 145 | "name": "Wifi", 146 | "dataType": { 147 | "type": "bool", 148 | "specs": { 149 | "0": "禁用", 150 | "1": "启用" 151 | } 152 | } 153 | } 154 | ] 155 | } 156 | }, 157 | { 158 | "identifier": "work_mode", 159 | "name": "工作模式", 160 | "accessMode": "rw", 161 | "required": false, 162 | "dataType": { 163 | "type": "enum", 164 | "specs": { 165 | "1": "周期性模式", 166 | "2": "智能模式" 167 | } 168 | } 169 | }, 170 | { 171 | "identifier": "work_cycle_period", 172 | "name": "工作模式循环周期", 173 | "accessMode": "rw", 174 | "required": false, 175 | "dataType": { 176 | "type": "int", 177 | "specs": { 178 | "min": "5", 179 | "max": "2147483647", 180 | "unit": "s", 181 | "unitName": "秒", 182 | "step": "1" 183 | } 184 | } 185 | }, 186 | { 187 | "identifier": "local_time", 188 | "name": "本地时间", 189 | "accessMode": "r", 190 | "required": false, 191 | "dataType": { 192 | "type": "date", 193 | "specs": {} 194 | } 195 | }, 196 | { 197 | "identifier": "low_power_alert_threshold", 198 | "name": "低电报警阈值", 199 | "accessMode": "rw", 200 | "required": false, 201 | "dataType": { 202 | "type": "int", 203 | "specs": { 204 | "min": "5", 205 | "max": "30", 206 | "step": "1" 207 | } 208 | } 209 | }, 210 | { 211 | "identifier": "low_power_shutdown_threshold", 212 | "name": "低电关机阈值", 213 | "accessMode": "rw", 214 | "required": false, 215 | "dataType": { 216 | "type": "int", 217 | "specs": { 218 | "min": "5", 219 | "max": "30", 220 | "step": "1" 221 | } 222 | } 223 | }, 224 | { 225 | "identifier": "sw_ota", 226 | "name": "OTA功能", 227 | "accessMode": "rw", 228 | "required": false, 229 | "dataType": { 230 | "type": "bool", 231 | "specs": { 232 | "0": "关", 233 | "1": "开" 234 | } 235 | } 236 | }, 237 | { 238 | "identifier": "sw_ota_auto_upgrade", 239 | "name": "OTA自动升级功能", 240 | "accessMode": "rw", 241 | "required": false, 242 | "dataType": { 243 | "type": "bool", 244 | "specs": { 245 | "0": "关", 246 | "1": "开" 247 | } 248 | } 249 | }, 250 | { 251 | "identifier": "sw_voice_listen", 252 | "name": "语音监听功能", 253 | "accessMode": "rw", 254 | "required": false, 255 | "dataType": { 256 | "type": "bool", 257 | "specs": { 258 | "0": "关", 259 | "1": "开" 260 | } 261 | } 262 | }, 263 | { 264 | "identifier": "sw_voice_record", 265 | "name": "录音上报功能", 266 | "accessMode": "rw", 267 | "required": false, 268 | "dataType": { 269 | "type": "bool", 270 | "specs": { 271 | "0": "关", 272 | "1": "开" 273 | } 274 | } 275 | }, 276 | { 277 | "identifier": "sw_fault_alert", 278 | "name": "故障报警功能", 279 | "accessMode": "rw", 280 | "required": false, 281 | "dataType": { 282 | "type": "bool", 283 | "specs": { 284 | "0": "关", 285 | "1": "开" 286 | } 287 | } 288 | }, 289 | { 290 | "identifier": "sw_low_power_alert", 291 | "name": "低电报警功能", 292 | "accessMode": "rw", 293 | "required": false, 294 | "dataType": { 295 | "type": "bool", 296 | "specs": { 297 | "0": "关", 298 | "1": "开" 299 | } 300 | } 301 | }, 302 | { 303 | "identifier": "sw_over_speed_alert", 304 | "name": "超速报警功能", 305 | "accessMode": "rw", 306 | "required": false, 307 | "dataType": { 308 | "type": "bool", 309 | "specs": { 310 | "0": "关", 311 | "1": "开" 312 | } 313 | } 314 | }, 315 | { 316 | "identifier": "sw_sim_abnormal_alert", 317 | "name": "SIM卡异常报警功能", 318 | "accessMode": "rw", 319 | "required": false, 320 | "dataType": { 321 | "type": "bool", 322 | "specs": { 323 | "0": "关", 324 | "1": "开" 325 | } 326 | } 327 | }, 328 | { 329 | "identifier": "sw_disassemble_alert", 330 | "name": "拆卸报警功能", 331 | "accessMode": "rw", 332 | "required": false, 333 | "dataType": { 334 | "type": "bool", 335 | "specs": { 336 | "0": "关", 337 | "1": "开" 338 | } 339 | } 340 | }, 341 | { 342 | "identifier": "sw_drive_behavior_alert", 343 | "name": "驾驶行为报警功能", 344 | "accessMode": "rw", 345 | "required": false, 346 | "dataType": { 347 | "type": "bool", 348 | "specs": { 349 | "0": "关", 350 | "1": "开" 351 | } 352 | } 353 | }, 354 | { 355 | "identifier": "drive_behavior_code", 356 | "name": "异常驾驶行为", 357 | "accessMode": "r", 358 | "required": false, 359 | "dataType": { 360 | "type": "enum", 361 | "specs": { 362 | "0": "无", 363 | "1": "急起", 364 | "2": "急停", 365 | "3": "左急转弯", 366 | "4": "右急转弯" 367 | } 368 | } 369 | }, 370 | { 371 | "identifier": "power_restart", 372 | "name": "模块重启", 373 | "accessMode": "rw", 374 | "required": false, 375 | "dataType": { 376 | "type": "enum", 377 | "specs": { 378 | "1": "重启" 379 | } 380 | } 381 | }, 382 | { 383 | "identifier": "over_speed_threshold", 384 | "name": "超速报警阈值", 385 | "accessMode": "rw", 386 | "required": false, 387 | "dataType": { 388 | "type": "int", 389 | "specs": { 390 | "min": "0", 391 | "max": "132", 392 | "unit": "km/h", 393 | "unitName": "千米每小时", 394 | "step": "1" 395 | } 396 | } 397 | }, 398 | { 399 | "identifier": "device_module_status", 400 | "name": "设备模块状态", 401 | "accessMode": "r", 402 | "required": false, 403 | "dataType": { 404 | "type": "struct", 405 | "specs": [ 406 | { 407 | "identifier": "net", 408 | "name": "网络状态", 409 | "dataType": { 410 | "type": "enum", 411 | "specs": { 412 | "0": "异常", 413 | "1": "正常" 414 | } 415 | } 416 | }, 417 | { 418 | "identifier": "location", 419 | "name": "定位状态", 420 | "dataType": { 421 | "type": "enum", 422 | "specs": { 423 | "0": "异常", 424 | "1": "正常" 425 | } 426 | } 427 | }, 428 | { 429 | "identifier": "temp_sensor", 430 | "name": "温湿度传感器状态", 431 | "dataType": { 432 | "type": "enum", 433 | "specs": { 434 | "0": "异常", 435 | "1": "正常" 436 | } 437 | } 438 | }, 439 | { 440 | "identifier": "light_sensor", 441 | "name": "光照传感器状态", 442 | "dataType": { 443 | "type": "enum", 444 | "specs": { 445 | "0": "异常", 446 | "1": "正常" 447 | } 448 | } 449 | }, 450 | { 451 | "identifier": "move_sensor", 452 | "name": "三轴加速传感器状态", 453 | "dataType": { 454 | "type": "enum", 455 | "specs": { 456 | "0": "异常", 457 | "1": "正常" 458 | } 459 | } 460 | }, 461 | { 462 | "identifier": "mike", 463 | "name": "麦克风状态", 464 | "dataType": { 465 | "type": "enum", 466 | "specs": { 467 | "0": "异常", 468 | "1": "正常" 469 | } 470 | } 471 | } 472 | ] 473 | } 474 | }, 475 | { 476 | "identifier": "gps_mode", 477 | "name": "GPS模块类型", 478 | "accessMode": "r", 479 | "required": false, 480 | "dataType": { 481 | "type": "enum", 482 | "specs": { 483 | "0": "无GPS模块", 484 | "1": "内置GPS模块", 485 | "2": "外置GPS模块" 486 | } 487 | } 488 | }, 489 | { 490 | "identifier": "user_ota_action", 491 | "name": "确认OTA升级", 492 | "accessMode": "rw", 493 | "desc": "用户操作,只写功能", 494 | "required": false, 495 | "dataType": { 496 | "type": "enum", 497 | "specs": { 498 | "0": "取消升级", 499 | "1": "确认升级" 500 | } 501 | } 502 | }, 503 | { 504 | "identifier": "ota_status", 505 | "name": "OTA升级状态", 506 | "accessMode": "r", 507 | "required": false, 508 | "dataType": { 509 | "type": "struct", 510 | "specs": [ 511 | { 512 | "identifier": "sys_current_version", 513 | "name": "系统当前版本", 514 | "dataType": { 515 | "type": "text", 516 | "specs": { 517 | "length": "1024" 518 | } 519 | } 520 | }, 521 | { 522 | "identifier": "sys_target_version", 523 | "name": "系统目标版本", 524 | "dataType": { 525 | "type": "text", 526 | "specs": { 527 | "length": "1024" 528 | } 529 | } 530 | }, 531 | { 532 | "identifier": "app_current_version", 533 | "name": "应用当前版本", 534 | "dataType": { 535 | "type": "text", 536 | "specs": { 537 | "length": "1024" 538 | } 539 | } 540 | }, 541 | { 542 | "identifier": "app_target_version", 543 | "name": "应用目标版本", 544 | "dataType": { 545 | "type": "text", 546 | "specs": { 547 | "length": "1024" 548 | } 549 | } 550 | }, 551 | { 552 | "identifier": "upgrade_module", 553 | "name": "当前升级模块", 554 | "dataType": { 555 | "type": "enum", 556 | "specs": { 557 | "0": "无", 558 | "1": "系统", 559 | "2": "应用" 560 | } 561 | } 562 | }, 563 | { 564 | "identifier": "upgrade_status", 565 | "name": "当前升级状态", 566 | "dataType": { 567 | "type": "enum", 568 | "specs": { 569 | "0": "无", 570 | "1": "待升级", 571 | "2": "升级中", 572 | "3": "升级成功", 573 | "4": "升级失败" 574 | } 575 | } 576 | } 577 | ] 578 | } 579 | }, 580 | { 581 | "identifier": "voltage", 582 | "name": "电池电压", 583 | "accessMode": "r", 584 | "required": false, 585 | "dataType": { 586 | "type": "int", 587 | "specs": { 588 | "min": "0", 589 | "max": "2147483647", 590 | "unit": "mV", 591 | "unitName": "毫伏", 592 | "step": "1" 593 | } 594 | } 595 | }, 596 | { 597 | "identifier": "current_speed", 598 | "name": "当前时速", 599 | "accessMode": "r", 600 | "required": false, 601 | "dataType": { 602 | "type": "float", 603 | "specs": { 604 | "min": "0", 605 | "max": "200.00", 606 | "unit": "km/h", 607 | "unitName": "千米每小时", 608 | "step": "0.01" 609 | } 610 | } 611 | }, 612 | { 613 | "identifier": "work_mode_timeline", 614 | "name": "休眠策略参考时间", 615 | "accessMode": "rw", 616 | "required": false, 617 | "dataType": { 618 | "type": "int", 619 | "specs": { 620 | "min": "3600", 621 | "max": "2147483647", 622 | "unit": "s", 623 | "unitName": "秒", 624 | "step": "1" 625 | } 626 | } 627 | }, 628 | { 629 | "identifier": "loc_gps_read_timeout", 630 | "name": "GPS信息读取超时时间", 631 | "accessMode": "rw", 632 | "desc": "-1:一直等待直到读取到数据才进行返回\n0:不等待,读取接口返回数据后立即返回\n>0: 等待超时时间,单位秒", 633 | "required": false, 634 | "dataType": { 635 | "type": "int", 636 | "specs": { 637 | "min": "-1", 638 | "max": "2147483647", 639 | "unit": "s", 640 | "unitName": "秒", 641 | "step": "1" 642 | } 643 | } 644 | }, 645 | { 646 | "identifier": "temperature", 647 | "name": "设备温度", 648 | "accessMode": "r", 649 | "required": false, 650 | "dataType": { 651 | "type": "double", 652 | "specs": { 653 | "min": "-40", 654 | "max": "125", 655 | "unit": "°C", 656 | "unitName": "摄氏度", 657 | "step": "0.01" 658 | } 659 | } 660 | }, 661 | { 662 | "identifier": "humidity", 663 | "name": "设备湿度", 664 | "accessMode": "r", 665 | "required": false, 666 | "dataType": { 667 | "type": "double", 668 | "specs": { 669 | "min": "0", 670 | "max": "100", 671 | "unit": "%RH", 672 | "unitName": "相对湿度", 673 | "step": "0.01" 674 | } 675 | } 676 | } 677 | ], 678 | "events": [ 679 | { 680 | "identifier": "post", 681 | "name": "post", 682 | "type": "info", 683 | "required": true, 684 | "desc": "属性上报", 685 | "method": "thing.event.property.post", 686 | "outputData": [ 687 | { 688 | "identifier": "GeoLocation", 689 | "name": "地理位置", 690 | "dataType": { 691 | "type": "struct", 692 | "specs": [ 693 | { 694 | "identifier": "Longitude", 695 | "name": "经度", 696 | "dataType": { 697 | "type": "double", 698 | "specs": { 699 | "min": "-180", 700 | "max": "180", 701 | "unit": "°", 702 | "unitName": "度", 703 | "step": "0.01" 704 | } 705 | } 706 | }, 707 | { 708 | "identifier": "Latitude", 709 | "name": "纬度", 710 | "dataType": { 711 | "type": "double", 712 | "specs": { 713 | "min": "-90", 714 | "max": "90", 715 | "unit": "°", 716 | "unitName": "度", 717 | "step": "0.01" 718 | } 719 | } 720 | }, 721 | { 722 | "identifier": "Altitude", 723 | "name": "海拔", 724 | "dataType": { 725 | "type": "double", 726 | "specs": { 727 | "min": "0", 728 | "max": "9999", 729 | "unit": "m", 730 | "unitName": "米", 731 | "step": "0.01" 732 | } 733 | } 734 | }, 735 | { 736 | "identifier": "CoordinateSystem", 737 | "name": "坐标系统", 738 | "dataType": { 739 | "type": "enum", 740 | "specs": { 741 | "1": "WGS_84", 742 | "2": "GCJ_02" 743 | } 744 | } 745 | } 746 | ] 747 | } 748 | }, 749 | { 750 | "identifier": "power_switch", 751 | "name": "开关机", 752 | "dataType": { 753 | "type": "bool", 754 | "specs": { 755 | "0": "关", 756 | "1": "开" 757 | } 758 | } 759 | }, 760 | { 761 | "identifier": "energy", 762 | "name": "电量", 763 | "dataType": { 764 | "type": "int", 765 | "specs": { 766 | "min": "0", 767 | "max": "100", 768 | "unit": "%", 769 | "unitName": "百分比", 770 | "step": "1" 771 | } 772 | } 773 | }, 774 | { 775 | "identifier": "phone_num", 776 | "name": "电话号码", 777 | "dataType": { 778 | "type": "text", 779 | "specs": { 780 | "length": "11" 781 | } 782 | } 783 | }, 784 | { 785 | "identifier": "loc_method", 786 | "name": "定位方式", 787 | "dataType": { 788 | "type": "struct", 789 | "specs": [ 790 | { 791 | "identifier": "gps", 792 | "name": "GPS", 793 | "dataType": { 794 | "type": "bool", 795 | "specs": { 796 | "0": "禁用", 797 | "1": "启用" 798 | } 799 | } 800 | }, 801 | { 802 | "identifier": "cell", 803 | "name": "基站", 804 | "dataType": { 805 | "type": "bool", 806 | "specs": { 807 | "0": "禁用", 808 | "1": "启用" 809 | } 810 | } 811 | }, 812 | { 813 | "identifier": "wifi", 814 | "name": "Wifi", 815 | "dataType": { 816 | "type": "bool", 817 | "specs": { 818 | "0": "禁用", 819 | "1": "启用" 820 | } 821 | } 822 | } 823 | ] 824 | } 825 | }, 826 | { 827 | "identifier": "work_mode", 828 | "name": "工作模式", 829 | "dataType": { 830 | "type": "enum", 831 | "specs": { 832 | "1": "周期性模式", 833 | "2": "智能模式" 834 | } 835 | } 836 | }, 837 | { 838 | "identifier": "work_cycle_period", 839 | "name": "工作模式循环周期", 840 | "dataType": { 841 | "type": "int", 842 | "specs": { 843 | "min": "5", 844 | "max": "2147483647", 845 | "unit": "s", 846 | "unitName": "秒", 847 | "step": "1" 848 | } 849 | } 850 | }, 851 | { 852 | "identifier": "local_time", 853 | "name": "本地时间", 854 | "dataType": { 855 | "type": "date", 856 | "specs": {} 857 | } 858 | }, 859 | { 860 | "identifier": "low_power_alert_threshold", 861 | "name": "低电报警阈值", 862 | "dataType": { 863 | "type": "int", 864 | "specs": { 865 | "min": "5", 866 | "max": "30", 867 | "step": "1" 868 | } 869 | } 870 | }, 871 | { 872 | "identifier": "low_power_shutdown_threshold", 873 | "name": "低电关机阈值", 874 | "dataType": { 875 | "type": "int", 876 | "specs": { 877 | "min": "5", 878 | "max": "30", 879 | "step": "1" 880 | } 881 | } 882 | }, 883 | { 884 | "identifier": "sw_ota", 885 | "name": "OTA功能", 886 | "dataType": { 887 | "type": "bool", 888 | "specs": { 889 | "0": "关", 890 | "1": "开" 891 | } 892 | } 893 | }, 894 | { 895 | "identifier": "sw_ota_auto_upgrade", 896 | "name": "OTA自动升级功能", 897 | "dataType": { 898 | "type": "bool", 899 | "specs": { 900 | "0": "关", 901 | "1": "开" 902 | } 903 | } 904 | }, 905 | { 906 | "identifier": "sw_voice_listen", 907 | "name": "语音监听功能", 908 | "dataType": { 909 | "type": "bool", 910 | "specs": { 911 | "0": "关", 912 | "1": "开" 913 | } 914 | } 915 | }, 916 | { 917 | "identifier": "sw_voice_record", 918 | "name": "录音上报功能", 919 | "dataType": { 920 | "type": "bool", 921 | "specs": { 922 | "0": "关", 923 | "1": "开" 924 | } 925 | } 926 | }, 927 | { 928 | "identifier": "sw_fault_alert", 929 | "name": "故障报警功能", 930 | "dataType": { 931 | "type": "bool", 932 | "specs": { 933 | "0": "关", 934 | "1": "开" 935 | } 936 | } 937 | }, 938 | { 939 | "identifier": "sw_low_power_alert", 940 | "name": "低电报警功能", 941 | "dataType": { 942 | "type": "bool", 943 | "specs": { 944 | "0": "关", 945 | "1": "开" 946 | } 947 | } 948 | }, 949 | { 950 | "identifier": "sw_over_speed_alert", 951 | "name": "超速报警功能", 952 | "dataType": { 953 | "type": "bool", 954 | "specs": { 955 | "0": "关", 956 | "1": "开" 957 | } 958 | } 959 | }, 960 | { 961 | "identifier": "sw_sim_abnormal_alert", 962 | "name": "SIM卡异常报警功能", 963 | "dataType": { 964 | "type": "bool", 965 | "specs": { 966 | "0": "关", 967 | "1": "开" 968 | } 969 | } 970 | }, 971 | { 972 | "identifier": "sw_disassemble_alert", 973 | "name": "拆卸报警功能", 974 | "dataType": { 975 | "type": "bool", 976 | "specs": { 977 | "0": "关", 978 | "1": "开" 979 | } 980 | } 981 | }, 982 | { 983 | "identifier": "sw_drive_behavior_alert", 984 | "name": "驾驶行为报警功能", 985 | "dataType": { 986 | "type": "bool", 987 | "specs": { 988 | "0": "关", 989 | "1": "开" 990 | } 991 | } 992 | }, 993 | { 994 | "identifier": "drive_behavior_code", 995 | "name": "异常驾驶行为", 996 | "dataType": { 997 | "type": "enum", 998 | "specs": { 999 | "0": "无", 1000 | "1": "急起", 1001 | "2": "急停", 1002 | "3": "左急转弯", 1003 | "4": "右急转弯" 1004 | } 1005 | } 1006 | }, 1007 | { 1008 | "identifier": "power_restart", 1009 | "name": "模块重启", 1010 | "dataType": { 1011 | "type": "enum", 1012 | "specs": { 1013 | "1": "重启" 1014 | } 1015 | } 1016 | }, 1017 | { 1018 | "identifier": "over_speed_threshold", 1019 | "name": "超速报警阈值", 1020 | "dataType": { 1021 | "type": "int", 1022 | "specs": { 1023 | "min": "0", 1024 | "max": "132", 1025 | "unit": "km/h", 1026 | "unitName": "千米每小时", 1027 | "step": "1" 1028 | } 1029 | } 1030 | }, 1031 | { 1032 | "identifier": "device_module_status", 1033 | "name": "设备模块状态", 1034 | "dataType": { 1035 | "type": "struct", 1036 | "specs": [ 1037 | { 1038 | "identifier": "net", 1039 | "name": "网络状态", 1040 | "dataType": { 1041 | "type": "enum", 1042 | "specs": { 1043 | "0": "异常", 1044 | "1": "正常" 1045 | } 1046 | } 1047 | }, 1048 | { 1049 | "identifier": "location", 1050 | "name": "定位状态", 1051 | "dataType": { 1052 | "type": "enum", 1053 | "specs": { 1054 | "0": "异常", 1055 | "1": "正常" 1056 | } 1057 | } 1058 | }, 1059 | { 1060 | "identifier": "temp_sensor", 1061 | "name": "温湿度传感器状态", 1062 | "dataType": { 1063 | "type": "enum", 1064 | "specs": { 1065 | "0": "异常", 1066 | "1": "正常" 1067 | } 1068 | } 1069 | }, 1070 | { 1071 | "identifier": "light_sensor", 1072 | "name": "光照传感器状态", 1073 | "dataType": { 1074 | "type": "enum", 1075 | "specs": { 1076 | "0": "异常", 1077 | "1": "正常" 1078 | } 1079 | } 1080 | }, 1081 | { 1082 | "identifier": "move_sensor", 1083 | "name": "三轴加速传感器状态", 1084 | "dataType": { 1085 | "type": "enum", 1086 | "specs": { 1087 | "0": "异常", 1088 | "1": "正常" 1089 | } 1090 | } 1091 | }, 1092 | { 1093 | "identifier": "mike", 1094 | "name": "麦克风状态", 1095 | "dataType": { 1096 | "type": "enum", 1097 | "specs": { 1098 | "0": "异常", 1099 | "1": "正常" 1100 | } 1101 | } 1102 | } 1103 | ] 1104 | } 1105 | }, 1106 | { 1107 | "identifier": "gps_mode", 1108 | "name": "GPS模块类型", 1109 | "dataType": { 1110 | "type": "enum", 1111 | "specs": { 1112 | "0": "无GPS模块", 1113 | "1": "内置GPS模块", 1114 | "2": "外置GPS模块" 1115 | } 1116 | } 1117 | }, 1118 | { 1119 | "identifier": "user_ota_action", 1120 | "name": "确认OTA升级", 1121 | "dataType": { 1122 | "type": "enum", 1123 | "specs": { 1124 | "0": "取消升级", 1125 | "1": "确认升级" 1126 | } 1127 | } 1128 | }, 1129 | { 1130 | "identifier": "ota_status", 1131 | "name": "OTA升级状态", 1132 | "dataType": { 1133 | "type": "struct", 1134 | "specs": [ 1135 | { 1136 | "identifier": "sys_current_version", 1137 | "name": "系统当前版本", 1138 | "dataType": { 1139 | "type": "text", 1140 | "specs": { 1141 | "length": "1024" 1142 | } 1143 | } 1144 | }, 1145 | { 1146 | "identifier": "sys_target_version", 1147 | "name": "系统目标版本", 1148 | "dataType": { 1149 | "type": "text", 1150 | "specs": { 1151 | "length": "1024" 1152 | } 1153 | } 1154 | }, 1155 | { 1156 | "identifier": "app_current_version", 1157 | "name": "应用当前版本", 1158 | "dataType": { 1159 | "type": "text", 1160 | "specs": { 1161 | "length": "1024" 1162 | } 1163 | } 1164 | }, 1165 | { 1166 | "identifier": "app_target_version", 1167 | "name": "应用目标版本", 1168 | "dataType": { 1169 | "type": "text", 1170 | "specs": { 1171 | "length": "1024" 1172 | } 1173 | } 1174 | }, 1175 | { 1176 | "identifier": "upgrade_module", 1177 | "name": "当前升级模块", 1178 | "dataType": { 1179 | "type": "enum", 1180 | "specs": { 1181 | "0": "无", 1182 | "1": "系统", 1183 | "2": "应用" 1184 | } 1185 | } 1186 | }, 1187 | { 1188 | "identifier": "upgrade_status", 1189 | "name": "当前升级状态", 1190 | "dataType": { 1191 | "type": "enum", 1192 | "specs": { 1193 | "0": "无", 1194 | "1": "待升级", 1195 | "2": "升级中", 1196 | "3": "升级成功", 1197 | "4": "升级失败" 1198 | } 1199 | } 1200 | } 1201 | ] 1202 | } 1203 | }, 1204 | { 1205 | "identifier": "voltage", 1206 | "name": "电池电压", 1207 | "dataType": { 1208 | "type": "int", 1209 | "specs": { 1210 | "min": "0", 1211 | "max": "2147483647", 1212 | "unit": "mV", 1213 | "unitName": "毫伏", 1214 | "step": "1" 1215 | } 1216 | } 1217 | }, 1218 | { 1219 | "identifier": "current_speed", 1220 | "name": "当前时速", 1221 | "dataType": { 1222 | "type": "float", 1223 | "specs": { 1224 | "min": "0", 1225 | "max": "200.00", 1226 | "unit": "km/h", 1227 | "unitName": "千米每小时", 1228 | "step": "0.01" 1229 | } 1230 | } 1231 | }, 1232 | { 1233 | "identifier": "work_mode_timeline", 1234 | "name": "休眠策略参考时间", 1235 | "dataType": { 1236 | "type": "int", 1237 | "specs": { 1238 | "min": "3600", 1239 | "max": "2147483647", 1240 | "unit": "s", 1241 | "unitName": "秒", 1242 | "step": "1" 1243 | } 1244 | } 1245 | }, 1246 | { 1247 | "identifier": "loc_gps_read_timeout", 1248 | "name": "GPS信息读取超时时间", 1249 | "dataType": { 1250 | "type": "int", 1251 | "specs": { 1252 | "min": "-1", 1253 | "max": "2147483647", 1254 | "unit": "s", 1255 | "unitName": "秒", 1256 | "step": "1" 1257 | } 1258 | } 1259 | }, 1260 | { 1261 | "identifier": "temperature", 1262 | "name": "设备温度", 1263 | "dataType": { 1264 | "type": "double", 1265 | "specs": { 1266 | "min": "-40", 1267 | "max": "125", 1268 | "unit": "°C", 1269 | "unitName": "摄氏度", 1270 | "step": "0.01" 1271 | } 1272 | } 1273 | }, 1274 | { 1275 | "identifier": "humidity", 1276 | "name": "设备湿度", 1277 | "dataType": { 1278 | "type": "double", 1279 | "specs": { 1280 | "min": "0", 1281 | "max": "100", 1282 | "unit": "%RH", 1283 | "unitName": "相对湿度", 1284 | "step": "0.01" 1285 | } 1286 | } 1287 | } 1288 | ] 1289 | }, 1290 | { 1291 | "identifier": "sos_alert", 1292 | "name": "SOS报警", 1293 | "type": "alert", 1294 | "required": false, 1295 | "method": "thing.event.sos_alert.post", 1296 | "outputData": [] 1297 | }, 1298 | { 1299 | "identifier": "fault_alert", 1300 | "name": "故障报警", 1301 | "type": "error", 1302 | "required": false, 1303 | "method": "thing.event.fault_alert.post", 1304 | "outputData": [] 1305 | }, 1306 | { 1307 | "identifier": "low_power_alert", 1308 | "name": "低电报警", 1309 | "type": "alert", 1310 | "required": false, 1311 | "method": "thing.event.low_power_alert.post", 1312 | "outputData": [] 1313 | }, 1314 | { 1315 | "identifier": "sim_abnormal_alert", 1316 | "name": "SIM卡异常报警", 1317 | "type": "alert", 1318 | "required": false, 1319 | "method": "thing.event.sim_abnormal_alert.post", 1320 | "outputData": [] 1321 | }, 1322 | { 1323 | "identifier": "drive_behavior_alert", 1324 | "name": "异常驾驶行为报警", 1325 | "type": "alert", 1326 | "required": false, 1327 | "method": "thing.event.drive_behavior_alert.post", 1328 | "outputData": [] 1329 | }, 1330 | { 1331 | "identifier": "disassemble_alert", 1332 | "name": "拆卸报警", 1333 | "type": "alert", 1334 | "required": false, 1335 | "method": "thing.event.disassemble_alert.post", 1336 | "outputData": [] 1337 | }, 1338 | { 1339 | "identifier": "over_speed_alert", 1340 | "name": "超速报警", 1341 | "type": "alert", 1342 | "required": false, 1343 | "method": "thing.event.over_speed_alert.post", 1344 | "outputData": [] 1345 | } 1346 | ], 1347 | "services": [ 1348 | { 1349 | "identifier": "set", 1350 | "name": "set", 1351 | "required": true, 1352 | "callType": "async", 1353 | "desc": "属性设置", 1354 | "method": "thing.service.property.set", 1355 | "inputData": [ 1356 | { 1357 | "identifier": "power_switch", 1358 | "name": "开关机", 1359 | "dataType": { 1360 | "type": "bool", 1361 | "specs": { 1362 | "0": "关", 1363 | "1": "开" 1364 | } 1365 | } 1366 | }, 1367 | { 1368 | "identifier": "phone_num", 1369 | "name": "电话号码", 1370 | "dataType": { 1371 | "type": "text", 1372 | "specs": { 1373 | "length": "11" 1374 | } 1375 | } 1376 | }, 1377 | { 1378 | "identifier": "loc_method", 1379 | "name": "定位方式", 1380 | "dataType": { 1381 | "type": "struct", 1382 | "specs": [ 1383 | { 1384 | "identifier": "gps", 1385 | "name": "GPS", 1386 | "dataType": { 1387 | "type": "bool", 1388 | "specs": { 1389 | "0": "禁用", 1390 | "1": "启用" 1391 | } 1392 | } 1393 | }, 1394 | { 1395 | "identifier": "cell", 1396 | "name": "基站", 1397 | "dataType": { 1398 | "type": "bool", 1399 | "specs": { 1400 | "0": "禁用", 1401 | "1": "启用" 1402 | } 1403 | } 1404 | }, 1405 | { 1406 | "identifier": "wifi", 1407 | "name": "Wifi", 1408 | "dataType": { 1409 | "type": "bool", 1410 | "specs": { 1411 | "0": "禁用", 1412 | "1": "启用" 1413 | } 1414 | } 1415 | } 1416 | ] 1417 | } 1418 | }, 1419 | { 1420 | "identifier": "work_mode", 1421 | "name": "工作模式", 1422 | "dataType": { 1423 | "type": "enum", 1424 | "specs": { 1425 | "1": "周期性模式", 1426 | "2": "智能模式" 1427 | } 1428 | } 1429 | }, 1430 | { 1431 | "identifier": "work_cycle_period", 1432 | "name": "工作模式循环周期", 1433 | "dataType": { 1434 | "type": "int", 1435 | "specs": { 1436 | "min": "5", 1437 | "max": "2147483647", 1438 | "unit": "s", 1439 | "unitName": "秒", 1440 | "step": "1" 1441 | } 1442 | } 1443 | }, 1444 | { 1445 | "identifier": "low_power_alert_threshold", 1446 | "name": "低电报警阈值", 1447 | "dataType": { 1448 | "type": "int", 1449 | "specs": { 1450 | "min": "5", 1451 | "max": "30", 1452 | "step": "1" 1453 | } 1454 | } 1455 | }, 1456 | { 1457 | "identifier": "low_power_shutdown_threshold", 1458 | "name": "低电关机阈值", 1459 | "dataType": { 1460 | "type": "int", 1461 | "specs": { 1462 | "min": "5", 1463 | "max": "30", 1464 | "step": "1" 1465 | } 1466 | } 1467 | }, 1468 | { 1469 | "identifier": "sw_ota", 1470 | "name": "OTA功能", 1471 | "dataType": { 1472 | "type": "bool", 1473 | "specs": { 1474 | "0": "关", 1475 | "1": "开" 1476 | } 1477 | } 1478 | }, 1479 | { 1480 | "identifier": "sw_ota_auto_upgrade", 1481 | "name": "OTA自动升级功能", 1482 | "dataType": { 1483 | "type": "bool", 1484 | "specs": { 1485 | "0": "关", 1486 | "1": "开" 1487 | } 1488 | } 1489 | }, 1490 | { 1491 | "identifier": "sw_voice_listen", 1492 | "name": "语音监听功能", 1493 | "dataType": { 1494 | "type": "bool", 1495 | "specs": { 1496 | "0": "关", 1497 | "1": "开" 1498 | } 1499 | } 1500 | }, 1501 | { 1502 | "identifier": "sw_voice_record", 1503 | "name": "录音上报功能", 1504 | "dataType": { 1505 | "type": "bool", 1506 | "specs": { 1507 | "0": "关", 1508 | "1": "开" 1509 | } 1510 | } 1511 | }, 1512 | { 1513 | "identifier": "sw_fault_alert", 1514 | "name": "故障报警功能", 1515 | "dataType": { 1516 | "type": "bool", 1517 | "specs": { 1518 | "0": "关", 1519 | "1": "开" 1520 | } 1521 | } 1522 | }, 1523 | { 1524 | "identifier": "sw_low_power_alert", 1525 | "name": "低电报警功能", 1526 | "dataType": { 1527 | "type": "bool", 1528 | "specs": { 1529 | "0": "关", 1530 | "1": "开" 1531 | } 1532 | } 1533 | }, 1534 | { 1535 | "identifier": "sw_over_speed_alert", 1536 | "name": "超速报警功能", 1537 | "dataType": { 1538 | "type": "bool", 1539 | "specs": { 1540 | "0": "关", 1541 | "1": "开" 1542 | } 1543 | } 1544 | }, 1545 | { 1546 | "identifier": "sw_sim_abnormal_alert", 1547 | "name": "SIM卡异常报警功能", 1548 | "dataType": { 1549 | "type": "bool", 1550 | "specs": { 1551 | "0": "关", 1552 | "1": "开" 1553 | } 1554 | } 1555 | }, 1556 | { 1557 | "identifier": "sw_disassemble_alert", 1558 | "name": "拆卸报警功能", 1559 | "dataType": { 1560 | "type": "bool", 1561 | "specs": { 1562 | "0": "关", 1563 | "1": "开" 1564 | } 1565 | } 1566 | }, 1567 | { 1568 | "identifier": "sw_drive_behavior_alert", 1569 | "name": "驾驶行为报警功能", 1570 | "dataType": { 1571 | "type": "bool", 1572 | "specs": { 1573 | "0": "关", 1574 | "1": "开" 1575 | } 1576 | } 1577 | }, 1578 | { 1579 | "identifier": "power_restart", 1580 | "name": "模块重启", 1581 | "dataType": { 1582 | "type": "enum", 1583 | "specs": { 1584 | "1": "重启" 1585 | } 1586 | } 1587 | }, 1588 | { 1589 | "identifier": "over_speed_threshold", 1590 | "name": "超速报警阈值", 1591 | "dataType": { 1592 | "type": "int", 1593 | "specs": { 1594 | "min": "0", 1595 | "max": "132", 1596 | "unit": "km/h", 1597 | "unitName": "千米每小时", 1598 | "step": "1" 1599 | } 1600 | } 1601 | }, 1602 | { 1603 | "identifier": "user_ota_action", 1604 | "name": "确认OTA升级", 1605 | "dataType": { 1606 | "type": "enum", 1607 | "specs": { 1608 | "0": "取消升级", 1609 | "1": "确认升级" 1610 | } 1611 | } 1612 | }, 1613 | { 1614 | "identifier": "work_mode_timeline", 1615 | "name": "休眠策略参考时间", 1616 | "dataType": { 1617 | "type": "int", 1618 | "specs": { 1619 | "min": "3600", 1620 | "max": "2147483647", 1621 | "unit": "s", 1622 | "unitName": "秒", 1623 | "step": "1" 1624 | } 1625 | } 1626 | }, 1627 | { 1628 | "identifier": "loc_gps_read_timeout", 1629 | "name": "GPS信息读取超时时间", 1630 | "dataType": { 1631 | "type": "int", 1632 | "specs": { 1633 | "min": "-1", 1634 | "max": "2147483647", 1635 | "unit": "s", 1636 | "unitName": "秒", 1637 | "step": "1" 1638 | } 1639 | } 1640 | } 1641 | ], 1642 | "outputData": [] 1643 | }, 1644 | { 1645 | "identifier": "get", 1646 | "name": "get", 1647 | "required": true, 1648 | "callType": "async", 1649 | "desc": "属性获取", 1650 | "method": "thing.service.property.get", 1651 | "inputData": [ 1652 | "GeoLocation", 1653 | "power_switch", 1654 | "energy", 1655 | "phone_num", 1656 | "loc_method", 1657 | "work_mode", 1658 | "work_cycle_period", 1659 | "local_time", 1660 | "low_power_alert_threshold", 1661 | "low_power_shutdown_threshold", 1662 | "sw_ota", 1663 | "sw_ota_auto_upgrade", 1664 | "sw_voice_listen", 1665 | "sw_voice_record", 1666 | "sw_fault_alert", 1667 | "sw_low_power_alert", 1668 | "sw_over_speed_alert", 1669 | "sw_sim_abnormal_alert", 1670 | "sw_disassemble_alert", 1671 | "sw_drive_behavior_alert", 1672 | "drive_behavior_code", 1673 | "power_restart", 1674 | "over_speed_threshold", 1675 | "device_module_status", 1676 | "gps_mode", 1677 | "user_ota_action", 1678 | "ota_status", 1679 | "voltage", 1680 | "current_speed", 1681 | "work_mode_timeline", 1682 | "loc_gps_read_timeout", 1683 | "temperature", 1684 | "humidity" 1685 | ], 1686 | "outputData": [ 1687 | { 1688 | "identifier": "GeoLocation", 1689 | "name": "地理位置", 1690 | "dataType": { 1691 | "type": "struct", 1692 | "specs": [ 1693 | { 1694 | "identifier": "Longitude", 1695 | "name": "经度", 1696 | "dataType": { 1697 | "type": "double", 1698 | "specs": { 1699 | "min": "-180", 1700 | "max": "180", 1701 | "unit": "°", 1702 | "unitName": "度", 1703 | "step": "0.01" 1704 | } 1705 | } 1706 | }, 1707 | { 1708 | "identifier": "Latitude", 1709 | "name": "纬度", 1710 | "dataType": { 1711 | "type": "double", 1712 | "specs": { 1713 | "min": "-90", 1714 | "max": "90", 1715 | "unit": "°", 1716 | "unitName": "度", 1717 | "step": "0.01" 1718 | } 1719 | } 1720 | }, 1721 | { 1722 | "identifier": "Altitude", 1723 | "name": "海拔", 1724 | "dataType": { 1725 | "type": "double", 1726 | "specs": { 1727 | "min": "0", 1728 | "max": "9999", 1729 | "unit": "m", 1730 | "unitName": "米", 1731 | "step": "0.01" 1732 | } 1733 | } 1734 | }, 1735 | { 1736 | "identifier": "CoordinateSystem", 1737 | "name": "坐标系统", 1738 | "dataType": { 1739 | "type": "enum", 1740 | "specs": { 1741 | "1": "WGS_84", 1742 | "2": "GCJ_02" 1743 | } 1744 | } 1745 | } 1746 | ] 1747 | } 1748 | }, 1749 | { 1750 | "identifier": "power_switch", 1751 | "name": "开关机", 1752 | "dataType": { 1753 | "type": "bool", 1754 | "specs": { 1755 | "0": "关", 1756 | "1": "开" 1757 | } 1758 | } 1759 | }, 1760 | { 1761 | "identifier": "energy", 1762 | "name": "电量", 1763 | "dataType": { 1764 | "type": "int", 1765 | "specs": { 1766 | "min": "0", 1767 | "max": "100", 1768 | "unit": "%", 1769 | "unitName": "百分比", 1770 | "step": "1" 1771 | } 1772 | } 1773 | }, 1774 | { 1775 | "identifier": "phone_num", 1776 | "name": "电话号码", 1777 | "dataType": { 1778 | "type": "text", 1779 | "specs": { 1780 | "length": "11" 1781 | } 1782 | } 1783 | }, 1784 | { 1785 | "identifier": "loc_method", 1786 | "name": "定位方式", 1787 | "dataType": { 1788 | "type": "struct", 1789 | "specs": [ 1790 | { 1791 | "identifier": "gps", 1792 | "name": "GPS", 1793 | "dataType": { 1794 | "type": "bool", 1795 | "specs": { 1796 | "0": "禁用", 1797 | "1": "启用" 1798 | } 1799 | } 1800 | }, 1801 | { 1802 | "identifier": "cell", 1803 | "name": "基站", 1804 | "dataType": { 1805 | "type": "bool", 1806 | "specs": { 1807 | "0": "禁用", 1808 | "1": "启用" 1809 | } 1810 | } 1811 | }, 1812 | { 1813 | "identifier": "wifi", 1814 | "name": "Wifi", 1815 | "dataType": { 1816 | "type": "bool", 1817 | "specs": { 1818 | "0": "禁用", 1819 | "1": "启用" 1820 | } 1821 | } 1822 | } 1823 | ] 1824 | } 1825 | }, 1826 | { 1827 | "identifier": "work_mode", 1828 | "name": "工作模式", 1829 | "dataType": { 1830 | "type": "enum", 1831 | "specs": { 1832 | "1": "周期性模式", 1833 | "2": "智能模式" 1834 | } 1835 | } 1836 | }, 1837 | { 1838 | "identifier": "work_cycle_period", 1839 | "name": "工作模式循环周期", 1840 | "dataType": { 1841 | "type": "int", 1842 | "specs": { 1843 | "min": "5", 1844 | "max": "2147483647", 1845 | "unit": "s", 1846 | "unitName": "秒", 1847 | "step": "1" 1848 | } 1849 | } 1850 | }, 1851 | { 1852 | "identifier": "local_time", 1853 | "name": "本地时间", 1854 | "dataType": { 1855 | "type": "date", 1856 | "specs": {} 1857 | } 1858 | }, 1859 | { 1860 | "identifier": "low_power_alert_threshold", 1861 | "name": "低电报警阈值", 1862 | "dataType": { 1863 | "type": "int", 1864 | "specs": { 1865 | "min": "5", 1866 | "max": "30", 1867 | "step": "1" 1868 | } 1869 | } 1870 | }, 1871 | { 1872 | "identifier": "low_power_shutdown_threshold", 1873 | "name": "低电关机阈值", 1874 | "dataType": { 1875 | "type": "int", 1876 | "specs": { 1877 | "min": "5", 1878 | "max": "30", 1879 | "step": "1" 1880 | } 1881 | } 1882 | }, 1883 | { 1884 | "identifier": "sw_ota", 1885 | "name": "OTA功能", 1886 | "dataType": { 1887 | "type": "bool", 1888 | "specs": { 1889 | "0": "关", 1890 | "1": "开" 1891 | } 1892 | } 1893 | }, 1894 | { 1895 | "identifier": "sw_ota_auto_upgrade", 1896 | "name": "OTA自动升级功能", 1897 | "dataType": { 1898 | "type": "bool", 1899 | "specs": { 1900 | "0": "关", 1901 | "1": "开" 1902 | } 1903 | } 1904 | }, 1905 | { 1906 | "identifier": "sw_voice_listen", 1907 | "name": "语音监听功能", 1908 | "dataType": { 1909 | "type": "bool", 1910 | "specs": { 1911 | "0": "关", 1912 | "1": "开" 1913 | } 1914 | } 1915 | }, 1916 | { 1917 | "identifier": "sw_voice_record", 1918 | "name": "录音上报功能", 1919 | "dataType": { 1920 | "type": "bool", 1921 | "specs": { 1922 | "0": "关", 1923 | "1": "开" 1924 | } 1925 | } 1926 | }, 1927 | { 1928 | "identifier": "sw_fault_alert", 1929 | "name": "故障报警功能", 1930 | "dataType": { 1931 | "type": "bool", 1932 | "specs": { 1933 | "0": "关", 1934 | "1": "开" 1935 | } 1936 | } 1937 | }, 1938 | { 1939 | "identifier": "sw_low_power_alert", 1940 | "name": "低电报警功能", 1941 | "dataType": { 1942 | "type": "bool", 1943 | "specs": { 1944 | "0": "关", 1945 | "1": "开" 1946 | } 1947 | } 1948 | }, 1949 | { 1950 | "identifier": "sw_over_speed_alert", 1951 | "name": "超速报警功能", 1952 | "dataType": { 1953 | "type": "bool", 1954 | "specs": { 1955 | "0": "关", 1956 | "1": "开" 1957 | } 1958 | } 1959 | }, 1960 | { 1961 | "identifier": "sw_sim_abnormal_alert", 1962 | "name": "SIM卡异常报警功能", 1963 | "dataType": { 1964 | "type": "bool", 1965 | "specs": { 1966 | "0": "关", 1967 | "1": "开" 1968 | } 1969 | } 1970 | }, 1971 | { 1972 | "identifier": "sw_disassemble_alert", 1973 | "name": "拆卸报警功能", 1974 | "dataType": { 1975 | "type": "bool", 1976 | "specs": { 1977 | "0": "关", 1978 | "1": "开" 1979 | } 1980 | } 1981 | }, 1982 | { 1983 | "identifier": "sw_drive_behavior_alert", 1984 | "name": "驾驶行为报警功能", 1985 | "dataType": { 1986 | "type": "bool", 1987 | "specs": { 1988 | "0": "关", 1989 | "1": "开" 1990 | } 1991 | } 1992 | }, 1993 | { 1994 | "identifier": "drive_behavior_code", 1995 | "name": "异常驾驶行为", 1996 | "dataType": { 1997 | "type": "enum", 1998 | "specs": { 1999 | "0": "无", 2000 | "1": "急起", 2001 | "2": "急停", 2002 | "3": "左急转弯", 2003 | "4": "右急转弯" 2004 | } 2005 | } 2006 | }, 2007 | { 2008 | "identifier": "power_restart", 2009 | "name": "模块重启", 2010 | "dataType": { 2011 | "type": "enum", 2012 | "specs": { 2013 | "1": "重启" 2014 | } 2015 | } 2016 | }, 2017 | { 2018 | "identifier": "over_speed_threshold", 2019 | "name": "超速报警阈值", 2020 | "dataType": { 2021 | "type": "int", 2022 | "specs": { 2023 | "min": "0", 2024 | "max": "132", 2025 | "unit": "km/h", 2026 | "unitName": "千米每小时", 2027 | "step": "1" 2028 | } 2029 | } 2030 | }, 2031 | { 2032 | "identifier": "device_module_status", 2033 | "name": "设备模块状态", 2034 | "dataType": { 2035 | "type": "struct", 2036 | "specs": [ 2037 | { 2038 | "identifier": "net", 2039 | "name": "网络状态", 2040 | "dataType": { 2041 | "type": "enum", 2042 | "specs": { 2043 | "0": "异常", 2044 | "1": "正常" 2045 | } 2046 | } 2047 | }, 2048 | { 2049 | "identifier": "location", 2050 | "name": "定位状态", 2051 | "dataType": { 2052 | "type": "enum", 2053 | "specs": { 2054 | "0": "异常", 2055 | "1": "正常" 2056 | } 2057 | } 2058 | }, 2059 | { 2060 | "identifier": "temp_sensor", 2061 | "name": "温湿度传感器状态", 2062 | "dataType": { 2063 | "type": "enum", 2064 | "specs": { 2065 | "0": "异常", 2066 | "1": "正常" 2067 | } 2068 | } 2069 | }, 2070 | { 2071 | "identifier": "light_sensor", 2072 | "name": "光照传感器状态", 2073 | "dataType": { 2074 | "type": "enum", 2075 | "specs": { 2076 | "0": "异常", 2077 | "1": "正常" 2078 | } 2079 | } 2080 | }, 2081 | { 2082 | "identifier": "move_sensor", 2083 | "name": "三轴加速传感器状态", 2084 | "dataType": { 2085 | "type": "enum", 2086 | "specs": { 2087 | "0": "异常", 2088 | "1": "正常" 2089 | } 2090 | } 2091 | }, 2092 | { 2093 | "identifier": "mike", 2094 | "name": "麦克风状态", 2095 | "dataType": { 2096 | "type": "enum", 2097 | "specs": { 2098 | "0": "异常", 2099 | "1": "正常" 2100 | } 2101 | } 2102 | } 2103 | ] 2104 | } 2105 | }, 2106 | { 2107 | "identifier": "gps_mode", 2108 | "name": "GPS模块类型", 2109 | "dataType": { 2110 | "type": "enum", 2111 | "specs": { 2112 | "0": "无GPS模块", 2113 | "1": "内置GPS模块", 2114 | "2": "外置GPS模块" 2115 | } 2116 | } 2117 | }, 2118 | { 2119 | "identifier": "user_ota_action", 2120 | "name": "确认OTA升级", 2121 | "dataType": { 2122 | "type": "enum", 2123 | "specs": { 2124 | "0": "取消升级", 2125 | "1": "确认升级" 2126 | } 2127 | } 2128 | }, 2129 | { 2130 | "identifier": "ota_status", 2131 | "name": "OTA升级状态", 2132 | "dataType": { 2133 | "type": "struct", 2134 | "specs": [ 2135 | { 2136 | "identifier": "sys_current_version", 2137 | "name": "系统当前版本", 2138 | "dataType": { 2139 | "type": "text", 2140 | "specs": { 2141 | "length": "1024" 2142 | } 2143 | } 2144 | }, 2145 | { 2146 | "identifier": "sys_target_version", 2147 | "name": "系统目标版本", 2148 | "dataType": { 2149 | "type": "text", 2150 | "specs": { 2151 | "length": "1024" 2152 | } 2153 | } 2154 | }, 2155 | { 2156 | "identifier": "app_current_version", 2157 | "name": "应用当前版本", 2158 | "dataType": { 2159 | "type": "text", 2160 | "specs": { 2161 | "length": "1024" 2162 | } 2163 | } 2164 | }, 2165 | { 2166 | "identifier": "app_target_version", 2167 | "name": "应用目标版本", 2168 | "dataType": { 2169 | "type": "text", 2170 | "specs": { 2171 | "length": "1024" 2172 | } 2173 | } 2174 | }, 2175 | { 2176 | "identifier": "upgrade_module", 2177 | "name": "当前升级模块", 2178 | "dataType": { 2179 | "type": "enum", 2180 | "specs": { 2181 | "0": "无", 2182 | "1": "系统", 2183 | "2": "应用" 2184 | } 2185 | } 2186 | }, 2187 | { 2188 | "identifier": "upgrade_status", 2189 | "name": "当前升级状态", 2190 | "dataType": { 2191 | "type": "enum", 2192 | "specs": { 2193 | "0": "无", 2194 | "1": "待升级", 2195 | "2": "升级中", 2196 | "3": "升级成功", 2197 | "4": "升级失败" 2198 | } 2199 | } 2200 | } 2201 | ] 2202 | } 2203 | }, 2204 | { 2205 | "identifier": "voltage", 2206 | "name": "电池电压", 2207 | "dataType": { 2208 | "type": "int", 2209 | "specs": { 2210 | "min": "0", 2211 | "max": "2147483647", 2212 | "unit": "mV", 2213 | "unitName": "毫伏", 2214 | "step": "1" 2215 | } 2216 | } 2217 | }, 2218 | { 2219 | "identifier": "current_speed", 2220 | "name": "当前时速", 2221 | "dataType": { 2222 | "type": "float", 2223 | "specs": { 2224 | "min": "0", 2225 | "max": "200.00", 2226 | "unit": "km/h", 2227 | "unitName": "千米每小时", 2228 | "step": "0.01" 2229 | } 2230 | } 2231 | }, 2232 | { 2233 | "identifier": "work_mode_timeline", 2234 | "name": "休眠策略参考时间", 2235 | "dataType": { 2236 | "type": "int", 2237 | "specs": { 2238 | "min": "3600", 2239 | "max": "2147483647", 2240 | "unit": "s", 2241 | "unitName": "秒", 2242 | "step": "1" 2243 | } 2244 | } 2245 | }, 2246 | { 2247 | "identifier": "loc_gps_read_timeout", 2248 | "name": "GPS信息读取超时时间", 2249 | "dataType": { 2250 | "type": "int", 2251 | "specs": { 2252 | "min": "-1", 2253 | "max": "2147483647", 2254 | "unit": "s", 2255 | "unitName": "秒", 2256 | "step": "1" 2257 | } 2258 | } 2259 | }, 2260 | { 2261 | "identifier": "temperature", 2262 | "name": "设备温度", 2263 | "dataType": { 2264 | "type": "double", 2265 | "specs": { 2266 | "min": "-40", 2267 | "max": "125", 2268 | "unit": "°C", 2269 | "unitName": "摄氏度", 2270 | "step": "0.01" 2271 | } 2272 | } 2273 | }, 2274 | { 2275 | "identifier": "humidity", 2276 | "name": "设备湿度", 2277 | "dataType": { 2278 | "type": "double", 2279 | "specs": { 2280 | "min": "0", 2281 | "max": "100", 2282 | "unit": "%RH", 2283 | "unitName": "相对湿度", 2284 | "step": "0.01" 2285 | } 2286 | } 2287 | } 2288 | ] 2289 | } 2290 | ] 2291 | } --------------------------------------------------------------------------------