目录

English | 简体中文


iot-device-sdk-cSharp开发指南

**在开始使用SDK其它功能之前,我们建议先阅读准备工作快速体验**。同时,本文档中各个功能都有对应的demo演示,后面每个介绍功能的章节最前面会有一个包含Demo源码,Demo名称名称的列表,示例如下:

Demo源码可以供您参考API使用的细节,Demo名称用于在配置文件里指定运行哪个Demo,具体如何使用Demo名称运行不同的Demo可参考后面的配置与启动demo的第二步。


">
">📌 TransmittableThreadLocal(TTL)
  • 🔧 功能
  • 🎨 需求场景
  • 👥 User Guide
  • 🔌 Java API Docs
  • 🍪 Maven依赖
  • 🔨 关于编译构建
  • ❓ FAQ
  • ✨ 使用TTL的好处与必要性
  • 🗿 更多文档
  • 📚 相关资料
  • 💗 Who Used
  • 👷 Contributors
  • Open-Source iOS Apps
  • libyara.NET
  • Hasura GraphQL Engine
  • node-firefox-build-tools
  • Node.js, auf Deutsch!
  • Overview
  • [EOL] Node API
  • Usergrid .NET SDK
  • QMUI iOS
  • Málaga Parking Data
  • Qakka
  • use-emotion-css
  • Visual Studio Setup Configuration Samples
  • 📊 GitHub Stats:
  • THUPC2026初赛
  • Hyperledger Fabric Packages for Go Chaincode
  • windows2019fs-release
  • Attention Please
  • 温馨提示
  • Beyond Closed-Pool Video Retrieval: A Benchmark and Agent Framework for Real-World Video Search and Moment Localization
  • ExtensionPointApi
  • extension-point-api
  • Rust support for Visual Studio Code (deprecated)
  • This extension is no longer maintained.
  • openapi 使用说明
  • Lunettes - Container Lifecycle Observability Service
  • Amazon IVS React Native Player
  • Outage Processing Tools
  • iojs-ms
  • BlockFramework
  • Sync_Bridge32
  • TensorRT Backend For ONNX
  • Installation
  • Repo2Run
  • #
  • #
  • Velocity Spring Boot Project
  • MakeFilm - AI 驱动的视频创作工作流
  • spring-boot-cnb
  • iojs-ta
  • iojs-vi
  • test-certs-site
  • linkerd examples
  • Modeling_Analysis
  • example-with-valtio
  • ISS Data
  • A writer for object file ar archives
  • Overview
  • Usage
  • Contact Information
  • Wayne 后端插件仓库
  • A Certifier Process for BrowserID
  • amazon-vpc-resource-controller-k8s
  • Zephyr Example Application
  • proxy-test
  • DM Kit 快速上手
  • Aliyun Ansible Modules Documentation
  • edp-cli
  • fluent-package-builder
  • jvm-application-cnb
  • 🌐 ETHEREUM ARBITRAGE-BOT PROFITABILITY ANALYSIS
  • Prometheus Ruby Client
  • Keychain Minder
  • MatxScript
  • Webpack Inspector
  • JavaScript Exercises
  • fscryptctl
  • sofa-lookout-node
  • iojs-bg
  • Frontend_Assets24
  • Spring Boot 学习示例
  • Important notice of archive
  • percy-node
  • Cloud Controller API v3 Style Guide
  • saber-data Build Status
  • libtest - Rust’s built-in unit-testing and benchmarking framework
  • RingMo-Framework
  • AstronClaw & Loomy 教程 🦞
  • libnetwork - networking for containers
  • PCG-第一次作业
  • AppNet_01
  • Apache ODE Console
  • tsunami-script
  • Jenkins X EKS Module
  • jx-environment-operator
  • 部署华为云容器实例CCI Workflow样例
  • Java SDK
  • Helm Acceptance Tests
  • puppet-kitchen
  • Weather Data Collector
  • PC2-NoiseofWeb
  • param_runner
  • 🌐 MemeBot MakaLive — Dashboard Público
  • TeeApps
  • please replace params
  • please replace params
  • log4net
  • Introduction
  • Documentation
  • Contributing
  • Developing
  • AWS Logging .NET
  • also
  • UsageFlow Go Middleware
  • GMPReachSDK
  • This repository has been migrated to https://github.com/mozilla/fxa/tree/master/packages/fxa-js-client
  • OpSec Puppet
  • Action Development Kit (ADK)
  • 🌍 We are Fuji Script
  • AMD Analyzer
  • Apache Karaf Wicket WebConsole
  • 新手指导 👈🏻
  • AutoBuildImmortalWrt
  • 🌟鸣谢
  • What the f*ck JavaScript?
  • Node Packaged Manuscript
  • Translations
  • Table of Contents
  • 💪🏻 Motivation
  • ✍🏻 Notation
  • 👀 Examples
  • 📚 Other resources
  • 🤝 Supporting
  • 🎓 License
  • DataX
  • DataX 商业版本
  • Features
  • DataX详细介绍
  • Quick Start
  • Support Data Channels
  • 阿里云DataWorks数据集成
  • 我要开发新的插件
  • 重要版本更新说明
  • 项目成员
  • License
  • 开源版DataX企业用户
  • helldivers-war-status
  • SPIRV-Registry
  • veScale Documentation
  • tw_main
  • gh-release
  • Nuid.js
  • ⚙ 自建汇聚订阅 CF-Workers-SUB
  • 🙏 致谢
  • Prompt Engineering Guide
  • 欢迎来到The Art of Git!
  • 介绍
  • 引擎类型
  • 下载
  • 编译和安装部署
  • 示例和使用指引
  • 文档&视频
  • 架构概要
  • 贡献
  • 联系我们
  • 谁在使用 Linkis
  • v1.8.0
  • edp-bcs
  • curl logo
  • deepdream
  • jello-command-install
  • Cacao Kit (Frontend)
  • nanoCore
  • svg-mixed-loader
  • QMQ
  • JDK最低版本要求
  • Maven
  • 快速开始
  • 技术支持
  • 开源协议
  • 用户(已经在生产使用)
  • Stars History
  • 生成式思维与知识工作流
  • A convention for Objective-C libraries
  • TRL - Transformers Reinforcement Learning
  • Current Time in Various Time Zones
  • SimpleRestClients
  • 装载分词模型
  • 单个样本输入,输入为Unicode编码的字符串
  • 批量样本输入, 输入为多个句子组成的list,平均速率会更快
  • 装载LAC模型
  • 单个样本输入,输入为Unicode编码的字符串
  • 批量样本输入, 输入为多个句子组成的list,平均速率更快
  • 装载词语重要性模型
  • 单个样本输入,输入为Unicode编码的字符串
  • 批量样本输入, 输入为多个句子组成的list,平均速率会更快
  • 装载干预词典, sep参数表示词典文件采用的分隔符,为None时默认使用空格或制表符’\t’
  • 干预后结果
  • 选择使用默认的词法分析模型
  • 训练和测试数据集,格式一致
  • 使用自己训练好的模型
  • Usergrid Swift SDK
  • yl_yy
  • Welcome to your Expo app 👋
  • Collusion Server Zero
  • Amazon Lightsail CLI Extensions
  • client-share-web
  • PUPPET-MOCK
  • CyberChef
  • @umijs/test-utils
  • AndFix
  • MUYUN
  • 阿里巴巴开放平台
  • Shmipc规范
  • SONA Overview
  • bedtools - the swiss army knife for genome arithmetic
  • [高软第八组] 智能代码分析器 (Smart Code Analyzer)
  • Neurodocker
  • Installation
  • Developer installation
  • Monopogen: SNV calling from single cell sequencing data
  • Fluent Bit Python Integration Test Suite
  • mysqlclient
  • Github代码自动Commit
  • Plato(柏拉图)
  • MessagePack Code Generator Build Status
  • GraphMB: Assembly Graph Metagenomic Binner
  • Introduction
  • SchurVINS
  • 5. Reproducibility
  • 6. Security
  • 7. Acknowledgement
  • 8. Citation
  • 9. We are Hiring!
  • habits-tracker
  • React · GitHub license npm version (Runtime) Build and Test (Compiler) TypeScript PRs Welcome
  • Automated-Commit
  • CONSENT
  • TASSL
  • DepotSample服务说明文档
  • Gallery Maker
  • #
  • #
  • #
  • CRoaring
  • Introduction
  • Objective
  • Requirements
  • Using as a CMake dependency
  • Amalgamation/Unity Build
  • API
  • Dealing with large volumes
  • Custom memory allocators
  • Example (C)
  • Example (C++)
  • Building with cmake (Linux and macOS, Visual Studio users should see below)
  • Building (Visual Studio under Windows)
  • AVX2-related throttling
  • Thread safety
  • How to best aggregate bitmaps?
  • Wrappers
  • Mailing list/discussion group
  • References about Roaring
  • MuSE
  • Kubernetes Release Tooling
  • BuboGPT: Enabling Visual Grounding in Multi-Modal LLMs
  • diffviewer
  • ">oncokb-annotator
  • formatR
  • 🤖 Minecraft AFK Bot (Mineflayer-Based)
  • Plasmid Copy Number Estimator
  • BinLorry
  • Automation + Tools Mozmill Repository
  • 123456
  • Visual Studio Locator
  • go-scm
  • fallback
  • ByteX(Infinite Possibilities)
  • public
  • Table of Contents
  • ViewBS
  • redisclient
  • auto-green
  • Guava: Google Core Libraries for Java
  • saber-dom Build Status
  • Apache Bloodhound
  • reCOGnizer
  • StyleExpert
  • PUPPET-WALNUT
  • Ant Design Pro For VSCode
  • Quickstart install
  • Ghost sponsors
  • Getting help
  • License & trademark
  • NATS Chocolatey Packaging
  • @umijs/route-utils
  • bd_token
  • Prodigal
  • Dominate
  • Examples
  • fis 解决方案
  • auto-green
  • 📊 GitHub Stats:
  • CNAI Model Format Specification
  • xgplayer-examples
  • ⚠️ This project has changed ownership
  • Metaserver
  • Primus
  • Qpid C++
  • Introduction
  • Performance
  • Building
  • Usage
  • Tests and benchmarks
  • Contributing to the Snappy Project
  • Contact
  • PXMeter - Structural Quality Assessment for Biomolecular Structure Prediction Models
  • You-Get
  • Security Special Interest Group
  • Facebook Business SDK for Java
  • fq
  • @eggjs/utils
  • FlutterGo
  • task.js
  • Contributing
  • Knover
  • Trusted Language Extensions for PostgreSQL (pg_tle)
  • Keyhouse
  • Example component for testing Konflux
  • HaplotagLR
  • The Go Programming Language
  • cuteFC
  • 201548300108042
  • 📈 Bot for Passive Income — My Experiment
  • lhs
  • Hyperledger FireFly Transaction Manager
  • Persistence
  • Configuration
  • Automated-Commit
  • san-validation
  • @umijs/assets
  • ZFP
  • SSE-Kit
  • JHEY
  • JD Chain SDK-Go
  • Overview
  • Mgcod
  • Summary
  • Setup
  • Example
  • Overview
  • More Examples
  • Documentation
  • Contributing
  • License
  • Contact Info
  • Nextstrain CLI
  • ">AzureGraph
  • opticlust
  • Installation
  • Tutorial output
  • Advantages of opticlust
  • Acknowledgements
  • How to cite
  • CamoFormer: Masked Separable Attention for Camouflaged Object Detection

  • 🎭 Playwright
  • getPass
  • Edgeone Keyless Server
  • mlstdb
  • ☕ Project Caffeine 项目
  • Cannoli
  • Urtopia US Shopify Theme - Developer Guide
  • Statsig’s Open-Source Status Page
  • iSeq: An integrated tool to fetch public Sequencing data
  • Weather API Status
  • MAGpurify
  • bold_identification
  • Auto Kernel Generator (AKG)
  • Synapse Python Client
  • ggimage: Use Image in ‘ggplot2’
  • CRISPR Comparison ToolKit (CCTK)
  • Flye assembler
  • Flye 2.9.6 release (2 May 2025)
  • Flye 2.9.5 release (27 Aug 2024)
  • Flye 2.9.4 release (14 May 2024)
  • CFL
  • decoupler - Ensemble of methods to infer enrichment scores
  • #
  • 1.1.0 (2022-07-05)
  • chiton
  • SE Office crx
  • scala-wechaty
  • hooks
  • Apollo Core Workspace
  • AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  • DreamO
  • MSTmap C++
  • The Rust Edition Guide
  • KornShell 93u+m
  • NorthStar - Prototyping Design System
  • Long-read Isoform Quantification and Analysis
  • NATS Steampipe Plugin
  • Minion
  • rhysdh540
  • thelaboratory.cc
  • CORSID
  • Queues.io
  • Developing
  • Deployment
  • Contributing
  • BayesTyper
  • fastcap
  • LongReadSum: A fast and flexible QC tool for long read sequencing data
  • README Contents
  • Installation using Anaconda
  • Installation using Docker
  • Building from source
  • MultiQC support
  • General Usage
  • Common parameters
  • WGS BAM
  • BAM with base modifications
  • RRMS BAM
  • RNA-Seq BAM
  • PacBio unaligned BAM
  • ONT POD5
  • ONT FAST5
  • Basecall summary
  • FASTQ
  • FASTA
  • Revision history
  • Getting help
  • Citing LongReadSum
  • #
  • sidecar-demos
  • ">ijtiff
  • gfw-toolkit
  • CellTypist website
  • Interactive tutorials
  • Install CellTypist
  • Usage (classification)
  • Citation
  • Hi my name is Kasemtan(Float)
  • Titan-Dex字节码操作框架
  • Get started building your personal website
  • auto-external-packages
  • About This Anvil App
  • GraphQL OpenTelemetry Working Group
  • gdata
  • cassis.js
  • ALFA: Annotation Landscape For Aligned reads
  • standard-redux-shape
  • Bamboo Soy for IntelliJ 🏮🍣🏮
  • refgenieserver
  • Popera
  • docs-credhub
  • fansi - ANSI Control Sequence Aware String Functions
  • Shipshape sample repository
  • Galah
  • egg-dingtalk
  • LinkCheckMD
  • ModelGavel
  • umi-notify
  • Bifrost
  • include <bifrost/CompactedDBG.hpp>
  • include <bifrost/ColoredCDBG.hpp>
  • 👋 Olá! Eu sou o Pedro Chaves
  • R package rBLAST - R Interface for the Basic Local Alignment Search Tool
  • mpich-yarn
  • Introduction
  • Compile
  • Configuation
  • Submit Jobs
  • Project SovereignNAS Status Dashboard
  • Awesome Stars Awesome
  • egg-view-vue
  • egg-sofa-antvip
  • dashboardthemes
  • kde1d
  • driftline_442X
  • The NCBI SRA (Sequence Read Archive)
  • Radiantkit
  • IsoTree
  • Description
  • Comparison against other libraries
  • Non-random splits
  • Different outlier scoring criteria
  • Distance / similarity calculations
  • Imputation of missing values
  • Highlights
  • Installation
  • Examples
  • Documentation
  • Reducing library size and compilation times
  • References
  • edpx-bat-ria
  • AWS X-Ray Daemon
  • snp2cell
  • Automated-Commit
  • netlify-slack
  • go-orchestrator
  • cirtap
  • aquila :eagle:"> Aquila :eagle:
  • Install through Bioconda (The latest version 1.0.0):
  • Install through Github:
  • Assembly for multiple libraries:
  • 《智能体工程与知识工作流》课程体系说明
  • 本仓库已经弃用,请访问最新的仓库:https://github.com/terraform-providers/terraform-provider-alicloud
  • 利用Terraform创建/配置Aliyun资源
  • vie-oj-fe
  • LepWrap
  • metabolights utils library">Metabolights MetaboLights Utils Library
  • fabric-x-evm
  • R Markdown Reimagined
  • auto-green
  • 欢迎来到The Art of Git!
  • build
  • InDelFixer
  • saber-showcase
  • kmer2stats
  • Input
  • Output
  • Tair KVCache
  • 联系我们
  • blue-crab
  • WARNING
  • Example comparison
  • Notes
  • Acknowledgement
  • Citation
  • GVCF2BED
  • DEPRECATED: you should use mhcgnomes instead
  • mhcnames
  • EPIC package
  • Introduction
  • contamMix
  • Deep-Learning学习笔记
  • 深度学习在图像处理中的应用教程
  • StemCNV-check
  • MaAsLin 3
  • DeepSeek 实用集成 Awesome
  • HAYSTAC: A Bayesian framework for robust and rapid species identification in high-throughput sequencing data
  • Amazon EKS Pod Identity agent
  • Python Typing Council
  • Overview
  • Why and When to use Corekaburra
  • Installation
  • Help
  • Example workflow
  • Inputs
  • Outputs
  • For more info
  • Bug reporting and feature requests
  • Licence
  • BaitFisher-package: Design DNA hybrid enrichment baits
  • RIAssigner
  • Resources and Packages
  • Development Guide
  • License
  • bambamc
  • Unified Post Processor (UPP)
  • Camunda 8 Helm
  • seaborn: statistical data visualization
  • VirAmp-Hub
  • The new CDN, powered by GitHub Actions
  • blastn2dotplots
  • Hi, I’m Henrique Arantes! Welcome to my probably outdated profile
  • Overview
  • Usage
  • Documentation
  • Bugs
  • VCF2Genome
  • Basic Usage description
  • gargammel: simulations of ancient DNA datasets
  • Excel and container images for DRA/JGA/AGD metadata XML submissions
  • 第五届Jittor挑战赛热身赛-生成手写数字baseline(CGAN)
  • UpSetR
  • Tree Transformer
  • Hola a todos…
  • PertFormer
  • Purpose
  • Quick start
  • Requirements and Installation
  • Input
  • Output
  • Usage guidelines
  • Time and memory footprint
  • Citation & Getting help
  • Pontoon Intro
  • GoogleTest
  • 🗝️🔒 TikTok Viewer Bot - TikTok Engagement Enhancer
  • Anise & Basil
  • Next AI Draw.io
  • AWS DynamoDB Trace Listener
  • EnviroAmpDesigner
  • smed_reu_ipnyb
  • auto-green
  • UF2 Bootloader
  • service-broker-store
  • Contributing
  • Working Group Charter
  • NCBI Datasets
  • LISI
  • PCM
  • legacy-cloud-providers
  • ncmaps
  • Buck2 Prelude
  • TenneT AFRR Bid Ladder Archive
  • 《智能体工程与知识工作流》课程体系说明
  • aroma.core: Core Methods and Classes Used by ‘aroma.*’ Packages Part of the Aroma Framework
  • undici-website
  • Smart Home Agent - OpenVela 智能家居控制系统
  • GMAIL MAKER BOTV2
  • Tools 🚀
  • SETUP 🎨
  • SETUP NOTE 🤖
  • NOTE 💡
  • Working ON?
  • #
  • PSI Spectral Library format - Python implementation
  • ">piawka
  • Installation
  • Usage
  • Citation
  • Hyperledger Fabric Client SDK for Go
  • Snapshot Restore for Python
  • Chatbot 1 to 2
  • resolvers.txt
  • Skeleton Engine Template
  • socorro-infra (public)
  • Default manifest
  • Socorro module
  • Building a Buildbox
  • Long-running services
  • ClermonTyping: an easy-to-use and accurate in silico method for Escherichia genus strain phylotyping
  • Automation Inspector
  • DataRangers
  • LHSC Wait Times
  • BYOL WebService
  • Overview
  • Configuration
  • OpenStack Dashboard Intergation
  • psychology
  • MARS
  • genomic_regions: consistent handling of intervals in genome coordinates
  • knn.covertree
  • about:home snippets server switcher
  • Chatbot Zero to ONE
  • RedHatDev 博客中文翻译
  • terraform-scalr-flat
  • 智能用户数据管理
  • DataRangers SDK - mp
  • 文件存储(FDS)Android SDK使用介绍
  • FDS Android SDK User Guide
  • Welcome to Apache ServiceMix NMR
  • Getting Started
  • JetStream-LeafNodes-Demo
  • QuizRace
  • Datenbankparameter setzen (Beispielwerte)
  • Schema importieren
  • gvcfgenotyper
  • Custom Go Plugin for Jaeger
  • jenkins-x-schemas
  • 《智能体工程与知识工作流》课程体系说明
  • otus-sunia-house
  • kg
  • PredictionIO Swift SDK
  • WindTerm
  • License
  • Introduction
  • Download
  • Source Code
  • Issues and feature requests
  • Screenshots
  • Features
  • Sftp Performance
  • Terminal Performance
  • Linux Terminal Performance
  • Latency
  • Shortcuts
  • Roadmap
  • Roadmap of v2.7 (February 2025, for reference only)
  • Acknowledgement
  • AWS IoT Device SDK for Swift
  • Volcengine Object Storage(TOS) .NET SDK
  • my_testrep
  • caebzo-weather-station-webscrape
  • Website Healthcheck Status
  • ossean-2
  • '>ggsignif: Significance Brackets for ‘ggplot2’
  • HISAT2-pipeline DOI
  • Apache Teaclave™ SGX SDK
  • TheNewStack 博客中文翻译
  • readminote
  • Hamburg Waiting Time Airport History
  • Nokia In-App Payment API samples for Nokia X
  • grunt-i18n-abide
  • About This Anvil App
  • ant-design-landing-build
  • UW Badminton Calendar 🏸
  • ProtoBuf
  • 使用方式(三种方式)
  • 改动功能
  • 当前版本 22.2.0
  • 使用文档
  • feature-preserve-portrait-editing
  • 百度云大模型内容安全MCP Server
  • 🚀 ComfyUI Lumi Batcher
  • FireFly Tokens Microservice for ERC20 & ERC721
  • golang_kits
  • chromVARmotifs
  • 《智能体工程与知识工作流》课程体系说明
  • NCBI Datasets
  • License
  • Release Notes
  • Documentation
  • Backwards Compatibility
  • Installation
  • Testing
  • Examples
  • Known Issues
  • Troubleshooting
  • Participate!
  • RLstduy
  • ExtractAdaptersFastqc
  • Documentation
  • About
  • Contact
  • BikeSharing360
  • BikeSharing360 Modern Kiosk with Cognitive Services
  • myelin-acorn-electron-hardware
  • MethylCIBERSORT
  • Cell type
  • 美赛(MCM/ICM*HiMCM)开源协作标准与资源库
  • iot-device-sdk-android开发指南
  • 目录
  • IRIDA SISTR Results
  • Quick Usage
  • Installation
  • Usage
  • Legal
  • 开源数学建模实战体系 | Open Modeling Mastery
  • 开源数学建模实战体系 | Open Modeling Mastery
  • Links
  • Showcase
  • Project
  • modelzoo 3.6.2
  • 开源数学建模实战体系 | Open Modeling Mastery
  • Jenkins X Azure Module
  • AWS IoT Device Shadow library
  • 欢迎来到The Art of Git!
  • AI⁺教育普惠计划 | 贡献看板
  • jittor-GG_Bond-CoraNodeClassify
  • iot-device-sdk-cSharp开发指南
  • 版本更新说明
  • 0.前言
  • 1.SDK简介
  • 2.准备工作
  • 3.快速体验
  • 4.SDK功能参考
  • 5.设备发放
  • 6.泛协议接入
  • 7.常见问题
  • 8.开源协议
  • 版本更新说明

    版本号 变更类型 功能描述说明
    1.3.4 功能增强 1.优化日志打印 2.oc开头SubscribeTopic 返回 topic 3.demo优化 4.网关接口bug修复 5. 升级目标框架。 以及其它优化
    1.3.3 新增功能 OTA升级支持网关模式
    1.3.2 功能增强 更新服务器ca证书
    1.3.1 修复 修复空指针异常,MQTT对象未释放等问题
    1.3.0 新功能 支持通过OBS升级软固件包
    1.2.0 新功能 增加泛协议功能
    1.1.1 功能增强 添加网关删除子设备功能,完善中英文描述
    1.1.0 新功能 新增网关与物模型功能
    1.0.0 第一次发布 提供基础的设备接入能力,sdk预置了设备接入地址及华为IoTDA平台配套的CA证书

    0.前言

    本文通过实例讲述iot-device-sdk-cSharp(以下简称SDK)帮助用户将设备经MQTT协议快速连接到华为IoTDA服务。

    要进一步了解本sdk中的接口对应的MQTT接口,您可以查看 用户指南

    1.SDK简介

    1.1 SDK功能支持

    SDK面向运算、存储能力较强的嵌入式终端设备,开发者通过调用SDK接口,便可实现设备与IoTDA服务(后续简出现的“服务”、“平台“均指IoTDA服务)双向行通讯。 SDK当前支持的功能有:

    功能 描述说明
    设备连接鉴权 作为客户端使用MQTT协议接入到平台。分为证书鉴权密钥鉴权两种认证方式。
    断线重连 当设备由于网络不稳定
    消息上报 用于设备将自定义数据上报给平台,平台将设备上报的消息转发给应用服务器或华为云其他云服务上进行存储和处理。
    属性上报 用于设备按产品模型中定义的格式将属性数据上报给平台。
    命令下发 用于平台向设备下发设备控制命令。平台下发命令后,需要设备及时将命令的执行结果返回给平台。
    设备影子 用于存储设备的在线状态、设备最近一次上报的设备属性值、应用服务器期望下发的配置。
    软固件(OTA)升级 用于与平台配合下载OTA升级包。
    时间同步 设备向平台发起时间同步请求。
    网关与子设备 网关设备:通过平台支持的协议,直接连接到平台的设备。子设备:针对未实现TCP/IP协议栈的设备,由于无法直接同平台通信,它需要通过网关进行数据转发。当前仅支持通过mqtt协议直连到平台的设备作为网关设备。
    文件上传/下载 支持设备将运行日志,配置信息等文件上传至平台,便于用户进行日志分析、故障定位、设备数据备份等。
    异常检测 提供安全检测能力,可持续检测设备的安全威胁。包括:1、内存泄漏检测 2、异常端口检测3、CPU使用率检测 4、磁盘空间检测 5、电池电量检测
    规则引擎 通过条件触发,基于预设的规则,引发多设备的协同反应,实现设备联动、智能控制。目前平台支持两种联动规则:云端规则和端侧规则。
    远程配置 提供远程配置功能,用户可用于在不中断设备运行的情况下,远程更新设备的系统参数、运行参数等配置信息。
    远程登录 支持通过控制台远程SSH登录设备,可在控制台输入设备支持的命令,进行功能调试及问题定位,从而方便地实现设备管理及远程运维
    泛协议接入 当非HTTP、MQTT、LWM2M等第三方协议接入时,需要在平台外部完成协议转换。推荐使用网关来完成协议转换,将第三方协议转成MQTT协议。
    设备发放 分为证书认证、密钥认证。主要用于分发到不同局点、实例的场景,动态完成不同批次设备初始化配置。

    1.1 SDK目录结构

    • iot-device-sdk-java:sdk代码
    • iot-device-demo:功能演示的demo代码
    • iot-tcp-device:用于模拟网关、网桥场景下通过tcp连接的设备demo

    2.准备工作

    3.快速体验

    本章将使用SmokeDetector Demo 指导您快速体验产品模型的创建、Demo的配置与启动、以及SDK基本功能的使用。

    3.1 创建产品模型

    为了方便体验,我们提供了一个烟感的产品模型,烟感会上报烟雾值、温度、湿度、烟雾报警、还支持响铃报警命令。 下面的子章节将以烟感为例,体验消息上报、属性上报等功能。 下面创建产品模型的流程也可以参考向导式体验智慧烟感接入平台

    1. 访问IoTDA平台并进入设备接入控制台,如果是第一次使用需要注册并登录.

    2. 登录成功后自动跳转,在设备接入控制台选择“产品”,单击右上角的“创建产品”,在弹出的页面中,填写“产品名称”、“协议类型”、“数据格式”、“厂商名称”、“所属行业”、“设备类型”等信息,然后点击右下角“立即创建”。

      • 协议类型选择“MQTT”
      • 数据格式选择“JSON”。

    3. 产品创建成功后,单击“详情”进入产品详情,在功能定义页面,单击“上传模型文件”,上传烟感产品模型

    3.2 创建设备

    1. 点击“设备”-> “所有设备”,点击右上角“注册设备”,选择产品所在的“资源空间”,选择上方创建的产品,填写设备标识码(一般是IMEI、MAC地址等),自定义“设备名称”,“密钥”如果不自定义,平台会自动生成。全部填写完毕后,点击“确定”。 img_2.png

    2. 可以直接复制设备秘钥,点击“保存并关闭”将自动将设备ID以txt文本形式下载到本地。 img_3.png

    3. 点击”设备“->“所有设备”,在最上方可看到该设备的状态是未激活。

    3.3 配置与启动Demo

    1. 获取接入地址,可在控制台的“总览”->“接入信息”中查看。 img_5.png

    2. 打开文件 iot-device-demo/config/DemoConfigDefault.json,将之前获取到的接入地址、设备ID以及设备密钥填入对应位置,或者将配置填入下面模板后再覆盖iot-device-demo/config/DemoConfigDefault.json

      {
        "DemoName": "SmokeDetector",
        "AuthConfig": {
          "AuthUseCert": false,
          "ServerAddress": "填入接入地址",
          "ServerPort": 8883,
          "DeviceId": "填入设备ID",
          "DeviceSecret": "填入设备密钥"
        }
      }

      其中DemoName用于指定运行的Demo,此处为SmokeDetector指定基于烟雾报警器产品模型的物模型编程Demo。该Sdk能运行的Demo名称可以参后面章节,几乎每一个功能点介绍的小节最前面会标注Demo名称。或者进入sdk目录下运行下面命令查看所有Demo名称列表:

      cd iot-device-demo
      dotnet run --project .\iot-device-demo.csproj

      demo_name_list

    3. 编译&运行

      进入sdk目录下,执行下面命令运行demo,命令末尾加参数为配置文件路径:

      cd iot-device-demo
      dotnet run --project .\iot-device-demo.csproj  .\config\DemoConfigDefault.json

      如果您使用旧版本5.0+的SDK并且无法升级到.NET 8.0,可以修改以下文件的TargetFramework。但请注意,目前除了.NET 8.0和.NET 6.0属于长期支持的版本外,其它更旧版版本均已不再支持

      上面使用run命令会自动编译,如果要手动编译某一个project,可以行下面命令:

      dotnet clean
      dotnet build

      输出示例如下,如果输出里有connect success则表示连接成功: img_6.png

    4. 查看设备运行情况

      在控制台筛选出该设备并进入设备详情页面 img_9.png 详情页下放”物模型数据“页面可以看到最新上报的数据 img_10.png

    4.SDK功能参考

    4.1 设备连接鉴权

    设备鉴权概述在线文档

    密钥鉴权

    密钥鉴权支持mqtt(1883)和mqtts(8883)接入,为安全起见,推荐使用8883端口接入平台。使用8883端口接入时需要用到iot-device-demo/config/certificate/DigiCertGlobalRootCA.crt.pem,该文件默认已预置各个region的根证书,如果连接不成功则尝试从这里下载对应region的pem证书并替换。

    使用Demo时时配置文件iot-device-demo/config/DemoConfigDefault.json中对应的配置项如下(无关配置项省略):

    {
      "AuthConfig": {
        "AuthUseCert": false,
        "ServerAddress": "接入地址",
        "ServerPort": 8883,
        "DeviceId": "设备Id",
        "DeviceSecret": "设备密钥"
      }
    }

    使用API实例化设备对象时参数如下:

    //                                接入地址,接入端口,设备ID,  设备密钥
    IoTDevice device = new IoTDevice("接入地址", 8883, "设备Id", "设备密钥");

    证书鉴权

    平台支持设备使用自己的X.509证书进行设备接入认证,使用前需要注册证书认证的设备并在设备接入控制台预置对应CA证书,详细指导请参考注册X.509证书认证的设备

    1. 制作完调测证书后,参考以下命令转换成pfx格式:

       openssl x509 -in deviceCert.pem -out deviceCert.crt  #先生成crt格式的证书
       openssl pkcs12 -export -out deviceCert.pfx -inkey deviceCert.key -in deviceCert.crt -certfile rootCA.pem
    2. 使用Demo时,把 iot-device-demo/config/DemoConfigDefault.json里的AuthUseCert改为true,同时DeviceCert改为生成的证书路径,示例如下:

      {
        "AuthConfig": {
          "AuthUseCert": true,
          "DeviceCert": "\config\certificate\deviceCert.pfx"
        }
      }

    示例中证书路径为config/certificate/deviceCert.pfx,部分IDE(如Rider)会在Debug文件中运行程序,您需要在iot-device-demo/CoreCapability/iot-device-demo.csproj添加一行

    <Content Include="config\certificate\deviceCert.pfx" CopyToOutputDirectory="PreserveNewest" />

    之后编译时证书也会被拷贝到Debug目录下。

    如果要程序化创建设备,可以参考iot-device-demo/DemoUtil/DemoDeviceHelper.cs中的CreateDevice函数。

    4.2 设备命令

    设备命令接口文档

    设备命令由两步骤组成:

    1. 平台命令下发
    2. 设备命令响应

    命令下发

    命令下发由平台向设备发送,下发方式参考 命令下发使用示例, 或则使用CreateCommand API

    命令下发时设置对应listener用来接收平台下发的命令:

        public class CommandSample : DeviceSample, CommandListener
        {
            // ......
            protected override void BeforeInitDevice()
            {
                Device.GetClient().commandListener = this;
                // ......

    实现回调接口OnCommand对命令进行处理:

            public void OnCommand(string requestId, string serviceId, string commandName, Dictionary<string, object> paras)
            {
                LOG.Info("onCommand, serviceId = {}", serviceId);
                LOG.Info("onCommand, name = {}", commandName);
                LOG.Info("onCommand, paras = {}", JsonUtil.ConvertObjectToJsonString(paras));
                // ......
            }

    命令响应

    紧接着命令处理完毕后,调用RespondCommand上报响应用于确认执行结果:

            public void OnCommand(string requestId, string serviceId, string commandName, Dictionary<string, object> paras)
            {
                // ......
                // Sends a command response.
                Device.GetClient().RespondCommand(requestId, new CommandRsp(respCode, respParams));
            }

    4.3 设备消息

    系统Topic消息上报

    消息是否上报到平台可以通过 消息跟踪查看, 或则使用ListDeviceMessages APIShowDeviceMessage API

    调用ReportDeviceMessage上报预定格式的消息

    // {"content":"hello word","object_device_id":null,"name":null,"id":null}
    Device.GetClient().ReportDeviceMessage(new DeviceMessage("hello word", testMqttV5Data));

    调用ReportRawDeviceMessage上报任意格式的消息:

    // hello word
    Device.GetClient().ReportRawDeviceMessage(new RawDeviceMessage("hello word", testMqttV5Data));

    系统Topic消息下发

    消息下发由平台向设备发送,下发方式参考 平台消息下发使用示例, 或则使用CreateMessage API

    1. SDK中需要进行以下操作: 实现RawDeviceMessageListener的类并创建实例同时设置其到对应的listener以监听下发消息:

              protected override void BeforeInitDevice()
              {
                  Device.GetClient().rawDeviceMessageListener = this;
              }
    2. public void OnRawDeviceMessage(RawDeviceMessage message)实现消息处理逻辑:

              public void OnRawDeviceMessage(RawDeviceMessage message)
              {
                  var deviceMessage = message.ToDeviceMessage();
                  if (deviceMessage == null)
                  {
                      //....
                  }
                  else
                  {
                      //....
                  }
      
              }

    RawDeviceMessage 本身只存储二进制payload,为了方便用户操作,此类提供下面的方法:

    public string StrPayload 以UTF8将字符串编码并存入payload,或则以UTF8解码payload为字符串并读取。

    public string ToUtf8String() 以UTF8解码payload为字符串并读取。

    public DeviceMessage ToDeviceMessage() 尝试将payload反序列化为预设格式DeviceMessage的对象,如果失败则返回null

    自定义topic消息上报

    要使用自定topic,平台也需要进行相应配置,详细可阅读自定义Topic通信概述。本SDK自定义topic在断链时会自动重新订阅。

    消息是否上报到平台可以通过 消息跟踪功能检测, 或则使用ListDeviceMessages APIShowDeviceMessage API

    自定义topic消息分为$oc前缀和非$oc前缀两种,均通过创建CustomMessageTopic时通过设置OcPrefix成员指定:

    // topic: "$oc/devices/{device-id}/user/ai"
    private static readonly CustomMessageTopic OC_CUSTOM_TOPIC = new CustomMessageTopic
        { Suffix = "ai", OcPrefix = true };
    
    // topic: "/ai/test/device/to/cloud"
    private static readonly CustomMessageTopic NO_OC_CUSTOM_TOPIC = new CustomMessageTopic
        { Suffix = "/ai/test/device/to/cloud", OcPrefix = false };

    调用ReportRawDeviceMessage(RawDeviceMessage, CustomMessageTopic)可以上报消息到自定topic:

             private void RunCustomTopicDemo()
            {
                //....
                // Reports a message with $oc custom topic.
                Device.GetClient()
                    .ReportRawDeviceMessage(new RawDeviceMessage("hello $oc custom topic"), OC_CUSTOM_TOPIC);
    
                // Reports a message with non-$oc custom topic.
                Device.GetClient()
                    .ReportRawDeviceMessage(new RawDeviceMessage("hello non-$oc custom topic"), NO_OC_CUSTOM_TOPIC);
            }

    自定义topic消息下发

    要使用自定topic,平台也需要进行相应配置,详细可阅读自定义Topic通信概述。本SDK自定义topic在断链时会自动重新订阅。

    自定义topic消息下发由平台向设备发送,下发方式参考 平台消息下发使用示例 或则使用CreateMessage API

    接收自定义topic的消息前需要使用SubscribeTopic(CustomMessageTopic)订阅自定义topic:

            private void RunCustomTopicDemo()
            {
                // You must configure the custom topic on the platform and set the topic prefix to $oc/devices/{device_id}/user/.
                // Use Postman to simulate the scenario in which an application uses the custom topic to deliver a command.
                Device.GetClient().SubscribeTopic(NO_OC_CUSTOM_TOPIC);
                fullNoOcCustomTopic = Device.GetClient().SubscribeTopic(OC_CUSTOM_TOPIC);
                // ......
            }

    然后实现RawDeviceMessageListener接口、创建其实例、设置其到对应的listener以监听下发消息:

            protected override void BeforeInitDevice()
            {
                Device.GetClient().rawDeviceMessageListener = this;
            }

    public void OnCustomRawDeviceMessage(string topic, bool topicStartsWithOc, RawDeviceMessage rawDeviceMessage)中实现处理消息的逻辑:

             void OnCustomRawDeviceMessage(string topic, bool topicStartsWithOc, RawDeviceMessage rawDeviceMessage)
            {
                LOG.Info("custom message received, topic:{}, topic starts with oc:{}, data:{}",
                    topic, topicStartsWithOc, rawDeviceMessage.payload);
            }

    4.4 设备属性

    设备属性上报

    设备最近上报的属性可以在“设备详情”页面查看,详细可参考设备属性上报的使用说明

    调用ReportProperties(List<ServiceProperty>)按产品模型中定义的格式将属性数据上报给平台:

            Device.GetClient().ReportProperties(GenerateMockProperty());

    上报成功后输出日志样例如下:

    2024-06-28 14:31:50.6884 | Info | IoT.Device.Demo.PropertyReportSample.OnMessagePublished:69 - pubSuccessMessage: "{"services":[{"service_id":"smokeDetector","properties":{"alarm":1,"temperature":23.45812,"humidity":56.89013,"smokeConcentration":89.5672},"eventTime":null}]}"

    平台设置设备属性

    设置设备属性请求由平台下发,需要通过UpdateProperties API触发。

    实现PropertyListener接口并创建实例,同时设置其到对应的listener以监听设置属性的请求:

            protected override void BeforeInitDevice()
            {
                Device.GetClient().messagePublishListener = this;
            }

    再在void OnPropertiesSet(string requestId, List<ServiceProperty> services)中实现修改设备上对应属性的逻辑。 处理完成后调用void RespondPropsSet(string requestId, IotResult iotResult)响应设置结果:

            public void OnPropertiesSet(string requestId, List<ServiceProperty> services)
            {
                LOG.Info("set properties request id: {}", requestId);
                LOG.Info("set properties services: {}", JsonUtil.ConvertObjectToJsonString(services));
    
                Device.GetClient().RespondPropsSet(requestId, IotResult.SUCCESS);
            }

    平台查询设备属性

    查询设备属性请求由平台下发,需要通过ListProperties API触发。

    1. 创建监听器:实现PropertyListener接口并创建实例,同时设置其到对应的listener以监听设置属性的请求:

              protected override void BeforeInitDevice()
              {
                  Device.GetClient().messagePublishListener = this;
              }
    2. 处理查询设备属性请求并响应: 在public void OnPropertiesGet(string requestId, string serviceId) 中实现获取serviceId对应属性的逻辑,之后调用void RespondPropsGet(string requestId, List<ServiceProperty> services)响应。

              public void OnPropertiesGet(string requestId, string serviceId)
              {
                  LOG.Info("requestId Get: {}", requestId);
                  LOG.Info("serviceId Get: {}", serviceId);
                  //.......
                  Device.GetClient().RespondPropsGet(requestId, properties);
              }

    设备侧获取平台的设备影子数据

    1. 请求设备影子:调用GetShadow(DeviceShadowRequest shadowRequest, string requestId = null) 接口上报获取设备请求,DeviceShadowRequest中的ServiceId不填时表示获取所有服务的影子数据,requestId不填时会自动生成并作为返回值:

              protected override void RunDemo()
              {
                  var reqId = Device.GetClient().GetShadow(new DeviceShadowRequest
                  {
                      ServiceId = null // service id in you product model, for example, "SmokeDetector"
                  });
                  LOG.Info("get shadow request id: {}", reqId);
              }
    2. 接收影子数据:实现DeviceShadowListener接口并创建实例,然后设置其到对应的listener以监听设置属性的请求:

              protected override void BeforeInitDevice()
              {
                  Device.GetClient().deviceShadowListener = this;
              }
    3. 处理影子消息:在OnShadowCommand(string requestId, string message)中实现的逻辑:

              public void OnShadowCommand(string requestId, string message)
              {
                  LOG.Info("receive device shadow, request id:{}, message:{}", requestId, message);
              }

    4.5 网关与子设备管理

    网关是一个特殊的设备,除具备一般设备功能之外,还具有子设备管理、子设备消息转发的功能。SDK提供了AbstractGateway抽象类来简化网关的实现。 该类提供了子设备管理功能,需要从平台获取子设备信息并保存(需要子类提供子设备持久化接口)、子设备下行消息转发功能(需要子类实现转发处理接口)、 以及上报子设备列表、上报子设备属性、上报子设备状态、上报子设备消息等接口。

    Gateway Demo使用说明

    Gateway Demo实现了一个简单TCP子设备模拟器、和一个对应的的网关,在此基础上您可以根据需要进行扩展。比如修改持久化方式、转发中增加消息格式的转换、实现其他子设备接入协议。 下面将按照使用步骤和功能阻隔介绍示例网关里的主要类。

    1. 启动Gateway

      配置与启动Demo中的命令相同,只需要将demo的名字改为Gateway即可。 Gateway的实现如下:

      • StringTcpServer负责TCP server职责,其基于DotNetty实现。
      • SimpleGateway中的继承自AbstractGateway,实现子设备管理和下行消息转发。
      • SubDevicesFilePersistence.cs 负责子设备信息持久化,采用json文件来保存子设备信息,并在内存中做了缓存。
      • Session.cs作为备会话类保存了设备id和TCP的channel的对应关系。

      另外配置文件针对Gateway Demo提供额外的GatewayConfig参数:

        {
           "GatewayConfig": {
              "ListenPort": 8081,
              "PreDeleteSubDeviceIds": [
                 "要删除的设备的device id"
              ],
              "PreAddSubDevice": [
                 {
                   "node_id": "要添加的设备的node id 1",
                   "product_id": "产品id 1"
                 },
                 {
                   "node_id": "要添加的设备的node id 2",
                   "product_id": "产品id 2"
                 }
              ]
           }
        }

      参数介绍如下:

      • ListenPort: 监听端口,子设备模拟器链接用
      • PreDeleteSubDeviceIds: Gateway启动后会立即演示删除子设备功能,子设备的id则放在这里配置
      • PreAddSubDevice: Gateway启动后会立即演示添加子设备功能,子设备的信息则放在这里配置
        • node_id:子设备node_id,加上product_id前缀后生成device id
        • product_id:平台上的产品id。

      一个完整的配置示例可以参考iot-device-demo/config/DemoGatewayConfig.json

    2. 启动TCP子设备模拟器: TCP子设备模拟器是一个简单的TCP客户端,负责连接Gateway的端口并将用户输入的消息发送给Gateway:

         cd iot-tcp-device
         dotnet run --project .\iot-tcp-device.csproj localhost 8081 mySubDevice1

      后面三个参数含义分别是:

      • Gateway的ip。这里是本地启动的Gateway,所以是localhost
      • Gateway的端口。和第一步中配置的端口填写成一样
      • 子设备id。用于模拟的子设备的node-id(设备标识码)

      切换回网关的日志,如果连接成功将会出现以下内容: img_13.png

    3. 返送消息: 返回到设备模拟器的console,输入下面的内容上报消息:

      message: this is a random message
    4. 发送属性: 在子设备模拟器的console,输入以下格式的内容上报属性:

      properties: smokeDetector, {"alarm":0,"temperature":10}

      切换回网关的日志,如果上报成功将会出现以下内容:

    5. 命令响应: 按照设备命令中操作向子设备下发命令时需要在子设备模拟器中手动回复命令响应,格式如下:

      cmdresp: requestId, result

      其中requestId为命令下发时对应的请求id,result则是命令执行结果,0代表成功,其它代表失败。示例如下,

    AbstractGateway

    AbstractGateway.cs提供了子设备消息上报、子设备消息下发处理,回调。上Demo中的SimpleGateway就是继承该类,实现了相关功能。

    下面分类介绍哪些接口需要被实现或调用1以实现完整的子设备管理。

    添加或删除子设备处理

    网关可以主动向平台发起删除或添加子设备请求,接口如下:

      ReportAddSubDevice(List<DeviceInfo> subDeviceInfo):void
      ReportDeleteSubDevice(List<string> devicesId):void
    

    同时平台也会下发删除或添加子设备的响应,由于AbstractGateway中已经用SubDevicesFilePersistence.cs类对象处理这一部分,您只需要实现一个SubDevicesFilePersistence.cs子类并在实例化AbstractGateway(的子类)时传入即可。

    下行消息处理

    网关收到平台下行消息时,需要转发给子设备。平台下行消息分为三种:设备消息、属性读写、命令、事件,您需要分别实现以下几个抽象接口以便处理消息:

    /// 子设备命令下发处理,网关需要转发给子设备,需要子类实现
    public abstract void OnSubdevCommand(string requestId, Command command);
    /// 子设备属性设置,网关需要转发给子设备,需要子类实现
    public abstract void OnSubdevPropertiesSet(string requestId, PropsSet propsSet);
    /// 子设备读属性,网关需要转发给子设备,需要子类实现
    public abstract void OnSubdevPropertiesGet(string requestId, PropsGet propsGet);
    /// 子设备消息下发,网关需要转发给子设备,需要子类实现
    public abstract void OnSubdevMessage(DeviceMessage message);
    /// 子设备时间下发,网关需要转发给子设备,需要子类实现
    OnSubdevEvent(string deviceId, DeviceEvent deviceEvent):void

    上行消息处理 上行消息均复用原有接口,仅需将对应子设备得devieId填入即可,以属性上报为例:

    var serviceProperty = new ServiceProperty
    {
        properties = new Dictionary<string, object>
        {
            // Sets properties based on the product model.
            { "alarm", 1 },
            { "temperature", 23.45812 },
            { "humidity", 56.89013 },
            { "smokeConcentration", 89.5672 }
        },
        serviceId = "smokeDetector" // The serviceId must be the same as that defined in the product model.
    };
    
    var deviceProperties = new DeviceProperties
    {
        DeviceId = "子设备id",
        services = new List<ServiceProperty> { serviceProperty }
    };
    Device.GetClient().ReportProperties(deviceProperties);

    其它

    //上报子设备状态
    ReportSubDeviceStatus(List<DeviceStatus> statuses):void
    //同步子设备信息 
    SyncSubDevices(bool syncAll):void

    4.6 软固件升级

    软固件升级需要在平台先上传软固件并创建任务,然后SDK才会接收到升级请求并开始处理。详细操作可以参考MQTT协议设备OTA固件升级。默认情况下,软固件升级示例中下载的文件将被统一下载到demo运行路径下的download文件夹中。

    img_12.png

    如果您需要高度自定义软固件处理流程,您需要实现OTAListener以监听软固件升级请求:

    public interface OTAListener
    {
        void OnQueryVersion(OTAQueryInfo queryInfo);
        void OnNewPackage(OTAPackage pkg);
        void OnNewPackageV2(OTAPackageV2 pkgV2);
    }

    然后处理请求中的url,最后再使用下面接口上报处理进度或结果:

    class OtaService {
        ///.....
        ReportOtaStatus(int result, int progress, string version, string description)
    }

    4.7 设备时间同步

    1. 请求时间同步:调用TimeService.RequestTimeSync请求时间同步

      protected override void RunDemo()
      {
          Device.timeSyncService.RequestTimeSync();
      }
    2. 接收时间同步消息:实现TimeSyncListener接口并创建实例,然后设置其到对应的listener以监听响应:

          protected override void BeforeInitDevice()
          {
              Device.timeSyncService.listener = this;
          }
    3. 处理时间同步消息:在OnTimeSyncResponse(string requestId, string message)中实现设置设备时钟的逻辑,下面为示例

            public void OnTimeSyncResponse(long deviceSendTime, long serverRecvTime, long serverSendTime)
            {
                long deviceRecvTime = Convert.ToInt64(IotUtil.GetTimeStamp());
                long now = (serverRecvTime + serverSendTime + deviceRecvTime - deviceSendTime) / 2;
                LOG.Info("now is {}", StampToDatetime(now));
            }

    上面demo中的算法来自设备时间同步响应

    4.8 设备信息上报

    调用Device.GetClient().ReportDeviceInfo("软件版本", "固件版本")上报设备信息:

            protected override void RunDemo()
            {
                Device.GetClient().ReportDeviceInfo("v1.1", "v1.1");
            }

    上报成功后可以在设备详情里看到对应的软固件版本信息: img_1.png

    4.9 设备日志收集

    使用设备日志需要您先在平台配置“运行日志”功能,请参考文档运行日志使用说明。运行日志开启之后调用SDK中对应的API才能将日志上传到平台。运行日志上报支持两种方式:

    1. 显示调用日志上传接口。

      使用Device.LogService.ReportLog接口直接生成日志消息并上报到到平台:

        Device.LogService.ReportLog(DateTimeOffset.Now.ToUnixTimeSeconds().ToString(),
                      LogService.LogType.DeviceStatus, "ONLINE");
    2. 将经过NLog组件输出的日志抓发到平台。

      SDK默认使用NLog日志组件并将上报到IoTDA作为一个可配置的target。打开iot-device-demo/CoreCapability/NLog.config,首先您可以看到一个名字为IoTDA类型为IoTDAtarget,在这里我们主要为这个target配置了输出格式:

      <target name="IoTDA" xsi:type="IoTDA" layout="${longdate} | ${level:uppercase=false} | ${callsite:fileName}:${callsite-linenumber} - ${message}${onexception:, error\: ${exception:format=type,message,method:innerExceptionSeparator= - :separator=. :maxInnerExceptionLevel=5:innerFormat=shortType,message,method} - stacktrace\: ${stacktrace}}" />

      在下面的rules里的第三个logger则使用过滤规则指定了什么日志将被写入IoTDA

        <logger name="*" minlevel="Debug" writeTo="IoTDA">
            <filters defaultAction='Ignore'>
                <when condition="contains('${callsite:fileName}','DeviceReportLogSample') and not contains('${callsite:fileName}','DemoMessagePublishListener')" action="Log" />
            </filters>
        </logger>

      注意我们这里这里主要使用的是白名单机制,即“指定需要收集的日志”。 如果过滤不慎则可能导致死循环,例如demo里的public void OnMessagePublished(RawMessage message)public void OnMessageUnPublished(RawMessage message)监听了消息推送的结果同时用NLog打印了日志,这意味着:

      1. 只要有消息被推送,这两个回调函数里就会产生日志。
      2. 如果不使用not contains('${callsite:fileName}','DemoMessagePublishListener')排除这里的日志,那么这里的消息又会被日志收集上报。
      3. 无论消息推送成功或失败,会再次触发这两个回调函数。

      从而导致死循环。

    4.10 远程配置

    使用远程配置需要先在设备接入控制台创建远程配置任务,操作步骤可以参考上列文档。 同时,SDK中需要配置对应的监听器处理回调。

    1. 实现并设置DeviceConfigListener

          public class DeviceConfigSample : DeviceSample, DeviceConfigListener
         {
              protected override void BeforeInitDevice()
              {
                  Device.DeviceConfigService.DeviceConfigListener = this;
              }
          }
    2. OnDeviceConfig中处理配置,并以DeviceConfigResponse类型的处理结果作为返回值:

      public DeviceConfigResponse OnDeviceConfig(Dictionary<string, object> configContent, string deviceId)
      {
          // use configuration to configure your device
          // ....
          return new DeviceConfigResponse { ResultCode = 0 };
      }

    4.11 文件上传下载

    在使用该功能前, 您其需要先在设备接入控制台配置obs 。详细操作参考文件上传

    SDK中FileManagerService类提供与MQTT接口一一对应的接口。但为了用户方便使用,SDK中还提供了SimpleLocalFileManager类,其包含了更加便捷的接口。如果您想直接使用FileManagerService接口,也可以参考SimpleLocalFileManager的源码。 使用详情可以参考iot-device-demo/CoreCapability/FileUploadDownloadSample.cs,这里演示了如何使用SimpleLocalFileManager将本地Nlog.config配置上传到obs、然后再将文件原样从obs下载回来的例子。

    文件上传

    1. 初始化SimpleLocalFileManager对象:

              protected override void RunDemo()
              {
                  var fsa = new SimpleLocalFileManager(Device.FileManagerService);
                  //...
    2. 调用UploadFile下载文件,其接收SimpleLocalFileManager.FileTransferRequest对象作为参数,主要参数如下:

      • Path:要上传的文件路径
      • CompleteListener:文件上传完毕后的回调(无论成功或失败)
      • FileName:上传到obs的文件名,不填时会自动从Path里提取并自动添加上时间戳
       var fileName = fsa.UploadFile(new SimpleLocalFileManager.FileTransferRequest
                  {
                      Path = IotUtil.GetRootDirectory() + @"\Nlog.config",
                      CompleteListener = UploadCompleteListener
                  });

    文件下载

    1. 初始化SimpleLocalFileManager对象:

      与同文件上传里相同。

    2. 调用UploadFile下载文件,其接收SimpleLocalFileManager.FileTransferRequest对象作为参数,主要参数如下:

      • Path:下载文件的存储路径
      • CompleteListener:文件下载完毕后的回调(无论成功或失败)
      • FileName:obs里的文件名,不填时会自动从Path里提取。注意这里和上传不同,自动生成的文件名不会自动添加上时间戳
          // download the uploaded NLOG.config with generated new name(e.g. Nlog-20240527-034141-867.config)
          fsa.DownloadFile(new SimpleLocalFileManager.FileTransferRequest
          {
              FileName = req.FileName, // filename in obs
              Path = IotUtil.GetRootDirectory() + @"\" + req.FileName
          });

    4.12 规则引擎

    端侧规则引擎在SDK中属于开箱即用功能,您只需在控制台编辑规则即可,SDK里只需通过开关开启该功能即可。在平台配置端侧规则引擎里有两种触发条件:

    1. 定时器条件:SDK会自动根据条件设置定时器并再定时器触发后检查其它条件(如果有)是否满足。
    2. 属性条件:该条件会在由您在调用ReportPorperties设备属性上报接口或者物模型编程里Service自动上报属性时触发检查。

    注意:为了直观地看出效果,如果您使用iot-device-demo/CoreCapability/DeviceRuleSample.cs并在云端更新规则,则该demo中会自动连续上报20次属性,Temperature,Humidity属性值则是随上报顺序被设置为从0到19,方便您观察属性条件的效果。

    SDK中端侧规则引擎提供额外接口满足以下需求。注意,下面均需在AbstractDevice.Init()前调用:

    1. 开启规则引擎

      规则引擎默认关闭,在Demo中使用以下代码开启规则引擎:

      Device.DeviceRuleService.EnableDeviceRule = true;
    2. 规则引擎支持将规则引擎缓存到本地并在重启时优先从本地读取规则,文件路径使用下面代码配置:

          Device.DeviceRuleService.DeviceRuleStoragePath = "rule.json";
    3. 规则引擎默认将触发的本设备命令发送到您设置的CommandListener 命令回调,当触发的命令不属于本设备时,您需要设置DeviceRuleCommandListener自行处理:

          private class DemoDeviceRuleCommandListener : DeviceRuleCommandListener
          {
              public void OnDeviceRuleCommand(string requestId, Command command)
              {
                  LOG.Info("get command sent to another device:{}", command);
              }
          }
          //.....
         Device.DeviceRuleService.DeviceRuleCommandListener = new DemoDeviceRuleCommandListener();

    4.13 远程登录

    SDK支持远程登录且SDK端无需额外配置,平台上的操作步骤参考设备远程登录

    4.14 异常检测

    在使用该功能前您需要在设备接入控制台配置异常检测,参考操作步骤

    1. 实现SecurityInfoGetListener接口。

      实现SecurityInfoGetListener接口以便异常检测服务定时获取系统信息,接口中各个方法的定义如下:

      • void OnStart(): 当异常检测服务启动时(任一检测项被开启)被调用,您可能需要在这个函数里分配资源以便后续获取系统信息
      • void OnStop(): 当异常检测服务停止时(所有检测项被关闭)被调用,您可能需要在这个函数里释放前面分配的资源
      • long OnGetMemoryTotalKb(): 获取内存总大小
      • long OnGetMemoryUsedKb(): 获取使用中的内存大小
      • IEnumerable<int> OnGetUsedPort(): 获取正在被使用的端口
      • int OnGetCpuPercentage(): 获取CPU使用率
      • long OnGetDiskTotalKb(): 获取所有磁盘的总大小
      • long OnGetDiskUsedKb(): 获取所有磁盘的总使用大小
      • int OnGetBatteryPercentage(): 获取电池使用率
      • bool OnGetLocalLoginInfo(): 获取是否有用户通过本地方式登录设备
      • bool OnGetFileTamperInfo(): 获取是否有关键文件被篡改
      • bool OnGetBruteForceLoginInfo(): 获取是否有用户尝试暴力破解登录
      • IEnumerable<IPAddress> OnGetMaliciousIp(): 获取所有恶意IP列表

      SDK默认提供了实现大部分接口的DefaultSecurityInfoGetListener(除了OnGetLocalLoginInfo(), OnGetFileTamperInfo(), OnGetBruteForceLoginInfo()),该Listener可以上报Linux/Windows相关信息,您可以参考该Listener实现相关逻辑。

    2. 设置Listener。 参考Demo,使用下面代码设置Listener:

      Device.SecurityDetectionService.SecurityInfoGetListener = new DemoSecurityInfoGetListener();
    3. 配置上报周期。

      参考Demo,使用下面代码设置上报周期:

      Device.SecurityDetectionService.ReportPeriod = TimeSpan.FromSeconds(5);

    4.15 设备任务

    设备任务暂不支持。

    4.16 消息重传

    消息重传 SDK中使用mqtt的QoS来保障消息可靠性,默认等级为Qos1,若需要修改则请操作ClientConf中的Qos参数。

    demo启动后会等待设备断链,您可以打开设备的消息跟踪后再将网络断开或者冻结设备。此时SDK中探测到断链后会不断尝试重连并自动上报5条设备消息。之后重新恢设备和网络,由于SDK中默认使用QoS1,那5条设备消息也能上报成功并且可以在消息跟踪中看到。

    4.17 断线重连

    运行本章节demo需要关闭自动重连

    SDK默认开启断线重连,如果需要关闭则需要修改作ClientConf中的AutoReconnectfalse。您可以使用ConnectListener来感知连接情况并使用DeviceClientCloseConnect方法实现自定义重连逻辑,或则处理业务上的逻辑,如”重新订阅自定义topic“,详细可参考demo代码。

    重连间隔使用指数延时,算法大致为每次失败后的延时将以指数级增长直到达到一个最大值,核心代码在CustomReconnectDelayMqttClientProxy.cs文件的BackDelayGenerator成员变量。 其中有几个关键参数可以修改:

    • MinBackoff: 最小退避时间,默认是1秒。
    • MaxBackoff: 最大退避时间,默认是5分钟。
    • DefaultBackoff: 退避时间基数,默认为1000秒。

    具体算法为:如果当前已经连续连接失败n次,每次延迟时间是退避时间基数x放大系数+最小退避时间, 其中放大系数是按指数趋势在2^(n-1)*0.82^(n-1)*1.2之间随机选一个。 如果带入默认参数,则为 1 + 2^(n-1)*0.81 + 2^(n-1)*1.2,下面给出前几次失败重连间隔的值:

    • 连接失败1次:可能延时1.8到2.8秒
    • 连接失败2次:可能延时2.6到3.4秒
    • 连接失败3次:可能延时4.2到5.8秒
    • 以此类推

    5.设备发放

    设备发放服务主要用于设备在多个IoT平台实例的发放、接入和迁移。设备在出厂时只需要烧录一个地址,然后在平台上通过策略制不同的设备接入不同的IoT平台。 设备上电后收到设备发放下发的新的平台连接地址,直接连接新的地址,免去二次烧录设备信息,同时还支持初始化的设备信息同步。 目前支持两大种设备类型的发放,功能如下:

    • 注册设备:将设备基本信息导入设备发放平台中,后续发放至不同的IoT平台。
    • 注册组: 可以实现批量设备的自注册,实现设备一键上电即可上云的动作。

    另外,下面的Demo种都需要用到scopeId, 您可以在设备发放页面点击设备->注册组列表查询: img_11.png

    注册设备发放

    设备发放需先获取发放接入地址,具体可参考终端节点

    1. 静态策略

      静态策略同时支持密钥和证书接入的设备,这里仅展示密钥接入,证书接入可以参考下面的“证书策略“。 更改以下配置iot-device-demo/config/DemoConfigDefault.json

      {
          "AuthConfig": {
              "AuthUseCert": true,
              "ServerAddress": "发放接入地址",
              "ServerPort": 8883,
              "DeviceId": "你的设备id",
              "DeviceSecret": "你的设备密钥",
          },
          "BootstrapConfig": {
              "ReportedData": "静态策略支持匹配上报消息,可以把关键字填到这里"
          }
      }

      或者以程序化的方式初始化Bootstrapclient:

          new BootstrapClient(bootstrapUri, port, deviceId, deviceSecret, null)
    2. 证书策略

      证书策略需要设备通过证书接入,证书制作过程和控制台配置可以参考MQTT X.509证书认证设备使用证书策略发放示例

      更改以下配置iot-device-demo/config/DemoConfigDefault.json

      {
          "AuthConfig": {
              "AuthUseCert": true,
              "ServerAddress": "发放接入地址",
              "ServerPort": 8883,
              "DeviceId": "你的设备id",
              "DeviceCert": "你生成的pfx证书",
              "DeviceCertPassword": "pfx证书密码"
          },
          "BootstrapConfig": {
          }
      }

      或者以程序化的方式初始化Bootstrapclient:

          new BootstrapClient(bootstrapUri, port, deviceId, deviceCert, null)
    3. 自定义策略

      该策略同时支持密钥和证书接入的设备,使用方式参考自定义策略

    注册组发放

    1. 静态策略

      静态策略同时支持密钥和证书接入的设备,这里仅展示密钥接入,证书接入可以参考下面的“证书策略“。 密钥需要在创建注册组时获取,详细可参考MQTT 注册组密钥认证静态策略发放示例

      更改以下配置iot-device-demo/config/DemoConfigDefault.json

      {
          "AuthConfig": {
              "AuthUseCert": true,
              "ServerAddress": "发放接入地址",
              "ServerPort": 8883,
              "DeviceId": "你的设备id",
              "DeviceSecret": "注意!这里现在填的时注册组密钥!",
          },
          "BootstrapConfig": {
              "ScopeId": "上面获取到的scopeId",
              "ReportedData": "静态策略支持匹配上报消息,可以把关键字填到这里"
          }
      }

      或者以程序化的方式初始化Bootstrapclient:

          new BootstrapClient(bootstrapUri, port, deviceId, regGroupSecret, scopeId)
    2. 证书策略

      证书策略需要设备通过证书接入,证书制作过程和控制台配置可以参考 MQTT X.509证书认证设备使用证书策略发放示例

      更改以下配置iot-device-demo/config/DemoConfigDefault.json

      {
          "AuthConfig": {
              "AuthUseCert": true,
              "ServerAddress": "发放接入地址",
              "ServerPort": 8883,
              "DeviceId": "你的设备id",
              "DeviceCert": "你生成的pfx证书",
              "DeviceCertPassword": "pfx证书密码"
          },
          "BootstrapConfig": {
              "ScopeId": "上面获取到的scopeId",
          }
      }

      或者以程序化的方式初始化Bootstrapclient:

          new BootstrapClient(bootstrapUri, port, deviceId, deviceCert, scopeId)
    3. 自定义策略

      该策略同时支持密钥和证书接入的注册组,使用方式参考MQTT 注册组自定义策略发放示例

    6.泛协议接入

    在第三方协议设备不能直接接入平台场景下,泛协议接入提供了在平台外部协议转换的功能。详细介绍可参考通过协议转换网关实现泛协议设备接入

    创建网桥

    在使用泛协议之前您需要创建网桥。如果要通过平台界面创建,请参考[创建网桥]。

    启动网桥

    修改接入地址iot-device-demo/config/DemoConfigDefault.json,将之前获取到的网桥接入信息填入对应位置,下面为模板:

    {
      "DemoName": "Bridge",
      "AuthConfig": {
        "ServerAddress": "mqtt server地址,咨询后获取",
        "ServerPort": "mqtt server端口,咨询后获取",
        "DeviceId": "网桥id",
        "DeviceSecret": "网桥密钥"
      },
      "BridgeConfig": {
        "ListenPort": 8081
      }
    }

    使用下面命令启动网桥demo,启动后网桥将作为一个tcp服务端开始监听请求:

     cd iot-device-demo
     dotnet run --project .\iot-device-demo.csproj

    出现下面日志表示启动成功: img_2.png

    模拟设备

    1. 启动TCP设备模拟器: TCP设备模拟器是一个简单的TCP客户端,负责连接Bridge的端口并将用户输入的消息发送给Bridge:

         cd iot-tcp-device
         dotnet run --project .\iot-tcp-device.csproj localhost 8081 myDeviceId myDeviceName

      后面三个参数含义分别是:

      • Bridge的ip。这里是本地启动的Bridge,所以是localhost
      • Bridge的端口。和第一步中配置的端口填写成一样
      • 设备id。用于模拟的设备的device-id(前缀+下划线+设备标识码)
      • 设备密钥。

      切换回网关的日志,如果连接成功将会出现以下内容: img_3.png

    2. 返送消息: 返回到设备模拟器的console,输入下面的内容上报消息:

      message: this is a random message

      img_6.png

    3. 发送属性: 在设备模拟器的console,输入以下格式的内容上报属性:

      properties: smokeDetector, {"alarm":1,"temperature":11.2}

      切换回网关的日志,如果上报成功将会出现以下内容: img_5.png

    4. 命令响应: 按照设备命令中操作向设备下发命令时需要在设备模拟器中手动回复命令响应,格式如下:

      cmdresp: requestId, result

      其中requestId为命令下发时对应的请求id,result则是命令执行结果,0代表成功,其它代表失败。示例如下, img_7.png

    7.常见问题

    • 建链返回:IoT.SDK.Device.Transport.Mqtt.MqttConnection.OnMqttClientConnectingFailed:282 - bad user name or password。 排查方法:
      1. 查看DeviceId是否错误:在控制台界面查看设备,在界面中复制设备ID ,即为SDK中deviceId的值。
      2. 确认密码是否正确:在设备创建时用户填入的密钥 即为SDK中DeviceSecret的值。若是忘记密码,可在设备详情页面重置密钥。

    8.开源协议

    • 遵循BSD-3开源许可协议
    关于
    2.4 MB
    邀请码
      Gitlink(确实开源)
    • 加入我们
    • 官网邮箱:gitlink@ccf.org.cn
    • QQ群
    • QQ群
    • 公众号
    • 公众号

    版权所有:中国计算机学会技术支持:开源发展技术委员会
    京ICP备13000930号-9 京公网安备 11010802032778号