├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature-request.md └── workflows │ ├── stale.yml │ └── sync_issues.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── docs ├── 01-Quick-Start │ ├── K1100-Quick-Start-Guide(old_version).md │ └── README.md ├── 02-Microsoft-Azure-IoT │ ├── 1-Connect SenseCAP to Azure IoT Central via Node-RED (SenseCAP) │ │ └── README.md │ ├── 1-Connect Wio Terminal to Microsoft Azure IoT Central (WiFi) │ │ └── README.md │ ├── 1-Connect the Wio Terminal to Microsoft Azure IoT Hub (WiFi) │ │ └── README.md │ ├── 1-Helium integrate into Azure IoT Hub │ │ └── README.md │ ├── 2-Develop in Microsoft Azure IoT Central │ │ └── README.md │ ├── 3-Configure Web APP Visualization │ │ └── README.md │ └── 3-Microsoft Azure IoT Data visualisation with Power BI │ │ └── README.md ├── 03-SenseCAP │ ├── 1-SenseCAP Console with Node-RED Quick Start │ │ └── README.md │ ├── 2-Connect SenseCAP to Azure IoT Central via Node-RED │ │ └── README.md │ ├── 2-Connect SenseCAP to InfluxDB via Node-RED │ │ └── README.md │ └── 2-Connect SenseCAP to Power BI via Node-RED │ │ └── README.md ├── 04-Sensor-Helium-TTN-Arduino-Programme │ ├── Grove Soil Moisture Sensor │ │ └── README.md │ ├── Grove Temp&Humi Sensor (SHT40) │ │ └── README.md │ ├── Grove VOC and eCO2 Gas Sensor (SGP30) │ │ └── README.md │ ├── Grove Vision AI Module │ │ └── README.md │ ├── Wio Terminal IMU Sensor │ │ └── README.md │ └── Wio Terminal Light Sensor │ │ └── README.md ├── 05-Helium │ ├── 0-Helium Introduction │ │ └── README.md │ ├── 1-Connect to Helium │ │ └── README.md │ ├── 2-Connect AWS IOT Core via Helium │ │ └── README.md │ ├── 2-Integrate into Azure IoT Hub │ │ └── README.md │ ├── 2-Integrate into Google Sheets via Helium │ │ └── README.md │ └── 3-Configure Web APP Visualization │ │ └── README.md ├── 06-TTN │ ├── 0-TTN Introduction │ │ └── README.md │ └── 1-Connect to TTN │ │ └── README.md ├── 07-WiFi │ ├── 0-Advanced Wi-Fi Usage │ │ └── README.md │ ├── 1-Connect Wio Terminal to Google Cloud IoT Core │ │ └── README.md │ ├── 1-Connect Wio Terminal to Microsoft Azure IoT Central │ │ └── README.md │ ├── 1-Connect the Wio Terminal to Microsoft Azure IoT Hub │ │ └── README.md │ ├── 1-Quick Start to Using Blynk │ │ └── README.md │ ├── 1-Quickly Start with Ubidots │ │ └── README.md │ └── 2-Develop with Ubidots │ │ └── README.md ├── 08-Cloud │ ├── Connect AWS IOT Core via Helium (Helium) │ │ └── README.md │ ├── Connect Wio Terminal to Google Cloud IoT Core (WiFi) │ │ └── README.md │ ├── Connect Wio Terminal to Microsoft Azure IoT Central (WiFi) │ │ └── README.md │ ├── Connect the Wio Terminal to Microsoft Azure IoT Hub (WiFi) │ │ └── README.md │ ├── Development with Ubidots │ │ └── README.md │ ├── Integrate into Azure IoT Hub (Helium) │ │ └── README.md │ ├── Quick Start to Using Blynk (WiFi) │ │ └── README.md │ └── Quickly Start with Ubidots (WiFi) │ │ └── README.md ├── 09-TinyML │ ├── Develop Edge Impulse application to cloud via Helium (built-in sensor) │ │ └── README.md │ ├── Train and Deploy Your Own AI Model Into Grove - Vision AI │ │ └── README.md │ └── Wio Terminal Edge Impulse Getting Started (built-in sensor) │ │ └── README.md ├── 10-Project │ └── Soil moisture monitoring alarm system │ │ └── README.md └── README.md ├── examples ├── Network │ ├── LoRaWAN │ │ ├── Binding-devices │ │ │ └── Binding-devices.ino │ │ ├── Frequency-select │ │ │ └── Frequency-select.ino │ │ ├── Network-Select │ │ │ └── Network-Select.ino │ │ └── connect-success │ │ │ └── connect-success.ino │ └── WiFi │ │ ├── connect-success │ │ └── connect-success.ino │ │ └── wifi-select │ │ └── wifi-select.ino ├── PAGE_TEMPLE │ └── PAGE_TEMPLE.ino ├── PAGE_WELCOME │ └── PAGE_WELCOME.ino ├── PAGE_process_tinyml │ ├── Free_Fonts.h │ └── PAGE_process_tinyml.ino ├── Process │ ├── PAGE_tf │ │ ├── PAGE_tf.ino │ │ ├── switch.cpp │ │ └── switch_ui.h │ └── Process_main │ │ ├── Free_Fonts.h │ │ ├── Process_main.ino │ │ └── README.md └── Sense │ ├── Auto-detect │ └── Auto-detect.ino │ ├── Built-in │ └── Built-in.ino │ └── Line-chart │ ├── Free_Fonts.h │ └── Line-chart.ino ├── include ├── AzureDpsClient.h ├── ButtonThread.h ├── LoRaThread.h ├── SDThread.h ├── SamplerThread.h ├── Signature.h ├── SysConfig.h ├── WiFiThread.h ├── sensor.h ├── ui.h └── utils.h ├── platformio.ini ├── src ├── AzureDpsClient.cpp ├── ButtonThread.cpp ├── FreeRTOSMemory.cpp ├── Free_Fonts.h ├── LoRaThread.cpp ├── SDThread.cpp ├── SamplerThread.cpp ├── Signature.cpp ├── SysConfig.cpp ├── WiFiThread.cpp ├── cm_backtrace │ ├── cm_backtrace.c │ ├── cm_backtrace.h │ ├── cmb_cfg.h │ ├── cmb_def.h │ └── fault_handler │ │ └── gcc │ │ └── cmb_fault.S ├── main.cpp ├── sensor.cpp ├── sensors │ ├── FakeSensor.cpp │ ├── FakeSensor.h │ ├── LIS3DHTRSensor.cpp │ ├── LIS3DHTRSensor.h │ ├── SensorsUtils.cpp │ ├── SensorsUtils.h │ ├── buildin_light_sensor.cpp │ ├── buildin_light_sensor.h │ ├── buildin_mic.cpp │ ├── buildin_mic.h │ ├── grove_sgp30_sensor.cpp │ ├── grove_sgp30_sensor.h │ ├── grove_sht4x_sensor.cpp │ ├── grove_sht4x_sensor.h │ ├── grove_soil_sensor.cpp │ ├── grove_soil_sensor.h │ ├── grove_visionai_sensor.cpp │ ├── grove_visionai_sensor.h │ ├── grove_vl53l0x_sensor.cpp │ └── grove_vl53l0x_sensor.h └── ui.cpp └── tools └── K1100-decoder.js /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: true 9 | AlignConsecutiveBitFields: true 10 | AlignConsecutiveDeclarations: true 11 | AlignEscapedNewlines: Right 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: false 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: MultiLine 27 | AttributeMacros: 28 | - __capability 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterCaseLabel: false 33 | AfterClass: false 34 | AfterControlStatement: Never 35 | AfterEnum: false 36 | AfterFunction: false 37 | AfterNamespace: false 38 | AfterObjCDeclaration: false 39 | AfterStruct: false 40 | AfterUnion: false 41 | AfterExternBlock: false 42 | BeforeCatch: false 43 | BeforeElse: false 44 | BeforeLambdaBody: false 45 | BeforeWhile: false 46 | IndentBraces: false 47 | SplitEmptyFunction: true 48 | SplitEmptyRecord: true 49 | SplitEmptyNamespace: true 50 | BreakBeforeBinaryOperators: None 51 | BreakBeforeConceptDeclarations: true 52 | BreakBeforeBraces: Attach 53 | BreakBeforeInheritanceComma: false 54 | BreakInheritanceList: BeforeColon 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializersBeforeComma: false 57 | BreakConstructorInitializers: BeforeColon 58 | BreakAfterJavaFieldAnnotations: false 59 | BreakStringLiterals: true 60 | ColumnLimit: 100 61 | CommentPragmas: '^ IWYU pragma:' 62 | QualifierAlignment: Leave 63 | CompactNamespaces: false 64 | ConstructorInitializerIndentWidth: 4 65 | ContinuationIndentWidth: 4 66 | Cpp11BracedListStyle: true 67 | DeriveLineEnding: true 68 | DerivePointerAlignment: false 69 | DisableFormat: false 70 | EmptyLineAfterAccessModifier: Never 71 | EmptyLineBeforeAccessModifier: LogicalBlock 72 | ExperimentalAutoDetectBinPacking: false 73 | PackConstructorInitializers: BinPack 74 | BasedOnStyle: '' 75 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 76 | AllowAllConstructorInitializersOnNextLine: true 77 | FixNamespaceComments: true 78 | ForEachMacros: 79 | - foreach 80 | - Q_FOREACH 81 | - BOOST_FOREACH 82 | IfMacros: 83 | - KJ_IF_MAYBE 84 | IncludeBlocks: Preserve 85 | IncludeCategories: 86 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 87 | Priority: 2 88 | SortPriority: 0 89 | CaseSensitive: false 90 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 91 | Priority: 3 92 | SortPriority: 0 93 | CaseSensitive: false 94 | - Regex: '.*' 95 | Priority: 1 96 | SortPriority: 0 97 | CaseSensitive: false 98 | IncludeIsMainRegex: '(Test)?$' 99 | IncludeIsMainSourceRegex: '' 100 | IndentAccessModifiers: false 101 | IndentCaseLabels: false 102 | IndentCaseBlocks: false 103 | IndentGotoLabels: true 104 | IndentPPDirectives: None 105 | IndentExternBlock: AfterExternBlock 106 | IndentRequires: false 107 | IndentWidth: 4 108 | IndentWrappedFunctionNames: false 109 | InsertTrailingCommas: None 110 | JavaScriptQuotes: Leave 111 | JavaScriptWrapImports: true 112 | KeepEmptyLinesAtTheStartOfBlocks: true 113 | LambdaBodyIndentation: Signature 114 | MacroBlockBegin: '' 115 | MacroBlockEnd: '' 116 | MaxEmptyLinesToKeep: 1 117 | NamespaceIndentation: None 118 | ObjCBinPackProtocolList: Auto 119 | ObjCBlockIndentWidth: 2 120 | ObjCBreakBeforeNestedBlockParam: true 121 | ObjCSpaceAfterProperty: false 122 | ObjCSpaceBeforeProtocolList: true 123 | PenaltyBreakAssignment: 2 124 | PenaltyBreakBeforeFirstCallParameter: 19 125 | PenaltyBreakComment: 300 126 | PenaltyBreakFirstLessLess: 120 127 | PenaltyBreakOpenParenthesis: 0 128 | PenaltyBreakString: 1000 129 | PenaltyBreakTemplateDeclaration: 10 130 | PenaltyExcessCharacter: 1000000 131 | PenaltyReturnTypeOnItsOwnLine: 60 132 | PenaltyIndentedWhitespace: 0 133 | PointerAlignment: Right 134 | PPIndentWidth: -1 135 | ReferenceAlignment: Pointer 136 | ReflowComments: true 137 | RemoveBracesLLVM: false 138 | SeparateDefinitionBlocks: Leave 139 | ShortNamespaceLines: 1 140 | SortIncludes: CaseSensitive 141 | SortJavaStaticImport: Before 142 | SortUsingDeclarations: true 143 | SpaceAfterCStyleCast: false 144 | SpaceAfterLogicalNot: false 145 | SpaceAfterTemplateKeyword: true 146 | SpaceBeforeAssignmentOperators: true 147 | SpaceBeforeCaseColon: false 148 | SpaceBeforeCpp11BracedList: false 149 | SpaceBeforeCtorInitializerColon: true 150 | SpaceBeforeInheritanceColon: true 151 | SpaceBeforeParens: ControlStatements 152 | SpaceBeforeParensOptions: 153 | AfterControlStatements: true 154 | AfterForeachMacros: true 155 | AfterFunctionDefinitionName: false 156 | AfterFunctionDeclarationName: false 157 | AfterIfMacros: true 158 | AfterOverloadedOperator: false 159 | BeforeNonEmptyParentheses: false 160 | SpaceAroundPointerQualifiers: Default 161 | SpaceBeforeRangeBasedForLoopColon: true 162 | SpaceInEmptyBlock: false 163 | SpaceInEmptyParentheses: false 164 | SpacesBeforeTrailingComments: 1 165 | SpacesInAngles: Never 166 | SpacesInConditionalStatement: false 167 | SpacesInContainerLiterals: true 168 | SpacesInCStyleCastParentheses: false 169 | SpacesInLineCommentPrefix: 170 | Minimum: 1 171 | Maximum: -1 172 | SpacesInParentheses: false 173 | SpacesInSquareBrackets: false 174 | SpaceBeforeSquareBrackets: false 175 | BitFieldColonSpacing: Both 176 | Standard: Latest 177 | StatementAttributeLikeMacros: 178 | - Q_EMIT 179 | StatementMacros: 180 | - Q_UNUSED 181 | - QT_REQUIRE_VERSION 182 | TabWidth: 8 183 | UseCRLF: false 184 | UseTab: Never 185 | WhitespaceSensitiveMacros: 186 | - STRINGIZE 187 | - PP_STRINGIZE 188 | - BOOST_PP_STRINGIZE 189 | - NS_SWIFT_NAME 190 | - CF_SWIFT_NAME 191 | ... 192 | 193 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature/function that you want to have for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 4 * * *' 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Checkout script repository 17 | uses: actions/checkout@v4 18 | with: 19 | repository: Seeed-Studio/sync-github-all-issues 20 | path: ci 21 | 22 | - name: Run script 23 | run: ./ci/tools/stale.sh 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/sync_issues.yml: -------------------------------------------------------------------------------- 1 | name: Automate Issue Management 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - assigned 9 | - unassigned 10 | - labeled 11 | - unlabeled 12 | - reopened 13 | 14 | jobs: 15 | add_issue_to_project: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add issue to GitHub Project 19 | uses: actions/add-to-project@v1.0.2 20 | with: 21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17 22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }} 23 | labeled: bug 24 | label-operator: NOT -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | .vs/ -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ], 7 | "unwantedRecommendations": [ 8 | "ms-vscode.cpptools-extension-pack" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "list": "cpp", 4 | "deque": "cpp", 5 | "string": "cpp", 6 | "vector": "cpp", 7 | "array": "cpp", 8 | "atomic": "cpp", 9 | "bit": "cpp", 10 | "*.tcc": "cpp", 11 | "cctype": "cpp", 12 | "clocale": "cpp", 13 | "cmath": "cpp", 14 | "compare": "cpp", 15 | "concepts": "cpp", 16 | "cstdarg": "cpp", 17 | "cstddef": "cpp", 18 | "cstdint": "cpp", 19 | "cstdio": "cpp", 20 | "cstdlib": "cpp", 21 | "cstring": "cpp", 22 | "cwchar": "cpp", 23 | "cwctype": "cpp", 24 | "unordered_map": "cpp", 25 | "exception": "cpp", 26 | "algorithm": "cpp", 27 | "functional": "cpp", 28 | "iterator": "cpp", 29 | "memory": "cpp", 30 | "memory_resource": "cpp", 31 | "numeric": "cpp", 32 | "optional": "cpp", 33 | "random": "cpp", 34 | "string_view": "cpp", 35 | "system_error": "cpp", 36 | "tuple": "cpp", 37 | "type_traits": "cpp", 38 | "utility": "cpp", 39 | "initializer_list": "cpp", 40 | "iosfwd": "cpp", 41 | "limits": "cpp", 42 | "new": "cpp", 43 | "ostream": "cpp", 44 | "ranges": "cpp", 45 | "stdexcept": "cpp", 46 | "streambuf": "cpp", 47 | "cinttypes": "cpp", 48 | "typeinfo": "cpp", 49 | "ctime": "cpp", 50 | "iostream": "cpp", 51 | "istream": "cpp", 52 | "sstream": "cpp", 53 | "queue": "cpp", 54 | "bitset": "cpp", 55 | "complex": "cpp", 56 | "map": "cpp", 57 | "set": "cpp", 58 | "iomanip": "cpp", 59 | "valarray": "cpp", 60 | "fstream": "cpp" 61 | } 62 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zuobaozhu@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## ✨ How you can contribute 2 | 3 | We value contributions and we provide the most active and constant contributors with public recognition, maintainer status and hardware goodies. If you are willing to contribute to our [GitHub](https://github.com/Seeed-Studio) Repositories, please contribute in the following way: 4 | 5 | - Triage open issues: try to reproduce issues reported by other users and confirm whether you can experience them as well, or ask users for more details if needed. Spot duplicates. Improve descriptions. Help users who ask for support. 6 | - Submit fixes and implementations: pick an open issue or feature request that you think you can implement yourself, and submit a pull request with an implementation. 7 | - Test open pull requests: try to run the proposed modifications and report your success or failure. Testing on real hardware takes time and any help in this will speed up our responsiveness in merging contributions. 8 | - Help others contribute by reviewing their code and suggesting good ways to implement fixes and features. 9 | - Write documentation and improve the existing content. 10 | - Assist in translations to your native tongue 🌎 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Seeed Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /docs/02-Microsoft-Azure-IoT/1-Connect the Wio Terminal to Microsoft Azure IoT Hub (WiFi)/README.md: -------------------------------------------------------------------------------- 1 | # Connecting the Wio Terminal to Microsoft Azure IoT 2 | 3 |
4 | 5 | >This is a document written by [**@Benjamin Cabé**](https://twitter.com/kartben). Thank you Benjamin for the great work! You may also find [Benjamin's work](https://github.com/kartben) here. 6 | 7 | This sample application shows you how to connect your [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) to [Azure IoT Hub](https://azure.microsoft.com/services/iot-hub). It is built on top of the [Azure SDK for Embedded C](https://github.com/Azure/azure-sdk-for-c), a small footprint, easy-to-port library for communicating with Azure services. 8 | 9 | To connect with Microsoft Azure IoT with Wio Terminal, please see the [**Benjamin's Guide**](https://github.com/kartben/wioterminal-azureiothub-sample). 10 | 11 | ## Connecting to MQTT Server 12 | 13 |
14 | 15 | If you want to connect Wio Terminal to MQTT servers(such as Microsoft Azure IoT), you may also check [**Benjamin's Guide for MQTT on Wio Terminal**](https://github.com/kartben/wioterminal-mqtts-sample)! 16 | 17 | ## Tech Support 18 | 19 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/)

-------------------------------------------------------------------------------- /docs/05-Helium/2-Connect AWS IOT Core via Helium/README.md: -------------------------------------------------------------------------------- 1 | # Connect AWS IOT Core via Helium 2 | 3 |
4 | 5 | ## Introduction to AWS IoT Core 6 | 7 | AWS IoT Core provides the cloud services that connect your IoT devices to other devices and AWS cloud services. AWS IoT provides device software that can help you integrate your IoT devices into AWS IoT-based solutions. If your devices can connect to AWS IoT, AWS IoT can connect them to the cloud services that AWS provides. 8 | 9 |
10 | 11 | AWS IoT lets you select the most appropriate and up-to-date technologies for your solution. To help you manage and support your IoT devices in the field, AWS IoT Core supports these protocols: 12 | 13 | - MQTT (Message Queuing and Telemetry Transport) 14 | - MQTT over WSS (Websockets Secure) 15 | - HTTPS (Hypertext Transfer Protocol - Secure) 16 | - LoRaWAN® (Long Range Wide Area Network) 17 | 18 | AWS IoT Core is a powerful offering that lets developers build device-based applications and services on the AWS Cloud. And this Integration via Helium Console automates the complexity of securely connecting your devices to AWS IoT Core. 19 | 20 | !!!Attention 21 | You may need to pay for AWS IoT Core to experience the full content of this tutorial. A detailed list of payments and costs you can approximate [here](https://calculator.aws/#/estimate). 22 | 23 | Based on the sending frequency of the code we have provided (sending data at approximately 15 second intervals), approximately 178,560 messages will be sent in a month, with a message size of approximately 3 to 4 KB and a monthly cost of 0.18 USD. 24 |
25 | 26 | 27 | ## Sign up for AWS IoT Core 28 | 29 | Please go to the [AWS IoT Core website](https://portal.aws.amazon.com/billing/signup#/start/email) and register an account. 30 | 31 |
32 | 33 | Fill out an email with your registered email address and a user name and you will receive an email from AWS with the six-digit verification code required to register. 34 | 35 | Enter your verification code and registration is complete. Sign in to AWS IoT Core with the email address you just filled in. 36 | 37 | After logging in, you will need to continue filling in personal information such as passwords and contacts. You will then be required to link a credit card to verify your personal information. 38 | 39 |
40 | 41 | When we log in to the AWS IoT Core console, we just select the **Root user** to log in. 42 | 43 |
44 | 45 | ## Create access to AWS IoT Core 46 | 47 | Create a new user with limited permissions that this Integration will use on AWS. 48 | 49 | 1. Open up the [AWS Console](https://console.aws.amazon.com/). 50 | 51 | 2. Click on Services menu in the upper-left, go to **Security, Identity, & Compliance**, then click **IAM**. 52 | 53 |
54 | 55 | We are now going to create a new **User**. 56 | 57 |
58 | 59 | Set the user name and select only **Acess key - Programmatic access**. 60 | 61 |
62 | 63 | In the next page, select **Attach existing policies directly** and type **AWSIoTConfigAccess** into the **Filter Policies** box and check the box to the left of the row. 64 | 65 |
66 | 67 | 68 | For other pages we leave the default or leave it empty and just keep clicking **Next** in the bottom right corner. 69 | 70 |
71 | 72 | We now attach a policy to the newly created user that defines what permissions they hold. 73 | 74 |
75 | 76 | 77 | !!!Attention 78 |
79 | 80 | Ensure you record and store these keys securely, as you will not have an opportunity to get access to them again! 81 | 82 | ## Add AWS IoT Core Integration in Helium 83 | 84 | We can go back to the [Helium console](https://console.helium.com/integrations) and create the AWS IoT Core to Helium integration. 85 | 86 |
87 | 88 | Click **Add Integration** in the new page. 89 | 90 |
91 | 92 | Fill in the Helium AWS IoT Core integration with the Access Key and Secret Key respectively, which are generated in the content of the **Create access to AWS IoT Core**. 93 | 94 |
95 | 96 | In Region, you need to fill in the same region code as the address where the AWS IoT Core server is located. This is in the top right hand corner of the AWS IoT Core console at the username. 97 | 98 |
99 | 100 | The highlighted area is allowed to be adjusted by the user. Here, for example, I have selected the region where the server is located as **US East (N. Virginia)** and the region code as **us-east-1**. Correspondingly, in Helium's Region I need to fill in the **us-east-1**. 101 | 102 |
103 | 104 | The Topic field is the AWS IoT MQTT topic that this integration will publish uplink messages to, from devices. 105 | 106 | Finally, we give our new Integration a name and click Create Integration. Your new Integration is now ready for use. 107 | 108 |
109 | 110 | 111 | ## Connecting Integrations to Devices 112 | 113 | Now, use the click and drag interface in the Helium Console to connect the device to the function (Decoder) to the AWS IoT Core as shown [previously](https://wiki.seeedstudio.com/Helium-Introduction/#helium-console-flows). 114 | 115 |
116 | 117 | At this point, follow the [previous steps](https://wiki.seeedstudio.com/Connecting-to-Helium/#upload-code-send-data-to-helium) to upload the code again, and Wio Terminal will reconnect to Helium and upload the data. 118 | 119 | We can also find out about the success of sending data by checking the data returned by the serial monitor. 120 | 121 |
122 | 123 | In the AWS IoT Core console, search for **IoT Core** to access the data management interface. 124 | 125 |
126 | 127 | - In the **Monitor** panel you can see and set up a number of data detection panels to see more visually how the sensor data is being received. 128 | 129 |
130 | 131 | - In **AWS IOT core -> All devices -> Things** you can see the ID information of the current device and also the activity status of the data in **AWS IOT core -> All devices -> Things -> Activity**. 132 | 133 |
134 | 135 |
136 | 137 | - The uplink messages for the data you can view in **AWS IOT core -> MQTT test client**. 138 | 139 | In the **Subscribe to a topic** tab, enter the topicName to subscribe to the topic on which your device publishes. For the getting started sample app, subscribe to **#**, which subscribes to all message topics. 140 | 141 | The topic message log page, **#** opens and **#** appears in the **Subscriptions** list. If the device that you configured in Configure your device is running the example program, you should see the messages it sends to AWS IoT in the **#** message log. The message log entries will appear below the Publish section when messages with the subscribed topic are received by AWS IoT. 142 | 143 | Messages published to subscribed topics appear in the message log as they are received, with the most recent message first. 144 | 145 |
146 | 147 | 148 | The message received is similar to the one shown below. The data that is useful to us is generally the content following the **payload**, which shows the values of the sensors. 149 | 150 |
151 | 152 | At this point, we have completed the entirety of Helium's integration into AWS IoT Core. If you want to do more with your data through AWS IoT Core, you can refer to the [Documentation Centre of AWS IoT Core](https://docs.aws.amazon.com/iot/index.html) to continue learning more in depth. 153 | 154 | 155 | ## Tech Support 156 | 157 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/)

158 | -------------------------------------------------------------------------------- /docs/05-Helium/2-Integrate into Google Sheets via Helium/README.md: -------------------------------------------------------------------------------- 1 | # Integrate into Google Sheets via Helium 2 | 3 |
4 | 5 | Google Sheets is a web-based application that enables users to create, update and modify spreadsheets and share the data online in real time. 6 | 7 | The Google Sheets online spreadsheet application enables users to create, edit and format spreadsheets online to organize and analyze information. Google Sheets is often compared to Microsoft Excel, as both applications are used for similar purposes. Google Sheets is essentially Google's cloud-based version of Microsoft Excel's basic features. 8 | 9 | Thanks to Helium's integration capabilities, we can easily save sensor data via Google Sheets and do some simple data analysis accordingly. 10 | 11 | ## Create Google Form 12 | 13 | If you have not registered for a Google account prior to learning this tutorial, please complete your Google account [here](https://accounts.google.com/signup/v2/webcreateaccount?biz=false&flowName=GlifWebSignIn&flowEntry=SignUp&hl=en-GB) first. 14 | 15 |
16 | 17 | Once you have completed your account registration, please login to the [Google Forms page](https://docs.google.com/forms/u/0/). Then, simply create a new Google Form. 18 | 19 |
20 | 21 | We recommend setting questions to "Short answer". 22 | 23 | Here, I will create a table using Vision AI Module as an example. This table should have two sets of data, one for the number of people detected and its confidence level. 24 | 25 |
26 | 27 | !!!Note 28 | Short Answer needs to be selected for each new sensor tag created. 29 | 30 | Head over to the responses tab and tell the form you want your results sent to Google Sheets by clicking the Google Sheets button. 31 | 32 |
33 | 34 | Simply enter the Google Form title in the new pop-up window and click the **Create** button at the bottom right. 35 | 36 |
37 | 38 | Make sure we have created the required columns. 39 | 40 |
41 | 42 | ## Make Form Public 43 | 44 | Go back to our form setup page and click on the **Send** button in the top right hand corner to get the link to share the form. 45 | 46 |
47 | 48 | You'll get a share link like this one. 49 | 50 | `https://docs.google.com/forms/d/e/1FAIpQLSce9ozQMVwdgIYXYyutRPeE5opGba6724QGEN_I_dvoEH_Muw/viewform?usp=sf_link` 51 | 52 | We're only after the ID of the form, so we're going to remove the prefix `https://docs.google.com/forms/d/e/` and suffix `/viewform?usp=sf_link`. We should be left with a big string that contains no slashes. 53 | 54 | `1FAIpQLSce9ozQMVwdgIYXYyutRPeE5opGba6724QGEN_I_dvoEH_Muw` 55 | 56 | Please record this ID, which will be used in the Helium integration. 57 | 58 | ## Add Google Sheets Integration in Helium 59 | 60 | Go back to Helium and add a Google Sheets integration in Console, go to Integrations on the left-hand menu. Select the integration to add - in this case, the Google Sheets integration as shown below. 61 | 62 |
63 | 64 | Click **Add Integration** in the new page. 65 | 66 |
67 | 68 | On the new page, we enter the form ID we obtained above into the corresponding field and click on **Get Google Form Fields** to check if the ID is correct. If, after clicking on it, we are able to get the content of the labels in the columns of the form, the link is correct. 69 | 70 |
71 | 72 | Click on **Generate Function Body w/ Fields Above** at the bottom and Helium will automatically generate the required decoder for us. 73 | 74 |
75 | 76 | !!!Tip 77 | At this point, you don't have to rush to click on the Add Integration button on the right, as the integration still needs a little modification to accommodate the sensor values we have passed on. 78 | 79 | 80 | ## Create your Decoder 81 | 82 | We have prepared the code for the complete decoder required to import all the sensors in the kit into Google Sheets for you, please refer to the table below. 83 | 84 | Before using the decoder code for the corresponding sensor, please ensure that you have followed the tutorial above to create and share the Google Form. And if you want to use the code provided by us directly, **the label of the sensor in your form should also match the code**. 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |
Sensor TypeDownload Address
Wio Terminal built-in light sensorDownload
Wio Terminal built-in IMU sensorDownload
Soil Moisture SensorDownload
VOC and eCO2 Gas Sensor (SGP30)Download
Temp&Humi Sensor (SHT40)Download
Vision AI ModuleDownload
117 | 118 | !!!Note 119 | The decoder used by Google Forms cannot be used with the decoder provided in the [Connecting to Helium](https://wiki.seeedstudio.com/Connecting-to-Helium/#write-decoders-function-for-different-sensors). 120 | 121 | Continuing from the previous step, we need to copy and replace the code area of Helium with the codec of the sensor you are using, and then just click Add Integration on the right hand side. 122 | 123 |
124 | 125 | Of course, don't forget that we need to add the integration of the decoder and Google Forms to the **Flow**. 126 | 127 |
128 | 129 | ## Upload code send data to Helium 130 | 131 | Please follow the instructions in the [Connecting to Helium tutorial](https://wiki.seeedstudio.com/Connecting-to-Helium/#upload-code-send-data-to-helium) to upload the code to send your sensor values to Helium. 132 | 133 | Once the data has started to be sent, you can see a live refresh of the data from Google Sheets. 134 | 135 |
136 | 137 |
138 | 139 |
140 | 141 |
142 | 143 |
144 | 145 |
146 | 147 | 148 | You can also do what I did above, add a variety of table styles to Google Sheets to make it more intuitive and easier for you to see data or understand trends in your data. 149 | 150 |
151 | 152 | 153 | ## Tech Support 154 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/).

155 | -------------------------------------------------------------------------------- /docs/07-WiFi/1-Connect the Wio Terminal to Microsoft Azure IoT Hub/README.md: -------------------------------------------------------------------------------- 1 | # Connecting the Wio Terminal to Microsoft Azure IoT 2 | 3 |
4 | 5 | >This is a document written by [**@Benjamin Cabé**](https://twitter.com/kartben). Thank you Benjamin for the great work! You may also find [Benjamin's work](https://github.com/kartben) here. 6 | 7 | This sample application shows you how to connect your [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) to [Azure IoT Hub](https://azure.microsoft.com/services/iot-hub). It is built on top of the [Azure SDK for Embedded C](https://github.com/Azure/azure-sdk-for-c), a small footprint, easy-to-port library for communicating with Azure services. 8 | 9 | To connect with Microsoft Azure IoT with Wio Terminal, please see the [**Benjamin's Guide**](https://github.com/kartben/wioterminal-azureiothub-sample). 10 | 11 | ## Connecting to MQTT Server 12 | 13 |
14 | 15 | If you want to connect Wio Terminal to MQTT servers(such as Microsoft Azure IoT), you may also check [**Benjamin's Guide for MQTT on Wio Terminal**](https://github.com/kartben/wioterminal-mqtts-sample)! 16 | 17 | ## Tech Support 18 | 19 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/)

-------------------------------------------------------------------------------- /docs/08-Cloud/Connect AWS IOT Core via Helium (Helium)/README.md: -------------------------------------------------------------------------------- 1 | # Connect AWS IOT Core via Helium 2 | 3 |
4 | 5 | ## Introduction to AWS IoT Core 6 | 7 | AWS IoT Core provides the cloud services that connect your IoT devices to other devices and AWS cloud services. AWS IoT provides device software that can help you integrate your IoT devices into AWS IoT-based solutions. If your devices can connect to AWS IoT, AWS IoT can connect them to the cloud services that AWS provides. 8 | 9 |
10 | 11 | AWS IoT lets you select the most appropriate and up-to-date technologies for your solution. To help you manage and support your IoT devices in the field, AWS IoT Core supports these protocols: 12 | 13 | - MQTT (Message Queuing and Telemetry Transport) 14 | - MQTT over WSS (Websockets Secure) 15 | - HTTPS (Hypertext Transfer Protocol - Secure) 16 | - LoRaWAN® (Long Range Wide Area Network) 17 | 18 | AWS IoT Core is a powerful offering that lets developers build device-based applications and services on the AWS Cloud. And this Integration via Helium Console automates the complexity of securely connecting your devices to AWS IoT Core. 19 | 20 | !!!Attention 21 | You may need to pay for AWS IoT Core to experience the full content of this tutorial. A detailed list of payments and costs you can approximate [here](https://calculator.aws/#/estimate). 22 | 23 | Based on the sending frequency of the code we have provided (sending data at approximately 15 second intervals), approximately 178,560 messages will be sent in a month, with a message size of approximately 3 to 4 KB and a monthly cost of 0.18 USD. 24 |
25 | 26 | 27 | ## Sign up for AWS IoT Core 28 | 29 | Please go to the [AWS IoT Core website](https://portal.aws.amazon.com/billing/signup#/start/email) and register an account. 30 | 31 |
32 | 33 | Fill out an email with your registered email address and a user name and you will receive an email from AWS with the six-digit verification code required to register. 34 | 35 | Enter your verification code and registration is complete. Sign in to AWS IoT Core with the email address you just filled in. 36 | 37 | After logging in, you will need to continue filling in personal information such as passwords and contacts. You will then be required to link a credit card to verify your personal information. 38 | 39 |
40 | 41 | When we log in to the AWS IoT Core console, we just select the **Root user** to log in. 42 | 43 |
44 | 45 | ## Create access to AWS IoT Core 46 | 47 | Create a new user with limited permissions that this Integration will use on AWS. 48 | 49 | 1. Open up the [AWS Console](https://console.aws.amazon.com/). 50 | 51 | 2. Click on Services menu in the upper-left, go to **Security, Identity, & Compliance**, then click **IAM**. 52 | 53 |
54 | 55 | We are now going to create a new **User**. 56 | 57 |
58 | 59 | Set the user name and select only **Acess key - Programmatic access**. 60 | 61 |
62 | 63 | In the next page, select **Attach existing policies directly** and type **AWSIoTConfigAccess** into the **Filter Policies** box and check the box to the left of the row. 64 | 65 |
66 | 67 | 68 | For other pages we leave the default or leave it empty and just keep clicking **Next** in the bottom right corner. 69 | 70 |
71 | 72 | We now attach a policy to the newly created user that defines what permissions they hold. 73 | 74 |
75 | 76 | 77 | !!!Attention 78 |
79 | 80 | Ensure you record and store these keys securely, as you will not have an opportunity to get access to them again! 81 | 82 | ## Add AWS IoT Core Integration in Helium 83 | 84 | We can go back to the [Helium console](https://console.helium.com/integrations) and create the AWS IoT Core to Helium integration. 85 | 86 |
87 | 88 | Click **Add Integration** in the new page. 89 | 90 |
91 | 92 | Fill in the Helium AWS IoT Core integration with the Access Key and Secret Key respectively, which are generated in the content of the **Create access to AWS IoT Core**. 93 | 94 |
95 | 96 | In Region, you need to fill in the same region code as the address where the AWS IoT Core server is located. This is in the top right hand corner of the AWS IoT Core console at the username. 97 | 98 |
99 | 100 | The highlighted area is allowed to be adjusted by the user. Here, for example, I have selected the region where the server is located as **US East (N. Virginia)** and the region code as **us-east-1**. Correspondingly, in Helium's Region I need to fill in the **us-east-1**. 101 | 102 |
103 | 104 | The Topic field is the AWS IoT MQTT topic that this integration will publish uplink messages to, from devices. 105 | 106 | Finally, we give our new Integration a name and click Create Integration. Your new Integration is now ready for use. 107 | 108 |
109 | 110 | 111 | ## Connecting Integrations to Devices 112 | 113 | Now, use the click and drag interface in the Helium Console to connect the device to the function (Decoder) to the AWS IoT Core as shown [previously](https://wiki.seeedstudio.com/Helium-Introduction/#helium-console-flows). 114 | 115 |
116 | 117 | At this point, follow the [previous steps](https://wiki.seeedstudio.com/Connecting-to-Helium/#upload-code-send-data-to-helium) to upload the code again, and Wio Terminal will reconnect to Helium and upload the data. 118 | 119 | We can also find out about the success of sending data by checking the data returned by the serial monitor. 120 | 121 |
122 | 123 | In the AWS IoT Core console, search for **IoT Core** to access the data management interface. 124 | 125 |
126 | 127 | - In the **Monitor** panel you can see and set up a number of data detection panels to see more visually how the sensor data is being received. 128 | 129 |
130 | 131 | - In **AWS IOT core -> All devices -> Things** you can see the ID information of the current device and also the activity status of the data in **AWS IOT core -> All devices -> Things -> Activity**. 132 | 133 |
134 | 135 |
136 | 137 | - The uplink messages for the data you can view in **AWS IOT core -> MQTT test client**. 138 | 139 | In the **Subscribe to a topic** tab, enter the topicName to subscribe to the topic on which your device publishes. For the getting started sample app, subscribe to **#**, which subscribes to all message topics. 140 | 141 | The topic message log page, **#** opens and **#** appears in the **Subscriptions** list. If the device that you configured in Configure your device is running the example program, you should see the messages it sends to AWS IoT in the **#** message log. The message log entries will appear below the Publish section when messages with the subscribed topic are received by AWS IoT. 142 | 143 | Messages published to subscribed topics appear in the message log as they are received, with the most recent message first. 144 | 145 |
146 | 147 | 148 | The message received is similar to the one shown below. The data that is useful to us is generally the content following the **payload**, which shows the values of the sensors. 149 | 150 |
151 | 152 | At this point, we have completed the entirety of Helium's integration into AWS IoT Core. If you want to do more with your data through AWS IoT Core, you can refer to the [Documentation Centre of AWS IoT Core](https://docs.aws.amazon.com/iot/index.html) to continue learning more in depth. 153 | 154 | 155 | ## Tech Support 156 | 157 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/)

158 | -------------------------------------------------------------------------------- /docs/08-Cloud/Connect the Wio Terminal to Microsoft Azure IoT Hub (WiFi)/README.md: -------------------------------------------------------------------------------- 1 | # Connecting the Wio Terminal to Microsoft Azure IoT 2 | 3 |
4 | 5 | >This is a document written by [**@Benjamin Cabé**](https://twitter.com/kartben). Thank you Benjamin for the great work! You may also find [Benjamin's work](https://github.com/kartben) here. 6 | 7 | This sample application shows you how to connect your [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) to [Azure IoT Hub](https://azure.microsoft.com/services/iot-hub). It is built on top of the [Azure SDK for Embedded C](https://github.com/Azure/azure-sdk-for-c), a small footprint, easy-to-port library for communicating with Azure services. 8 | 9 | To connect with Microsoft Azure IoT with Wio Terminal, please see the [**Benjamin's Guide**](https://github.com/kartben/wioterminal-azureiothub-sample). 10 | 11 | ## Connecting to MQTT Server 12 | 13 |
14 | 15 | If you want to connect Wio Terminal to MQTT servers(such as Microsoft Azure IoT), you may also check [**Benjamin's Guide for MQTT on Wio Terminal**](https://github.com/kartben/wioterminal-mqtts-sample)! 16 | 17 | ## Tech Support 18 | 19 | Please submit any technical issue into our [forum](https://forum.seeedstudio.com/)

-------------------------------------------------------------------------------- /examples/Network/LoRaWAN/Binding-devices/Binding-devices.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | void DISPLAY_INIT() // Display initialization, black background rotation 13 | { 14 | tft.begin(); 15 | tft.setRotation(3); 16 | tft.fillScreen(TFT_BLACK); 17 | } 18 | 19 | void BindDev_Display() // Select Frequency band interface 20 | { 21 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 22 | 23 | // put your main code here 24 | spr.setFreeFont(FSSB9); 25 | spr.setTextColor(TFT_BLACK); 26 | 27 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 28 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 29 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 30 | 31 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 32 | spr.fillRect(30 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(70, 130, 160)); 33 | 34 | spr.fillCircle(160, 55, 10, TFT_BLUE); //button to the left to select LoRa network 35 | 36 | spr.drawString("Sense", 32, 11, GFXFF); 37 | spr.drawString("Process", 127, 11, GFXFF); 38 | 39 | spr.setTextColor(TFT_BLACK); 40 | spr.drawString("Network", 231, 11, GFXFF); 41 | 42 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 43 | 44 | spr.setFreeFont(FSS9); 45 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 46 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 47 | 48 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 49 | spr.drawString(" WiFi ", 205, 48, GFXFF); //WiFi(Ubidots) 50 | 51 | spr.setTextColor(TFT_WHITE); 52 | spr.drawString("Please download and register an account", 30, 3.8 * FONT_ROW_HEIGHT, 2); 53 | spr.drawString("on our SenseCAP Mate APP, then scan the", 30, 4.6 * FONT_ROW_HEIGHT, 2); 54 | spr.drawString("QR code on the back of Grove-Wio E5", 30, 5.4 * FONT_ROW_HEIGHT, 2); 55 | spr.drawString("(which is included in the kit) to bind", 30, 6.2 * FONT_ROW_HEIGHT, 2); 56 | spr.drawString("your device to the cloud.", 30, 7.0 * FONT_ROW_HEIGHT, 2); 57 | 58 | spr.setFreeFont(FSS12); 59 | spr.drawString("OK", 36 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 60 | 61 | spr.setFreeFont(FSS9); 62 | spr.drawString("Network :", 5, 218 , GFXFF); 63 | 64 | spr.setTextColor(TFT_RED); //Networking status indication:OFF 65 | spr.drawString("OFF", 82, 218 , GFXFF); 66 | 67 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 68 | // spr.drawString("LoRa(SenseCAP)", 82, 218 , GFXFF); //Show the network you are in 69 | 70 | spr.pushSprite(0, 0); 71 | spr.deleteSprite(); 72 | } 73 | 74 | void setup() 75 | { 76 | DISPLAY_INIT(); 77 | } 78 | 79 | void loop() 80 | { 81 | BindDev_Display(); 82 | } 83 | -------------------------------------------------------------------------------- /examples/Network/LoRaWAN/Frequency-select/Frequency-select.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | 13 | //Key 14 | int key_status = 0; 15 | 16 | void key() //set button 17 | { 18 | if (digitalRead(WIO_KEY_C) == LOW) { 19 | Serial.println("A Key pressed"); 20 | key_status = 1; 21 | } 22 | else if (digitalRead(WIO_KEY_B) == LOW) { 23 | Serial.println("B Key pressed"); 24 | key_status = 2; 25 | } 26 | else if (digitalRead(WIO_KEY_A) == LOW) { 27 | Serial.println("C Key pressed"); 28 | key_status = 3; 29 | } 30 | } 31 | 32 | void DISPLAY_INIT() // Display initialization, black background rotation 33 | { 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_BLACK); 37 | } 38 | 39 | void Bandselect_Display(int key) // Select Frequency band interface 40 | { 41 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 42 | 43 | // put your main code here 44 | spr.setFreeFont(FSSB9); 45 | spr.setTextColor(TFT_BLACK); 46 | 47 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 50 | 51 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 52 | 53 | spr.fillCircle(160, 55, 10, TFT_BLUE); //button to the left to select LoRa network 54 | 55 | spr.drawString("Sense", 32, 11, GFXFF); 56 | spr.drawString("Process", 127, 11, GFXFF); 57 | 58 | spr.setTextColor(TFT_BLACK); 59 | spr.drawString("Network", 231, 11, GFXFF); 60 | 61 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 62 | 63 | spr.setFreeFont(FSS9); 64 | // spr.setTextColor(TFT_WHITE, tft.color565(143, 195, 31)); 65 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 66 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 67 | 68 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 69 | spr.drawString(" WiFi ", 205, 48, GFXFF); //WiFi(Ubidots) 70 | 71 | spr.setTextColor(TFT_WHITE); 72 | spr.drawString("Select and confirm LoRaWAN frequency band", 20, 3.8 * FONT_ROW_HEIGHT, 2); 73 | 74 | if(key == 1) //Press the A button to select the US915 band 75 | { 76 | spr.fillRect(18, 4.8 * FONT_ROW_HEIGHT, 80, 3.2 * FONT_ROW_HEIGHT, tft.color565(0, 139, 0)); 77 | spr.drawString("US915 is commonly used in North America.", 25, 8.5 * FONT_ROW_HEIGHT, 2); 78 | } 79 | if(key == 2) //Press the B button to select the EU868 band 80 | { 81 | spr.fillRect(118, 4.8 * FONT_ROW_HEIGHT, 80, 3.2 * FONT_ROW_HEIGHT, tft.color565(0, 139, 0)); 82 | spr.drawString("EU868 is commonly used in the European region.", 10, 8.5 * FONT_ROW_HEIGHT, 2); 83 | } 84 | if(key == 3) //Press the C button to select the AU915 band 85 | { 86 | spr.fillRect(218, 4.8 * FONT_ROW_HEIGHT, 80, 3.2 * FONT_ROW_HEIGHT, tft.color565(0, 139, 0)); 87 | spr.drawString("AU915 is commonly used in Australia region.", 18, 8.5 * FONT_ROW_HEIGHT, 2); 88 | } 89 | 90 | spr.drawString("US", 20, 5 * FONT_ROW_HEIGHT, GFXFF); 91 | spr.drawString("EU", 120, 5 * FONT_ROW_HEIGHT, GFXFF); 92 | spr.drawString("AU", 220, 5 * FONT_ROW_HEIGHT, GFXFF); 93 | 94 | spr.setFreeFont(FSS24); 95 | spr.drawString("915", 20, 6 * FONT_ROW_HEIGHT, GFXFF); 96 | spr.drawString("868", 120, 6 * FONT_ROW_HEIGHT, GFXFF); 97 | spr.drawString("915", 220, 6 * FONT_ROW_HEIGHT, GFXFF); 98 | 99 | spr.setFreeFont(FSS9); 100 | spr.drawString("Network :", 5, 218 , GFXFF); 101 | 102 | spr.setTextColor(TFT_RED); //Networking status indication:OFF 103 | spr.drawString("OFF", 82, 218 , GFXFF); 104 | 105 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 106 | // spr.drawString("ON", 82, 218 , GFXFF); 107 | 108 | spr.pushSprite(0, 0); 109 | spr.deleteSprite(); 110 | } 111 | 112 | void setup() 113 | { 114 | DISPLAY_INIT(); 115 | pinMode(WIO_KEY_C, INPUT_PULLUP); 116 | pinMode(WIO_KEY_B, INPUT_PULLUP); 117 | pinMode(WIO_KEY_A, INPUT_PULLUP); 118 | } 119 | 120 | void loop() 121 | { 122 | key(); //ABC button to select network 123 | Bandselect_Display(key_status); 124 | } 125 | -------------------------------------------------------------------------------- /examples/Network/LoRaWAN/Network-Select/Network-Select.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | 13 | //Key 14 | int key_status = 0; 15 | 16 | void key() //set button 17 | { 18 | if (digitalRead(WIO_KEY_C) == LOW) { 19 | Serial.println("A Key pressed"); 20 | key_status = 1; 21 | } 22 | else if (digitalRead(WIO_KEY_B) == LOW) { 23 | Serial.println("B Key pressed"); 24 | key_status = 2; 25 | } 26 | else if (digitalRead(WIO_KEY_A) == LOW) { 27 | Serial.println("C Key pressed"); 28 | key_status = 3; 29 | } 30 | } 31 | 32 | void DISPLAY_INIT() // Display initialization, black background rotation 33 | { 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_BLACK); 37 | } 38 | 39 | void NetworkHome_Display() // Select network interface 40 | { 41 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 42 | 43 | // put your main code here 44 | spr.setFreeFont(FSSB9); 45 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 46 | 47 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 50 | 51 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 52 | 53 | spr.drawString("Sense", 32, 11, GFXFF); 54 | spr.drawString("Process", 127, 11, GFXFF); 55 | 56 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 57 | spr.drawString("Network", 231, 11, GFXFF); 58 | 59 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 60 | 61 | spr.fillCircle(175, 56, 10, tft.color565(190, 190, 190)); //Default in no network state selected 62 | 63 | spr.setFreeFont(FSS9); 64 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 65 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 66 | spr.drawString(" WiFi ", 205, 48, GFXFF); //WiFi(Ubidots) 67 | 68 | spr.setTextColor(TFT_WHITE, TFT_BLACK); 69 | spr.drawString("Please toggle the bottom right", 30, 95 + FONT_ROW_HEIGHT, GFXFF); 70 | spr.drawString("button left and right to select", 30, 95 + 2 * FONT_ROW_HEIGHT, GFXFF); 71 | spr.drawString("the network.", 30, 95 + 3 * FONT_ROW_HEIGHT, GFXFF); 72 | 73 | spr.drawString("Network :", 5, 218 , GFXFF); 74 | 75 | 76 | spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 77 | spr.drawString("OFF", 82, 218 , GFXFF); 78 | 79 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 80 | // spr.drawString("LoRa(SenseCAP)", 82, 218 , GFXFF); //Show the network you are in 81 | 82 | spr.pushSprite(0, 0); 83 | spr.deleteSprite(); 84 | } 85 | 86 | void NetSelection(int key) 87 | { 88 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 89 | 90 | // put your main code here 91 | spr.setFreeFont(FSSB9); 92 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 93 | 94 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 95 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 96 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 97 | spr.fillRect(30 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(70, 130, 160)); 98 | 99 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 100 | 101 | spr.drawString("Sense", 32, 11, GFXFF); 102 | spr.drawString("Process", 127, 11, GFXFF); 103 | 104 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 105 | spr.drawString("Network", 231, 11, GFXFF); 106 | 107 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 108 | 109 | spr.setFreeFont(FSS9); 110 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 111 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 112 | spr.drawString(" WiFi ", 205, 48, GFXFF); //WiFi(Ubidots) 113 | 114 | if(key == 0)spr.fillCircle(175, 56, 10, tft.color565(190, 190, 190)); //Default in no network state selected 115 | if(key == 1)spr.fillCircle(160, 55, 10, TFT_BLUE); //button to the left to select LoRa network 116 | if(key == 2)spr.fillCircle(175, 56, 10, tft.color565(190, 190, 190)); //button to the middle, do not select the network 117 | if(key == 3)spr.fillCircle(192, 55, 10, TFT_BLUE); //button to the right to select the WiFi network 118 | 119 | spr.setTextColor(TFT_WHITE); 120 | spr.drawString("Please press the bottom right", 35, 75 + FONT_ROW_HEIGHT, GFXFF); 121 | spr.drawString("button to confirm your network", 35, 75 + 2 * FONT_ROW_HEIGHT, GFXFF); 122 | spr.drawString("selection.", 35, 75 + 3 * FONT_ROW_HEIGHT, GFXFF); 123 | 124 | spr.setFreeFont(FSS12); 125 | spr.drawString("OK", 36 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 126 | 127 | spr.setFreeFont(FSS9); 128 | spr.drawString("Network :", 5, 218 , GFXFF); 129 | 130 | 131 | spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 132 | spr.drawString("OFF", 82, 218 , GFXFF); 133 | 134 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 135 | // spr.drawString("LoRa(SenseCAP)", 82, 218 , GFXFF); //Show the network you are in 136 | 137 | spr.pushSprite(0, 0); 138 | spr.deleteSprite(); 139 | } 140 | 141 | void WioE5connect_Display() 142 | { 143 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 144 | 145 | // put your main code here 146 | spr.setFreeFont(FSSB9); 147 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 148 | 149 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 150 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 151 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 152 | spr.fillRect(30 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(70, 130, 160)); 153 | 154 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 155 | 156 | spr.drawString("Sense", 32, 11, GFXFF); 157 | spr.drawString("Process", 127, 11, GFXFF); 158 | 159 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 160 | spr.drawString("Network", 231, 11, GFXFF); 161 | 162 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 163 | 164 | spr.setFreeFont(FSS9); 165 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 166 | spr.drawString(" LoRa ", 5, 48, GFXFF); 167 | spr.drawString(" WiFi ", 205, 48, GFXFF); //WiFi(Ubidots) 168 | 169 | spr.fillCircle(175, 56, 10, tft.color565(190, 190, 190)); //Default in no network state selected 170 | 171 | spr.setTextColor(TFT_WHITE); 172 | spr.drawString("Please connect the Grove-Wio E5", 25, 75 + FONT_ROW_HEIGHT, GFXFF); 173 | spr.drawString("to the Grove connector on the", 25, 75 + 2 * FONT_ROW_HEIGHT, GFXFF); 174 | spr.drawString("bottom right side of the screen.", 25, 75 + 3 * FONT_ROW_HEIGHT, GFXFF); 175 | 176 | spr.setFreeFont(FSS12); 177 | spr.drawString("OK", 36 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 178 | 179 | spr.setFreeFont(FSS9); 180 | spr.drawString("Network :", 5, 218 , GFXFF); 181 | 182 | 183 | spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 184 | spr.drawString("OFF", 82, 218 , GFXFF); 185 | 186 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 187 | // spr.drawString("LoRa(SenseCAP)", 82, 218 , GFXFF); //Show the network you are in 188 | 189 | spr.pushSprite(0, 0); 190 | spr.deleteSprite(); 191 | } 192 | 193 | void setup() 194 | { 195 | DISPLAY_INIT(); 196 | pinMode(WIO_KEY_C, INPUT_PULLUP); 197 | pinMode(WIO_KEY_B, INPUT_PULLUP); 198 | pinMode(WIO_KEY_A, INPUT_PULLUP); 199 | } 200 | 201 | void loop() 202 | { 203 | key(); //ABC button to select network 204 | NetworkHome_Display(); 205 | delay(2000); 206 | NetSelection(key_status); 207 | delay(2000); 208 | WioE5connect_Display(); 209 | delay(2000); 210 | } 211 | -------------------------------------------------------------------------------- /examples/Network/LoRaWAN/connect-success/connect-success.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | 13 | //Key 14 | int key_status = 0; 15 | 16 | void key() //set button 17 | { 18 | if (digitalRead(WIO_KEY_C) == LOW) { 19 | Serial.println("A Key pressed"); 20 | key_status = 1; 21 | } 22 | else if (digitalRead(WIO_KEY_B) == LOW) { 23 | Serial.println("B Key pressed"); 24 | key_status = 2; 25 | } 26 | else if (digitalRead(WIO_KEY_A) == LOW) { 27 | Serial.println("C Key pressed"); 28 | key_status = 3; 29 | } 30 | } 31 | 32 | void DISPLAY_INIT() // Display initialization, black background rotation 33 | { 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_BLACK); 37 | } 38 | 39 | void ConnectSuc_Display(int key) // Select Frequency band interface 40 | { 41 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 42 | 43 | // put your main code here 44 | spr.setFreeFont(FSSB9); 45 | spr.setTextColor(TFT_BLACK); 46 | 47 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 50 | 51 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 52 | spr.fillRect(28 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 25 * PIXEL, FONT_ROW_HEIGHT + 14, tft.color565(160, 34, 34)); 53 | 54 | spr.fillCircle(160, 55, 10, TFT_BLUE); //button to the left to select LoRa network 55 | 56 | spr.drawString("Sense", 32, 11, GFXFF); 57 | spr.drawString("Process", 127, 11, GFXFF); 58 | 59 | spr.setTextColor(TFT_BLACK); 60 | spr.drawString("Network", 231, 11, GFXFF); 61 | 62 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 63 | 64 | spr.setFreeFont(FSS9); 65 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 66 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 67 | 68 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 69 | spr.drawString(" WiFi ", 205, 48, GFXFF); //iFi(Ubidots) 70 | 71 | spr.setTextColor(TFT_WHITE); 72 | spr.drawString("Connected: LoRa ", 30, 3.8 * FONT_ROW_HEIGHT, 2); //(SenseCAP) 73 | spr.drawString("Signal:", 30, 4.8 * FONT_ROW_HEIGHT, 2); 74 | spr.drawString("All data:", 30, 5.8 * FONT_ROW_HEIGHT, 2); 75 | spr.drawString("packets", 140, 5.8 * FONT_ROW_HEIGHT, 2); 76 | spr.drawString("Success:", 30, 6.8 * FONT_ROW_HEIGHT, 2); 77 | spr.drawString("packets", 140, 6.8 * FONT_ROW_HEIGHT, 2); 78 | 79 | spr.setFreeFont(FSSB9); 80 | spr.setTextColor(tft.color565(0, 139, 0)); 81 | spr.drawString("10000", 90, 5.8 * FONT_ROW_HEIGHT, 2); //Show total number of packages issued 82 | spr.drawString("999", 90, 6.8 * FONT_ROW_HEIGHT, 2); //Shows the number of successful deliveries 83 | 84 | // spr.fillRect(78, 110, 3, 11, tft.color565(100, 100, 100)); //No signal 85 | // spr.fillRect(84, 107, 3, 14, tft.color565(100, 100, 100)); 86 | // spr.fillRect(90, 104, 3, 17, tft.color565(100, 100, 100)); 87 | // spr.fillRect(96, 101, 3, 20, tft.color565(100, 100, 100)); 88 | 89 | if(key == 0) //Press the A button to disconnect 90 | { 91 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //Two-frame signal 92 | spr.fillRect(84, 107, 3, 14, tft.color565(0, 139, 0)); 93 | spr.fillRect(90, 104, 3, 17, tft.color565(100, 100, 100)); 94 | spr.fillRect(96, 101, 3, 20, tft.color565(100, 100, 100)); 95 | 96 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_GREEN); //Data transmission status: normal 97 | spr.setTextColor(TFT_WHITE); 98 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 99 | spr.drawString("Success", 245, 6.6 * FONT_ROW_HEIGHT, 2); 100 | 101 | spr.setFreeFont(FSS9); 102 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 103 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //(SenseCAP) 104 | } 105 | if(key == 1) //Press the A button to disconnect 106 | { 107 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //Four-frame signal 108 | spr.fillRect(84, 107, 3, 14, tft.color565(0, 139, 0)); 109 | spr.fillRect(90, 104, 3, 17, tft.color565(0, 139, 0)); 110 | spr.fillRect(96, 101, 3, 20, tft.color565(0, 139, 0)); 111 | 112 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_GREEN); //Data transmission status: normal 113 | spr.setTextColor(TFT_WHITE); 114 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 115 | spr.drawString("Success", 245, 6.6 * FONT_ROW_HEIGHT, 2); 116 | 117 | spr.setFreeFont(FSS9); 118 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 119 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //LoRa(SenseCAP) 120 | } 121 | if(key == 2) //Press the B button to disconnect 122 | { 123 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //One frame signal 124 | spr.fillRect(84, 107, 3, 14, tft.color565(100, 100, 100)); 125 | spr.fillRect(90, 104, 3, 17, tft.color565(100, 100, 100)); 126 | spr.fillRect(96, 101, 3, 20, tft.color565(100, 100, 100)); 127 | 128 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, tft.color565(255, 165, 0)); //Data transmission status: Packet loss 129 | spr.setTextColor(TFT_WHITE); 130 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 131 | spr.drawString("Failed", 250, 6.6 * FONT_ROW_HEIGHT, 2); 132 | 133 | spr.setFreeFont(FSS9); 134 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 135 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //LoRa (SenseCAP) 136 | } 137 | if(key == 3) //Press the C button to disconnect 138 | { 139 | spr.fillRect(78, 110, 3, 11, tft.color565(140, 42, 42)); //No signal 140 | spr.fillRect(84, 107, 3, 14, tft.color565(140, 42, 42)); 141 | spr.fillRect(90, 104, 3, 17, tft.color565(140, 42, 42)); 142 | spr.fillRect(96, 101, 3, 20, tft.color565(140, 42, 42)); 143 | 144 | 145 | // Demo version we dont display "Join loRaWAN failed" 146 | // spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_RED); //Data transmission status: join failed 147 | // spr.setTextColor(TFT_WHITE); 148 | // spr.drawString("Join LoRaWAN", 220, 5.8 * FONT_ROW_HEIGHT, 2); 149 | // spr.drawString("Failed", 250, 6.6 * FONT_ROW_HEIGHT, 2); 150 | 151 | spr.setFreeFont(FSS9); 152 | spr.setTextColor(TFT_RED); //Networking status indication:OFF 153 | spr.drawString("OFF", 82, 218 , GFXFF); 154 | } 155 | 156 | spr.setFreeFont(FSS9); 157 | spr.setTextColor(TFT_WHITE); 158 | spr.drawString("Disconnect", 29 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 159 | 160 | spr.setFreeFont(FSS9); 161 | spr.drawString("Network :", 5, 218 , GFXFF); 162 | 163 | spr.pushSprite(0, 0); 164 | spr.deleteSprite(); 165 | } 166 | 167 | void Disconnect_Tip() // Pop-up prompt for sensor insertion 168 | { 169 | spr.createSprite(240, 116); 170 | spr.fillScreen(tft.color565(211, 211, 211)); 171 | 172 | spr.setFreeFont(FSS9); 173 | spr.setTextColor(TFT_BLACK); 174 | spr.drawString("Network will be disconnected", 3, 30, GFXFF); 175 | 176 | spr.fillRect(40, 70, 65, 35, tft.color565(140, 42, 42)); 177 | spr.fillRect(139, 70, 65, 35, tft.color565(70, 130, 160)); 178 | 179 | spr.setTextColor(TFT_WHITE); 180 | spr.drawString("Yes", 57, 78, GFXFF); 181 | spr.drawString("No", 162, 78, GFXFF); 182 | 183 | spr.pushSprite(40, 64); 184 | spr.deleteSprite(); 185 | } 186 | 187 | void setup() 188 | { 189 | DISPLAY_INIT(); 190 | pinMode(WIO_KEY_C, INPUT_PULLUP); 191 | pinMode(WIO_KEY_B, INPUT_PULLUP); 192 | pinMode(WIO_KEY_A, INPUT_PULLUP); 193 | } 194 | 195 | void loop() 196 | { 197 | key(); //ABC button to select network 198 | ConnectSuc_Display(key_status); 199 | delay(2000); 200 | Disconnect_Tip(); 201 | delay(2000); 202 | } 203 | -------------------------------------------------------------------------------- /examples/Network/WiFi/connect-success/connect-success.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | 13 | //Key 14 | int key_status = 0; 15 | 16 | void key() //set button 17 | { 18 | if (digitalRead(WIO_KEY_C) == LOW) { 19 | Serial.println("A Key pressed"); 20 | key_status = 1; 21 | } 22 | else if (digitalRead(WIO_KEY_B) == LOW) { 23 | Serial.println("B Key pressed"); 24 | key_status = 2; 25 | } 26 | else if (digitalRead(WIO_KEY_A) == LOW) { 27 | Serial.println("C Key pressed"); 28 | key_status = 3; 29 | } 30 | } 31 | 32 | void DISPLAY_INIT() // Display initialization, black background rotation 33 | { 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_BLACK); 37 | } 38 | 39 | void ConnectSuc_Display(int key) // Select Frequency band interface 40 | { 41 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 42 | 43 | // put your main code here 44 | spr.setFreeFont(FSSB9); 45 | spr.setTextColor(TFT_BLACK); 46 | 47 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 50 | 51 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 52 | spr.fillRect(28 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 25 * PIXEL, FONT_ROW_HEIGHT + 14, tft.color565(160, 34, 34)); 53 | 54 | spr.fillCircle(192, 55, 10, TFT_BLUE); //button to the right to select the WiFi network 55 | 56 | spr.drawString("Sense", 32, 11, GFXFF); 57 | spr.drawString("Process", 127, 11, GFXFF); 58 | 59 | spr.setTextColor(TFT_BLACK); 60 | spr.drawString("Network", 231, 11, GFXFF); 61 | 62 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 63 | 64 | spr.setFreeFont(FSS9); 65 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 66 | spr.drawString("WiFi ", 205, 48, GFXFF); // WiFi(Ubidots) 67 | 68 | spr.setFreeFont(FSS9); 69 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 70 | spr.drawString("LoRa ", 5, 48, GFXFF); // LoRa(Sencecap) 71 | 72 | spr.setTextColor(TFT_WHITE); 73 | spr.drawString("Connected: WiFi ", 30, 3.8 * FONT_ROW_HEIGHT, 2); 74 | spr.drawString("Signal:", 30, 4.8 * FONT_ROW_HEIGHT, 2); 75 | spr.drawString("All data:", 30, 5.8 * FONT_ROW_HEIGHT, 2); 76 | spr.drawString("packets", 140, 5.8 * FONT_ROW_HEIGHT, 2); 77 | spr.drawString("Success:", 30, 6.8 * FONT_ROW_HEIGHT, 2); 78 | spr.drawString("packets", 140, 6.8 * FONT_ROW_HEIGHT, 2); 79 | 80 | spr.setFreeFont(FSSB9); 81 | spr.setTextColor(tft.color565(0, 139, 0)); 82 | spr.drawString("10000", 90, 5.8 * FONT_ROW_HEIGHT, 2); //Show total number of packages issued 83 | spr.drawString("999", 90, 6.8 * FONT_ROW_HEIGHT, 2); //Shows the number of successful deliveries 84 | 85 | if(key == 0) //Press the A button to disconnect 86 | { 87 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //Two-frame signal 88 | spr.fillRect(84, 107, 3, 14, tft.color565(0, 139, 0)); 89 | spr.fillRect(90, 104, 3, 17, tft.color565(100, 100, 100)); 90 | spr.fillRect(96, 101, 3, 20, tft.color565(100, 100, 100)); 91 | 92 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_GREEN); //Data transmission status: normal 93 | spr.setTextColor(TFT_WHITE); 94 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 95 | spr.drawString("Success", 245, 6.6 * FONT_ROW_HEIGHT, 2); 96 | 97 | spr.setFreeFont(FSS9); 98 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 99 | spr.drawString(" WiFi ", 82, 218 , GFXFF); // WIFI(Ubidots) 100 | } 101 | if(key == 1) //Press the A button to disconnect 102 | { 103 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //Four-frame signal 104 | spr.fillRect(84, 107, 3, 14, tft.color565(0, 139, 0)); 105 | spr.fillRect(90, 104, 3, 17, tft.color565(0, 139, 0)); 106 | spr.fillRect(96, 101, 3, 20, tft.color565(0, 139, 0)); 107 | 108 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_GREEN); //Data transmission status: normal 109 | spr.setTextColor(TFT_WHITE); 110 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 111 | spr.drawString("Success", 245, 6.6 * FONT_ROW_HEIGHT, 2); 112 | 113 | spr.setFreeFont(FSS9); 114 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 115 | spr.drawString(" WiFi ", 82, 218 , GFXFF); //WiFi(Ubidots) 116 | } 117 | if(key == 2) //Press the B button to disconnect 118 | { 119 | spr.fillRect(78, 110, 3, 11, tft.color565(0, 139, 0)); //One frame signal 120 | spr.fillRect(84, 107, 3, 14, tft.color565(100, 100, 100)); 121 | spr.fillRect(90, 104, 3, 17, tft.color565(100, 100, 100)); 122 | spr.fillRect(96, 101, 3, 20, tft.color565(100, 100, 100)); 123 | 124 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, tft.color565(255, 165, 0)); //Data transmission status: Packet loss 125 | spr.setTextColor(TFT_WHITE); 126 | spr.drawString("Send", 253, 5.8 * FONT_ROW_HEIGHT, 2); 127 | spr.drawString("Failed", 250, 6.6 * FONT_ROW_HEIGHT, 2); 128 | 129 | spr.setFreeFont(FSS9); 130 | spr.setTextColor(tft.color565(0, 139, 0), TFT_BLACK); //Networking status indication:ON 131 | spr.drawString(" WiFi ", 82, 218 , GFXFF); 132 | } 133 | if(key == 3) //Press the C button to disconnect 134 | { 135 | spr.fillRect(78, 110, 3, 11, tft.color565(140, 42, 42)); //No signal 136 | spr.fillRect(84, 107, 3, 14, tft.color565(140, 42, 42)); 137 | spr.fillRect(90, 104, 3, 17, tft.color565(140, 42, 42)); 138 | spr.fillRect(96, 101, 3, 20, tft.color565(140, 42, 42)); 139 | 140 | spr.fillCircle(265, 4.9 * FONT_ROW_HEIGHT, 10, TFT_RED); //Data transmission status: join failed 141 | spr.setTextColor(TFT_WHITE); 142 | spr.drawString("Join WiFi", 240, 5.8 * FONT_ROW_HEIGHT, 2); 143 | spr.drawString("Failed", 250, 6.6 * FONT_ROW_HEIGHT, 2); 144 | 145 | spr.setFreeFont(FSS9); 146 | spr.setTextColor(TFT_RED); //Networking status indication:OFF 147 | spr.drawString("OFF", 82, 218 , GFXFF); 148 | } 149 | 150 | spr.setFreeFont(FSS9); 151 | spr.setTextColor(TFT_WHITE); 152 | spr.drawString("Disconnect", 29 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 153 | 154 | spr.setFreeFont(FSS9); 155 | spr.drawString("Network :", 5, 218 , GFXFF); 156 | 157 | spr.pushSprite(0, 0); 158 | spr.deleteSprite(); 159 | } 160 | 161 | void Disconnect_Tip() // Pop-up prompt for sensor insertion 162 | { 163 | spr.createSprite(240, 116); 164 | spr.fillScreen(tft.color565(211, 211, 211)); 165 | 166 | spr.setFreeFont(FSS9); 167 | spr.setTextColor(TFT_BLACK); 168 | spr.drawString("Network will be disconnected", 3, 30, GFXFF); 169 | 170 | spr.fillRect(40, 70, 65, 35, tft.color565(140, 42, 42)); 171 | spr.fillRect(139, 70, 65, 35, tft.color565(70, 130, 160)); 172 | 173 | spr.setTextColor(TFT_WHITE); 174 | spr.drawString("Yes", 57, 78, GFXFF); 175 | spr.drawString("No", 162, 78, GFXFF); 176 | 177 | spr.pushSprite(40, 64); 178 | spr.deleteSprite(); 179 | } 180 | 181 | void setup() 182 | { 183 | DISPLAY_INIT(); 184 | pinMode(WIO_KEY_C, INPUT_PULLUP); 185 | pinMode(WIO_KEY_B, INPUT_PULLUP); 186 | pinMode(WIO_KEY_A, INPUT_PULLUP); 187 | } 188 | 189 | void loop() 190 | { 191 | key(); //ABC button to select network 192 | ConnectSuc_Display(key_status); 193 | delay(2000); 194 | Disconnect_Tip(); 195 | delay(2000); 196 | } 197 | -------------------------------------------------------------------------------- /examples/Network/WiFi/wifi-select/wifi-select.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | 13 | //Key 14 | int key_status = 0; 15 | 16 | void key() //set button 17 | { 18 | if (digitalRead(WIO_KEY_C) == LOW) { 19 | Serial.println("A Key pressed"); 20 | key_status = 1; 21 | } 22 | else if (digitalRead(WIO_KEY_B) == LOW) { 23 | Serial.println("B Key pressed"); 24 | key_status = 2; 25 | } 26 | else if (digitalRead(WIO_KEY_A) == LOW) { 27 | Serial.println("C Key pressed"); 28 | key_status = 3; 29 | } 30 | } 31 | 32 | void DISPLAY_INIT() // Display initialization, black background rotation 33 | { 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_BLACK); 37 | } 38 | 39 | void WifiSelection() 40 | { 41 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 42 | 43 | // put your main code here 44 | spr.setFreeFont(FSSB9); 45 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 46 | 47 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 50 | spr.fillRect(30 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(70, 130, 160)); 51 | 52 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 53 | 54 | spr.drawString("Sense", 32, 11, GFXFF); 55 | spr.drawString("Process", 127, 11, GFXFF); 56 | 57 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 58 | spr.drawString("Network", 231, 11, GFXFF); 59 | 60 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 61 | 62 | spr.setFreeFont(FSS9); 63 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 64 | spr.drawString(" WiFi ", 205, 48, GFXFF); //(Ubidots) 65 | 66 | spr.setFreeFont(FSS9); 67 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 68 | spr.drawString(" LoRa ", 5, 48, GFXFF); //LoRa(SenseCAP) 69 | 70 | spr.fillCircle(192, 55, 10, TFT_BLUE); //button to the right to select the WiFi network 71 | 72 | spr.setTextColor(TFT_WHITE); 73 | spr.drawString("Please refer to the wiki to modify", 25, 75 + FONT_ROW_HEIGHT, GFXFF); 74 | spr.drawString("the configuration file and send it", 25, 75 + 2 * FONT_ROW_HEIGHT, GFXFF); 75 | spr.drawString("to this device.", 25, 75 + 3 * FONT_ROW_HEIGHT, GFXFF); 76 | 77 | spr.setFreeFont(FSS12); 78 | spr.drawString("OK", 36 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 79 | 80 | spr.setFreeFont(FSS9); 81 | spr.drawString("Network :", 5, 218 , GFXFF); 82 | 83 | 84 | spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 85 | spr.drawString("OFF", 82, 218 , GFXFF); 86 | 87 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 88 | // spr.drawString("WiFi(Ubidots)", 82, 218 , GFXFF); //Show the network you are in 89 | 90 | spr.pushSprite(0, 0); 91 | spr.deleteSprite(); 92 | } 93 | 94 | void WifiWait_Display() 95 | { 96 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 97 | 98 | // put your main code here 99 | spr.setFreeFont(FSSB9); 100 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 101 | 102 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 103 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 104 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 105 | 106 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 107 | 108 | spr.drawString("Sense", 32, 11, GFXFF); 109 | spr.drawString("Process", 127, 11, GFXFF); 110 | 111 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 112 | spr.drawString("Network", 231, 11, GFXFF); 113 | 114 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 115 | 116 | spr.setFreeFont(FSS9); 117 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 118 | spr.drawString(" WiFi ", 205, 48, GFXFF); // 119 | 120 | spr.setFreeFont(FSS9); 121 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 122 | spr.drawString(" LoRa ", 5, 48, GFXFF); 123 | 124 | spr.fillCircle(192, 55, 10, TFT_BLUE); //button to the right to select the WiFi network 125 | 126 | spr.setTextColor(TFT_WHITE); 127 | spr.drawString("Waiting for configuration...", 55, 75 + 2.5 * FONT_ROW_HEIGHT, GFXFF); 128 | 129 | spr.setFreeFont(FSS9); 130 | spr.drawString("Network :", 5, 218 , GFXFF); 131 | 132 | 133 | spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 134 | spr.drawString("OFF", 82, 218 , GFXFF); 135 | 136 | // spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 137 | // spr.drawString("WiFi(Ubidots)", 82, 218 , GFXFF); //Show the network you are in 138 | 139 | spr.pushSprite(0, 0); 140 | spr.deleteSprite(); 141 | } 142 | 143 | void Wificonnect_Display() 144 | { 145 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 146 | 147 | // put your main code here 148 | spr.setFreeFont(FSSB9); 149 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 150 | 151 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 152 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 153 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 154 | spr.fillRect(30 * PIXEL, 8.0 * FONT_ROW_HEIGHT, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(70, 130, 160)); 155 | 156 | spr.fillRect(156, 54, 40, 4, tft.color565(220, 220, 220)); 157 | 158 | spr.drawString("Sense", 32, 11, GFXFF); 159 | spr.drawString("Process", 127, 11, GFXFF); 160 | 161 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 162 | spr.drawString("Network", 231, 11, GFXFF); 163 | 164 | spr.drawLine(0, 3.5 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 3.5 * FONT_ROW_HEIGHT, TFT_WHITE); 165 | 166 | spr.setFreeFont(FSS9); 167 | spr.setTextColor(TFT_WHITE, tft.color565(0, 139, 0)); 168 | spr.drawString(" WiFi ", 205, 48, GFXFF); 169 | 170 | spr.setFreeFont(FSS9); 171 | spr.setTextColor(TFT_WHITE, tft.color565(100, 100, 100)); 172 | spr.drawString(" LoRa ", 5, 48, GFXFF); 173 | 174 | spr.fillCircle(192, 55, 10, TFT_BLUE); //button to the right to select the WiFi network 175 | 176 | spr.setTextColor(TFT_WHITE); 177 | spr.drawString("Successful!", 115, 75 + 2 * FONT_ROW_HEIGHT, GFXFF); 178 | 179 | spr.setFreeFont(FSS12); 180 | spr.drawString("OK", 36 * PIXEL, 8.4 * FONT_ROW_HEIGHT, GFXFF); 181 | 182 | spr.setFreeFont(FSS9); 183 | spr.drawString("Network :", 5, 218 , GFXFF); 184 | 185 | 186 | // spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 187 | // spr.drawString("OFF", 82, 218 , GFXFF); 188 | 189 | spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 190 | spr.drawString(" WiFi ", 82, 218 , GFXFF); //Show the network you are in 191 | 192 | spr.pushSprite(0, 0); 193 | spr.deleteSprite(); 194 | } 195 | 196 | void setup() 197 | { 198 | DISPLAY_INIT(); 199 | pinMode(WIO_KEY_C, INPUT_PULLUP); 200 | pinMode(WIO_KEY_B, INPUT_PULLUP); 201 | pinMode(WIO_KEY_A, INPUT_PULLUP); 202 | } 203 | 204 | void loop() 205 | { 206 | WifiSelection(); 207 | delay(2000); 208 | WifiWait_Display(); 209 | delay(2000); 210 | Wificonnect_Display(); 211 | delay(2000); 212 | } 213 | -------------------------------------------------------------------------------- /examples/PAGE_TEMPLE/PAGE_TEMPLE.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | void DISPLAY_INIT() // Display initialization, black background rotation 13 | { 14 | tft.begin(); 15 | tft.setRotation(3); 16 | tft.fillScreen(TFT_BLACK); 17 | } 18 | 19 | void Network_state(int s_key) 20 | { 21 | switch (s_key) 22 | { 23 | case 0: 24 | spr.setTextColor(TFT_RED); 25 | spr.drawString("OFF", 82, 218 , GFXFF); 26 | break; 27 | case 1: 28 | spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 29 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //Show the network you are in 30 | break; 31 | default:; 32 | } 33 | spr.setTextColor(TFT_WHITE); 34 | spr.drawString("Network :", 5, 218, GFXFF); 35 | } 36 | 37 | void Sense_Display() // Sense interface display 38 | { 39 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 40 | 41 | // put your main code here 42 | spr.setFreeFont(FSSB9); 43 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 44 | 45 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 46 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 47 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 48 | 49 | spr.drawString("Process", 127, 11, GFXFF); 50 | spr.drawString("Network", 231, 11, GFXFF); 51 | 52 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 53 | spr.drawString("Sense", 32, 11, GFXFF); 54 | 55 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 56 | 57 | spr.setFreeFont(FSS9); 58 | spr.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 59 | spr.fillRect(128, 50, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 60 | spr.drawString("Sensor", 132, 54, GFXFF); 61 | 62 | Network_state(1); 63 | 64 | spr.pushSprite(0, 0); 65 | spr.deleteSprite(); 66 | } 67 | 68 | void setup() 69 | { 70 | DISPLAY_INIT(); 71 | } 72 | 73 | void loop() 74 | { 75 | Sense_Display(); 76 | } 77 | -------------------------------------------------------------------------------- /examples/PAGE_WELCOME/PAGE_WELCOME.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "disk91_LoRaE5.h" 5 | #include "LIS3DHTR.h" 6 | #include "Seeed_Arduino_GroveAI.h" 7 | #include "seeed_line_chart.h" 8 | #include 9 | 10 | TFT_eSPI tft = TFT_eSPI(); 11 | #define DATA_MAX_SIZE 30 // maximum size of data 12 | #define MAX_SIZE 30 // maximum size of data 13 | doubles data; // Initilising a doubles type to store data 14 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 15 | LIS3DHTR lis; 16 | 17 | 18 | // Display size settings 19 | #define SCREEN_WIDTH 320 20 | #define SCREEN_HIGH 240 21 | #define SCREEN_PADDING 10 22 | #define PIXEL 4 23 | const static unsigned int FONT_SIZE = 2; // rate 24 | const static unsigned int FONT_ROW_HEIGHT = 22; // px 25 | const static unsigned int FONT_LEFT_START = 0; // px 26 | const static unsigned int FONT_COLOR = TFT_WHITE; 27 | const static unsigned int FONT_BG_COLOR = TFT_RED; 28 | const static unsigned int BACKGROUD = TFT_BLACK; 29 | 30 | 31 | void setup() 32 | { 33 | pinMode(A0, INPUT); 34 | tft.begin(); 35 | tft.setRotation(3); 36 | tft.fillScreen(TFT_WHITE); 37 | } 38 | 39 | void PAGE() //Set Band Page 40 | { 41 | tft.fillScreen(TFT_BLACK); 42 | tft.fillRect(0, 140, 320, 100, TFT_WHITE); 43 | tft.setTextSize(1); 44 | tft.setTextColor(TFT_BLACK); 45 | tft.setTextDatum(MC_DATUM); 46 | tft.fillRect(0, 0, 30, 10, TFT_CYAN); 47 | tft.fillRect(73, 0, 40, 10, TFT_GREEN); 48 | tft.fillRect(154, 0, 40, 10, TFT_YELLOW); 49 | tft.drawString("Please select LoRaWAN", 160, 160, 4); 50 | tft.drawString("frequency bands for your", 160, 190, 4); 51 | tft.drawString("device connection.", 160, 220, 4); 52 | 53 | tft.drawLine(12, 30, 12, 125, TFT_CYAN); 54 | tft.drawLine(12, 125, 245, 125, TFT_CYAN); 55 | 56 | tft.drawLine(90, 30, 90, 105, TFT_GREEN); 57 | tft.drawLine(90, 105, 245, 105, TFT_GREEN); 58 | 59 | tft.drawLine(168, 30, 168, 85, TFT_YELLOW); 60 | tft.drawLine(168, 85, 245, 85, TFT_YELLOW); 61 | 62 | tft.setTextColor(TFT_CYAN, TFT_BLACK); 63 | tft.drawString("Button A", 0, 23, 2); 64 | tft.drawString("EU868", 280, 125, 2); 65 | 66 | tft.setTextColor(TFT_GREEN, TFT_BLACK); 67 | tft.drawString("Button B", 95, 23, 2); 68 | tft.drawString("US915", 280, 105, 2); 69 | 70 | tft.setTextColor(TFT_YELLOW, TFT_BLACK); 71 | tft.drawString("Button C", 174, 23, 2); 72 | tft.drawString("AU915", 280, 85, 2); 73 | 74 | tft.setTextDatum(0); 75 | } 76 | 77 | void loop() 78 | { 79 | PAGE(); 80 | } 81 | -------------------------------------------------------------------------------- /examples/PAGE_process_tinyml/PAGE_process_tinyml.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 11 | 12 | void DISPLAY_INIT() // Display initialization, black background rotation 13 | { 14 | tft.begin(); 15 | tft.setRotation(3); 16 | tft.fillScreen(TFT_BLACK); 17 | } 18 | 19 | void Process_main(){ 20 | spr.drawString("Vision AI real-time analysis", 24, 71, GFXFF); 21 | 22 | spr.drawString("TinyML Example", 24, 71, GFXFF); 23 | 24 | spr.drawString("Vision AI real-time analysis", 24, 71, GFXFF); 25 | } 26 | void Sense_Display() // Sense interface display 27 | { 28 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 29 | 30 | // put your main code here 31 | 32 | Process_main(); 33 | 34 | spr.setFreeFont(FSSB9); 35 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 36 | 37 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 38 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 39 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 40 | 41 | spr.drawString("Sense", 32, 11, GFXFF); 42 | spr.drawString("Process", 127, 11, GFXFF); 43 | spr.drawString("Network", 231, 11, GFXFF); 44 | 45 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 46 | 47 | spr.setFreeFont(FSS9); 48 | spr.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 49 | spr.fillRect(127, 53.5, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 50 | spr.drawString("Sensor", 130, 56, GFXFF); 51 | 52 | spr.pushSprite(0, 0); 53 | spr.deleteSprite(); 54 | } 55 | 56 | 57 | 58 | void setup() 59 | { 60 | DISPLAY_INIT(); 61 | } 62 | 63 | void loop() 64 | { 65 | Sense_Display(); 66 | } 67 | -------------------------------------------------------------------------------- /examples/Process/PAGE_tf/PAGE_tf.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "disk91_LoRaE5.h" 5 | #include "LIS3DHTR.h" 6 | #include "Seeed_Arduino_GroveAI.h" 7 | #include "seeed_line_chart.h" 8 | #include 9 | #include "Free_Fonts.h" 10 | TFT_eSPI tft = TFT_eSPI(); 11 | #define DATA_MAX_SIZE 30 // maximum size of data 12 | #define MAX_SIZE 30 // maximum size of data 13 | doubles data; // Initilising a doubles type to store data 14 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 15 | LIS3DHTR lis; 16 | 17 | // Display size settings 18 | #define SCREEN_WIDTH 320 19 | #define SCREEN_HIGH 240 20 | #define SCREEN_PADDING 0 21 | #define PIXEL 4 22 | const static unsigned int FONT_SIZE = 2; // rate 23 | const static unsigned int FONT_ROW_HEIGHT = 22; // px 24 | const static unsigned int FONT_LEFT_START = 0; // px 25 | const static unsigned int FONT_COLOR = TFT_WHITE; 26 | const static unsigned int FONT_BG_COLOR = TFT_RED; 27 | const static unsigned int BACKGROUD = TFT_BLACK; 28 | int conf = 0; //Confidence 29 | int num = 0; //number of people 30 | int light = 0, mic_val = 0; //Light value, microphone loudness 31 | bool col = false; //control lora wan light color 32 | float x_values = 0.0, y_value = 0.0, z_val = 0.0; // Imu value 33 | int conf_avg = 0; 34 | 35 | int gg_switch = 0; 36 | int gg_switch_k = 1; 37 | int gg_switch_circle = 10; // r outer great circle radius 38 | int gg_switch_rect_width = 20; // width x++ rectangle width 39 | int gg_switch_rect_high = 1; // high y++ 40 | int gg_switch_location_x = FONT_LEFT_START + 260; // location left center 41 | int gg_switch_location_y = 115; 42 | int gg_switch_state = 0; // 0 off 1 on 43 | unsigned int gg_switch_state_color[4] = {tft.color565(211, 211, 211), TFT_BLUE, tft.color565(201, 201, 201), tft.color565(65, 105, 235)}; 44 | 45 | void switch_button_gui(int gg_switch_location_x, int gg_switch_location_y, int gg_switch_circle, int gg_switch_rect_width, int gg_switch) 46 | { 47 | if (gg_switch == 1) 48 | { 49 | spr.fillCircle(gg_switch_location_x + gg_switch_rect_width, gg_switch_location_y, gg_switch_circle, gg_switch_state_color[gg_switch]); 50 | spr.fillCircle(gg_switch_location_x, gg_switch_location_y, gg_switch_circle / 2, gg_switch_state_color[gg_switch + 2]); 51 | spr.fillRect(gg_switch_location_x, gg_switch_location_y - gg_switch_circle / 2, gg_switch_rect_width, gg_switch_circle + 1, gg_switch_state_color[gg_switch + 2]); 52 | } 53 | else 54 | { 55 | spr.fillCircle(gg_switch_location_x, gg_switch_location_y, gg_switch_circle, gg_switch_state_color[gg_switch]); 56 | spr.fillCircle(gg_switch_location_x + gg_switch_rect_width, gg_switch_location_y, gg_switch_circle / 2, gg_switch_state_color[gg_switch + 2]); 57 | spr.fillRect(gg_switch_location_x, gg_switch_location_y - gg_switch_circle / 2, gg_switch_rect_width, gg_switch_circle + 1, gg_switch_state_color[gg_switch + 2]); 58 | } 59 | } 60 | 61 | void DISPLAY_INIT() // Display initialization, black background rotation 62 | { 63 | tft.begin(); 64 | tft.setRotation(3); 65 | tft.fillScreen(TFT_BLACK); 66 | } 67 | 68 | void Sense_Display() // Sense interface display 69 | { 70 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 71 | spr.setFreeFont(FSSB9); 72 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 73 | 74 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 75 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 76 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 77 | 78 | spr.drawString("Sense", 32, 11, GFXFF); 79 | spr.drawString("Process", 127, 11, GFXFF); 80 | spr.drawString("Network", 231, 11, GFXFF); 81 | 82 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 83 | 84 | spr.setFreeFont(FSS9); 85 | spr.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 86 | spr.fillRect(127, 53.5, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 87 | spr.drawString("Sensor", 130, 56, GFXFF); 88 | } 89 | 90 | void setup() 91 | { 92 | pinMode(A0, INPUT); 93 | DISPLAY_INIT(); 94 | pinMode(WIO_KEY_A, INPUT_PULLUP); 95 | pinMode(WIO_KEY_B, INPUT_PULLUP); 96 | pinMode(WIO_KEY_C, INPUT_PULLUP); 97 | } 98 | int gg_storage_is_full = 0; 99 | void Page_tf() 100 | { 101 | 102 | char str_num[1], str_conf[1], str_light[1], str_mic_val[1], str_x_values[8], str_y_value[8], str_z_val[8]; 103 | sprintf(str_num, "%d", num); 104 | sprintf(str_conf, "%d", conf_avg); 105 | sprintf(str_light, "%d", light); 106 | sprintf(str_mic_val, "%d", mic_val); 107 | snprintf((char *)str_x_values, 8, "%.2f", x_values); 108 | snprintf((char *)str_y_value, 8, "%.2f", y_value); 109 | snprintf((char *)str_z_val, 8, "%.2f", z_val); 110 | 111 | conf_avg = 0; 112 | 113 | Sense_Display(); 114 | spr.setTextColor(TFT_WHITE); 115 | spr.drawString("Save to TF card ", 40, gg_switch_location_y - gg_switch_circle, FONT4); 116 | 117 | if (digitalRead(WIO_KEY_A) == LOW) 118 | { 119 | Serial.println("A Key pressed"); 120 | gg_switch_k *= -1; 121 | delay(200); 122 | } 123 | if (digitalRead(WIO_KEY_B) == LOW) 124 | { 125 | Serial.println("B Key pressed"); 126 | gg_storage_is_full++; 127 | delay(200); 128 | } 129 | 130 | if (gg_switch_k > 0) 131 | { 132 | gg_switch = 1; 133 | } 134 | else 135 | { 136 | gg_switch = 0; 137 | } 138 | 139 | switch_button_gui(gg_switch_location_x, gg_switch_location_y, gg_switch_circle, gg_switch_rect_width, gg_switch); 140 | // int gg_storage_is_full = 1 ; 141 | 142 | if (gg_storage_is_full % 2) 143 | { 144 | spr.setTextColor(TFT_YELLOW); 145 | spr.setFreeFont(FSSB9); 146 | spr.drawTriangle(148, 155, 159, 132, 170, 155, TFT_YELLOW); 147 | spr.drawString("! ", 158, 140, 2); 148 | spr.drawString("TF card storage space is fully occupied ", 30, 160, 2); 149 | } 150 | 151 | else 152 | { 153 | if (gg_switch == 0) 154 | { 155 | spr.setTextColor(TFT_YELLOW); 156 | spr.setFreeFont(FSSB9); 157 | spr.drawString("Please insert TF card to activate this function ", 10, 140, 2); 158 | } 159 | else 160 | { 161 | spr.fillRect(40, 130, 250, 50, TFT_WHITE); 162 | spr.setTextColor(TFT_BLACK); 163 | spr.setFreeFont(FSSB9); 164 | spr.drawString("Saving has been started", 60, 140, GFXFF); 165 | } 166 | } 167 | 168 | spr.setTextColor(TFT_YELLOW); 169 | spr.drawString("Network:", 10, 220, GFXFF); 170 | spr.setTextColor(tft.color565(254, 0, 0)); 171 | spr.drawString("OFF", 100, 220, GFXFF); 172 | 173 | spr.pushSprite(0 + SCREEN_PADDING, 0 + SCREEN_PADDING); 174 | spr.deleteSprite(); 175 | } 176 | void loop() 177 | { 178 | Page_tf(); 179 | delay(200); 180 | } 181 | -------------------------------------------------------------------------------- /examples/Process/PAGE_tf/switch.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/SenseCraft-Wio/b4f4a40438d0e877676e3b84ae07432ffea0d5cc/examples/Process/PAGE_tf/switch.cpp -------------------------------------------------------------------------------- /examples/Process/PAGE_tf/switch_ui.h: -------------------------------------------------------------------------------- 1 | #ifndef Morse_h 2 | #define Morse_h 3 | 4 | class Switch_UI 5 | { 6 | public: 7 | Morse(int pin); 8 | void dot(); 9 | void dash(); 10 | private: 11 | int _pin; 12 | }; 13 | 14 | #endif -------------------------------------------------------------------------------- /examples/Process/Process_main/Process_main.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | #define MOVE_PIXEL_y 20 // Virtual to Reality Moving Distance 11 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 12 | #include "RTC_SAMD51.h" 13 | #include "DateTime.h" 14 | #include 15 | 16 | RTC_SAMD51 rtc; 17 | 18 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 19 | 20 | void DISPLAY_INIT() // Display initialization, black background rotation 21 | { 22 | tft.begin(); 23 | tft.setRotation(3); 24 | tft.fillScreen(TFT_BLACK); 25 | } 26 | 27 | void Process_main(int page) 28 | { 29 | //Add page 0 here; page3 For the convenience of testing, this function can be called, or it can be called independently 30 | //case 0 Vision AI log 31 | //case 1 Proccsee Home 32 | //case 2 TinyML example 33 | //case 3 TinyML has entered 34 | switch (page) 35 | { 36 | case 0: 37 | Vision_AI_real_time_analysis(); 38 | return; 39 | case 1: 40 | spr.setTextColor(TFT_WHITE); 41 | spr.drawString("Vision AI real-time analysis", 63, 33 + MOVE_PIXEL_y, GFXFF); 42 | spr.fillRect(24, 71 + MOVE_PIXEL_y - 3, 221, FONT_ROW_HEIGHT, tft.color565(0, 204, 2)); 43 | break; 44 | case 2: 45 | spr.setTextColor(TFT_WHITE); 46 | spr.drawString("TinyML Example", 107, 32 + MOVE_PIXEL_y, GFXFF); 47 | spr.fillRect(24, 100 + MOVE_PIXEL_y - 3, 135, FONT_ROW_HEIGHT, tft.color565(0, 204, 2)); 48 | break; 49 | case 3: 50 | Process_TinyML_ENTER(); 51 | return; 52 | default:; 53 | } 54 | spr.setFreeFont(FSS9); 55 | spr.setTextColor(TFT_WHITE); 56 | spr.drawString("Vision AI real-time analysis", 24, 71 + MOVE_PIXEL_y, GFXFF); 57 | spr.drawString("TinyML Example", 24, 100 + MOVE_PIXEL_y, GFXFF); 58 | 59 | spr.setTextColor(tft.color565(169, 169, 169)); 60 | spr.drawString("Data Filter(In Development)", 24, 129 + MOVE_PIXEL_y, GFXFF); 61 | } 62 | 63 | void Network_state(int s_key) 64 | { 65 | switch (s_key) 66 | { 67 | case 0: 68 | spr.setTextColor(TFT_RED); 69 | spr.drawString("OFF", 80, 215, GFXFF); 70 | break; 71 | case 1: 72 | spr.setTextColor(TFT_GREEN); 73 | spr.drawString("ON", 80, 215, GFXFF); 74 | break; 75 | default:; 76 | } 77 | spr.setTextColor(TFT_WHITE); 78 | spr.drawString("Network:", 7, 215, GFXFF); 79 | } 80 | 81 | void Process_TinyML_ENTER(void) 82 | { 83 | spr.setTextColor(TFT_WHITE); 84 | spr.drawString("Please scan the QR ", 135, 86, GFXFF); 85 | spr.drawString("code on the screen ", 135, 106, GFXFF); 86 | spr.drawString("to view the Github", 135, 126, GFXFF); 87 | spr.drawString("sample tutorial ", 135, 146, GFXFF); 88 | double PIXELL = 3; 89 | 90 | spr.fillRect(13, 70, 115, 115, TFT_WHITE); 91 | QRCode qrcode; 92 | uint8_t *qrcodeData = (uint8_t *)malloc(qrcode_getBufferSize(5)); 93 | qrcode_initText(&qrcode, qrcodeData, 5, 0, "https://wiki.seeedstudio.com/K1100-Getting-Started/#tinyml-section"); 94 | for (uint8_t y = 0; y < qrcode.size; y++) 95 | { 96 | // Each horizontal module 97 | for (uint8_t x = 0; x < qrcode.size; x++) 98 | { 99 | if (qrcode_getModule(&qrcode, x, y)) 100 | spr.fillRect(x * PIXELL + 15, y * PIXELL + 70 + 2, PIXELL, PIXELL, TFT_BLACK); 101 | } 102 | } 103 | 104 | free(qrcodeData); 105 | } 106 | 107 | int i = 0; 108 | void Vision_AI_real_time_analysis(void) // todo 109 | { 110 | spr.setTextColor(TFT_WHITE); 111 | spr.drawString("Vision AI real-time analysis", 64, 52, GFXFF); 112 | spr.fillRect(40, 73, 216 + 20, 117 + 15, tft.color565(128, 128, 128)); 113 | DateTime now = rtc.now(); 114 | // Serial.print(now.second(), DEC); 115 | spr.drawString("Time", 52, 80, GFXFF); 116 | spr.drawString("Data", 140, 80, GFXFF); 117 | 118 | char buf_T[4][20]; 119 | 120 | uint8_t HH = now.hour(); 121 | uint8_t MM = now.minute(); 122 | uint8_t SS = now.second(); 123 | 124 | int kk = i % 4; 125 | sprintf(buf_T[i % 4], "%02d:%02d:%02d ", HH, MM, SS); 126 | i++; 127 | if (i == 4) 128 | { 129 | i = 0; 130 | } 131 | 132 | for (int i = 0; i < 4; i++) 133 | { 134 | int MM_add = 0; 135 | if (SS + i > 59) 136 | { 137 | MM += 1; 138 | SS -= 60; 139 | } 140 | if (MM > 59) 141 | { 142 | HH += 1; 143 | MM -= 60; 144 | } 145 | sprintf(buf_T[i], " %02d:%02d:%02d ", HH, MM, SS + i); 146 | } 147 | for (int gg = 0; gg < 4; gg++) 148 | { 149 | spr.drawString(buf_T[gg], 45, 103 + gg * 26, GFXFF); 150 | } 151 | } 152 | 153 | void Process_Display(int G, int G_network) // Sense interface display 154 | { 155 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 156 | 157 | // choose func here 158 | Process_main(G); 159 | // Process_TinyML_ENTER(); 160 | // Vision_AI_real_time_analysis(); 161 | spr.setFreeFont(FSSB9); 162 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 163 | 164 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 165 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 166 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 167 | 168 | spr.setFreeFont(FSS9); 169 | spr.setTextColor(TFT_BLACK); 170 | spr.drawString("Sense", 32, 11, GFXFF); 171 | spr.drawString("Process", 127, 11, GFXFF); 172 | spr.drawString("Network", 231, 11, GFXFF); 173 | 174 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 175 | 176 | Network_state(G_network); 177 | 178 | spr.pushSprite(0, 0); 179 | spr.deleteSprite(); 180 | } 181 | 182 | void setup() 183 | { 184 | DISPLAY_INIT(); 185 | rtc.begin(); 186 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 187 | Serial.println("adjust time!"); 188 | rtc.adjust(now); 189 | 190 | pinMode(WIO_KEY_A, INPUT_PULLUP); 191 | pinMode(WIO_KEY_B, INPUT_PULLUP); 192 | pinMode(WIO_KEY_C, INPUT_PULLUP); 193 | } 194 | 195 | int gg_switch = 0; 196 | int gg_switch_flag = 0; 197 | int gg_network_flag = 0; 198 | void loop() 199 | { 200 | // test block begin 201 | if (digitalRead(WIO_KEY_B) == LOW) 202 | { 203 | Serial.println("B Key pressed"); 204 | gg_switch++; 205 | delay(200); 206 | } 207 | if (digitalRead(WIO_KEY_C) == LOW) 208 | { 209 | Serial.println("C Key pressed"); 210 | gg_network_flag++; 211 | delay(200); 212 | } 213 | 214 | Process_Display(gg_switch % 4, gg_network_flag % 2); 215 | } 216 | -------------------------------------------------------------------------------- /examples/Process/Process_main/README.md: -------------------------------------------------------------------------------- 1 | # Process part 2 | 3 | The page is implemented as follows according to the modao documentation requirements. Functions are decoupled and can be called independently of each other. As a test ino, burn under example/Process_main and click A to check the network status display in the lower left corner. Click B to view the interfaces in Process. In the Ai vision Log part, due to the limited ability of unfamiliar with ardiuno, the queue of uint8_t and int did not construct the time data currently displayed. 4 | 5 | Process_Display(); // 6 | Process_TinyML_ENTER(); // 7 | Vision_AI_real_time_analysis(); // 8 | Network_state(int s_key); // Change network status 1 display ON 0 display OFF can be imported into Process_Display or anywhere 9 | 10 | | Code | Content | Status| 11 | | :------------ |:---------------:| -----:| 12 | |Vision AI log| Vision_AI_real_time_analysis() |✅ | 13 | |Tiny ml has entered| Process_TinyML_ENTER() |✅✅ | 14 | |Network| Network_state(int s_key)|✅✅| 15 | |Proccsee Home| Network_state(int s_key)|✅✅| 16 | 17 | ## Process_Display() 18 | 19 | draw top three buttons background color default bottom layer 20 | 21 | ## Process_main(int page) 22 | 23 | !!!Note 24 | Add page 0 here; page 3 For the convenience of testing, this function can be called, or it can be called independently 25 | 26 | - case 0 Vision AI log 27 | - case 1 Proccsee Home 28 | - case 2 Tiny ml example 29 | - case 3 Tiny ml has entered 30 | 31 | ## Network_state(int s_key) 32 | 33 | The network status display function Network in the lower left corner. 1 ON 0 OFF 34 | 35 | ## Vision_AI_real_time_analysis(void) 36 | 37 | Vision AI log 38 | 39 | ## Process_TinyML_ENTER() 40 | 41 | This is the interface that TinyML has entered in order to present the QR code. 42 | https://www.arduino.cc/reference/en/libraries/qrcode/ this [library](https://www.arduino.cc/reference/en/libraries/qrcode/) 43 | 44 | -------------------------------------------------------------------------------- /examples/Sense/Auto-detect/Auto-detect.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 8 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 9 | #define PIXEL 4 // Width of one letter 10 | #define LEFT_SIDE 70 11 | #define HIGHT_SIDE 47 12 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 13 | 14 | 15 | void DISPLAY_INIT() // Display initialization, black background rotation 16 | { 17 | tft.begin(); 18 | tft.setRotation(3); 19 | tft.fillScreen(TFT_BLACK); 20 | } 21 | 22 | void Sense_AutoDetecte_Display() //Display screen for accessing sensors 23 | { 24 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 25 | 26 | // put your main code here 27 | spr.setFreeFont(FSSB9); 28 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 29 | 30 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 31 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 32 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 33 | 34 | spr.drawString("Process", 127, 11, GFXFF); 35 | spr.drawString("Network", 231, 11, GFXFF); 36 | 37 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 38 | spr.drawString("Sense", 32, 11, GFXFF); 39 | 40 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 41 | 42 | spr.setFreeFont(FSS9); 43 | spr.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 44 | spr.fillRect(128, 50, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 45 | spr.drawString("Sensor", 132, 54, GFXFF); 46 | 47 | spr.setTextColor(TFT_WHITE, TFT_BLACK); 48 | spr.drawString("Sound", 100 - LEFT_SIDE, 80, GFXFF); 49 | spr.drawString("IMU", 209 - LEFT_SIDE, 80, GFXFF); 50 | spr.drawString("ADD", 316 - LEFT_SIDE, 80, GFXFF); 51 | 52 | spr.setFreeFont(FSS24); 53 | spr.drawString("356", 20, 115 , GFXFF); // Display the value of loudness 54 | spr.setFreeFont(FSS12); 55 | spr.drawString("0.10", 205 - LEFT_SIDE, 102 , GFXFF); //Display the value of IMU X-axis 56 | spr.drawString("-0.23", 205 - LEFT_SIDE, 126 , GFXFF); //Display the value of IMU Y-axis 57 | spr.drawString("-2.33", 205 - LEFT_SIDE, 150 , GFXFF); //Display the value of IMU Z-axis 58 | spr.setFreeFont(FSS9); 59 | spr.drawString("X,Y,Z", 205 - LEFT_SIDE, 174 , GFXFF); 60 | 61 | spr.fillCircle(163, 200, 3, tft.color565(0, 193, 255)); 62 | spr.fillCircle(146, 200, 3, tft.color565(220, 220, 220)); 63 | 64 | spr.fillRect(244, 117, 40, 40, TFT_WHITE); 65 | spr.fillRect(263, 123, 3, 26, TFT_BLACK); 66 | spr.fillRect(251, 135, 26, 3, TFT_BLACK); 67 | 68 | spr.drawString("Network :", 5, 218 , GFXFF); 69 | 70 | // spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 71 | // spr.drawString("OFF", 82, 218 , GFXFF); 72 | 73 | spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 74 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //Show the network you are in 75 | 76 | spr.pushSprite(0, 0); 77 | spr.deleteSprite(); 78 | } 79 | 80 | void Insert_Tip() // Pop-up prompt for sensor insertion 81 | { 82 | spr.createSprite(240, 116); 83 | spr.fillScreen(tft.color565(211, 211, 211)); 84 | 85 | spr.setFreeFont(FSS9); 86 | spr.setTextColor(TFT_BLACK, tft.color565(211, 211, 211)); 87 | spr.drawString("Please plug in 1 sensor first", 10, 30, GFXFF); 88 | 89 | spr.fillCircle(108, 90, 3, tft.color565(190, 190, 190)); 90 | spr.fillCircle(118, 90, 3, tft.color565(140, 140, 140)); 91 | spr.fillCircle(128, 90, 3, tft.color565(105, 105, 105)); 92 | 93 | spr.pushSprite(40, 64); 94 | spr.deleteSprite(); 95 | } 96 | 97 | void Connect_Success_Display() //Connect sensor success alert pop-up. 98 | { 99 | spr.createSprite(240, 116); 100 | spr.fillScreen(tft.color565(211, 211, 211)); 101 | 102 | spr.setFreeFont(FSS9); 103 | spr.setTextColor(TFT_BLACK, tft.color565(211, 211, 211)); 104 | spr.drawString("Vision AI Sensor connected", 10, 30, GFXFF); 105 | 106 | spr.fillCircle(118, 85, 20, tft.color565(0, 139, 0)); 107 | spr.fillCircle(118, 85, 17, tft.color565(211, 211, 211)); 108 | 109 | //spr.drawLine(117, 86, 118, 89, tft.color565(0, 255, 0)); 110 | spr.fillTriangle(107, 84, 128, 75, 118, 95, tft.color565(0, 139, 0)); 111 | spr.fillTriangle(107, 80, 128, 71, 118, 91, tft.color565(211, 211, 211)); 112 | 113 | spr.pushSprite(40, 64); 114 | spr.deleteSprite(); 115 | } 116 | 117 | void setup() { 118 | DISPLAY_INIT(); 119 | } 120 | 121 | void loop() { 122 | Sense_AutoDetecte_Display(); 123 | delay(2000); 124 | Insert_Tip(); 125 | delay(2000); 126 | Connect_Success_Display(); 127 | delay(2000); 128 | } 129 | -------------------------------------------------------------------------------- /examples/Sense/Built-in/Built-in.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Free_Fonts.h" 3 | 4 | TFT_eSPI tft; 5 | TFT_eSprite spr = TFT_eSprite(&tft); 6 | 7 | 8 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 9 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 10 | #define PIXEL 4 // Width of one letter 11 | #define LEFT_SIDE 70 12 | #define HIGHT_SIDE 47 13 | const static unsigned int FONT_ROW_HEIGHT = 22; // The height of a letter 14 | 15 | 16 | void DISPLAY_INIT() // Display initialization, black background rotation 17 | { 18 | tft.begin(); 19 | tft.setRotation(3); 20 | tft.fillScreen(TFT_BLACK); 21 | } 22 | 23 | void Sense_BuiltIn_Display() // Wio terminal built-in sensor interface, the main boot screen. 24 | { 25 | spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 26 | 27 | // put your main code here 28 | spr.setFreeFont(FSSB9); 29 | spr.setTextColor(TFT_BLACK, TFT_WHITE); 30 | 31 | spr.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 32 | spr.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 33 | spr.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 34 | 35 | spr.drawString("Process", 127, 11, GFXFF); 36 | spr.drawString("Network", 231, 11, GFXFF); 37 | 38 | spr.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 39 | spr.drawString("Sense", 32, 11, GFXFF); 40 | 41 | 42 | spr.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 43 | 44 | spr.setFreeFont(FSS9); 45 | spr.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 46 | spr.fillRect(128, 50, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 47 | spr.drawString("Sensor", 132, 54, GFXFF); 48 | 49 | spr.setTextColor(TFT_WHITE, TFT_BLACK); 50 | spr.drawString("Light", 100 - LEFT_SIDE, 80, GFXFF); 51 | spr.drawString("Sound", 209 - LEFT_SIDE, 80, GFXFF); 52 | spr.drawString("IMU", 316 - LEFT_SIDE, 80, GFXFF); 53 | 54 | spr.setFreeFont(FSS24); 55 | spr.drawString("77", 20, 115 , GFXFF); // Display the value of the light sensor 56 | spr.drawString("356", 125, 115 , GFXFF); // Display the value of loudness 57 | spr.setFreeFont(FSS12); 58 | spr.drawString("0.10", 241, 102 , GFXFF); //Display the value of IMU X-axis 59 | spr.drawString("-0.23", 241, 126 , GFXFF); //Display the value of IMU Y-axis 60 | spr.drawString("-2.33", 241, 150 , GFXFF); //Display the value of IMU Z-axis 61 | spr.setFreeFont(FSS9); 62 | spr.drawString("X,Y,Z", 316 - LEFT_SIDE, 174 , GFXFF); 63 | 64 | spr.fillCircle(146, 200, 3, tft.color565(0, 193, 255)); 65 | spr.fillCircle(163, 200, 3, tft.color565(220, 220, 220)); 66 | 67 | spr.drawString("Network :", 5, 218 , GFXFF); 68 | 69 | // spr.setTextColor(TFT_RED, TFT_BLACK); //Networking status indication:OFF 70 | // spr.drawString("OFF", 82, 218 , GFXFF); 71 | 72 | spr.setTextColor(TFT_GREEN, TFT_BLACK); //Networking status indication:ON 73 | spr.drawString(" LoRa ", 82, 218 , GFXFF); //Show the network you are in 74 | 75 | spr.pushSprite(0, 0); 76 | spr.deleteSprite(); 77 | } 78 | 79 | void setup() { 80 | DISPLAY_INIT(); 81 | } 82 | 83 | void loop() { 84 | Sense_BuiltIn_Display(); 85 | } 86 | -------------------------------------------------------------------------------- /examples/Sense/Line-chart/Line-chart.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "disk91_LoRaE5.h" 5 | #include "LIS3DHTR.h" 6 | #include "Seeed_Arduino_GroveAI.h" 7 | #include "seeed_line_chart.h" 8 | #include 9 | #include "Free_Fonts.h" 10 | 11 | TFT_eSPI tft = TFT_eSPI(); 12 | #define DATA_MAX_SIZE 30 // maximum size of data 13 | #define MAX_SIZE 30 // maximum size of data 14 | doubles data; // Initilising a doubles type to store data 15 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 16 | LIS3DHTR lis; 17 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 18 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 19 | #define PIXEL 4 // Width of one letter 20 | 21 | // Display size settings 22 | #define SCREEN_WIDTH 320 23 | #define SCREEN_HIGH 240 24 | #define SCREEN_PADDING 0 25 | #define PIXEL 4 26 | const static unsigned int FONT_SIZE = 2; // rate 27 | const static unsigned int FONT_ROW_HEIGHT = 22; // px 28 | const static unsigned int FONT_LEFT_START = 0; // px 29 | const static unsigned int FONT_COLOR = TFT_WHITE; 30 | const static unsigned int FONT_BG_COLOR = TFT_RED; 31 | const static unsigned int BACKGROUD = TFT_BLACK; 32 | 33 | void DISPLAY_INIT() // Display initialization, black background rotation 34 | { 35 | tft.begin(); 36 | tft.setRotation(3); 37 | tft.fillScreen(TFT_BLACK); 38 | } 39 | 40 | void Sense_Display() // Sense interface display 41 | { 42 | 43 | // spr.createSprite(SCREEN_WIDTH, SCREEN_HIGH); 44 | 45 | tft.setFreeFont(FSSB9); 46 | tft.setTextColor(TFT_BLACK, TFT_WHITE); 47 | 48 | tft.fillRect(4 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 49 | tft.drawString("Sense", 32, 11, GFXFF); 50 | 51 | tft.fillRect(30 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, tft.color565(135, 206, 235)); 52 | tft.setTextColor(TFT_BLACK, tft.color565(135, 206, 235)); 53 | tft.drawString("Process", 127, 11, GFXFF); 54 | 55 | tft.setTextColor(TFT_BLACK, TFT_WHITE); 56 | tft.fillRect(56 * PIXEL, 0, 21 * PIXEL, FONT_ROW_HEIGHT + 15, TFT_WHITE); 57 | tft.drawString("Network", 231, 11, GFXFF); 58 | 59 | tft.drawLine(0, 2 * FONT_ROW_HEIGHT, SCREEN_WIDTH, 2 * FONT_ROW_HEIGHT, TFT_WHITE); 60 | 61 | tft.setFreeFont(FSS9); 62 | tft.setTextColor(TFT_BLACK, tft.color565(220, 220, 220)); 63 | tft.fillRect(127, 53.5, 16 * PIXEL, FONT_ROW_HEIGHT, tft.color565(220, 220, 220)); 64 | tft.drawString("Sensor", 130, 56, GFXFF); 65 | } 66 | 67 | void setup() 68 | { 69 | pinMode(A0, INPUT); 70 | tft.begin(); 71 | tft.setRotation(3); 72 | tft.fillScreen(TFT_BLACK); 73 | // DISPLAY_INIT(); 74 | } 75 | 76 | int brightness; 77 | void loop() 78 | { 79 | // brightness = analogRead(A0); 80 | 81 | Sense_Display(); 82 | tft.fillRect(18, 78, 24, 110, TFT_WHITE); 83 | 84 | brightness = analogRead(WIO_MIC); 85 | 86 | if (data.size() > DATA_MAX_SIZE) // keep the old line chart front 87 | { 88 | data.pop(); // this is used to remove the first read variable 89 | } 90 | 91 | data.push(brightness); // read variables and store in data 92 | 93 | // Settings for the line graph 94 | auto content = line_chart(20, 80); //(x,y) where the line graph begins 95 | content 96 | // .height(tft.height() - header.height() * 1.5 - 50) // actual height of the line chart 97 | // .width(tft.width() - content.x() * 2) // actual width of the line chart 98 | .height(120) 99 | .width(260) 100 | .based_on(0.0) // Starting point of y-axis, must be a float 101 | .show_circle(false) // drawing a cirle at each point, default is on. 102 | .value(data) // passing through the data to line graph 103 | .max_size(MAX_SIZE) 104 | .color(TFT_GREEN) // Setting the color for the line 105 | // .backgroud(tft.color565(0,0,0)) // Setting the color for the backgroud 106 | .backgroud(tft.color565(0, 0, 0)) 107 | .draw(&tft); 108 | 109 | // spr.fillRect(0, 201, 320, 39, TFT_BLACK); 110 | tft.setFreeFont(FSSB9); 111 | tft.setTextColor(TFT_YELLOW); 112 | tft.drawString("Network:", 10, 220, GFXFF); 113 | tft.setTextColor(tft.color565(254, 0, 0)); 114 | tft.drawString("OFF", 100, 220, GFXFF); 115 | // tft.pushSprite(0, 0); 116 | // tft.deleteSprite(); 117 | delay(2); 118 | } 119 | -------------------------------------------------------------------------------- /include/AzureDpsClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class AzureDpsClient 8 | { 9 | public: 10 | AzureDpsClient(); 11 | AzureDpsClient(const AzureDpsClient&) = delete; 12 | AzureDpsClient& operator=(const AzureDpsClient&) = delete; 13 | 14 | std::string GetEndpoint() const { return Endpoint; } 15 | void SetEndpoint(const std::string& endpoint) { Endpoint = endpoint; } 16 | std::string GetIdScope() const { return IdScope; } 17 | void SetIdScope(const std::string& idScope) { IdScope = idScope; } 18 | std::string GetRegistrationId() const { return RegistrationId; } 19 | void SetRegistrationId(const std::string& registrationId) { RegistrationId = registrationId; } 20 | 21 | int Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId); 22 | 23 | std::vector GetSignature(const uint64_t& expirationEpochTime); 24 | 25 | std::string GetMqttClientId(); 26 | std::string GetMqttUsername(); 27 | std::string GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime); 28 | 29 | std::string GetRegisterPublishTopic(); 30 | std::string GetRegisterSubscribeTopic() const; 31 | int RegisterSubscribeWork(const std::string& topic, const std::vector& payload); 32 | bool IsRegisterOperationCompleted(); 33 | int GetWaitBeforeQueryStatusSeconds() const; 34 | std::string GetQueryStatusPublishTopic(); 35 | 36 | bool IsAssigned(); 37 | std::string GetHubHost(); 38 | std::string GetDeviceId(); 39 | 40 | private: 41 | std::string Endpoint; 42 | std::string IdScope; 43 | std::string RegistrationId; 44 | 45 | az_iot_provisioning_client ProvClient; 46 | 47 | bool ResponseValid; 48 | std::string ResponseTopic; 49 | std::vector ResponsePayload; 50 | az_iot_provisioning_client_register_response Response; 51 | 52 | private: 53 | static az_iot_provisioning_client_operation_status GetOperationStatus(az_iot_provisioning_client_register_response& response); 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /include/ButtonThread.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __BUTTON_H__ 3 | #define __BUTTON_H__ 4 | 5 | #include "Arduino.h" 6 | #include "Seeed_Arduino_ooFreeRTOS.h" 7 | #include "utils.h" 8 | 9 | // create a buttion class use ooFreeRTOS task 10 | 11 | using namespace cpp_freertos; 12 | 13 | class ButtonThread : public Thread 14 | { 15 | public: 16 | ButtonThread(Message &q); 17 | 18 | protected: 19 | virtual void Run(); 20 | 21 | private: 22 | uint8_t buttonState; // the current reading from the input pin 23 | uint8_t lastButtonState = LOW; // the previous reading from the input pin 24 | 25 | // the following variables are unsigned longs because the time, measured in 26 | // milliseconds, will quickly become a bigger number than can be stored in an int. 27 | unsigned long lastDebounceTime = 0; // the last time the output pin was toggled 28 | unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers 29 | 30 | Message &Mail; 31 | 32 | const uint8_t btn[8] = {WIO_KEY_A, WIO_KEY_B, WIO_KEY_C, WIO_5S_UP, WIO_5S_DOWN, WIO_5S_LEFT, WIO_5S_RIGHT, WIO_5S_PRESS}; 33 | }; 34 | 35 | #endif // __BUTTON_H__ -------------------------------------------------------------------------------- /include/LoRaThread.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __LORATHREAD_H__ 3 | #define __LORATHREAD_H__ 4 | 5 | #include "Arduino.h" 6 | #include "Seeed_Arduino_ooFreeRTOS.h" 7 | #include "SysConfig.h" 8 | #include "disk91_LoRaE5.h" 9 | #include "utils.h" 10 | #include 11 | 12 | // create a buttion class use ooFreeRTOS task 13 | 14 | using namespace cpp_freertos; 15 | 16 | class LoRaThread : public Thread { 17 | public: 18 | LoRaThread(SysConfig &config); 19 | void LoRaPushData(std::vector d); 20 | 21 | private: 22 | void Init(); 23 | void Join(); 24 | bool SendDeviceInfo(); 25 | bool SendVisionAIInfo(); 26 | bool SendBuildinSensorData(); 27 | bool SendGroveSensorData(); 28 | bool SendAiVisionData(); 29 | bool SendData(uint8_t *data, uint8_t len, uint8_t ver); 30 | 31 | protected: 32 | virtual void Run(); 33 | 34 | private: 35 | SysConfig &cfg; 36 | Disk91_LoRaE5 *lorae5; 37 | const uint8_t v1 = 2; 38 | const uint8_t v2 = 3; 39 | uint8_t downlink_rxBuff[16]; 40 | uint8_t downlink_rxSize = 16; 41 | uint8_t downlink_rxPort; 42 | uint8_t frequency; 43 | 44 | std::vector lora_data; 45 | bool lora_data_ready = true; 46 | }; 47 | 48 | #endif // __LORATHREAD_H__ -------------------------------------------------------------------------------- /include/SDThread.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDTHREAD_H__ 2 | #define __SDTHREAD_H__ 3 | #include "DateTime.h" 4 | #include "RTC_SAMD51.h" 5 | #include "SD/Seeed_SD.h" 6 | #include "SysConfig.h" 7 | #include "utils.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace cpp_freertos; 15 | 16 | class SDThread : public Thread { 17 | public: 18 | SDThread(SysConfig &config); 19 | void SDPushData(std::vector d); 20 | 21 | protected: 22 | virtual void Run(); 23 | uint8_t status(); 24 | void saveData(String sensorName, int32_t *sensorData, int len, uint8_t type); 25 | void Readdata(String sensorName); 26 | 27 | private: 28 | SysConfig &cfg; 29 | 30 | private: 31 | std::vector sd_data; 32 | bool sd_data_ready = true; 33 | RTC_SAMD51 rtc; 34 | File myFile; 35 | bool is_connected = false; 36 | SemaphoreHandle_t wait_sd_data = NULL; 37 | }; 38 | 39 | #endif // __SDTHREAD_H__ -------------------------------------------------------------------------------- /include/SamplerThread.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SAMPLER_H 3 | #define __SAMPLER_H 4 | #include "SysConfig.h" 5 | #include "WiFiThread.h" 6 | #include "LoRaThread.h" 7 | #include "SDThread.h" 8 | #include "ui.h" 9 | #include "sensor.h" 10 | #include "utils.h" 11 | #include 12 | #include 13 | 14 | using namespace cpp_freertos; 15 | 16 | class SamplerThread : public Thread { 17 | public: 18 | SamplerThread(SysConfig &config, UI &ui); 19 | 20 | protected: 21 | virtual void Run(); 22 | 23 | private: 24 | int DelayInMs; 25 | sensor_base *sensor; 26 | 27 | private: 28 | struct sensor_data sdata; 29 | 30 | UI &display; 31 | SysConfig &cfg; 32 | 33 | private: 34 | WiFiThread *wifi; 35 | LoRaThread *lora; 36 | SDThread *sd; 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /include/Signature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature); 7 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId); 8 | -------------------------------------------------------------------------------- /include/SysConfig.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SYSCONFIG_H__ 3 | #define __SYSCONFIG_H__ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "utils.h" 10 | 11 | 12 | #include 13 | using namespace cpp_freertos; 14 | class SysConfig { 15 | public: 16 | /* wifi */ 17 | String ssid; 18 | String password; 19 | mqtt_server cloud = CLOUD_AZURE; 20 | /* ubidots */ 21 | String mqtt_client_name; 22 | String token; 23 | String device_label; 24 | /* azure */ 25 | String id_scope; 26 | String registration_id; 27 | String symmetric_key; 28 | 29 | uint8_t lora_frequency; 30 | bool lora_on = false; 31 | bool wifi_on = false; 32 | bool wificonnected = false; 33 | int16_t wifi_rssi = 0; 34 | lora_status_type lora_status = LORA_INIT_START; 35 | int16_t lora_rssi = 0; 36 | int16_t lora_fcnt = 0; 37 | int16_t lora_sucess_cnt = 0; 38 | uint8_t sd_status = 0; // 0- not init, 1- connected, 2- sd full 39 | uint16_t sensor_save_flag = 0; 40 | 41 | static SemaphoreHandle_t lock; 42 | 43 | public: 44 | SysConfig(/* args */); 45 | ~SysConfig(); 46 | void init(); 47 | 48 | void ReadConfigParam(const String filename, char *prefix_param, String *param); 49 | void ReadAllConfig(); 50 | 51 | void WriteConfigParam(char *filename, char *prefix_param, char *param); 52 | void WriteConfigTemp(); 53 | 54 | private: 55 | /* data */ 56 | bool spi_flash_mount; 57 | bool cfg_available; 58 | Adafruit_USBD_MSC usb_msc; 59 | }; 60 | 61 | #endif // __SYSCONFIG_H__ -------------------------------------------------------------------------------- /include/WiFiThread.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIFITHREAD_H__ 2 | #define __WIFITHREAD_H__ 3 | #include "AzureDpsClient.h" 4 | #include "Seeed_Arduino_ooFreeRTOS.h" 5 | #include "Signature.h" 6 | #include "SysConfig.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define MQTT_BROKER "industrial.api.ubidots.com" 18 | 19 | #define USE_DPS 20 | #define MQTT_PACKET_SIZE 1024 21 | #define TOKEN_LIFESPAN 3600 22 | #ifndef USE_DPS 23 | #define IOT_CONFIG_IOTHUB "global.azure-devices-provisioning.net" 24 | #define IOT_CONFIG_DEVICE_ID "qian-test" 25 | #endif 26 | #define IOT_CONFIG_GLOBAL_DEVICE_ENDPOINT "global.azure-devices-provisioning.net" 27 | #define IOT_CONFIG_MODEL_ID "dtmi:seeedkk:wioterminal:wioterminal_aziot_example;5" 28 | #define AZ_RETURN_IF_FAILED(exp) \ 29 | do { \ 30 | az_result const _result = (exp); \ 31 | if (az_result_failed(_result)) { \ 32 | return _result; \ 33 | } \ 34 | } while (0) 35 | #define AZ_SPAN_LITERAL_FROM_CHAR(STRING_LITERAL) \ 36 | { \ 37 | ._internal = { \ 38 | .ptr = (uint8_t *)(STRING_LITERAL), \ 39 | .size = strlen(STRING_LITERAL), \ 40 | }, \ 41 | } 42 | 43 | using namespace cpp_freertos; 44 | 45 | class WiFiThread : public Thread { 46 | public: 47 | WiFiThread(SysConfig &config); 48 | void WiFiPushData(std::vector d); 49 | 50 | protected: 51 | virtual void Run(); 52 | 53 | int ConnectToHub(az_iot_hub_client *iot_hub_client, const std::string &symmetricKey, 54 | const uint64_t &expirationEpochTime); 55 | int RegisterDeviceToDPS(const std::string &endpoint, const std::string &idScope, 56 | const std::string ®istrationId, const std::string &symmetricKey, 57 | const uint64_t &expirationEpochTime); 58 | void MqttSubscribeCallbackDPS(char *topic, byte *payload, unsigned int length); 59 | void MqttSubscribeCallbackHub(char *topic, byte *payload, unsigned int length); 60 | void HandleCommandMessage(az_span payload, az_iot_hub_client_method_request *command_request); 61 | int SendCommandResponse(az_iot_hub_client_method_request *request, uint16_t status, 62 | az_span response); 63 | void reconnect(); 64 | void send_data(); 65 | 66 | az_result publish_azure(); 67 | void publish_ubidots(); 68 | 69 | private: 70 | SysConfig &cfg; 71 | 72 | private: 73 | const char *ssid = "ssid"; 74 | const char *password = "password"; 75 | std::vector wifi_data; 76 | bool wifi_data_ready = true; 77 | WiFiClientSecure wifiClient; 78 | PubSubClient *client; 79 | WiFiUDP wifi_udp; 80 | NTP *ntp; 81 | std::string HubHost; 82 | std::string DeviceId; 83 | AzureDpsClient DpsClient; 84 | unsigned long DpsPublishTimeOfQueryStatus = 0; 85 | az_iot_hub_client HubClient; 86 | uint64_t reconnectTime; 87 | }; 88 | 89 | #endif // __WIFITHREAD_H__ -------------------------------------------------------------------------------- /include/sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __SENSOR_H 2 | #define __SENSOR_H 3 | 4 | #include "SysConfig.h" 5 | #include 6 | #include "utils.h" 7 | 8 | #define LOG_MAX_SIZE 8 9 | 10 | typedef void (*sampler_callback)(const void *sample_buf, unsigned char byteLenght); 11 | 12 | 13 | class sensor_base 14 | { 15 | public: 16 | static std::vector slog; 17 | virtual void init() = 0; 18 | virtual bool read(struct sensor_data *data) = 0; 19 | virtual const char *get_name() = 0; 20 | void pushlog(const char *msg); 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /include/ui.h: -------------------------------------------------------------------------------- 1 | #ifndef __UI_H__ 2 | #define __UI_H__ 3 | #include "Free_Fonts.h" 4 | #include "Seeed_Arduino_ooFreeRTOS.h" 5 | #include "SysConfig.h" 6 | #include "seeed_line_chart.h" 7 | #include "sensor.h" 8 | #include "utils.h" 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace cpp_freertos; 14 | 15 | #define SCREEN_WIDTH 320 // Wio Terminal Maximum Width 16 | #define SCREEN_HIGH 240 // Wio Terminal Maximum Height 17 | 18 | #define SENSOR_NUM_MAX 6 // Maximum number of sensors 19 | #define LINE_DATA_MAX_SIZE 30 // maximum size of data 20 | #define DRAW_LINE_MAX_NUM 1 // maximum num of draw line 21 | #define SHOW_LOG_MAX_SIZE 11 // maximum size of log 22 | 23 | enum page_state { NETWORKPAGE, PROCESSPAGE, SENSEPAGE }; 24 | 25 | #define NONE_PRESSED 0x0F 26 | 27 | #define FIRST_PAGE 0 28 | #define LORA_PAGE 0 29 | #define WIFI_PAGE 1 30 | 31 | // define a struct with keyboard statemachine 32 | struct PagesStateMachine { 33 | page_state mainstate; 34 | uint8_t key; 35 | int8_t sense_select; 36 | int8_t process_select; 37 | int8_t network_select; 38 | }; 39 | struct State { 40 | int8_t current_page; 41 | bool is_next; 42 | int8_t s_select; 43 | }; 44 | 45 | struct NetworkState { 46 | int8_t current_network; 47 | struct State nw_state; // network wifi state 48 | struct State nl_state; // network lora state 49 | }; 50 | 51 | struct LoRaBandInfo { 52 | char *type; 53 | char *frequency; 54 | char *country; 55 | uint8_t band; 56 | }; 57 | 58 | typedef bool (*page_t)(uint8_t key); 59 | 60 | class UI : public Thread { 61 | public: 62 | // UI(TFT_eSPI &lcd, TFT_eSprite &display, SysConfig &config, Message &m1); 63 | UI(TFT_eSPI &lcd, SysConfig &config, Message &m1); 64 | 65 | protected: 66 | virtual void Run(); 67 | 68 | public: 69 | void UIPushData(std::vector d); 70 | void UIPushLog(std::vector d); 71 | 72 | private: 73 | TFT_eSPI &tft; 74 | // TFT_eSprite &spr; 75 | 76 | Message &btnMail; 77 | 78 | SysConfig &cfg; 79 | 80 | std::vector s_data; 81 | bool s_data_ready = true; 82 | 83 | std::vector a_log; 84 | bool log_ready = true; 85 | 86 | uint8_t rotate_status = 0; 87 | bool rotate_flag = false; 88 | 89 | uint8_t buff[256]; 90 | struct sensor_data sdata; 91 | 92 | struct PagesStateMachine page; 93 | 94 | bool data_refresh; // if new data push, refresh data in screen 95 | bool layout_refresh; // if a button pressed, refresh layout 96 | 97 | /* Label: basic and simple UI elements */ 98 | void Label_Network(void); 99 | void Label_Hardware(uint8_t status); 100 | void Label_SensorInfo(String name, String unit, uint8_t pos); 101 | void Label_SensorData(sensor_data& data, uint8_t pos, uint16_t bg_color); 102 | void Label_SensorAdd(uint8_t pos); 103 | void Label_Subtitle(String value); 104 | void Label_CentreBtn(String name, uint16_t color); 105 | 106 | /* Widget: advanced and complex UI elements */ 107 | void Widget_Title(uint8_t t); 108 | void Widget_SaveButton(uint8_t button); 109 | void Widget_Signal(int16_t signal, int32_t x, int32_t y); 110 | void Widget_PagePos(int PAGES, int _CHOOSE_PAGE); 111 | void Widget_LoraState(int32_t x, int32_t y); 112 | 113 | void StatusMachine(struct State *ui_state, uint8_t key); 114 | 115 | struct LoRaBandInfo lora_band_info[3] = { 116 | {"US", "915", "North America", 2}, 117 | {"EU", "868", "European Region", 1}, 118 | {"AU", "915", "Australia", 9}, 119 | }; 120 | 121 | struct State u_state = {0, true, 0}; 122 | void NetworkPageManager(uint8_t keys); 123 | bool Network_Home(uint8_t select); 124 | bool Network_Connect(uint8_t select); 125 | bool Network_LoRa_Band(uint8_t select); 126 | bool Network_LoRa_Confirm(uint8_t select); 127 | bool Network_Disconnect(uint8_t select); 128 | 129 | struct State p_state = {0, true, 0}; 130 | void ProcessPageManager(uint8_t keys); 131 | bool Process_1(uint8_t select); 132 | bool Process_2(uint8_t select); 133 | 134 | struct State s_state = {0, true, 0}; 135 | void SensePageManager(uint8_t keys); 136 | bool Sensor_1(uint8_t select); 137 | bool Sensor_2(uint8_t select); 138 | bool Sensor_3(uint8_t select); 139 | 140 | void PageMangent(uint8_t key); 141 | 142 | typedef bool (UI::*page_t)(uint8_t key); 143 | typedef void (UI::*main_t)(uint8_t key); 144 | 145 | enum uplink_index { HOME_S, CONNECT, DISCONNECT_S, LORABAND_S, LORACONFIRM }; 146 | page_t uplink [5] = { &UI::Network_Home, &UI::Network_Connect, &UI::Network_Disconnect, 147 | &UI::Network_LoRa_Band, &UI::Network_LoRa_Confirm }; 148 | page_t process[2] = { &UI::Process_1, &UI::Process_2}; 149 | page_t sense [3] = { &UI::Sensor_1, &UI::Sensor_2, &UI::Sensor_3}; 150 | main_t get_page[3] = {&UI::NetworkPageManager, &UI::ProcessPageManager, &UI::SensePageManager}; 151 | // void (UI::*get_page[3])(uint8_t key) = {&UI::NetworkPageManager, &UI::ProcessPageManager, &UI::SensePageManager}; 152 | 153 | private: 154 | // inline function, 4byte uint8_t to float 155 | void uint8_to_float(uint8_t *data, float *destination); 156 | 157 | // temp data 158 | int temp_light; 159 | int temp_mic; 160 | doubles line_chart_data[4]; 161 | }; 162 | 163 | #endif // __UI_H__ 164 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | #include 4 | 5 | #define LOGSS Serial1 6 | // #define CN_VER 7 | #ifdef CN_VER 8 | #define DEVICE "SenseCAP K1101" 9 | #else 10 | #define DEVICE "SenseCAP K1100" 11 | #endif 12 | #define VERSION "v0.4" 13 | 14 | enum mqtt_server { 15 | CLOUD_AZURE, 16 | CLOUD_UBIDOTS, 17 | }; 18 | 19 | enum button_state { 20 | NETWORK_PRESSED, 21 | PROCESS_PRESSED, 22 | SENSE_PRESSED, 23 | UP_PRESSED, 24 | DOWN_PRESSED, 25 | LEFT_PRESSED, 26 | RIGHT_PRESSED, 27 | SELECT_PRESSED, 28 | }; 29 | 30 | enum lora_status_type { 31 | LORA_INIT_START, 32 | LORA_INIT_FAILED, 33 | LORA_INIT_SUCCESS, 34 | LORA_JOIN_FAILED, 35 | LORA_JOIN_SUCCESS, 36 | LORA_SEND_FAILED, 37 | LORA_SEND_SUCCESS, 38 | }; 39 | 40 | enum sensor_data_type { 41 | SENSOR_DATA_TYPE_INT32 = 0, 42 | SENSOR_DATA_TYPE_FLOAT, 43 | }; 44 | 45 | enum sensor_ui_type { 46 | SENSOR_UI_TYPE_NORMAL = 0, 47 | SENSOR_UI_TYPE_AVERAGE, 48 | }; 49 | 50 | struct sensor_data { 51 | const char *name; 52 | const char *data_unit; 53 | const void *data; 54 | unsigned char size; 55 | uint16_t id; 56 | bool status; // 0: normal, 1: error 57 | uint8_t data_type = 0; // 0: int32_t, 1: float(*100) 58 | uint8_t ui_type = 0; // 0: normal, 1: average value 59 | }; 60 | 61 | struct log_data { 62 | char data[64]; 63 | uint32_t time; 64 | }; 65 | 66 | enum sensor_type { 67 | /* buildin sensor */ 68 | BUILDIN_LIGHT = 1, 69 | BUILDIN_MIC, 70 | LIS3DHTRSENSOR, 71 | /* grove i2c sensor */ 72 | GROVE_VISIONAI, 73 | GROVE_SHT4X, 74 | GROVE_SGP30, 75 | GROVE_VL53L0X, 76 | /* grove analog sensor */ 77 | GROVE_SOIL, 78 | }; 79 | 80 | enum lora_freq { 81 | UNDEFINED, 82 | EU868, 83 | US915, 84 | AS923_1, 85 | AS923_2, 86 | AS923_3, 87 | AS923_4, 88 | KR920, 89 | IN865, 90 | AU915, 91 | }; 92 | 93 | #ifdef DEBUG 94 | extern void LogMemoryUsage(const char *s); 95 | extern void LogHeapChange(const char *s); 96 | extern void LogTaskTrace(); 97 | #endif // DEBUG 98 | 99 | #endif // __UTILS_H__ 100 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | [env:seeed_wio_terminal] 2 | platform = atmelsam 3 | board = seeed_wio_terminal 4 | framework = arduino 5 | platform_packages = framework-arduino-samd-seeed@https://github.com/Seeed-Studio/ArduinoCore-samd.git#k1100 6 | lib_deps = 7 | https://github.com/Seeed-Studio/Seeed_Arduino_rpcWiFi 8 | https://github.com/Seeed-Studio/Seeed_Arduino_rpcUnified 9 | https://github.com/Seeed-Studio/Seeed_Arduino_mbedtls 10 | https://github.com/IsQianGe/pubsubclient.git 11 | https://github.com/Seeed-Studio/Seeed_Arduino_FS 12 | https://github.com/Seeed-Studio/Seeed_Arduino_SFUD 13 | https://github.com/Seeed-Studio/Seeed_Arduino_FreeRTOS#k1100 14 | https://github.com/Seeed-Studio/Seeed_Arduino_ooFreeRTOS 15 | https://github.com/Seeed-Studio/Seeed_Arduino_Linechart 16 | https://github.com/Seeed-Studio/Seeed_Arduino_GroveAI#k1100 17 | https://github.com/Seeed-Studio/Seeed_Arduino_LoRaE5 18 | https://github.com/Seeed-Studio/Seeed_Arduino_LIS3DHTR 19 | https://github.com/Seeed-Studio/Seeed_Arduino_LCD 20 | https://github.com/LynnL4/Adafruit_TinyUSB_Arduino 21 | https://github.com/ricmoo/QRCode 22 | https://github.com/IsQianGe/Arduino_sht4x_softwire 23 | https://github.com/IsQianGe/Arduino_sgp30_softwire 24 | https://github.com/Seeed-Studio/Grove-Ranging-sensor-VL53L0X#K1101 25 | https://github.com/Seeed-Studio/Arduino_Software_I2C#k1100 26 | adafruit/Adafruit Zero DMA Library 27 | SPI 28 | Wire 29 | SoftwareSerial 30 | https://github.com/Seeed-Studio/Seeed_Arduino_RTC 31 | https://github.com/IsQianGe/CSV-Parser-for-Arduino.git 32 | https://github.com/sstaub/NTP 33 | https://github.com/SeeedJP/pio-azure-sdk-for-c#1.1.0 34 | 35 | build_unflags = -std=gnu++11 36 | 37 | build_flags = 38 | -Wl,-u,_printf_float 39 | -Wl,-u,_scanf_float 40 | -Wl,--wrap,_write 41 | -Wl,-u,__wrap__write 42 | -DARDUINO_WIO_TERMINAL 43 | -DSEEED_K1100_DEV_KIT 44 | -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=calloc -Wl,--wrap=realloc 45 | -DAZ_NO_LOGGING 46 | -DDEBUG=1 47 | -DUSE_TINYUSB 48 | -std=gnu++14 49 | -DCM_DEBUG 50 | -Isrc/cm_backtrace 51 | -DUSE_FREERTOS 52 | -I"${platformio.libdeps_dir}/seeed_wio_terminal/Seeed Arduino FreeRTOS/src" -------------------------------------------------------------------------------- /src/AzureDpsClient.cpp: -------------------------------------------------------------------------------- 1 | #include "AzureDpsClient.h" 2 | #include 3 | #include 4 | 5 | static constexpr size_t SignatureMaxSize = 256; 6 | static constexpr size_t MqttClientIdMaxSize = 128; 7 | static constexpr size_t MqttUsernameMaxSize = 128; 8 | static constexpr size_t MqttPasswordMaxSize = 300; 9 | static constexpr size_t RegisterPublishTopicMaxSize = 128; 10 | static constexpr size_t QueryStatusPublishTopicMaxSize = 256; 11 | 12 | AzureDpsClient::AzureDpsClient() : 13 | ResponseValid{ false } 14 | { 15 | } 16 | 17 | int AzureDpsClient::Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId) 18 | { 19 | ResponseValid = false; 20 | 21 | Endpoint = endpoint; 22 | IdScope = idScope; 23 | RegistrationId = registrationId; 24 | 25 | const az_span endpointSpan{ az_span_create((uint8_t*)&Endpoint[0], Endpoint.size()) }; 26 | const az_span idScopeSpan{ az_span_create((uint8_t*)&IdScope[0], IdScope.size()) }; 27 | const az_span registrationIdSpan{ az_span_create((uint8_t*)&RegistrationId[0], RegistrationId.size()) }; 28 | if (az_result_failed(az_iot_provisioning_client_init(&ProvClient, endpointSpan, idScopeSpan, registrationIdSpan, NULL))) return -1; 29 | 30 | return 0; 31 | } 32 | 33 | std::vector AzureDpsClient::GetSignature(const uint64_t& expirationEpochTime) 34 | { 35 | uint8_t signature[SignatureMaxSize]; 36 | az_span signatureSpan = az_span_create(signature, sizeof(signature)); 37 | az_span signatureValidSpan; 38 | if (az_result_failed(az_iot_provisioning_client_sas_get_signature(&ProvClient, expirationEpochTime, signatureSpan, &signatureValidSpan))) return std::vector(); 39 | 40 | return std::vector(az_span_ptr(signatureValidSpan), az_span_ptr(signatureValidSpan) + az_span_size(signatureValidSpan)); 41 | } 42 | 43 | std::string AzureDpsClient::GetMqttClientId() 44 | { 45 | char mqttClientId[MqttClientIdMaxSize]; 46 | if (az_result_failed(az_iot_provisioning_client_get_client_id(&ProvClient, mqttClientId, sizeof(mqttClientId), NULL))) return std::string(); 47 | 48 | return mqttClientId; 49 | } 50 | 51 | std::string AzureDpsClient::GetMqttUsername() 52 | { 53 | char mqttUsername[MqttUsernameMaxSize]; 54 | if (az_result_failed(az_iot_provisioning_client_get_user_name(&ProvClient, mqttUsername, sizeof(mqttUsername), NULL))) return std::string(); 55 | 56 | return mqttUsername; 57 | } 58 | 59 | std::string AzureDpsClient::GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime) 60 | { 61 | char mqttPassword[MqttPasswordMaxSize]; 62 | az_span encryptedSignatureSpan = az_span_create((uint8_t*)&encryptedSignature[0], encryptedSignature.size()); 63 | if (az_result_failed(az_iot_provisioning_client_sas_get_password(&ProvClient, encryptedSignatureSpan, expirationEpochTime, AZ_SPAN_EMPTY, mqttPassword, sizeof(mqttPassword), NULL))) return std::string(); 64 | 65 | return mqttPassword; 66 | } 67 | 68 | std::string AzureDpsClient::GetRegisterPublishTopic() 69 | { 70 | char registerPublishTopic[RegisterPublishTopicMaxSize]; 71 | if (az_result_failed(az_iot_provisioning_client_register_get_publish_topic(&ProvClient, registerPublishTopic, sizeof(registerPublishTopic), NULL))) return std::string(); 72 | 73 | return registerPublishTopic; 74 | } 75 | 76 | std::string AzureDpsClient::GetRegisterSubscribeTopic() const 77 | { 78 | return AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC; 79 | } 80 | 81 | int AzureDpsClient::RegisterSubscribeWork(const std::string& topic, const std::vector& payload) 82 | { 83 | ResponseValid = false; 84 | 85 | ResponseTopic = topic; 86 | ResponsePayload = payload; 87 | 88 | if (az_result_failed(az_iot_provisioning_client_parse_received_topic_and_payload(&ProvClient, az_span_create((uint8_t*)&ResponseTopic[0], ResponseTopic.size()), az_span_create((uint8_t*)&ResponsePayload[0], ResponsePayload.size()), &Response))) return -1; 89 | 90 | ResponseValid = true; 91 | 92 | return 0; 93 | } 94 | 95 | bool AzureDpsClient::IsRegisterOperationCompleted() 96 | { 97 | if (!ResponseValid) return false; 98 | 99 | return az_iot_provisioning_client_operation_complete(GetOperationStatus(Response)); 100 | } 101 | 102 | int AzureDpsClient::GetWaitBeforeQueryStatusSeconds() const 103 | { 104 | if (!ResponseValid) return 0; 105 | 106 | return Response.retry_after_seconds; 107 | } 108 | 109 | std::string AzureDpsClient::GetQueryStatusPublishTopic() 110 | { 111 | if (!ResponseValid) return std::string(); 112 | 113 | char queryStatusPublishTopic[QueryStatusPublishTopicMaxSize]; 114 | if (az_result_failed(az_iot_provisioning_client_query_status_get_publish_topic(&ProvClient, Response.operation_id, queryStatusPublishTopic, sizeof(queryStatusPublishTopic), NULL))) return std::string(); 115 | 116 | return queryStatusPublishTopic; 117 | } 118 | 119 | bool AzureDpsClient::IsAssigned() 120 | { 121 | if (!ResponseValid) return false; 122 | 123 | return GetOperationStatus(Response) == AZ_IOT_PROVISIONING_STATUS_ASSIGNED; 124 | } 125 | 126 | std::string AzureDpsClient::GetHubHost() 127 | { 128 | if (!IsAssigned()) return std::string(); 129 | 130 | const az_span& span{ Response.registration_state.assigned_hub_hostname }; 131 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 132 | } 133 | 134 | std::string AzureDpsClient::GetDeviceId() 135 | { 136 | if (!IsAssigned()) return std::string(); 137 | 138 | const az_span& span{ Response.registration_state.device_id }; 139 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 140 | } 141 | 142 | az_iot_provisioning_client_operation_status AzureDpsClient::GetOperationStatus(az_iot_provisioning_client_register_response& response) 143 | { 144 | return response.operation_status; 145 | } 146 | -------------------------------------------------------------------------------- /src/ButtonThread.cpp: -------------------------------------------------------------------------------- 1 | #include "ButtonThread.h" 2 | 3 | ButtonThread::ButtonThread(Message &m) : Thread("ButtonThread", 128, 3), Mail(m) { 4 | Start(); 5 | }; 6 | 7 | void ButtonThread::Run() { 8 | LOGSS.println("Starting ButtonThread "); 9 | for (uint8_t i = 0; i < 8; i++) { 10 | pinMode(btn[i], INPUT_PULLUP); 11 | } 12 | uint8_t Message[8]; 13 | while (true) { 14 | Delay(Ticks::MsToTicks(10)); 15 | 16 | for (uint8_t i = 0; i < 8; i++) { 17 | if (digitalRead(btn[i]) == LOW) { 18 | Delay(Ticks::MsToTicks(100)); 19 | if (digitalRead(btn[i]) == LOW) { 20 | // avoid send 0 to Message 21 | Message[0] = i + 1; 22 | Mail.Send(Message, strlen((const char *)Message)); 23 | } 24 | } 25 | } 26 | // LOGSS.printf("ButtonThread Free Bytes Remaining %d\r\n", 27 | // uxTaskGetStackHighWaterMark(GetHandle())); 28 | } 29 | } -------------------------------------------------------------------------------- /src/FreeRTOSMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include 3 | #if 0 4 | // #ifdef __cplusplus 5 | // extern "C" { 6 | // #endif 7 | // void *malloc(size_t size) { 8 | // /* Call the FreeRTOS version of malloc. */ 9 | // return pvPortMalloc(size); 10 | // } 11 | // void free(void *ptr) { 12 | // /* Call the FreeRTOS version of free. */ 13 | // vPortFree(ptr); 14 | // } 15 | 16 | // #ifdef __cplusplus 17 | // } 18 | // #endif 19 | 20 | /*inline void *operator new(size_t size) 21 | { 22 | void *p; 23 | if(uxTaskGetNumberOfTasks()) 24 | p=pvPortMalloc(size); 25 | else 26 | p=malloc(size); 27 | return p; 28 | } 29 | inline void operator delete(void *p) noexcept 30 | { 31 | if(uxTaskGetNumberOfTasks()) 32 | vPortFree( p ); 33 | else 34 | free( p ); 35 | p = NULL; 36 | }*/ 37 | 38 | // Define the �new� operator for C++ to use the freeRTOS memory management 39 | // functions. THIS IS NOT OPTIONAL! 40 | // 41 | void *operator new(size_t size) { 42 | void *p; 43 | 44 | if (uxTaskGetNumberOfTasks()) 45 | p = pvPortMalloc(size); 46 | else 47 | p = malloc(size); 48 | 49 | /*#ifdef __EXCEPTIONS 50 | if (p==0) // did pvPortMalloc succeed? 51 | throw std::bad_alloc(); // ANSI/ISO compliant behavior 52 | #endif*/ 53 | 54 | return p; 55 | } 56 | 57 | // 58 | // Define the �delete� operator for C++ to use the freeRTOS memory management 59 | // functions. THIS IS NOT OPTIONAL! 60 | // 61 | void operator delete(void *p) noexcept { 62 | 63 | if (uxTaskGetNumberOfTasks()) 64 | vPortFree(p); 65 | else 66 | free(p); 67 | 68 | p = NULL; 69 | } 70 | 71 | void *operator new[](size_t size) { 72 | void *p; 73 | 74 | if (uxTaskGetNumberOfTasks()) 75 | p = pvPortMalloc(size); 76 | else 77 | p = malloc(size); 78 | 79 | /*#ifdef __EXCEPTIONS 80 | if (p==0) // did pvPortMalloc succeed? 81 | throw std::bad_alloc(); // ANSI/ISO compliant behavior 82 | #endif*/ 83 | 84 | return p; 85 | } 86 | 87 | // 88 | // Define the �delete� operator for C++ to use the freeRTOS memory management 89 | // functions. THIS IS NOT OPTIONAL! 90 | // 91 | void operator delete[](void *p) noexcept { 92 | 93 | if (uxTaskGetNumberOfTasks()) 94 | vPortFree(p); 95 | else 96 | free(p); 97 | 98 | p = NULL; 99 | } 100 | #endif -------------------------------------------------------------------------------- /src/SDThread.cpp: -------------------------------------------------------------------------------- 1 | #include "SDThread.h" 2 | #include "utils.h" 3 | 4 | SDThread::SDThread(SysConfig &config) : Thread("SDThread", 128 * 22, 2), cfg(config) { 5 | Start(); 6 | } 7 | 8 | // 0- not init, 1- connected, 2- sd full 9 | uint8_t SDThread::status() { 10 | uint64_t cardSize; 11 | if (cfg.sd_status == 0) { 12 | SD.end(); 13 | if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI, 4000000UL)) { // SD卡 14 | LOGSS.println("initialization failed!"); 15 | return 0; 16 | } 17 | } 18 | cardSize = SD.totalBytes(); 19 | if (cardSize == 0) { 20 | LOGSS.println("SD card is disconnected!"); 21 | return 0; 22 | } 23 | cfg.sd_status = 1; 24 | if (cardSize - SD.usedBytes() < 1024 * 1024) { 25 | LOGSS.println("SD card is full!"); 26 | return 2; 27 | } 28 | return 1; 29 | } 30 | //保存传感器数值到SD卡,参数:传感器名(同时也是文件名称),数据,数据长度 31 | void SDThread::saveData(String sensorName, int32_t *sensorData, int len, uint8_t type) { 32 | String fileName = sensorName + ".csv"; 33 | // LOGSS.println(fileName); 34 | if (SD.exists(fileName)) // header只写一次 35 | { 36 | myFile = SD.open(fileName, FILE_WRITE); //追加写模式 37 | LOGSS.printf("file %s does not found, creating...\r\n", fileName.c_str()); 38 | myFile.print(sensorName + ","); 39 | myFile.print("timestamp,"); 40 | for (int i = 0; i < len - 1; i++) { 41 | myFile.print("data[" + String(i + 1) + "]"); 42 | myFile.print(","); 43 | } 44 | myFile.println("data[" + String(len) + "]"); 45 | myFile.close(); 46 | } 47 | myFile = SD.open(fileName, FILE_APPEND); //追加写模式 48 | myFile.print(sensorName); 49 | myFile.print(","); 50 | 51 | DateTime now = rtc.now(); //读写当前时间 52 | myFile.print(String(now.year()) + "-" + String(now.month()) + "-" + String(now.day()) + " " + 53 | String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()) + 54 | ","); 55 | 56 | for (int i = 0; i < len; i++) //写入传感器值 57 | { 58 | /* 根据传感器值类型进行写入 */ 59 | if (type == SENSOR_DATA_TYPE_FLOAT) { 60 | myFile.print(sensorData[i]/100); 61 | myFile.print("."); 62 | myFile.print(sensorData[i]%100); 63 | } else { 64 | myFile.print(sensorData[i]); 65 | } 66 | /* 判断是否写完所有传感器值 */ 67 | if (i+1 < len) { 68 | myFile.print(","); 69 | } else { 70 | myFile.println(" "); 71 | } 72 | } 73 | 74 | myFile.close(); 75 | } 76 | 77 | void SDThread::Readdata(String sensorName) { 78 | CSV_Parser cp(/*format*/ "ssffff", /*has_header*/ true, /*delimiter*/ ','); 79 | 80 | String fileName = sensorName + ".csv"; 81 | 82 | char arr[sensorName.length() + 1]; 83 | strcpy(arr, sensorName.c_str()); 84 | if (cp.readSDfile2(fileName)) { //读模式打开文件,读header 85 | char **column_1 = (char **)cp[arr]; 86 | char **column_2 = (char **)cp["timestamp"]; 87 | float *column_3 = (float *)cp["data1"]; 88 | float *column_4 = (float *)cp["data2"]; 89 | float *column_5 = (float *)cp["data3"]; 90 | float *column_6 = (float *)cp["data4"]; 91 | // float *column_7 = (float*)cp["data5"]; 92 | 93 | for (int i = 0; i < cp.getRowsCount(); i++) { //解析csv文件 94 | LOGSS.print(column_1[i]); 95 | LOGSS.print(" - "); 96 | LOGSS.print(column_2[i]); 97 | LOGSS.print(" - "); 98 | LOGSS.print(column_3[i], DEC); 99 | LOGSS.print(" - "); 100 | LOGSS.print(column_4[i], DEC); 101 | LOGSS.print(" - "); 102 | LOGSS.print(column_5[i], DEC); 103 | LOGSS.print(" - "); 104 | LOGSS.print(column_6[i], DEC); 105 | LOGSS.println(); 106 | // LOGSS.print(column_6[i], DEC); LOGSS.print(" - "); 107 | // LOGSS.print(column_7[i], DEC); LOGSS.println(); 108 | } 109 | 110 | // output parsed values (allows to check that the file was parsed correctly) 111 | cp.print(); // assumes that "LOGSS.begin()" was called before (otherwise it won't work) 112 | } else { 113 | LOGSS.println("ERROR: File does not exist..."); 114 | } 115 | } 116 | 117 | void SDThread::Run() { 118 | if (wait_sd_data == NULL) { 119 | wait_sd_data = xSemaphoreCreateBinary(); 120 | } 121 | rtc.begin(); 122 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 123 | rtc.adjust(now); 124 | now = rtc.now(); 125 | while (true) { 126 | if (xSemaphoreTake(wait_sd_data, portMAX_DELAY) == pdTRUE) { 127 | sd_data_ready = false; 128 | for (auto data : sd_data) { 129 | if (cfg.sensor_save_flag & (1 << data.id)) { 130 | cfg.sd_status = status(); 131 | if (cfg.sd_status == 1) { 132 | saveData(String(data.name), (int32_t *)data.data, data.size/4, 133 | data.data_type); 134 | } 135 | } 136 | } 137 | sd_data_ready = true; 138 | } 139 | Delay(Ticks::MsToTicks(1000)); 140 | } 141 | } 142 | 143 | void SDThread::SDPushData(std::vector d) { 144 | // A loop to deep copy param of d vector into new sd_data queue 145 | // by Iterative method 146 | if (sd_data_ready) { 147 | sd_data.clear(); 148 | sd_data.shrink_to_fit(); 149 | for (auto data : d) 150 | sd_data.push_back(*data); 151 | if (wait_sd_data != NULL) { 152 | xSemaphoreGive(wait_sd_data); 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /src/SamplerThread.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SamplerThread.h" 3 | #include "sensor.h" 4 | #include "sensors/FakeSensor.h" 5 | #include "sensors/LIS3DHTRSensor.h" 6 | #include "sensors/buildin_light_sensor.h" 7 | #include "sensors/buildin_mic.h" 8 | #include "sensors/grove_sgp30_sensor.h" 9 | #include "sensors/grove_sht4x_sensor.h" 10 | #include "sensors/grove_vl53l0x_sensor.h" 11 | #include "sensors/grove_soil_sensor.h" 12 | #include "sensors/grove_visionai_sensor.h" 13 | #include "sensors/SensorsUtils.h" 14 | #include 15 | 16 | SamplerThread::SamplerThread(SysConfig &config, UI &ui) 17 | : Thread("SamplerThread", 128 * 4, 1), cfg(config), display(ui) { 18 | // start thread when created 19 | Start(); 20 | } 21 | 22 | void SamplerThread::Run() { 23 | wifi = new WiFiThread(cfg); 24 | lora = new LoRaThread(cfg); 25 | sd = new SDThread(cfg); 26 | 27 | std::vector sensors; 28 | sensors.push_back(new buildin_light_sensor()); 29 | sensors.push_back(new buildin_mic()); 30 | sensors.push_back(new LIS3DHTRSensor()); // buildin-imu 31 | sensors.push_back(new grove_soil_sensor()); 32 | sensors.push_back(new grove_sht4x_sensor()); 33 | sensors.push_back(new grove_sgp30_sensor()); 34 | sensors.push_back(new grove_vl53l0x_sensor()); 35 | sensors.push_back(new grove_visionai_sensor()); 36 | // sensors.push_back(new FakeSensor()); 37 | 38 | for (auto sensor : sensors) { 39 | sensor->init(); 40 | } 41 | 42 | while (true) { 43 | std::vector datas; 44 | for (auto sensor : sensors) { 45 | if (sensor->read(&sdata)) { 46 | // LOGSS.printf("Sampling %s\r\n", sdata.name); 47 | // for (size_t i = 0; i < sdata.size; i++) { 48 | // LOGSS.printf("%02x ", ((uint8_t *)sdata.data)[i]); 49 | // } 50 | // for (auto sensor : sensors) { 51 | // LOGSS.printf("Sampling %s\n", sensor->get_name()); 52 | // } 53 | // LOGSS.println(sensors.size()); 54 | // sensorMail.Send((void *)&sdata, sizeof(sdata)); 55 | // deep Copy data into datas vector 56 | datas.push_back(new sensor_data(sdata)); 57 | } 58 | // LOGSS.println("SamplerThread"); 59 | } 60 | lora->LoRaPushData(datas); 61 | wifi->WiFiPushData(datas); 62 | sd->SDPushData(datas); 63 | display.UIPushData(datas); 64 | display.UIPushLog(sensor_base::slog); 65 | for (auto data : datas) { 66 | delete data; 67 | } 68 | datas.clear(); 69 | datas.shrink_to_fit(); 70 | Delay(Ticks::MsToTicks(SENSOR_READ_DELAY)); 71 | // LOGSS.printf("SamplerThread Stacks Free Bytes Remaining %d\r\n", 72 | // uxTaskGetStackHighWaterMark(GetHandle())); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Signature.cpp: -------------------------------------------------------------------------------- 1 | #include "Signature.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature) 8 | { 9 | unsigned char base64DecodedSymmetricKey[symmetricKey.size() + 1]; 10 | 11 | // Base64-decode device key 12 | // <-- symmetricKey 13 | // --> base64DecodedSymmetricKey 14 | size_t base64DecodedSymmetricKeyLength; 15 | if (mbedtls_base64_decode(base64DecodedSymmetricKey, sizeof(base64DecodedSymmetricKey), &base64DecodedSymmetricKeyLength, (unsigned char*)&symmetricKey[0], symmetricKey.size()) != 0) abort(); 16 | if (base64DecodedSymmetricKeyLength == 0) abort(); 17 | 18 | // SHA-256 encrypt 19 | // <-- base64DecodedSymmetricKey 20 | // <-- signature 21 | // --> encryptedSignature 22 | uint8_t encryptedSignature[32]; // SHA-256 23 | mbedtls_md_context_t ctx; 24 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 25 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 26 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedSymmetricKey, base64DecodedSymmetricKeyLength) != 0) abort(); 27 | if (mbedtls_md_hmac_update(&ctx, &signature[0], signature.size()) != 0) abort(); 28 | if (mbedtls_md_hmac_finish(&ctx, encryptedSignature) != 0) abort(); 29 | mbedtls_md_free(&ctx); 30 | 31 | // Base64 encode encrypted signature 32 | // <-- encryptedSignature 33 | // --> b64encHmacsha256Signature 34 | char b64encHmacsha256Signature[(size_t)(sizeof(encryptedSignature) * 1.5f) + 1]; 35 | size_t b64encHmacsha256SignatureLength; 36 | if (mbedtls_base64_encode((unsigned char*)b64encHmacsha256Signature, sizeof(b64encHmacsha256Signature), &b64encHmacsha256SignatureLength, encryptedSignature, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 37 | 38 | return std::string(b64encHmacsha256Signature, b64encHmacsha256SignatureLength); 39 | } 40 | 41 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId) 42 | { 43 | unsigned char base64DecodedMasterKey[masterKey.size() + 1]; 44 | 45 | // Base64-decode device key 46 | // <-- masterKey 47 | // --> base64DecodedMasterKey 48 | size_t base64DecodedMasterKeyLength; 49 | if (mbedtls_base64_decode(base64DecodedMasterKey, sizeof(base64DecodedMasterKey), &base64DecodedMasterKeyLength, (unsigned char*)&masterKey[0], masterKey.size()) != 0) abort(); 50 | if (base64DecodedMasterKeyLength == 0) abort(); 51 | 52 | // SHA-256 encrypt 53 | // <-- base64DecodedMasterKey 54 | // <-- registrationId 55 | // --> derivedSymmetricKey 56 | uint8_t derivedSymmetricKey[32]; // SHA-256 57 | mbedtls_md_context_t ctx; 58 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 59 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 60 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedMasterKey, base64DecodedMasterKeyLength) != 0) abort(); 61 | if (mbedtls_md_hmac_update(&ctx, (const unsigned char*)®istrationId[0], registrationId.size()) != 0) abort(); 62 | if (mbedtls_md_hmac_finish(&ctx, derivedSymmetricKey) != 0) abort(); 63 | mbedtls_md_free(&ctx); 64 | 65 | // Base64 encode encrypted signature 66 | // <-- derivedSymmetricKey 67 | // --> b64encDerivedSymmetricKey 68 | char b64encDerivedSymmetricKey[(size_t)(sizeof(derivedSymmetricKey) * 1.5f) + 1]; 69 | size_t b64encDerivedSymmetricKeyLength; 70 | if (mbedtls_base64_encode((unsigned char*)b64encDerivedSymmetricKey, sizeof(b64encDerivedSymmetricKey), &b64encDerivedSymmetricKeyLength, derivedSymmetricKey, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 71 | 72 | return std::string(b64encDerivedSymmetricKey, b64encDerivedSymmetricKeyLength); 73 | } 74 | -------------------------------------------------------------------------------- /src/SysConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "SysConfig.h" 2 | 3 | using namespace cpp_freertos; 4 | 5 | SemaphoreHandle_t SysConfig::lock = NULL; 6 | 7 | extern "C" { 8 | void cm_printf(const char *format, ...) { 9 | char print_buf[1024] = {0}; 10 | 11 | va_list args; 12 | va_start(args, format); 13 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 14 | va_end(args); 15 | 16 | if (r > 0) { 17 | LOGSS.write(print_buf); 18 | } 19 | } 20 | } 21 | 22 | static int32_t msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize, uint32_t offset) { 23 | // LOGSS.printf("read: lba:%d, bufsize:%d, offset: %d\n", lba, bufsize, offset); 24 | uint32_t ret_size = -1; 25 | 26 | xSemaphoreTake(SysConfig::lock, portMAX_DELAY); 27 | 28 | const sfud_flash *_flash = sfud_get_device_table() + 0; 29 | uint8_t result = 30 | sfud_read(_flash, lba * _flash->chip.erase_gran + offset, bufsize, (uint8_t *)buffer); 31 | if (result == SFUD_SUCCESS) { 32 | ret_size = bufsize; 33 | } 34 | xSemaphoreGive(SysConfig::lock); 35 | return ret_size; 36 | } 37 | 38 | static int32_t msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize, uint32_t offset) { 39 | // LOGSS.printf("write: lba:%d, bufsize:%d, offset:%d\n", lba, bufsize, offset); 40 | uint32_t ret_size = -1; 41 | const sfud_flash *_flash = sfud_get_device_table() + 0; 42 | uint8_t result = SFUD_SUCCESS; 43 | xSemaphoreTake(SysConfig::lock, portMAX_DELAY); 44 | if (offset == 0) { 45 | result = sfud_erase_write(_flash, lba * _flash->chip.erase_gran, bufsize, buffer); 46 | } else { 47 | result = sfud_write(_flash, lba * _flash->chip.erase_gran + offset, bufsize, buffer); 48 | } 49 | if (result == SFUD_SUCCESS) { 50 | ret_size = bufsize; 51 | } 52 | xSemaphoreGive(SysConfig::lock); 53 | return ret_size; 54 | } 55 | 56 | static void msc_flush_cb(void) { 57 | } 58 | 59 | SysConfig::SysConfig(/* args */) { 60 | } 61 | 62 | SysConfig::~SysConfig() { 63 | } 64 | 65 | void SysConfig::init() { 66 | // mount filesystem 67 | if (SysConfig::lock == NULL) { 68 | SysConfig::lock = xSemaphoreCreateMutex(); 69 | } 70 | spi_flash_mount = SFUD.begin(); 71 | 72 | //If the flash mount is successful, map the space 73 | if (spi_flash_mount) { 74 | const sfud_flash *_flash = sfud_get_device_table() + 0; 75 | // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters 76 | // respectively 77 | usb_msc.setID("K1101", "Mass Storage", "1.0"); 78 | // Set disk size 79 | usb_msc.setCapacity((_flash->chip.capacity / _flash->chip.erase_gran), 80 | _flash->chip.erase_gran); 81 | // Set callback 82 | usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); 83 | // Set Lun ready (RAM disk is always ready) 84 | usb_msc.setUnitReady(true); 85 | usb_msc.begin(); 86 | ReadAllConfig(); 87 | } 88 | // pinMode(SDCARD_DET_PIN, INPUT); 89 | // if (digitalRead(SDCARD_DET_PIN) == LOW) { 90 | // sd_mount = SD.begin(SDCARD_SS_PIN, SDCARD_SPI, 4000000UL); 91 | // }else 92 | // LOGSS.println("sd card not insert"); 93 | } 94 | 95 | // void SysConfig::set_lora_freq(uint8_t frequency) 96 | // { 97 | // this->frequency = frequency; 98 | // } 99 | 100 | // uint8_t SysConfig::get_lora_freq() 101 | // { 102 | // return this->frequency; 103 | // } 104 | 105 | void SysConfig::ReadConfigParam(const String filename, char *prefix_param, String *param) { 106 | xSemaphoreTake(SysConfig::lock, portMAX_DELAY); 107 | if (spi_flash_mount && cfg_available) { 108 | File config = SFUD.open(filename, "r"); 109 | if (config) { 110 | if (config.find(prefix_param) == true) { 111 | *param = config.readStringUntil('\n'); 112 | param->trim(); 113 | } else { // missing parameter 114 | cfg_available = false; 115 | } 116 | config.close(); 117 | } 118 | } 119 | xSemaphoreGive(SysConfig::lock); 120 | } 121 | 122 | void SysConfig::ReadAllConfig() { 123 | if (SFUD.exists("config.txt")) { 124 | cfg_available = true; // assume that the configuration is available 125 | ReadConfigParam("config.txt", "SSID=", &this->ssid); 126 | ReadConfigParam("config.txt", "PASSWORD=", &this->password); 127 | ReadConfigParam("config.txt", "MQTT_CLIENT_NAME=", &this->mqtt_client_name); 128 | ReadConfigParam("config.txt", "TOKEN=", &this->token); 129 | ReadConfigParam("config.txt", "DEVICE_LABEL=", &this->device_label); 130 | ReadConfigParam("config.txt", "ID_SCOPE=", &this->id_scope); 131 | ReadConfigParam("config.txt", "DEVICE_ID=", &this->registration_id); 132 | ReadConfigParam("config.txt", "PRIMARY_KEY=", &this->symmetric_key); 133 | if (!cfg_available) { 134 | SFUD.remove("config.txt"); 135 | LOGSS.println("missing parameter!"); 136 | ReadAllConfig(); 137 | } 138 | } else { // config file does not exist, create a template 139 | WriteConfigTemp(); 140 | // WriteConfigParam("config.txt", "SSID=", "WiFi_Name"); 141 | // WriteConfigParam("config.txt", "PASSWORD=", "WiFi_Password"); 142 | // WriteConfigParam("config.txt", "MQTT_CLIENT_NAME=", "Topic"); 143 | // WriteConfigParam("config.txt", "TOKEN=", "Default_Token"); 144 | // WriteConfigParam("config.txt", "DEVICE_LABEL=", "Device_Name"); 145 | // WriteConfigParam("config.txt", "ID_SCOPE=", "Default_ID_Scope"); 146 | // WriteConfigParam("config.txt", "DEVICE_ID=", "Default_Device_ID"); 147 | // WriteConfigParam("config.txt", "PRIMARY_KEY=", "Default_Primay_Key"); 148 | } 149 | } 150 | 151 | void SysConfig::WriteConfigParam(char *filename, char *prefix_param, char *param) { 152 | xSemaphoreTake(SysConfig::lock, portMAX_DELAY); 153 | LOGSS.println("===> write param"); 154 | if (spi_flash_mount) { 155 | File config = SFUD.open(filename, "r+"); 156 | if (config) { // file already has content 157 | LOGSS.println("cfg file already has content"); 158 | if (config.find(prefix_param) == true) { // param already in the file 159 | config.seek(config.position()); 160 | } 161 | config.print(prefix_param); 162 | config.print(param); 163 | config.print("\n"); 164 | } else { // file is empty 165 | LOGSS.println("cfg file is empty"); 166 | config = SFUD.open(filename, "w"); 167 | if (config) { 168 | config.print(prefix_param); 169 | config.print(param); 170 | config.print("\n"); 171 | } 172 | } 173 | config.close(); 174 | } 175 | xSemaphoreGive(SysConfig::lock); 176 | } 177 | 178 | void SysConfig::WriteConfigTemp() { 179 | xSemaphoreTake(SysConfig::lock, portMAX_DELAY); 180 | File config = SFUD.open("config.txt", "w"); 181 | if (config) { 182 | config.print("SSID=WiFi_Name\n"); 183 | config.print("PASSWORD=WiFi_Password\n"); 184 | config.print("MQTT_CLIENT_NAME=Topic\n"); 185 | config.print("TOKEN=Default_Token\n"); 186 | config.print("DEVICE_LABEL=Device_Name\n"); 187 | config.print("ID_SCOPE=Default_ID_Scope\n"); 188 | config.print("DEVICE_ID=Default_Device_ID\n"); 189 | config.print("PRIMARY_KEY=Default_Primay_Key\n"); 190 | } 191 | config.close(); 192 | xSemaphoreGive(SysConfig::lock); 193 | } -------------------------------------------------------------------------------- /src/cm_backtrace/cm_backtrace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the CmBacktrace Library. 3 | * 4 | * Copyright (c) 2016, Armink, 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * 'Software'), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * Function: It is an head file for this library. You can see all be called functions. 26 | * Created on: 2016-12-15 27 | */ 28 | 29 | #ifndef _CORTEXM_BACKTRACE_H_ 30 | #define _CORTEXM_BACKTRACE_H_ 31 | #ifdef __cplusplus 32 | extern "C"{ 33 | #endif 34 | #include "cmb_def.h" 35 | 36 | void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver); 37 | void cm_backtrace_firmware_info(void); 38 | size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp); 39 | void cm_backtrace_assert(uint32_t sp); 40 | void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp); 41 | #ifdef __cplusplus 42 | }//extern "C"{ 43 | #endif 44 | #endif /* _CORTEXM_BACKTRACE_H_ */ 45 | -------------------------------------------------------------------------------- /src/cm_backtrace/cmb_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the CmBacktrace Library. 3 | * 4 | * Copyright (c) 2016, Armink, 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * 'Software'), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * Function: It is the configure head file for this library. 26 | * Created on: 2016-12-15 27 | */ 28 | 29 | #ifndef _CMB_CFG_H_ 30 | #define _CMB_CFG_H_ 31 | 32 | /* print line, must config by user */ 33 | #define cmb_println(...) cm_printf(__VA_ARGS__);cm_printf("\r\n"); /* e.g., printf(__VA_ARGS__);printf("\r\n") */ 34 | /* enable bare metal(no OS) platform */ 35 | /* #define CMB_USING_BARE_METAL_PLATFORM */ 36 | /* enable OS platform */ 37 | #define CMB_USING_OS_PLATFORM 1 38 | /* OS platform type, must config when CMB_USING_OS_PLATFORM is enable */ 39 | #define CMB_OS_PLATFORM_TYPE CMB_OS_PLATFORM_FREERTOS /* CMB_OS_PLATFORM_RTT or CMB_OS_PLATFORM_UCOSII or CMB_OS_PLATFORM_UCOSIII or CMB_OS_PLATFORM_FREERTOS */ 40 | /* cpu platform type, must config by user */ 41 | #define CMB_CPU_PLATFORM_TYPE CMB_CPU_ARM_CORTEX_M4 /* CMB_CPU_ARM_CORTEX_M0 or CMB_CPU_ARM_CORTEX_M3 or CMB_CPU_ARM_CORTEX_M4 or CMB_CPU_ARM_CORTEX_M7 */ 42 | /* enable dump stack information */ 43 | #define CMB_USING_DUMP_STACK_INFO 1 44 | /* language of print information */ 45 | /* #define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH(default) or CMB_PRINT_LANGUAGE_CHINESE */ 46 | #endif /* _CMB_CFG_H_ */ 47 | -------------------------------------------------------------------------------- /src/cm_backtrace/fault_handler/gcc/cmb_fault.S: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the CmBacktrace Library. 3 | * 4 | * Copyright (c) 2016, Armink, 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * 'Software'), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * Function: Fault handler by GCC assembly code 26 | * Created on: 2016-12-16 27 | */ 28 | 29 | .syntax unified 30 | .thumb 31 | .text 32 | 33 | /* NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file. */ 34 | 35 | .global HardFault_Handler 36 | .type HardFault_Handler, %function 37 | HardFault_Handler: 38 | MOV r0, lr /* get lr */ 39 | MOV r1, sp /* get stack pointer (current is MSP) */ 40 | BL cm_backtrace_fault 41 | 42 | Fault_Loop: 43 | BL Fault_Loop /* while(1) */ 44 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ButtonThread.h" 3 | #include "FreeRTOS.h" 4 | #include "LoRaThread.h" 5 | #include "SamplerThread.h" 6 | #include "Seeed_Arduino_ooFreeRTOS.h" 7 | #include "SysConfig.h" 8 | #include "ui.h" 9 | #include 10 | #include 11 | #ifdef CM_DEBUG 12 | #include "cm_backtrace.h" 13 | #endif 14 | #define HARDWARE_VERSION "seeed_k1100_dev_kit" 15 | #define SOFTWARE_VERSION "V1.0.0" 16 | 17 | #define ANSI_R "\x1b[31m" 18 | #define ANSI_G "\x1b[32m" 19 | #define ANSI_Y "\x1b[33m" 20 | #define ANSI_B "\x1b[34m" 21 | #define ANSI_MAGENTA "\x1b[35m" 22 | #define ANSI_CYAN "\x1b[36m" 23 | #define ANSI_RESET "\x1b[0m" 24 | 25 | using namespace cpp_freertos; 26 | 27 | TFT_eSPI tft; 28 | // TFT_eSprite spr = TFT_eSprite(&tft); 29 | 30 | void display_init() // Display initialization, black background rotation 31 | { 32 | tft.begin(); 33 | tft.setRotation(3); 34 | tft.fillScreen(TFT_BLACK); 35 | tft.setTextColor(TFT_WHITE); 36 | tft.setFreeFont(FSSB9); 37 | tft.drawString(DEVICE, 90, 110, GFXFF); 38 | tft.setFreeFont(FSS9); 39 | tft.drawString(VERSION, 150, 150, FONT2); 40 | } 41 | 42 | using namespace std; 43 | void LogMemoryUsage(const char *s); 44 | void LogHeapChange(const char *s); 45 | void LogTaskTrace(void); 46 | 47 | void setup() { 48 | LOGSS.begin(115200); 49 | display_init(); 50 | SysConfig *cfg = new SysConfig(); 51 | cfg->init(); 52 | 53 | #ifdef CM_DEBUG 54 | cm_backtrace_init("Seeed K1100 dev kit", HARDWARE_VERSION, SOFTWARE_VERSION); 55 | #endif 56 | // put your setup code here, to run once: 57 | uint32_t start = millis(); 58 | while (!LOGSS && (millis() - start) < 1500) 59 | ; // Open the Serial Monitor to get started or wait for 1.5" 60 | 61 | 62 | Message *btnMail = new Message(256); 63 | // Message *sensorMail = new Message(256); 64 | 65 | ButtonThread *btn = new ButtonThread(*btnMail); 66 | UI *u = new UI(tft, *cfg, *btnMail); 67 | SamplerThread *sampler = new SamplerThread(*cfg, *u); 68 | } 69 | 70 | // Get the size of memory left in the system in freertos. 71 | void LogMemoryUsage(const char *s) { 72 | int CurFree, MinFree, Percentage; 73 | int Total = configTOTAL_HEAP_SIZE; 74 | CurFree = xPortGetFreeHeapSize(); 75 | MinFree = xPortGetMinimumEverFreeHeapSize(); 76 | Percentage = (Total-CurFree)*100 / Total; 77 | string UsageGraph = "["ANSI_G; 78 | for(int i=0; i<25; i++) 79 | { 80 | if(i == Percentage/4) 81 | UsageGraph += "#"ANSI_RESET; 82 | else 83 | UsageGraph += "#"; 84 | } 85 | UsageGraph += "]"; 86 | LOGSS.println("====== RTOS HEAP USAGE ======="); 87 | LOGSS.printf("| Log in : "ANSI_Y"%s \r\n"ANSI_RESET, s); 88 | LOGSS.printf("| Total : "ANSI_B"%d "ANSI_RESET"bytes\r\n", Total); 89 | LOGSS.printf("| Maximum : "ANSI_R"%d "ANSI_RESET"bytes\r\n", Total-MinFree); 90 | LOGSS.printf("| Current : "ANSI_G"%d "ANSI_RESET"bytes\r\n", (Total-CurFree), UsageGraph.c_str()); 91 | LOGSS.printf("| %s \r\n", UsageGraph.c_str()); 92 | } 93 | 94 | void LogTaskTrace() { 95 | char TraceBuf[512]; 96 | vTaskList(TraceBuf); 97 | LOGSS.println("========= RTOS task stack usage =========="); 98 | LOGSS.println("TaskName State Priority FreeStack"); 99 | LOGSS.printf("%s", TraceBuf); 100 | LOGSS.println("================== end ==================="); 101 | } 102 | 103 | void LogHeapChange(const char *s) { 104 | static int pre_free_heap = 0; 105 | int heap_change = configTOTAL_HEAP_SIZE - xPortGetFreeHeapSize() - pre_free_heap; 106 | if(heap_change > 0) { 107 | LOGSS.printf(ANSI_R" => %s +%d\r\n"ANSI_RESET, s, heap_change); 108 | } 109 | else if(heap_change < 0) { 110 | LOGSS.printf(ANSI_G" => %s %d\r\n"ANSI_RESET, s, heap_change); 111 | } 112 | pre_free_heap += heap_change; 113 | } 114 | 115 | void loop() { 116 | // LOGSS.printf("Main Stacks Free Bytes Remaining %d\r\n", uxTaskGetStackHighWaterMark(NULL)); 117 | vTaskDelete(NULL); 118 | } 119 | -------------------------------------------------------------------------------- /src/sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "sensor.h" 2 | 3 | std::vector sensor_base::slog; 4 | 5 | void sensor_base::pushlog(const char *msg) 6 | { 7 | log_data log; 8 | strcpy(log.data, msg); 9 | log.time = millis(); 10 | if (slog.size() > LOG_MAX_SIZE) 11 | { 12 | slog.erase(slog.begin()); 13 | } 14 | slog.push_back(log); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/sensors/FakeSensor.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file FakeSensor.cpp 3 | * @author Baozhu Zuo (zuobaozhu@gmail.com) 4 | * @brief This is a fake sensor drive, which simulates random disconnection of the sensor during use 5 | * and random acquisition of measured data. 6 | * @version 0.1 7 | * @date 2022-08-07 8 | * 9 | * @copyright Copyright (c) 2022 Seeed technology inc. 10 | * 11 | */ 12 | #include "FakeSensor.h" 13 | #include "Arduino.h" 14 | 15 | Fake::Fake() : Thread("Fake", 128, 1) { 16 | } 17 | void Fake::Run() { 18 | uint16_t delay; 19 | while (true) { 20 | delay = random(100,2000); 21 | dsize = random(0,10); 22 | for (int i = 0; i < dsize; i++) { 23 | data[i] = random(-10000, 10000); 24 | } 25 | status = random(0, 2); 26 | Delay(Ticks::MsToTicks(delay)); 27 | } 28 | } 29 | 30 | FakeSensor::FakeSensor() { 31 | fake = new Fake(); 32 | } 33 | 34 | void FakeSensor::init() { 35 | fake->Start(); 36 | } 37 | 38 | bool FakeSensor::read(struct sensor_data *data) { 39 | data->data = fake->data; 40 | data->size = fake->dsize*sizeof(int); 41 | data->id = 0; 42 | data->name = name; 43 | data->status = fake->status; 44 | return data->size == 0 ? false : true; 45 | } 46 | 47 | const char *FakeSensor::get_name() { 48 | return this->name; 49 | } -------------------------------------------------------------------------------- /src/sensors/FakeSensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __FAKESENSOR_H__ 2 | #define __FAKESENSOR_H__ 3 | 4 | #include "sensor.h" 5 | #include "utils.h" 6 | 7 | #include 8 | 9 | using namespace cpp_freertos; 10 | 11 | class Fake : public Thread { 12 | 13 | public: 14 | Fake(); 15 | int data[10]; 16 | uint8_t dsize; 17 | bool status; 18 | 19 | protected: 20 | virtual void Run(); 21 | }; 22 | 23 | class FakeSensor : public sensor_base { 24 | public: 25 | FakeSensor(); 26 | void init(); 27 | bool read(struct sensor_data *data); 28 | const char *get_name(); 29 | 30 | private: 31 | const char *name = "FakeSensor"; 32 | bool status; 33 | Fake *fake; 34 | }; 35 | 36 | #endif // __FAKESENSOR_H__ -------------------------------------------------------------------------------- /src/sensors/LIS3DHTRSensor.cpp: -------------------------------------------------------------------------------- 1 | #include "LIS3DHTRSensor.h" 2 | #include "SensorsUtils.h" 3 | 4 | LIS3DHTRSensor::LIS3DHTRSensor() { 5 | } 6 | 7 | void LIS3DHTRSensor::init() { 8 | if (I2CScanner(LIS3DHTR_DEFAULT_ADDRESS, Wire)) { 9 | lis.begin(Wire); 10 | lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); // Data output rate 11 | lis.setFullScaleRange(LIS3DHTR_RANGE_2G); 12 | status = true; 13 | } else { 14 | status = false; 15 | } 16 | } 17 | 18 | bool LIS3DHTRSensor::read(struct sensor_data *sdata) { 19 | float x_values, y_values, z_values; 20 | 21 | sdata->id = LIS3DHTRSENSOR; 22 | sdata->name = name; 23 | 24 | if (status) { 25 | if (!I2CScanner(LIS3DHTR_DEFAULT_ADDRESS, Wire)) { 26 | status = false; 27 | return false; 28 | } 29 | 30 | lis.getAcceleration(&x_values, &y_values, &z_values); 31 | data[0] = (int)(x_values * 100); 32 | data[1] = (int)(y_values * 100); 33 | data[2] = (int)(z_values * 100); 34 | sdata->data = data; 35 | sdata->data_type = SENSOR_DATA_TYPE_FLOAT; 36 | sdata->size = sizeof(data); 37 | sdata->id = LIS3DHTRSENSOR; 38 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 39 | sdata->data_unit = data_unit; 40 | sdata->status = true; 41 | return true; 42 | } else { 43 | sdata->data = NULL; 44 | sdata->status = false; 45 | init(); // init again, try to find the sensor 46 | return false; 47 | } 48 | } 49 | 50 | const char *LIS3DHTRSensor::get_name() { 51 | return this->name; 52 | } 53 | -------------------------------------------------------------------------------- /src/sensors/LIS3DHTRSensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIS3DHTRSENSOR_H__ 2 | #define __LIS3DHTRSENSOR_H__ 3 | #include "sensor.h" 4 | #include "utils.h" 5 | #include "Wire.h" 6 | #include "LIS3DHTR.h" 7 | 8 | 9 | 10 | class LIS3DHTRSensor : public sensor_base 11 | { 12 | public: 13 | LIS3DHTRSensor(); 14 | void init(); 15 | bool read(struct sensor_data *data); 16 | const char *get_name(); 17 | private: 18 | const char *name = "IMU"; //LIS3DHTR 19 | const char *data_unit = "X-Y-Z"; 20 | int data[3]; 21 | 22 | bool status; 23 | 24 | LIS3DHTR lis; 25 | }; 26 | 27 | #endif // __LIS3DHTRSENSOR_H__ -------------------------------------------------------------------------------- /src/sensors/SensorsUtils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Arduino.h" 3 | #include "Wire.h" 4 | #include "SoftwareI2C.h" 5 | #include "sensor.h" 6 | #include "SensorsUtils.h" 7 | 8 | SoftwareI2C softwarei2c; 9 | 10 | template bool I2CScanner(uint8_t address, T wire) { 11 | uint8_t error = 0; 12 | wire.begin(); 13 | wire.beginTransmission(address & 0x7F); 14 | 15 | error = wire.endTransmission(); 16 | 17 | // features: for samd21 & samd51 18 | if (error == 0) { 19 | wire.beginTransmission(0x1); 20 | error = wire.endTransmission(); 21 | if (error == 0) { 22 | wire.beginTransmission(0x7F); 23 | error = wire.endTransmission(); 24 | if (error == 0) 25 | return false; 26 | } 27 | } else { 28 | return false; 29 | } 30 | 31 | return true; 32 | } 33 | template bool I2CScanner(uint8_t address, TwoWire wire); 34 | 35 | template bool I2CScanner(T wire) { 36 | for (unsigned char i = 1; i <= 127; i++) { 37 | if (wire.beginTransmission(i)) { 38 | // LOGSS.printf("Found I2C device at address: "); 39 | // LOGSS.println( i); 40 | return true; 41 | } 42 | wire.endTransmission(); 43 | } 44 | // LOGSS.println(" not Found I2C device "); 45 | return false; 46 | } 47 | template bool I2CScanner(SoftwareI2C wire); 48 | 49 | /************************************************************************************************* 50 | Function Name: Grove_I2C_Check 51 | Description: check for i2c sensor connect 52 | Return: true: i2c sensor connected 53 | *************************************************************************************************/ 54 | bool Grove_I2C_Check(SoftwareI2C& wire){ 55 | wire.begin(SOFT_I2C_SDA, SOFT_I2C_SCL); 56 | for(int i=0; i bool I2CScanner(uint8_t address, T wire); 29 | template bool I2CScanner(T wire); 30 | #endif // __SENSORSUTILS_H__ -------------------------------------------------------------------------------- /src/sensors/buildin_light_sensor.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "buildin_light_sensor.h" 3 | #include "Arduino.h" 4 | 5 | buildin_light_sensor::buildin_light_sensor() { 6 | } 7 | void buildin_light_sensor::init() { 8 | pinMode(WIO_LIGHT, INPUT); 9 | } 10 | 11 | bool buildin_light_sensor::read(struct sensor_data *sdata) { 12 | light_value = analogRead(WIO_LIGHT); 13 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 14 | sdata->data = &light_value; 15 | sdata->size = sizeof(light_value); 16 | sdata->id = BUILDIN_LIGHT; 17 | sdata->name = name; 18 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 19 | sdata->data_unit = data_unit; 20 | sdata->status = true; 21 | return true; 22 | } 23 | 24 | const char *buildin_light_sensor::get_name() { 25 | return "light"; 26 | } 27 | 28 | // buildin_light_sensor buildin_light; -------------------------------------------------------------------------------- /src/sensors/buildin_light_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __BUILDIN_LIGHT_SENSOR_H 2 | #define __BUILDIN_LIGHT_SENSOR_H 3 | 4 | #include "sensor.h" 5 | #include "utils.h" 6 | 7 | class buildin_light_sensor : public sensor_base 8 | { 9 | public: 10 | buildin_light_sensor(); 11 | void init(); 12 | const char *get_name(); 13 | bool read(struct sensor_data *data); 14 | private: 15 | const char *name = "Light"; /// buildin-light 16 | const char *data_unit = " "; 17 | int light_value; 18 | 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /src/sensors/buildin_mic.cpp: -------------------------------------------------------------------------------- 1 | #include "buildin_mic.h" 2 | #include "Arduino.h" 3 | 4 | buildin_mic::buildin_mic() { 5 | } 6 | void buildin_mic::init() { 7 | pinMode(WIO_MIC, INPUT); 8 | } 9 | bool buildin_mic::read(struct sensor_data *sdata) { 10 | mic_value = analogRead(WIO_MIC); 11 | if(mic_value < 250) 12 | mic_value = 0; 13 | else 14 | mic_value = (uint32_t)((mic_value - 250) / 3.19); 15 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 16 | sdata->data = &mic_value; 17 | sdata->size = sizeof(mic_value); 18 | sdata->id = BUILDIN_MIC; 19 | sdata->name = name; 20 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 21 | sdata->data_unit = data_unit; 22 | sdata->status = true; 23 | return true; 24 | } 25 | 26 | const char *buildin_mic::get_name() { 27 | return "buildin-mic"; 28 | } 29 | -------------------------------------------------------------------------------- /src/sensors/buildin_mic.h: -------------------------------------------------------------------------------- 1 | #ifndef __BUILDIN_MIC_H 2 | #define __BUILDIN_MIC_H 3 | 4 | #include "sensor.h" 5 | #include "utils.h" 6 | 7 | 8 | class buildin_mic : public sensor_base 9 | { 10 | public: 11 | buildin_mic(); 12 | void init(); 13 | bool read(struct sensor_data *data); 14 | const char *get_name(); 15 | private: 16 | const char *name = "Sound"; //buildin-mic 17 | const char *data_unit = "dB"; 18 | int mic_value; 19 | 20 | }; 21 | 22 | // buildin_mic buildin_mic; 23 | #endif -------------------------------------------------------------------------------- /src/sensors/grove_sgp30_sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "grove_sgp30_sensor.h" 2 | #include "Arduino.h" 3 | #include "SensorsUtils.h" 4 | 5 | grove_sgp30_sensor::grove_sgp30_sensor() { } 6 | void grove_sgp30_sensor::init() { 7 | if (is_connected) { 8 | sgp30.begin(softwarei2c); 9 | sgp30.initAirQuality(); 10 | } 11 | } 12 | 13 | bool grove_sgp30_sensor::read(struct sensor_data *sdata) { 14 | /* check out connection */ 15 | if (!I2C_Detect(grove_i2c_addr[S_SGP30], softwarei2c)) { 16 | is_connected = false; 17 | return false; 18 | } 19 | else if (!is_connected) { // first connect 20 | is_connected = true; 21 | init(); 22 | return false; // waiting for next read 23 | } 24 | 25 | /* check out measurement */ 26 | if (sgp30.measureAirQuality() != SGP30_SUCCESS) { 27 | sdata->status = false; 28 | sgp30.initAirQuality(); 29 | } else { 30 | sdata->status = true; 31 | sgp30_value[0] = sgp30.CO2; 32 | sgp30_value[1] = sgp30.TVOC; 33 | 34 | sdata->data = sgp30_value; 35 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 36 | sdata->size = sizeof(sgp30_value); 37 | sdata->id = GROVE_SGP30; 38 | sdata->name = name; 39 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 40 | sdata->data_unit = data_unit; 41 | } 42 | return sdata->status; 43 | } 44 | 45 | const char *grove_sgp30_sensor::get_name() { 46 | return "sgp30"; 47 | } 48 | 49 | // grove_sgp30_sensor buildin_sgp30; // Serial.println("Measurement failed!"); -------------------------------------------------------------------------------- /src/sensors/grove_sgp30_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GROVE_SGP30_SENSOR_H 2 | #define __GROVE_SGP30_SENSOR_H 3 | 4 | #include "SparkFun_SGP30_Arduino_Library.h" 5 | #include "sensor.h" 6 | #include "utils.h" 7 | #include "SoftwareI2C.h" 8 | 9 | #define SGP30_SDAPIN D1 10 | #define SGP30_SCLPIN D0 11 | 12 | class grove_sgp30_sensor : public sensor_base { 13 | public: 14 | grove_sgp30_sensor(); 15 | void init(); 16 | const char *get_name(); 17 | bool read(struct sensor_data *data); 18 | bool is_connected; 19 | 20 | private: 21 | const char *name = "Gas"; 22 | const char *data_unit = "ppm,ppb"; 23 | int sgp30_value[2]; 24 | SGP30 sgp30; 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /src/sensors/grove_sht4x_sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "grove_sht4x_sensor.h" 2 | #include "Arduino.h" 3 | #include "SensorsUtils.h" 4 | #include "SoftwareI2C.h" 5 | 6 | grove_sht4x_sensor::grove_sht4x_sensor() { } 7 | void grove_sht4x_sensor::init() { 8 | if (is_connected) { 9 | sht4x.setPort(softwarei2c); 10 | sht4x.setChipType(SHT4X_CHIPTYPE_A); 11 | sht4x.setMode(SHT4X_CMD_MEAS_HI_PREC); 12 | sht4x.checkSerial(); 13 | } 14 | } 15 | 16 | bool grove_sht4x_sensor::read(struct sensor_data *sdata) { 17 | /* check out connection */ 18 | if (!I2C_Detect(grove_i2c_addr[S_SHT4X], softwarei2c)) { 19 | is_connected = false; 20 | return false; 21 | } 22 | else if (!is_connected) { // first connect 23 | is_connected = true; 24 | init(); 25 | return false; // waiting for next read 26 | } 27 | 28 | /* check out measurement */ 29 | if (sht4x.measure() != SHT4X_STATUS_OK) { 30 | sdata->status = false; 31 | } else { 32 | sdata->status = true; 33 | sht4x_value[0] = (sht4x.TcrcOK) ? (int32_t)(sht4x.TtoDegC() * 100) : 0xFF; 34 | sht4x_value[1] = (sht4x.RHcrcOK) ? (int32_t)(sht4x.RHtoPercent() * 100) : 0xFF; 35 | sdata->data = sht4x_value; 36 | sdata->data_type = SENSOR_DATA_TYPE_FLOAT; 37 | sdata->size = sizeof(sht4x_value); 38 | sdata->id = GROVE_SHT4X; 39 | sdata->name = name; 40 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 41 | sdata->data_unit = data_unit; 42 | return sdata->status; 43 | } 44 | return sdata->status; 45 | } 46 | 47 | const char *grove_sht4x_sensor::get_name() { 48 | return "sht4x"; 49 | } 50 | -------------------------------------------------------------------------------- /src/sensors/grove_sht4x_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GROVE_SHT4X_SENSOR_H 2 | #define __GROVE_SHT4X_SENSOR_H 3 | #include "SHT4x.h" 4 | #include "sensor.h" 5 | #include "utils.h" 6 | #include "SoftwareI2C.h" 7 | 8 | #define SHT4X_SDAPIN D1 9 | #define SHT4X_SCLPIN D0 10 | 11 | class grove_sht4x_sensor : public sensor_base 12 | { 13 | public: 14 | grove_sht4x_sensor(); 15 | const char *get_name(); 16 | void init(); 17 | bool read(struct sensor_data *data); 18 | bool is_connected; 19 | 20 | private: 21 | const char *name = "T_H"; 22 | const char *data_unit = "C,%RH"; 23 | int sht4x_value[2]; 24 | SHT4x sht4x; 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /src/sensors/grove_soil_sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "grove_soil_sensor.h" 2 | #include "SensorsUtils.h" 3 | 4 | grove_soil_sensor::grove_soil_sensor() { 5 | } 6 | void grove_soil_sensor::init() { 7 | is_available = (Grove_I2C_Check(softwarei2c)) ? false : true; 8 | } 9 | 10 | bool grove_soil_sensor::read(struct sensor_data *sdata) { 11 | uint16_t sum = 0, data[READ_NUM] = {0}; 12 | double variance = 0.0; 13 | init(); 14 | if (!is_available) { 15 | return false; 16 | } 17 | analogRead(SOILPIN); 18 | delay(2); 19 | // sum 20 | for (int i = 0; i < READ_NUM; i++) { 21 | data[i] = analogRead(SOILPIN); 22 | delayMicroseconds(2); 23 | sum += data[i]; 24 | } 25 | //Find the variance 26 | for (int i = 0; i < READ_NUM; i++) { 27 | variance = variance + pow(data[i] - sum / READ_NUM, 2); 28 | } 29 | variance = variance / READ_NUM; 30 | 31 | if (variance > DATA_VARIANCE_MAX || sum / READ_NUM > SOIL_DATA_MAX) 32 | return false; 33 | soil_value = sum / READ_NUM; 34 | sdata->data = &soil_value; 35 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 36 | sdata->size = sizeof(soil_value); 37 | sdata->id = GROVE_SOIL; 38 | sdata->name = name; 39 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 40 | sdata->data_unit = data_unit; 41 | sdata->status = true; 42 | return true; 43 | } 44 | 45 | const char *grove_soil_sensor::get_name() { 46 | return "soil"; 47 | } 48 | 49 | // grove_soil_sensor buildin_soil; // Serial.println("Measurement failed!"); -------------------------------------------------------------------------------- /src/sensors/grove_soil_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GROVE_SOIL_SENSOR_H 2 | #define __GROVE_SOIL_SENSOR_H 3 | 4 | #include "sensor.h" 5 | #include "utils.h" 6 | #include "Arduino.h" 7 | #include "SoftwareI2C.h" 8 | 9 | #define SOILPIN A0 10 | #define READ_NUM 10 11 | #define SOIL_DATA_MAX 1000 12 | #define DATA_VARIANCE_MAX 20 13 | #define SOFTWRIE_SDAPIN D1 14 | #define SOFTWRIE_SCLPIN D0 15 | 16 | class grove_soil_sensor : public sensor_base { 17 | public: 18 | grove_soil_sensor(); 19 | void init(); 20 | const char *get_name(); 21 | bool read(struct sensor_data *data); 22 | bool is_available; 23 | 24 | private: 25 | const char *name = "Soil"; 26 | const char *data_unit = " "; 27 | int soil_value; 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /src/sensors/grove_visionai_sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "grove_visionai_sensor.h" 2 | #include "Arduino.h" 3 | #include "SensorsUtils.h" 4 | 5 | Visionai::Visionai() : Thread("Visionai", 256, 1) { 6 | } 7 | 8 | void Visionai::pushlog(const char *msg) { 9 | log_data log; 10 | strcpy(log.data, msg); 11 | log.time = millis(); 12 | if (ai_log.size() > LOG_MAX_SIZE) { 13 | ai_log.erase(ai_log.begin()); 14 | } 15 | ai_log.push_back(log); 16 | } 17 | 18 | void Visionai::Run() { 19 | char log[32]; 20 | // softwarei2c.begin(VISIONAI_SDAPIN, VISIONAI_SCLPIN); 21 | ai.begin(ALGO_OBJECT_DETECTION, MODEL_EXT_INDEX_1); // Object detection and externel model 1 22 | while (true) { 23 | uint32_t tick = millis(); 24 | if (ai.invoke()) // begin invoke 25 | { 26 | while (1) // wait for invoking finished 27 | { 28 | CMD_STATE_T ret = ai.state(); 29 | if (ret == CMD_STATE_IDLE) { 30 | break; 31 | } else if (ret == CMD_STATE_ERROR) { 32 | pushlog("Vision Ai is disconnect."); 33 | status = false; 34 | goto next; 35 | } 36 | Delay(Ticks::MsToTicks(100)); 37 | } 38 | dsize = ai.get_result_len(); // receive how many people detect 39 | if (dsize > 0 && dsize <= MAX_DETECTION) { 40 | int time1 = millis() - tick; 41 | sprintf(log, "Time consuming: %d", time1); 42 | pushlog(log); 43 | sprintf(log, "Number of people: %d", dsize); 44 | pushlog(log); 45 | object_detection_t g_data; // get data 46 | for (int i = 0; i < dsize; i++) { 47 | sprintf(log, "Detecting and calculating: %d", i + 1); 48 | pushlog(log); 49 | ai.get_result(i, (uint8_t *)&g_data, sizeof(object_detection_t)); // get result 50 | data[i] = (g_data.confidence < 100) ? g_data.confidence : 100; 51 | sprintf(log, "confidence: %d", data[i]); 52 | pushlog(log); 53 | } 54 | } else { 55 | dsize = 0; 56 | data[0] = 0; 57 | pushlog("No identification"); 58 | } 59 | status = true; 60 | } else { 61 | pushlog("Vision Ai is disconnect."); 62 | status = false; 63 | } 64 | next: 65 | Delay(Ticks::MsToTicks(SENSOR_READ_DELAY)); 66 | } 67 | } 68 | 69 | grove_visionai_sensor::grove_visionai_sensor() { 70 | visionai = new Visionai(); 71 | } 72 | void grove_visionai_sensor::init() { 73 | visionai->Start(); 74 | // if (is_connected) { 75 | // ai.begin(ALGO_OBJECT_DETECTION, MODEL_EXT_INDEX_1); 76 | // } 77 | } 78 | 79 | bool grove_visionai_sensor::read(struct sensor_data *sdata) { 80 | /* check out connection */ 81 | // if (!I2C_Detect(grove_i2c_addr[S_VISION], softwarei2c)) { 82 | // is_connected = false; 83 | // return false; 84 | // } else if (!is_connected) { // first connect 85 | // is_connected = true; 86 | // init(); 87 | // return false; // waiting for next read 88 | // } 89 | 90 | sdata->size = visionai->dsize * sizeof(visionai->data[0]); 91 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 92 | sdata->data = &visionai->data; 93 | sdata->id = GROVE_VISIONAI; 94 | sdata->name = name; 95 | sdata->status = visionai->status; 96 | sdata->ui_type = SENSOR_UI_TYPE_AVERAGE; 97 | sdata->data_unit = data_unit; 98 | grove_visionai_sensor::slog = visionai->ai_log; 99 | return sdata->status; 100 | } 101 | 102 | const char *grove_visionai_sensor::get_name() { 103 | return "visionai"; 104 | } 105 | 106 | // grove_visionai_sensor buildin_visionai; -------------------------------------------------------------------------------- /src/sensors/grove_visionai_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GROVE_VISIONAI_SENSOR_H 2 | #define __GROVE_VISIONAI_SENSOR_H 3 | 4 | #include "Seeed_Arduino_GroveAI.h" 5 | #include "SoftwareI2C.h" 6 | #include "SensorsUtils.h" 7 | #include "SysConfig.h" 8 | #include "sensor.h" 9 | #include 10 | #include 11 | 12 | using namespace cpp_freertos; 13 | 14 | #define VISIONAI_SDAPIN D1 15 | #define VISIONAI_SCLPIN D0 16 | #define MAX_DETECTION 10 17 | 18 | class Visionai : public Thread { 19 | 20 | public: 21 | Visionai(); 22 | int data[20]; 23 | uint8_t dsize; 24 | bool status; 25 | std::vector ai_log; 26 | // SoftwareI2C softwarei2c; 27 | GroveAI ai = GroveAI(softwarei2c); 28 | 29 | protected: 30 | virtual void Run(); 31 | void pushlog(const char *msg); 32 | }; 33 | 34 | class grove_visionai_sensor : public sensor_base { 35 | public: 36 | grove_visionai_sensor(); 37 | void init(); 38 | const char *get_name(); 39 | bool read(struct sensor_data *data); 40 | bool is_connected; 41 | 42 | private: 43 | const char *name = "Vision"; 44 | const char *data_unit = "count,%"; 45 | int visionai_value[20]; 46 | Visionai *visionai; 47 | // GroveAI ai = GroveAI(softwarei2c); 48 | }; 49 | 50 | #endif -------------------------------------------------------------------------------- /src/sensors/grove_vl53l0x_sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "grove_vl53l0x_sensor.h" 2 | #include "Arduino.h" 3 | #include "SensorsUtils.h" 4 | #include "SoftwareI2C.h" 5 | 6 | grove_vl53l0x_sensor::grove_vl53l0x_sensor() { } 7 | void grove_vl53l0x_sensor::init() { 8 | if (is_connected) { 9 | VL53L0X_Error ret = VL53L0X_ERROR_NONE; 10 | ret = VL53L0X.VL53L0X_common_init(); 11 | ret = VL53L0X.VL53L0X_high_accuracy_ranging_init(); 12 | // VL53L0X.VL53L0X_high_speed_ranging_init(); 13 | // VL53L0X.VL53L0X_long_distance_ranging_init(); 14 | // VL53L0X.VL53L0X_single_ranging_init(); 15 | if (ret != VL53L0X_ERROR_NONE) 16 | LOGSS.printf("init failed, error code: %d\r\n", ret); 17 | } 18 | } 19 | 20 | bool grove_vl53l0x_sensor::read(struct sensor_data *sdata) { 21 | /* check out connection */ 22 | if (!I2C_Detect(grove_i2c_addr[S_VL53LX0], softwarei2c)) { 23 | is_connected = false; 24 | return false; 25 | } 26 | else if (!is_connected) { // first connect 27 | is_connected = true; 28 | init(); 29 | return false; // waiting for next read 30 | } 31 | 32 | /* check out measurement */ 33 | VL53L0X_RangingMeasurementData_t range_data; 34 | VL53L0X_Error ret = VL53L0X.PerformSingleRangingMeasurement(&range_data); 35 | if (ret != VL53L0X_ERROR_NONE) { 36 | LOGSS.printf("mesurement failed, error code : %d\r\n", ret); 37 | memset(&range_data, 0, sizeof(VL53L0X_RangingMeasurementData_t)); 38 | sdata->status = false; 39 | } else { 40 | vl53l0x_value = range_data.RangeMilliMeter; 41 | if (vl53l0x_value > 2000) { 42 | vl53l0x_value = 2000; 43 | // LOGSS.println("VL53L0X : out of range"); 44 | } 45 | sdata->data = &vl53l0x_value; 46 | sdata->data_type = SENSOR_DATA_TYPE_INT32; 47 | sdata->size = sizeof(vl53l0x_value); 48 | sdata->id = GROVE_VL53L0X; 49 | sdata->name = name; 50 | sdata->ui_type = SENSOR_UI_TYPE_NORMAL; 51 | sdata->data_unit = data_unit; 52 | sdata->status = true; 53 | } 54 | return sdata->status; 55 | } 56 | 57 | const char *grove_vl53l0x_sensor::get_name() { 58 | return "vl53l0x"; 59 | } -------------------------------------------------------------------------------- /src/sensors/grove_vl53l0x_sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GROVE_VL53L0X_SENSOR_H 2 | #define __GROVE_VL53L0X_SENSOR_H 3 | #include "Seeed_vl53l0x.h" 4 | #include "sensor.h" 5 | #include "utils.h" 6 | #include "SoftwareI2C.h" 7 | 8 | #define VL53L0X_SDAPIN D1 9 | #define VL53L0X_SCLPIN D0 10 | 11 | class grove_vl53l0x_sensor : public sensor_base 12 | { 13 | public: 14 | grove_vl53l0x_sensor(); 15 | const char *get_name(); 16 | void init(); 17 | bool read(struct sensor_data *data); 18 | bool is_connected; 19 | private: 20 | const char *name = "Distance"; 21 | const char *data_unit = "mm"; 22 | int vl53l0x_value; 23 | 24 | Seeed_vl53l0x VL53L0X; 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /tools/K1100-decoder.js: -------------------------------------------------------------------------------- 1 | function Decoder(bytes, port) { 2 | 3 | var decoded = {}; 4 | 5 | function transformersint(bytes){ 6 | value = bytes[0] * 256 + bytes[1]; 7 | if (value == 32768){ 8 | return; 9 | } 10 | if (value > 32768) { 11 | value = 32768 - value; 12 | } 13 | value = value; 14 | return value; 15 | } 16 | 17 | function transformersfloat(bytes){ 18 | value = bytes[0] * 256 + bytes[1]; 19 | if (value == 32768){ 20 | return; 21 | } 22 | if (value > 32768) { 23 | value = 32768 - value; 24 | } 25 | value = value; 26 | return value/100; 27 | } 28 | 29 | function transformersAI(bytes){ 30 | value = bytes[0]; 31 | if (value == 255 || value >100){ 32 | return; 33 | } 34 | return value; 35 | } 36 | 37 | if (port == 3) { 38 | if(bytes[0]==0x40) { 39 | decoded.light = transformersint(bytes.slice(1, 3)); 40 | decoded.mic = transformersint(bytes.slice(3, 5)); 41 | decoded.imux = transformersfloat(bytes.slice(5, 7)); 42 | decoded.imuy = transformersfloat(bytes.slice(7, 9)); 43 | decoded.imuz = transformersfloat(bytes.slice(9, 11)); 44 | } 45 | if(bytes[0]==0x42) { 46 | decoded.temp = transformersfloat(bytes.slice(1, 3)); 47 | decoded.humi = transformersfloat(bytes.slice(3, 5)); 48 | decoded.voc = transformersint(bytes.slice(5, 7)); 49 | decoded.co2 = transformersint(bytes.slice(7, 9)); 50 | decoded.soil = transformersint(bytes.slice(9, 11)); 51 | } 52 | if(bytes[0]==0x44) { 53 | decoded.confidence_1 = transformersAI(bytes.slice(2)); 54 | decoded.confidence_2 = transformersAI(bytes.slice(4)); 55 | decoded.confidence_3 = transformersAI(bytes.slice(6)); 56 | decoded.confidence_4 = transformersAI(bytes.slice(8)); 57 | decoded.confidence_5 = transformersAI(bytes.slice(10)); 58 | } 59 | 60 | } 61 | 62 | return decoded; 63 | } --------------------------------------------------------------------------------