diff --git a/package-lock.json b/package-lock.json
index a8dffac838..c74d15161b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,7 +21,7 @@
},
"devDependencies": {
"ajv": "^6.12.6",
- "ajv-cli": "^5.0.0",
+ "ajv-cli": "^0.6.0",
"prettier": "^2.6.2"
}
},
@@ -42,75 +42,29 @@
}
},
"node_modules/ajv-cli": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-5.0.0.tgz",
- "integrity": "sha512-LY4m6dUv44HTyhV+u2z5uX4EhPYTM38Iv1jdgDJJJCyOOuqB8KtZEGjPZ2T+sh5ZIJrXUfgErYx/j3gLd3+PlQ==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-0.6.0.tgz",
+ "integrity": "sha512-85CnFX7Nft+UvmAi1fHNnqrtOiSL8KW/o4hS096AVT1P+45SAe5YO242pn9+rqC9F1UKyeFioCG52jKXTOI2FA==",
"dev": true,
"dependencies": {
- "ajv": "^8.0.0",
- "fast-json-patch": "^2.0.0",
- "glob": "^7.1.0",
- "js-yaml": "^3.14.0",
- "json-schema-migrate": "^2.0.0",
- "json5": "^2.1.3",
+ "ajv": "^3.8.0",
+ "glob": "^7.0.3",
"minimist": "^1.2.0"
},
"bin": {
- "ajv": "dist/index.js"
- },
- "peerDependencies": {
- "ts-node": ">=9.0.0"
- },
- "peerDependenciesMeta": {
- "ts-node": {
- "optional": true
- }
+ "ajv": "index.js"
}
},
"node_modules/ajv-cli/node_modules/ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ajv-cli/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/ajv-cli/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "3.8.10",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-3.8.10.tgz",
+ "integrity": "sha512-h74deHfbgeB8TuWq6UQxP4fwsCbo9T+pvWofl4pEdZzI6lMSSFAWZr3PsNXHjSFABCj49j6fgbzUTHWIrMdHMw==",
"dev": true,
"dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
+ "co": "^4.6.0",
+ "json-stable-stringify": "^1.0.1"
}
},
- "node_modules/ajv-cli/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -164,6 +118,16 @@
"wrap-ansi": "^7.0.0"
}
},
+ "node_modules/co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+ "dev": true,
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -199,43 +163,12 @@
"node": ">=6"
}
},
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
- "node_modules/fast-json-patch": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz",
- "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^2.0.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/fast-json-patch/node_modules/fast-deep-equal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
- "dev": true
- },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -343,53 +276,31 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/json-schema-migrate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-migrate/-/json-schema-migrate-2.0.0.tgz",
- "integrity": "sha512-r38SVTtojDRp4eD6WsCqiE0eNDt4v1WalBXb9cyZYw9ai5cGtBwzRNWjHzJl38w6TxFkXAIA7h+fyX3tnrAFhQ==",
- "dev": true,
- "dependencies": {
- "ajv": "^8.0.0"
- }
- },
- "node_modules/json-schema-migrate/node_modules/ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/json-schema-migrate/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "node_modules/json-stable-stringify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz",
+ "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==",
"dev": true,
- "bin": {
- "json5": "lib/cli.js"
+ "dependencies": {
+ "jsonify": "^0.0.1"
},
- "engines": {
- "node": ">=6"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/jsonify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
+ "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/lodash.isequal": {
@@ -509,21 +420,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -640,56 +536,25 @@
}
},
"ajv-cli": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-5.0.0.tgz",
- "integrity": "sha512-LY4m6dUv44HTyhV+u2z5uX4EhPYTM38Iv1jdgDJJJCyOOuqB8KtZEGjPZ2T+sh5ZIJrXUfgErYx/j3gLd3+PlQ==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-0.6.0.tgz",
+ "integrity": "sha512-85CnFX7Nft+UvmAi1fHNnqrtOiSL8KW/o4hS096AVT1P+45SAe5YO242pn9+rqC9F1UKyeFioCG52jKXTOI2FA==",
"dev": true,
"requires": {
- "ajv": "^8.0.0",
- "fast-json-patch": "^2.0.0",
- "glob": "^7.1.0",
- "js-yaml": "^3.14.0",
- "json-schema-migrate": "^2.0.0",
- "json5": "^2.1.3",
+ "ajv": "^3.8.0",
+ "glob": "^7.0.3",
"minimist": "^1.2.0"
},
"dependencies": {
"ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "version": "3.8.10",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-3.8.10.tgz",
+ "integrity": "sha512-h74deHfbgeB8TuWq6UQxP4fwsCbo9T+pvWofl4pEdZzI6lMSSFAWZr3PsNXHjSFABCj49j6fgbzUTHWIrMdHMw==",
"dev": true,
"requires": {
- "sprintf-js": "~1.0.2"
+ "co": "^4.6.0",
+ "json-stable-stringify": "^1.0.1"
}
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
}
}
},
@@ -737,6 +602,12 @@
"wrap-ansi": "^7.0.0"
}
},
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+ "dev": true
+ },
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -766,35 +637,12 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
- },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
- "fast-json-patch": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz",
- "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^2.0.1"
- },
- "dependencies": {
- "fast-deep-equal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
- "dev": true
- }
- }
- },
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -875,45 +723,25 @@
"argparse": "^2.0.1"
}
},
- "json-schema-migrate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-migrate/-/json-schema-migrate-2.0.0.tgz",
- "integrity": "sha512-r38SVTtojDRp4eD6WsCqiE0eNDt4v1WalBXb9cyZYw9ai5cGtBwzRNWjHzJl38w6TxFkXAIA7h+fyX3tnrAFhQ==",
- "dev": true,
- "requires": {
- "ajv": "^8.0.0"
- },
- "dependencies": {
- "ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- }
- }
- },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
- "json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "json-stable-stringify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz",
+ "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==",
+ "dev": true,
+ "requires": {
+ "jsonify": "^0.0.1"
+ }
+ },
+ "jsonify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
+ "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
"dev": true
},
"lodash.isequal": {
@@ -1000,18 +828,6 @@
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
diff --git a/package.json b/package.json
index e68a5ae44c..d3440cfb7c 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"homepage": "https://github.com/TheThingsNetwork/lorawan-devices#readme",
"devDependencies": {
"ajv": "^6.12.6",
- "ajv-cli": "^5.0.0",
+ "ajv-cli": "^0.6.0",
"prettier": "^2.6.2"
},
"dependencies": {
diff --git a/vendor/dingtek/dc413-codec.yaml b/vendor/dingtek/dc413-codec.yaml
new file mode 100644
index 0000000000..eec92f1f82
--- /dev/null
+++ b/vendor/dingtek/dc413-codec.yaml
@@ -0,0 +1,113 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dc413.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x02, 0x11, 0x06, 0xA4, 0x00, 0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ level: 1700
+ alarmLevel: false
+ alarmFall: false
+ alarmBattery: false
+ angle: 0
+ temperature: 22
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x19, 0x03, 0x02, 0x06, 0x3C, 0x1E, 0x4B, 0x14, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81]
+ output:
+ data:
+ firmware: '3.2'
+ uploadInterval: 6
+ detectInterval: 60
+ levelThreshold: 30
+ fallThreshold: 20
+ fallEnable: true
+ workMode: 1
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dc413.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change periodic detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change full alarm threshold to 35cm
+ input:
+ data:
+ levelThreshold: 35
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ fPort: 3
+ - description: change motion alarm threshold to 45°
+ input:
+ data:
+ fallThreshold: 45
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x32, 0x44, 0x38, 0x31]
+ fPort: 3
+ - description: enable tilt detection
+ input:
+ data:
+ fallEnable: true
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dc413.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change full alarm threshold to 35cm
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 35
+ - description: change motion alarm threshold to 45°
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x32, 0x44, 0x38, 0x31]
+ output:
+ data:
+ fallThreshold: 45
+ - description: enable motion detection
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ fallEnable: true
diff --git a/vendor/dingtek/dc413.js b/vendor/dingtek/dc413.js
new file mode 100644
index 0000000000..14fc7cf71e
--- /dev/null
+++ b/vendor/dingtek/dc413.js
@@ -0,0 +1,223 @@
+var units = [' ℃', ' hours', ' minutes', ' mm', ' °', ' cm'];
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+
+ switch (input.bytes.length) {
+ case 17:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmFall: Boolean(input.bytes[12] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ angle: input.bytes[9] & (0x0f === 0x00) ? input.bytes[10] : 0 - input.bytes[10],
+ temperature: input.bytes[8],
+ frameCounter: (input.bytes[13] << 8) + input.bytes[14],
+ },
+ };
+ case 25:
+ var data_type = input.bytes[3];
+ if (data_type === 0x03) {
+ return {
+ // Decoded parameter
+ data: {
+ firmware: input.bytes[5] + '.' + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ levelThreshold: input.bytes[9],
+ fallThreshold: input.bytes[11],
+ fallEnable: Boolean(input.bytes[12]),
+ workMode: input.bytes[14],
+ },
+ };
+ }
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var periodic_interval = input.data.uploadInterval;
+ var periodic_interval_high = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var periodic_interval_low = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (periodic_interval > 168 || periodic_interval < 1) {
+ return {
+ errors: ['periodic upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, periodic_interval_high, periodic_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detection_interval = input.data.detectInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['periodic detection interval range 1-60 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var full_alarm_threshold = input.data.levelThreshold;
+ var full_alarm_threshold_high = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var full_alarm_threshold_low = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (full_alarm_threshold > 255 || full_alarm_threshold < 15) {
+ return {
+ errors: ['full alarm threshold range 15-255 cm.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, full_alarm_threshold_high, full_alarm_threshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.fallThreshold != null && !isNaN(input.data.fallThreshold)) {
+ var tilt_alarm_threshold = input.data.fallThreshold;
+ var tilt_alarm_threshold_high = tilt_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var tilt_alarm_threshold_low = tilt_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (tilt_alarm_threshold > 90 || tilt_alarm_threshold < 15) {
+ return {
+ errors: ['tilt alarm threshold range 15-90 °.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, tilt_alarm_threshold_high, tilt_alarm_threshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.fallEnable != null && input.data.fallEnable === !!input.data.fallEnable) {
+ var tilt_enable = input.data.fallEnable;
+ if (tilt_enable === true) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x39, 0x38, 0x31],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 4:
+ return {
+ data: {
+ fallThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x09:
+ return {
+ data: {
+ fallEnable: false,
+ },
+ };
+ case 0x0a:
+ return {
+ data: {
+ fallEnable: true,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
diff --git a/vendor/dingtek/dc413.png b/vendor/dingtek/dc413.png
new file mode 100644
index 0000000000..d2a5322ec9
Binary files /dev/null and b/vendor/dingtek/dc413.png differ
diff --git a/vendor/dingtek/dc413.yaml b/vendor/dingtek/dc413.yaml
new file mode 100644
index 0000000000..e295af4dae
--- /dev/null
+++ b/vendor/dingtek/dc413.yaml
@@ -0,0 +1,155 @@
+name: dc413
+description: The CNDingtek dc413 is a smart manhole sensor that integrates a liquid/solid level sensor and a movement sensor. Suitable for measuring water and sewage levels in wells and manholes. The data is sent to a LoRaWAN network, then the application server for further processing.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.2'
+ numeric: 12
+ - version: '1.3'
+ numeric: 13
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.2'
+ - '1.3'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc413-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc413-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc413-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dc413-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dc413-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dc413-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc413-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ - motion
+ #- full_alarm
+ #- fire_alarm
+ #- battery_alarm
+ #- angle
+ #- temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 115
+ height: 40
+
+# Weight in grams (optional)
+weight: 150
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP68
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/manhole-sensor-dc413
+#dataSheetURL: http://www.dingtek.com/documents/19/dc413_Smart_Manhole_LoRaWAN_Datasheet_V1.2.pdf
+
+# Photos
+photos:
+ main: dc413.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/bqGKnRtoLwo
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dc500-codec.yaml b/vendor/dingtek/dc500-codec.yaml
new file mode 100644
index 0000000000..d8c5d4362e
--- /dev/null
+++ b/vendor/dingtek/dc500-codec.yaml
@@ -0,0 +1,98 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dc500.js
+ # Examples (optional)
+ examples:
+ - description: event trigger upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x02, 0x01, 0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ peopleCounter: 257
+ alarmCounter: false
+ alarmBattery: true
+ volt: 3.67
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x02, 0x03, 0x0C, 0x01, 0x03, 0x04, 0x01, 0xF4, 0x1E, 0x81]
+ output:
+ data:
+ firmware: '1.3'
+ uploadInterval: 4
+ peopleCounterThreshold: 500
+ batteryThreshold: 30
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dc500.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ data:
+ uploadInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+
+ - description: change people counter threshold to 500
+ input:
+ data:
+ peopleCounterThreshold: 500
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x46, 0x34, 0x38, 0x31]
+ fPort: 3
+
+ - description: change battery threshold to 30%
+ input:
+ data:
+ batteryThreshold: 30
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x45, 0x38, 0x31]
+ fPort: 3
+
+ - description: zero people counter
+ input:
+ data:
+ zeroPeopleCounter: 1
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dc500.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 10
+ - description: change people counter threshold to 500
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x46, 0x34, 0x38, 0x31]
+ output:
+ data:
+ peopleCounterThreshold: 500
+ - description: change battery threshold to 30%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x45, 0x38, 0x31]
+ output:
+ data:
+ batteryThreshold: 30
+
+ - description: zero people counter
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31]
+ output:
+ data:
+ zeroPeopleCounter: 1
diff --git a/vendor/dingtek/dc500.js b/vendor/dingtek/dc500.js
new file mode 100644
index 0000000000..80403454a8
--- /dev/null
+++ b/vendor/dingtek/dc500.js
@@ -0,0 +1,195 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 21:
+ return {
+ // Decoded data
+ data: {
+ peopleCounter: ((input.bytes[5] << 8) + input.bytes[6]),
+ alarmCounter: Boolean(input.bytes[7] & 0xF0),
+ alarmBattery: Boolean(input.bytes[7] & 0x0F),
+ volt: ((input.bytes[9] << 8) + input.bytes[10]) / 100,
+ frameCounter: (input.bytes[17] << 8) + input.bytes[18],
+ },
+ };
+ case 12:
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ batteryThreshold: input.bytes[10],
+ peopleCounterThreshold: (input.bytes[8] << 8) + input.bytes[9],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 168 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.peopleCounterThreshold != null && !isNaN(input.data.peopleCounterThreshold)) {
+ var peopleCounterThreshold = input.data.peopleCounterThreshold;
+ var peopleCounter_1st = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[0].charCodeAt(0);
+ var peopleCounter_2nd = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[1].charCodeAt(0);
+ var peopleCounter_3rd = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[2].charCodeAt(0);
+ var peopleCounter_4th = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[3].charCodeAt(0);
+ if (peopleCounterThreshold > 65535 || peopleCounterThreshold < 1) {
+ return {
+ errors: ['people counter range 1-65535.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, peopleCounter_1st, peopleCounter_2nd, peopleCounter_3rd, peopleCounter_4th, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.zeroPeopleCounter != null && !isNaN(input.data.zeroPeopleCounter)) {
+ var zeroPeopleCounter = input.data.zeroPeopleCounter;
+ if (zeroPeopleCounter != 1) {
+ return {
+ errors: ['zero people counter: 1.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ if (input_length == 16)
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]) + String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16);
+ else
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ peopleCounterThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+
+ case 9:
+ switch (value) {
+ case 0x0F:
+ return {
+ data: {
+ zeroPeopleCounter: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/dc500.png b/vendor/dingtek/dc500.png
new file mode 100644
index 0000000000..263a03eeba
Binary files /dev/null and b/vendor/dingtek/dc500.png differ
diff --git a/vendor/dingtek/dc500.yaml b/vendor/dingtek/dc500.yaml
new file mode 100644
index 0000000000..251a6c1d54
--- /dev/null
+++ b/vendor/dingtek/dc500.yaml
@@ -0,0 +1,159 @@
+name: dc500
+description: The CNDingtek dc500 is a pir people counter, which calculate the people number.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.4'
+ numeric: 14
+ - version: '1.5'
+ numeric: 15
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.4'
+ - '1.5'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc500-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc500-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc500-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dc500-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dc500-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dc500-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc500-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - pulse count
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ #- temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 80
+ width: 78
+ height: 40
+
+# Weight in grams (optional)
+weight: 240
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/people-counting-sensor-dc500
+#dataSheetURL: http://www.dingtek.com/documents/23/dc500_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: dc500.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/qzEZIBocfFg
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dc510-codec.yaml b/vendor/dingtek/dc510-codec.yaml
new file mode 100644
index 0000000000..3ebd5cb43a
--- /dev/null
+++ b/vendor/dingtek/dc510-codec.yaml
@@ -0,0 +1,99 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dc510.js
+ # Examples (optional)
+ examples:
+ - description: event trigger upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x15, 0x01, 0x12, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x10, 0x00, 0x01, 0xA4, 0x00, 0x01, 0x81]
+ output:
+ data:
+ peopleCounter: 5
+ alarmCounter: true
+ alarmBattery: false
+ temperature: 20
+ volt: 4.2
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [80, 0x00, 0x15, 0x03, 0x0D, 0x01, 0x03, 0x04, 0x01, 0xF4, 0x14, 0x01, 0x81]
+ output:
+ data:
+ firmware: '1.3'
+ uploadInterval: 4
+ peopleCounterThreshold: 500
+ batteryThreshold: 20
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dc510.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ data:
+ uploadInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+
+ - description: change people counter threshold to 500
+ input:
+ data:
+ peopleCounterThreshold: 500
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x46, 0x34, 0x38, 0x31]
+ fPort: 3
+
+ - description: change battery threshold to 30%
+ input:
+ data:
+ batteryThreshold: 30
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x45, 0x38, 0x31]
+ fPort: 3
+
+ - description: zero people counter
+ input:
+ data:
+ zeroPeopleCounter: 1
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dc510.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 10
+ - description: change people counter threshold to 500
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x46, 0x34, 0x38, 0x31]
+ output:
+ data:
+ peopleCounterThreshold: 500
+ - description: change battery threshold to 30%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x45, 0x38, 0x31]
+ output:
+ data:
+ batteryThreshold: 30
+
+ - description: zero people counter
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31]
+ output:
+ data:
+ zeroPeopleCounter: 1
diff --git a/vendor/dingtek/dc510.js b/vendor/dingtek/dc510.js
new file mode 100644
index 0000000000..dbd6814a97
--- /dev/null
+++ b/vendor/dingtek/dc510.js
@@ -0,0 +1,238 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 18:
+ return {
+ // Decoded data
+ data: {
+ peopleCounter: ((input.bytes[5] << 8) + input.bytes[6]),
+ alarmCounter: Boolean(input.bytes[11] & 0xF0),
+ alarmBattery: Boolean(input.bytes[12] & 0x0F),
+ temperature: input.bytes[8],
+ volt: ((input.bytes[13] << 8) + input.bytes[14]) / 100,
+ frameCounter: (input.bytes[15] << 8) + input.bytes[16],
+ },
+ };
+ case 13:
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ batteryThreshold: input.bytes[10],
+ peopleCounterThreshold: (input.bytes[8] << 8) + input.bytes[9],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 168 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.peopleCounterThreshold != null && !isNaN(input.data.peopleCounterThreshold)) {
+ var peopleCounterThreshold = input.data.peopleCounterThreshold;
+ var peopleCounter_1st = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[0].charCodeAt(0);
+ var peopleCounter_2nd = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[1].charCodeAt(0);
+ var peopleCounter_3rd = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[2].charCodeAt(0);
+ var peopleCounter_4th = peopleCounterThreshold.toString(16).padStart(4, '0').toUpperCase()[3].charCodeAt(0);
+ if (peopleCounterThreshold > 65535 || peopleCounterThreshold < 1) {
+ return {
+ errors: ['people counter range 1-65535.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, peopleCounter_1st, peopleCounter_2nd, peopleCounter_3rd, peopleCounter_4th, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.zeroPeopleCounter != null && !isNaN(input.data.zeroPeopleCounter)) {
+ var zeroPeopleCounter = input.data.zeroPeopleCounter;
+ if (zeroPeopleCounter != 1) {
+ return {
+ errors: ['zero people counter: 1.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x46, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.factoryReset != null && !isNaN(input.data.factoryReset)) {
+ var factoryReset = input.data.factoryReset;
+ if (factoryReset != 1) {
+ return {
+ errors: ['factory reset: 1.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x44, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.reset != null && !isNaN(input.data.reset)) {
+ var reset = input.data.reset;
+ if (reset != 1) {
+ return {
+ errors: ['reset: 1.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x32, 0x38, 0x31],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ if (input_length == 16)
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]) + String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16);
+ else
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ peopleCounterThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+
+ case 9:
+ switch (value) {
+ case 0x02:
+ return {
+ data: {
+ reset: 1,
+ },
+ };
+ case 0x0D:
+ return {
+ data: {
+ factoryReset: 1,
+ },
+ };
+ case 0x0F:
+ return {
+ data: {
+ zeroPeopleCounter: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/dc510.png b/vendor/dingtek/dc510.png
new file mode 100644
index 0000000000..6a630ab632
Binary files /dev/null and b/vendor/dingtek/dc510.png differ
diff --git a/vendor/dingtek/dc510.yaml b/vendor/dingtek/dc510.yaml
new file mode 100644
index 0000000000..65c905d3e4
--- /dev/null
+++ b/vendor/dingtek/dc510.yaml
@@ -0,0 +1,159 @@
+name: dc510
+description: The CNDingtek dc510 is a pir people counter for indoor using, which calculate the people number.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc510-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc510-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc510-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dc510-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dc510-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dc510-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc510-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - pulse count
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ #- temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 110
+ width: 109
+ height: 25
+
+# Weight in grams (optional)
+weight: 80
+
+# Battery information (optional)
+battery:
+ replaceable: false
+ type: 1000mAh
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/people-counter-dc510
+#dataSheetURL: http://www.dingtek.com/documents/23/dc510_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: dc510.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/hyZHpHczhfY
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dc600-codec.yaml b/vendor/dingtek/dc600-codec.yaml
new file mode 100644
index 0000000000..4ff5b7d2a9
--- /dev/null
+++ b/vendor/dingtek/dc600-codec.yaml
@@ -0,0 +1,70 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dc600.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x01, 0x11, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x81]
+ output:
+ data:
+ monitorStatus: true
+ alarmChannel1: false
+ alarmChannel2: false
+ alarmChannel3: false
+ alarmChannel4: false
+ alarmBattery: false
+ temperature: 25
+ frameCounter: 0
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x11, 0x01, 0x04, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.4'
+ uploadInterval: 24
+ batteryThreshold: 20
+ monitorStatus: true
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dc600.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: set battery alarm threshold to 20%
+ input:
+ data:
+ batteryThreshold: 20
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dc600.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+
+ - description: set battery alarm threshold to 20%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ output:
+ data:
+ batteryThreshold: 20
diff --git a/vendor/dingtek/dc600.js b/vendor/dingtek/dc600.js
new file mode 100644
index 0000000000..3e62b923f8
--- /dev/null
+++ b/vendor/dingtek/dc600.js
@@ -0,0 +1,190 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 17:
+ if (input.bytes[3] != 0x03) {
+ return {
+ // Decoded data
+ data: {
+ monitorStatus: !Boolean(input.bytes[11] & 0x01),
+ alarmChannel1: !Boolean(input.bytes[12] & 0x10),
+ alarmChannel2: !Boolean(input.bytes[12] & 0x20),
+ alarmChannel3: !Boolean(input.bytes[12] & 0x40),
+ alarmChannel4: !Boolean(input.bytes[12] & 0x80),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ temperature: input.bytes[8],
+ frameCounter: (input.bytes[13] << 8) + input.bytes[14],
+ },
+ };
+ } else {
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ batteryThreshold: input.bytes[11],
+ monitorStatus: !Boolean(input.bytes[12] & 0x01),
+ },
+ };
+ }
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 168 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['Battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.monitorStatus != null && !isNaN(input.data.monitorStatus)) {
+ var monitorStatus = input.data.monitorStatus;
+ if (monitorStatus == 0) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31],
+ };
+ } else if (monitorStatus == 1){
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x39, 0x38, 0x31],
+ };
+ }else{
+ return {
+ errors: ['Monitor status range 0-1.'],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x09:
+ return {
+ data: {
+ monitorStatus: 1,
+ },
+ };
+ case 0x0A:
+ return {
+ data: {
+ monitorStatus: 1,
+ },
+ };
+ case 0x0D:
+ return {
+ data: {
+ reset: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/dc600.png b/vendor/dingtek/dc600.png
new file mode 100644
index 0000000000..92eee7cb19
Binary files /dev/null and b/vendor/dingtek/dc600.png differ
diff --git a/vendor/dingtek/dc600.yaml b/vendor/dingtek/dc600.yaml
new file mode 100644
index 0000000000..c53b29f62d
--- /dev/null
+++ b/vendor/dingtek/dc600.yaml
@@ -0,0 +1,158 @@
+name: dc600
+description: The CNDingtek dc600 is water leakage sensor with up to 4 channels.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc600-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc600-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dc600-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dc600-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dc600-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dc600-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dc600-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - water
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 80
+ width: 78
+ height: 30
+
+# Weight in grams (optional)
+weight: 240
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: 8000mAh
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP66
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/water-leak-sensor-dc600
+#dataSheetURL: http://www.dingtek.com/documents/23/dc600_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: dc600.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+#videos:
+#main: https://youtu.be/T8q0kb5tMXY
+#other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df200-codec.yaml b/vendor/dingtek/df200-codec.yaml
new file mode 100644
index 0000000000..1e7edef3b0
--- /dev/null
+++ b/vendor/dingtek/df200-codec.yaml
@@ -0,0 +1,98 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df200.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x01, 0x0F, 0x02, 0x4C, 0x00, 0x19, 0x4B, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ level: 75
+ alarmLevel: false
+ alarmBattery: false
+ temperature: 25
+ volt: 5.88
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x0D, 0x01, 0x02, 0x18, 0x0A, 0x14, 0x19, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.2'
+ uploadInterval: 24
+ detectInterval: 10
+ batteryThreshold: 20
+ levelThreshold: 25
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df200.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ data:
+ uploadInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change level alarm threshold to 50%
+ input:
+ data:
+ levelThreshold: 50
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x33, 0x32, 0x38, 0x31]
+ fPort: 3
+
+ - description: change battery threshold to 20%
+ input:
+ data:
+ batteryThreshold: 20
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df200.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 10
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change level alarm threshold to 50%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x33, 0x32, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 50
+
+ - description: change battery threshold to 20%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ output:
+ data:
+ batteryThreshold: 20
diff --git a/vendor/dingtek/df200.js b/vendor/dingtek/df200.js
new file mode 100644
index 0000000000..c46be6ba12
--- /dev/null
+++ b/vendor/dingtek/df200.js
@@ -0,0 +1,205 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 15:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[9]),
+ alarmLevel: Boolean(input.bytes[10] & 0x0f),
+ alarmBattery: Boolean(input.bytes[7] & 0x0f),
+ temperature: input.bytes[8],
+ volt: ((input.bytes[5] << 8) + input.bytes[6]) / 100,
+ frameCounter: (input.bytes[11] << 8) + input.bytes[12],
+ },
+ };
+ case 13:
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ batteryThreshold: input.bytes[9],
+ levelThreshold: input.bytes[10],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 255 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-255 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detectInterval = input.data.detectInterval;
+ var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detectInterval > 255 || detectInterval < 1) {
+ return {
+ errors: ['detection interval range 1-255 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var levelThreshold = input.data.levelThreshold;
+ var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (levelThreshold!=25 && levelThreshold !=50 && levelThreshold !=75 && levelThreshold !=100) {
+ return {
+ errors: ['level alarm threshold range 25/50/75/100.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold>99 || batteryThreshold<5) {
+ return {
+ errors: ['battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35,batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+
+ case 9:
+ switch (value) {
+ case 0x00:
+ return {
+ data: {
+ calibration: 0,
+ },
+ };
+ case 0x01:
+ return {
+ data: {
+ calibration: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/df200.png b/vendor/dingtek/df200.png
new file mode 100644
index 0000000000..62e6fddf34
Binary files /dev/null and b/vendor/dingtek/df200.png differ
diff --git a/vendor/dingtek/df200.yaml b/vendor/dingtek/df200.yaml
new file mode 100644
index 0000000000..74225a8467
--- /dev/null
+++ b/vendor/dingtek/df200.yaml
@@ -0,0 +1,159 @@
+name: df200
+description: The CNDingtek df200 is soap dispenser level sensor, which detect the liquid level in the dispenser.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df200-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df200-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df200-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df200-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df200-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df200-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df200-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 158
+ width: 116
+ height: 286
+
+# Weight in grams (optional)
+weight: 750
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: D size
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/dispenser-level-sensor-df200
+#dataSheetURL: http://www.dingtek.com/documents/23/df200_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df200.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/TSreE_67FVE
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df400-codec.yaml b/vendor/dingtek/df400-codec.yaml
new file mode 100644
index 0000000000..205321b48f
--- /dev/null
+++ b/vendor/dingtek/df400-codec.yaml
@@ -0,0 +1,99 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df400.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x01, 0x11, 0x02, 0x4C, 0x00, 0x19, 0x00, 0x46, 0x4B, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ level: 70
+ percent: 75
+ alarmLevel: false
+ alarmBattery: false
+ temperature: 25
+ volt: 5.88
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x0D, 0x00, 0x02, 0x18, 0x1E, 0x14, 0x0A, 0x00, 0x81]
+ output:
+ data:
+ firmware: '0.2'
+ uploadInterval: 24
+ detectInterval: 30
+ batteryThreshold: 20
+ levelThreshold: 10
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df400.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ data:
+ uploadInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change level alarm threshold to 50%
+ input:
+ data:
+ levelThreshold: 50
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x33, 0x32, 0x38, 0x31]
+ fPort: 3
+
+ - description: change battery threshold to 20%
+ input:
+ data:
+ batteryThreshold: 20
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df400.js
+ examples:
+ - description: change periodic upload interval to 10 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 10
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change level alarm threshold to 50%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x33, 0x32, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 50
+
+ - description: change battery threshold to 20%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x31, 0x34, 0x38, 0x31]
+ output:
+ data:
+ batteryThreshold: 20
diff --git a/vendor/dingtek/df400.js b/vendor/dingtek/df400.js
new file mode 100644
index 0000000000..70f2e55594
--- /dev/null
+++ b/vendor/dingtek/df400.js
@@ -0,0 +1,194 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 17:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[9] << 8) + input.bytes[10],
+ percent: (input.bytes[11]),
+ alarmLevel: Boolean(input.bytes[12] & 0x0f),
+ alarmBattery: Boolean(input.bytes[7] & 0x0f),
+ temperature: input.bytes[8],
+ volt: ((input.bytes[5] << 8) + input.bytes[6]) / 100,
+ frameCounter: (input.bytes[13] << 8) + input.bytes[14],
+ },
+ };
+ case 13:
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ batteryThreshold: input.bytes[9],
+ levelThreshold: input.bytes[10],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 255 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-255 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detectInterval = input.data.detectInterval;
+ var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detectInterval > 255 || detectInterval < 1) {
+ return {
+ errors: ['detection interval range 1-255 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var levelThreshold = input.data.levelThreshold;
+ var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (levelThreshold > 99 || levelThreshold < 1) {
+ return {
+ errors: ['level alarm threshold range 1-99,unit %.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+
+ case 9:
+ switch (value) {
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/df400.png b/vendor/dingtek/df400.png
new file mode 100644
index 0000000000..4491cea133
Binary files /dev/null and b/vendor/dingtek/df400.png differ
diff --git a/vendor/dingtek/df400.yaml b/vendor/dingtek/df400.yaml
new file mode 100644
index 0000000000..e276b344df
--- /dev/null
+++ b/vendor/dingtek/df400.yaml
@@ -0,0 +1,159 @@
+name: df400
+description: The CNDingtek df400 is tissue dispenser level sensor, which detect the paper in the dispenser.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df400-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df400-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df400-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df400-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df400-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df400-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df400-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 120
+ width: 64
+ height: 18
+
+# Weight in grams (optional)
+weight: 40
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER14500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/toilet-paper-level-sensor-df400
+#dataSheetURL: http://www.dingtek.com/documents/23/df400_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df400.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/0v9kJNyk2PY
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df555-codec.yaml b/vendor/dingtek/df555-codec.yaml
new file mode 100644
index 0000000000..d12bee2c0a
--- /dev/null
+++ b/vendor/dingtek/df555-codec.yaml
@@ -0,0 +1,94 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df555.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload without gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0, 1, 1, 0x11, 7, 0xD0, 0, 0x19, 0, 0, 0, 0, 0, 1, 0, 0x81]
+ output:
+ data:
+ level: 2000
+ alarmLevel: false
+ alarmBattery: false
+ temperature: 25
+ frameCounter: 1
+
+ - description: heartbeat upload with gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x01, 0x19, 0x07, 0xD0, 0x01, 0xCD, 0x03, 0xE9, 0x42, 0xEF, 0x27, 0x20, 0x42, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ level: 2000
+ longitude: '116.507430'
+ latitude: '40.038999'
+ alarmLevel: false
+ alarmBattery: false
+ temperature: 25
+ frameCounter: 1
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x11, 0x01, 0x04, 0x18, 0x01, 0x1E, 0x4B, 0x1E, 0x00, 0x02, 0x00, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.4'
+ uploadInterval: 24
+ detectInterval: 1
+ levelThreshold: 30
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df555.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change level alarm threshold to 35cm
+ input:
+ data:
+ levelThreshold: 35
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df555.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change level alarm threshold to 35cm
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 35
diff --git a/vendor/dingtek/df555.js b/vendor/dingtek/df555.js
new file mode 100644
index 0000000000..6c8b81d2b9
--- /dev/null
+++ b/vendor/dingtek/df555.js
@@ -0,0 +1,291 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 17:
+ if (input.bytes[3] != 0x03) {
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ temperature: input.bytes[8],
+ frameCounter: (input.bytes[13] << 8) + input.bytes[14],
+ },
+ };
+ } else {
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ levelThreshold: input.bytes[9],
+ workMode: input.bytes[14],
+ },
+ };
+ }
+
+ case 25:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[19] >> 4),
+ alarmBattery: Boolean(input.bytes[20] & 0x0f),
+ longitude: hex2float((input.bytes[11] << 24) + (input.bytes[10] << 16) + (input.bytes[9] << 8) + input.bytes[8]).toFixed(6),
+ latitude: hex2float((input.bytes[15] << 24) + (input.bytes[14] << 16) + (input.bytes[13] << 8) + input.bytes[12]).toFixed(6),
+ temperature: input.bytes[16],
+ frameCounter: (input.bytes[21] << 8) + input.bytes[22],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 255 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-255 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detectInterval = input.data.detectInterval;
+ var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detectInterval > 255 || detectInterval < 1) {
+ return {
+ errors: ['detection interval range 1-255 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var levelThreshold = input.data.levelThreshold;
+ var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (levelThreshold > 255 || levelThreshold < 15) {
+ return {
+ errors: ['Level alarm threshold range 15-255.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['Battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.gpsEnable != null && !isNaN(input.data.gpsEnable)) {
+ var gpsEnable = input.data.gpsEnable;
+ if (gpsEnable == true || gpsEnable == 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x31, 0x38, 0x31],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x30, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.workMode != null && !isNaN(input.data.workMode)) {
+ var workMode = input.data.workMode;
+ if (workMode === 0) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x35, 0x38, 0x31],
+ };
+ } else if (workMode === 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x36, 0x38, 0x31],
+ };
+ } else if (workMode === 2) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x45, 0x38, 0x31],
+ };
+ }else{
+ return {
+ errors: ['Work mode range 0-2.'],
+ }
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x00:
+ return {
+ data: {
+ gpsEnable: 0,
+ },
+ };
+ case 0x01:
+ return {
+ data: {
+ gpsEnable: 1,
+ },
+ };
+ case 0x02:
+ return {
+ data: {
+ reset: 1,
+ },
+ };
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+ case 0x0E:
+ return {
+ data: {
+ workMode: 2,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
+
diff --git a/vendor/dingtek/df555.png b/vendor/dingtek/df555.png
new file mode 100644
index 0000000000..7015492fd5
Binary files /dev/null and b/vendor/dingtek/df555.png differ
diff --git a/vendor/dingtek/df555.yaml b/vendor/dingtek/df555.yaml
new file mode 100644
index 0000000000..0925ba9145
--- /dev/null
+++ b/vendor/dingtek/df555.yaml
@@ -0,0 +1,158 @@
+name: df555
+description: The CNDingtek df555 is an ultrasonic level for kinds tank, which is installed on top of the tank.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df555-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df555-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df555-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df555-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df555-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df555-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df555-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ - gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 95
+ height: 123
+
+# Weight in grams (optional)
+weight: 500
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP67
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/top-installation-level-sensor-df555
+#dataSheetURL: http://www.dingtek.com/documents/23/df555_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df555.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/CEzacjJCQm4
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df556-codec.yaml b/vendor/dingtek/df556-codec.yaml
new file mode 100644
index 0000000000..b1ce958143
--- /dev/null
+++ b/vendor/dingtek/df556-codec.yaml
@@ -0,0 +1,114 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df556.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload without gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x16, 0x02, 0x12, 0x02, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x00, 0x01, 0x81]
+ output:
+ data:
+ level: 613
+ gpsEnabled: false
+ alarmLevel: false
+ alarmBattery: false
+ volt: 360
+ frameCounter: 1
+
+ - description: heartbeat upload with gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x16, 0x02, 0x1A, 0x02, 0x65, 0x01, 0xCD, 0x03, 0xE9, 0x42, 0xEF, 0x27, 0x20, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x00, 0x01, 0x81]
+ output:
+ data:
+ level: 613
+ gpsEnabled: true
+ longitude: '116.507430'
+ latitude: '40.038999'
+ alarmLevel: false
+ alarmBattery: false
+ volt: 360
+ frameCounter: 1
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x16, 0x03, 0x11, 0x04, 0x05, 0x00, 0x3C, 0x0A, 0x1E, 0x4B, 0x03, 0xE8, 0x14, 0x00, 0x81]
+ output:
+ data:
+ firmware: '4.5'
+ uploadInterval: 60
+ detectInterval: 10
+ levelThreshold: 30
+ density: 1000
+ batteryThreshold: 20
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df556.js
+ examples:
+ - description: change periodic upload interval to 60 minutes
+ input:
+ data:
+ uploadInterval: 60
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x30, 0x33, 0x43, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change level alarm threshold to 35cm
+ input:
+ data:
+ levelThreshold: 35
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ fPort: 3
+
+ - description: change liquid density to 1000mg/cm3
+ input:
+ data:
+ density: 1000
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x41, 0x30, 0x33, 0x45, 0x38, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df556.js
+ examples:
+ - description: change periodic upload interval to 60 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x30, 0x33, 0x43, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 60
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change level alarm threshold to 35cm
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 35
+
+ - description: change liquid density to 1000mg/cm3
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x41, 0x30, 0x33, 0x45, 0x38, 0x38, 0x31]
+ output:
+ data:
+ density: 1000
diff --git a/vendor/dingtek/df556.js b/vendor/dingtek/df556.js
new file mode 100644
index 0000000000..52764c4247
--- /dev/null
+++ b/vendor/dingtek/df556.js
@@ -0,0 +1,335 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 18:
+ if (input.bytes[3] != 0x03) {
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ gpsEnabled: Boolean(input.bytes[7]),
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ volt: (input.bytes[13] << 8) + input.bytes[14],
+ frameCounter: (input.bytes[15] << 8) + input.bytes[16],
+ },
+ };
+ } else {
+ return {
+ errors: ['wrong length'],
+ };
+ }
+ case 17:
+ if (input.bytes[3] == 0x03) {
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: (input.bytes[7] << 8) + input.bytes[8],
+ detectInterval: input.bytes[9],
+ levelThreshold: input.bytes[10],
+ density: (input.bytes[12] << 8) + input.bytes[13],
+ batteryThreshold: input.bytes[14],
+ workMode: input.bytes[15],
+ },
+ };
+ } else {
+ return {
+ errors: ['wrong length'],
+ };
+ }
+ case 26:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ gpsEnabled: Boolean(input.bytes[7]),
+ alarmLevel: Boolean(input.bytes[19] >> 4),
+ alarmBattery: Boolean(input.bytes[20] & 0x0f),
+ longitude: hex2float((input.bytes[11] << 24) + (input.bytes[10] << 16) + (input.bytes[9] << 8) + input.bytes[8]).toFixed(6),
+ latitude: hex2float((input.bytes[15] << 24) + (input.bytes[14] << 16) + (input.bytes[13] << 8) + input.bytes[12]).toFixed(6),
+ volt: (input.bytes[21] << 8) + input.bytes[22],
+ frameCounter: (input.bytes[23] << 8) + input.bytes[24],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadIntervalStr= uploadInterval.toString(16).padStart(4, '0').toUpperCase();
+ var uploadInterval3rd = uploadIntervalStr[0].charCodeAt(0);
+ var uploadInterval2nd = uploadIntervalStr[1].charCodeAt(0);
+ var uploadInterval1st = uploadIntervalStr[2].charCodeAt(0);
+ var uploadInterval0zr = uploadIntervalStr[3].charCodeAt(0);
+ if (uploadInterval > 65535 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-65535 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval3rd, uploadInterval2nd,uploadInterval1st,uploadInterval0zr, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detection_interval = input.data.detectInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['cyclic detection interval range 1-60 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.density != null && !isNaN(input.data.density)) {
+ var density = input.data.density;
+ var densityStr= density.toString(16).padStart(4, '0').toUpperCase();
+ var density3rd = densityStr[0].charCodeAt(0);
+ var density2nd = densityStr[1].charCodeAt(0);
+ var density1st = densityStr[2].charCodeAt(0);
+ var density0zr = densityStr[3].charCodeAt(0);
+ if (density > 65535 || density < 1) {
+ return {
+ errors: ['upload interval range 1-65535 mg/cm3 .'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x41, density3rd, density2nd,density1st,density0zr, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var levelThreshold = input.data.levelThreshold;
+ var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (levelThreshold > 255 || levelThreshold < 1) {
+ return {
+ errors: ['Level alarm threshold range 1-255.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['Battery alarm threshold range 5-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.gpsEnable != null && !isNaN(input.data.gpsEnable)) {
+ var gpsEnable = input.data.gpsEnable;
+ if (gpsEnable == true || gpsEnable == 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x31, 0x38, 0x31],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x30, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.workMode != null && !isNaN(input.data.workMode)) {
+ var workMode = input.data.workMode;
+ if (workMode === 0) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x35, 0x38, 0x31],
+ };
+ } else if (workMode === 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x36, 0x38, 0x31],
+ };
+ } else if (workMode === 2) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x45, 0x38, 0x31],
+ };
+ } else {
+ return {
+ errors: ['Work mode range 0-2.'],
+ }
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]) + String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16),
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 10:
+ return {
+ data: {
+ density: parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]) + String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16),
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x00:
+ return {
+ data: {
+ gpsEnable: 0,
+ },
+ };
+ case 0x01:
+ return {
+ data: {
+ gpsEnable: 1,
+ },
+ };
+ case 0x02:
+ return {
+ data: {
+ reset: 1,
+ },
+ };
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+
+ case 0x0E:
+ return {
+ data: {
+ workMode: 2,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/df556.png b/vendor/dingtek/df556.png
new file mode 100644
index 0000000000..62e6fddf34
Binary files /dev/null and b/vendor/dingtek/df556.png differ
diff --git a/vendor/dingtek/df556.yaml b/vendor/dingtek/df556.yaml
new file mode 100644
index 0000000000..ef511463ac
--- /dev/null
+++ b/vendor/dingtek/df556.yaml
@@ -0,0 +1,158 @@
+name: df556
+description: The CNDingtek df556 is a pressure type level for kinds tank, which is installed on top of the tank.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df556-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df556-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df556-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df556-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df556-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df556-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df556-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ - gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 95
+ height: 123
+
+# Weight in grams (optional)
+weight: 820
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP67
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/pressure-liquid-level-sens-df556
+#dataSheetURL: http://www.dingtek.com/documents/23/df556_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df556.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/Q_t8VMRS5nk
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df701-codec.yaml b/vendor/dingtek/df701-codec.yaml
new file mode 100644
index 0000000000..14ccb4f675
--- /dev/null
+++ b/vendor/dingtek/df701-codec.yaml
@@ -0,0 +1,81 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df701.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x02, 0x12, 0x27, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x00, 0x01, 0x81]
+ output:
+ data:
+ level: 9999
+ alarmLevel: false
+ alarmBattery: false
+ volt: 3.60
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x0C, 0x01, 0x02, 0x0A, 0x0A, 0x14, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.2'
+ uploadInterval: 10
+ detectInterval: 10
+ levelThreshold: 20
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df701.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change full alarm threshold to 35cm
+ input:
+ data:
+ levelThreshold: 35
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df701.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change full alarm threshold to 35cm
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 35
diff --git a/vendor/dingtek/df701.js b/vendor/dingtek/df701.js
new file mode 100644
index 0000000000..ccd69ae82c
--- /dev/null
+++ b/vendor/dingtek/df701.js
@@ -0,0 +1,241 @@
+var units = [' ℃', ' hours', ' minutes', ' mm', ' °', ' cm'];
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+
+ switch (input.bytes.length) {
+ case 18:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ volt: ((input.bytes[13] << 8) + input.bytes[14]) / 100,
+ frameCounter: (input.bytes[15] << 8) + input.bytes[16],
+ },
+ };
+
+ case 12:
+ var data_type = input.bytes[3];
+ if (data_type === 0x03) {
+ return {
+ // Decoded parameter
+ data: {
+ firmware: input.bytes[5] + '.' + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ levelThreshold: input.bytes[9],
+ workMode: input.bytes[10],
+ },
+ };
+ }
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var periodic_interval = input.data.uploadInterval;
+ var periodic_interval_high = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var periodic_interval_low = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (periodic_interval > 168 || periodic_interval < 1) {
+ return {
+ errors: ['periodic upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, periodic_interval_high, periodic_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detection_interval = input.data.detectInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['cyclic detection interval range 1-60 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var full_alarm_threshold = input.data.levelThreshold;
+ var full_alarm_threshold_high = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var full_alarm_threshold_low = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (full_alarm_threshold > 255 || full_alarm_threshold < 15) {
+ return {
+ errors: ['full alarm threshold range 15-255 cm.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, full_alarm_threshold_high, full_alarm_threshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.workMode != null) {
+ var workMode = input.data.workMode;
+ switch (workMode) {
+ case 0:
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x30, 0x38, 0x31],
+ };
+ break;
+ case 1:
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x31, 0x38, 0x31],
+ };
+ break;
+ case 2:
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x45, 0x38, 0x31],
+ };
+ break;
+ default:
+ break;
+ }
+ }
+
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x03:
+ return {
+ data: {
+ activeMode: ABP,
+ },
+ };
+ case 0x04:
+ return {
+ data: {
+ activeMode: OTAA,
+ },
+ };
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+ case 0x0e:
+ return {
+ data: {
+ workMode: 2,
+ },
+ };
+ case 0x09:
+ return {
+ data: {
+ fallEnable: false,
+ },
+ };
+ case 0x0a:
+ return {
+ data: {
+ fallEnable: true,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
diff --git a/vendor/dingtek/df701.png b/vendor/dingtek/df701.png
new file mode 100644
index 0000000000..c445359b5e
Binary files /dev/null and b/vendor/dingtek/df701.png differ
diff --git a/vendor/dingtek/df701.yaml b/vendor/dingtek/df701.yaml
new file mode 100644
index 0000000000..8e2c5045c4
--- /dev/null
+++ b/vendor/dingtek/df701.yaml
@@ -0,0 +1,157 @@
+name: df701
+description: The CNDingtek df701 is a laser level sensor for indoor waste bins. The measured data is reported to a LoRaWAN® network that notifies garbage collecting authorities to collect and empty the bins.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df701-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df701-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df701-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df701-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df701-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df701-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df701-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ #- gps
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ #- temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ length: 67
+ width: 59
+ height: 23
+
+# Weight in grams (optional)
+weight: 70
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER18505
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/waste-bin-sensor-df701
+#dataSheetURL: http://www.dingtek.com/documents/23/df701_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df701.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+#videos:
+#main: https://youtu.be/86XVM0thJMY
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/df703-codec.yaml b/vendor/dingtek/df703-codec.yaml
new file mode 100644
index 0000000000..f09f47f966
--- /dev/null
+++ b/vendor/dingtek/df703-codec.yaml
@@ -0,0 +1,145 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: df703.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload without gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0, 1, 1, 0x11, 7, 0xD0, 0, 0x19, 0, 0, 0, 0, 0, 1, 0, 0x81]
+ output:
+ data:
+ level: 2000
+ alarmLevel: false
+ alarmFire: false
+ alarmFall: false
+ alarmBattery: false
+ angle: 0
+ temperature: 25
+ frameCounter: 1
+
+ - description: heartbeat upload with gps
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x01, 0x19, 0x07, 0xD0, 0x01, 0xCD, 0x03, 0xE9, 0x42, 0xEF, 0x27, 0x20, 0x42, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x81]
+ output:
+ data:
+ level: 2000
+ longitude: '116.507430'
+ latitude: '40.038999'
+ alarmLevel: false
+ alarmFire: false
+ alarmFall: false
+ alarmBattery: false
+ angle: 0
+ temperature: 25
+ frameCounter: 1
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x19, 0x01, 0x04, 0x18, 0x01, 0x1E, 0x4B, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.4'
+ uploadInterval: 24
+ detectInterval: 1
+ levelThreshold: 30
+ fireThreshold: 75
+ fallThreshold: 30
+ fallEnable: false
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: df703.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change full alarm threshold to 35cm
+ input:
+ data:
+ levelThreshold: 35
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ fPort: 3
+ - description: change fire alarm threshold to 70℃
+ input:
+ data:
+ fireThreshold: 70
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, 0x34, 0x36, 0x38, 0x31]
+ fPort: 3
+ - description: change tilt alarm threshold to 45°
+ input:
+ data:
+ fallThreshold: 45
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x32, 0x44, 0x38, 0x31]
+ fPort: 3
+ - description: enable fall detection
+ input:
+ data:
+ fallEnable: true
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: df703.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change full alarm threshold to 35cm
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x32, 0x33, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 35
+ - description: change fire alarm threshold to 70℃
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, 0x34, 0x36, 0x38, 0x31]
+ output:
+ data:
+ fireThreshold: 70
+ - description: change tilt alarm threshold to 45°
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x32, 0x44, 0x38, 0x31]
+ output:
+ data:
+ fallThreshold: 45
+ - description: enable tilt detection
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ fallEnable: true
diff --git a/vendor/dingtek/df703.js b/vendor/dingtek/df703.js
new file mode 100644
index 0000000000..4b4847efe2
--- /dev/null
+++ b/vendor/dingtek/df703.js
@@ -0,0 +1,309 @@
+var units = [' ℃', ' hours', ' minutes', ' mm', ' °', ' cm'];
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+
+ switch (input.bytes.length) {
+ case 17:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmFire: Boolean(input.bytes[11] & 0x0f),
+ alarmFall: Boolean(input.bytes[12] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ angle: (input.bytes[9] & (0x0f === 0x00) ? input.bytes[10] : 0 - input.bytes[10]),
+ temperature: input.bytes[8],
+ frameCounter: (input.bytes[13] << 8) + input.bytes[14],
+ },
+ };
+
+ case 25:
+ var data_type = input.bytes[3];
+ if (data_type === 0x03) {
+ return {
+ // Decoded parameter
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ levelThreshold: input.bytes[9],
+ fireThreshold: input.bytes[10],
+ fallThreshold: input.bytes[11],
+ fallEnable: Boolean(input.bytes[12]),
+ workMode:input.bytes[14],
+ },
+ };
+ } else {
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ longitude: hex2float((input.bytes[11] << 24) + (input.bytes[10] << 16) + (input.bytes[9] << 8) + input.bytes[8]).toFixed(6),
+ latitude: hex2float((input.bytes[15] << 24) + (input.bytes[14] << 16) + (input.bytes[13] << 8) + input.bytes[12]).toFixed(6),
+ alarmLevel: Boolean(input.bytes[19] >> 4),
+ alarmFire: Boolean(input.bytes[19] & 0x0f),
+ alarmFall: Boolean(input.bytes[20] >> 4),
+ alarmBattery: Boolean(input.bytes[20] & 0x0f),
+ angle: (input.bytes[17] & (0x0f === 0x00) ? input.bytes[18] : 0 - input.bytes[18]),
+ temperature: input.bytes[16],
+ frameCounter: (input.bytes[21] << 8) + input.bytes[22],
+ },
+ };
+ }
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 168 || uploadInterval < 1) {
+ return {
+ errors: ['periodic upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detection_interval = input.data.detectInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['cyclic detection interval range 1-60 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var full_alarm_threshold = input.data.levelThreshold;
+ var full_alarm_threshold_high = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var full_alarm_threshold_low = full_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (full_alarm_threshold > 255 || full_alarm_threshold < 15) {
+ return {
+ errors: ['full alarm threshold range 15-255 cm.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, full_alarm_threshold_high, full_alarm_threshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.fireThreshold != null && !isNaN(input.data.fireThreshold)) {
+ var fireThreshold = input.data.fireThreshold;
+ var fireThreshold_high = fireThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var fireThreshold_low = fireThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (fireThreshold > 255 || fireThreshold < 1) {
+ return {
+ errors: ['fire alarm threshold range 1-255 cellus degree.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, fireThreshold_high, fireThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.fallThreshold != null && !isNaN(input.data.fallThreshold)) {
+ var tilt_alarm_threshold = input.data.fallThreshold;
+ var tilt_alarm_threshold_high = tilt_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var tilt_alarm_threshold_low = tilt_alarm_threshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (tilt_alarm_threshold > 90 || tilt_alarm_threshold < 15) {
+ return {
+ errors: ['fall alarm threshold range 15-90 °.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, tilt_alarm_threshold_high, tilt_alarm_threshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.fallEnable != null && input.data.fallEnable === !!input.data.fallEnable) {
+ var tilt_enable = input.data.fallEnable;
+ if (tilt_enable === true) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x41, 0x38, 0x31],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x39, 0x38, 0x31],
+ };
+ }
+ }
+
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 3:
+ return {
+ data: {
+ fireThreshold: value,
+ },
+ };
+ case 4:
+ return {
+ data: {
+ fallThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x00:
+ return {
+ data: {
+ gpsEnable: false,
+ },
+ };
+ case 0x01:
+ return {
+ data: {
+ gpsEnable: true,
+ },
+ };
+ case 0x03:
+ return {
+ data: {
+ activeMode: ABP,
+ },
+ };
+ case 0x04:
+ return {
+ data: {
+ activeMode: OTAA,
+ },
+ };
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+ case 0x0E:
+ return {
+ data: {
+ workMode: 2,
+ },
+ };
+ case 0x09:
+ return {
+ data: {
+ fallEnable: false,
+ },
+ };
+ case 0x0a:
+ return {
+ data: {
+ fallEnable: true,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
diff --git a/vendor/dingtek/df703.png b/vendor/dingtek/df703.png
new file mode 100644
index 0000000000..338da0cb47
Binary files /dev/null and b/vendor/dingtek/df703.png differ
diff --git a/vendor/dingtek/df703.yaml b/vendor/dingtek/df703.yaml
new file mode 100644
index 0000000000..6e2da7b977
--- /dev/null
+++ b/vendor/dingtek/df703.yaml
@@ -0,0 +1,157 @@
+name: df703
+description: The CNDingtek df703 is an ultrasonic level waste bin sensor that consists of a level sensor, fire sensor, and accelerometer. The measured data is reported to a LoRaWAN® network that notifies garbage collecting authorities to collect and empty the bins.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df703-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df703-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: df703-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: df703-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: df703-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: df703-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: df703-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ - gps
+ - motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 115
+ height: 40
+
+# Weight in grams (optional)
+weight: 150
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP68
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/waste-bin-sensor-df703
+#dataSheetURL: http://www.dingtek.com/documents/23/df703_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: df703.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/eJ1fTiSvOSw
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dingtek-profile-470.yaml b/vendor/dingtek/dingtek-profile-470.yaml
index 7977c4b208..ea3470a072 100644
--- a/vendor/dingtek/dingtek-profile-470.yaml
+++ b/vendor/dingtek/dingtek-profile-470.yaml
@@ -1,5 +1,5 @@
-macVersion: 1.0.2
-regionalParametersVersion: RP001-1.0.2
+macVersion: 1.0.3
+regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 20
supports32bitFCnt: true
diff --git a/vendor/dingtek/dingtek-profile-865.yaml b/vendor/dingtek/dingtek-profile-865.yaml
index aec7ad6d23..5cb3e039bb 100644
--- a/vendor/dingtek/dingtek-profile-865.yaml
+++ b/vendor/dingtek/dingtek-profile-865.yaml
@@ -1,5 +1,5 @@
-macVersion: 1.0.2
-regionalParametersVersion: RP001-1.0.2
+macVersion: 1.0.3
+regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 30
supports32bitFCnt: true
diff --git a/vendor/dingtek/dingtek-profile-915.yaml b/vendor/dingtek/dingtek-profile-915.yaml
index aec7ad6d23..5cb3e039bb 100644
--- a/vendor/dingtek/dingtek-profile-915.yaml
+++ b/vendor/dingtek/dingtek-profile-915.yaml
@@ -1,5 +1,5 @@
-macVersion: 1.0.2
-regionalParametersVersion: RP001-1.0.2
+macVersion: 1.0.3
+regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 30
supports32bitFCnt: true
diff --git a/vendor/dingtek/dingtek-profile-923.yaml b/vendor/dingtek/dingtek-profile-923.yaml
index 310e161f67..31c0dee4e5 100644
--- a/vendor/dingtek/dingtek-profile-923.yaml
+++ b/vendor/dingtek/dingtek-profile-923.yaml
@@ -1,5 +1,5 @@
-macVersion: 1.0.2
-regionalParametersVersion: RP001-1.0.2
+macVersion: 1.0.3
+regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 16
supports32bitFCnt: true
diff --git a/vendor/dingtek/do200-codec.yaml b/vendor/dingtek/do200-codec.yaml
new file mode 100644
index 0000000000..80d209db80
--- /dev/null
+++ b/vendor/dingtek/do200-codec.yaml
@@ -0,0 +1,85 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: do200.js
+ # Examples (optional)
+ examples:
+ - description: telemetry upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x02, 0x01, 0x15, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6F, 0x00, 0x79, 0xFF, 0xB0, 0xFF, 0xF5, 0x00, 0x00, 0x00, 0x81]
+ output:
+ data:
+ level: 0
+ volt: 3.67
+ alarmPark: false
+ alarmLevel: false
+ alarmMagnet: false
+ alarmBattery: false
+ xMagnet: 121
+ yMagnet: -80
+ zMagnet: -11
+ Frame_Counter: 0
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x02, 0x03, 0x11, 0x00, 0x0B, 0x18, 0x02, 0x0A, 0x05, 0xA0, 0x00, 0x3C, 0x00, 0x00, 0x81]
+ output:
+ data:
+ firmware: '0.11'
+ uploadInterval: 24
+ ultraDetectInterval: 2
+ magDetectInterval: 10
+ magThreshold: 60
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: do200.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change geomagnetic detection interval to 10 seconds
+ input:
+ data:
+ magDetectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x34, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change geomagnetic threshold to 60mGs
+ input:
+ data:
+ magThreshold: 60
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x32, 0x33, 0x43, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: do200.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change geomagnetic detection interval to 10 seconds
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x34, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ magDetectInterval: 10
+ - description: change geomagnetic threshold to 60mGs
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x32, 0x33, 0x43, 0x38, 0x31]
+ output:
+ data:
+ magThreshold: 60
diff --git a/vendor/dingtek/do200.js b/vendor/dingtek/do200.js
new file mode 100644
index 0000000000..058e30cfd7
--- /dev/null
+++ b/vendor/dingtek/do200.js
@@ -0,0 +1,215 @@
+var units = [' ℃', ' hours', ' minutes', ' mm', ' °', ' cm'];
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+
+ switch (input.bytes.length) {
+ case 21:
+ var mag_x = (input.bytes[11] << 8) + input.bytes[12];
+ var mag_y = (input.bytes[13] << 8) + input.bytes[14];
+ var mag_z = (input.bytes[15] << 8) + input.bytes[16];
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ volt: ((input.bytes[9] << 8) + input.bytes[10]) / 100,
+ alarmPark: Boolean(input.bytes[7] >> 4),
+ alarmLevel: Boolean(input.bytes[7] & 0x0f),
+ alarmMagnet: Boolean(input.bytes[8] >> 4),
+ alarmBattery: Boolean(input.bytes[8] & 0x0f),
+ xMagnet: mag_x > 32767 ? mag_x - 65536 : mag_x,
+ yMagnet: mag_y > 32767 ? mag_y - 65536 : mag_y,
+ zMagnet: mag_z > 32767 ? mag_z - 65536 : mag_z,
+ Frame_Counter: (input.bytes[17] << 8) + input.bytes[18],
+ },
+ };
+
+ case 17:
+ var data_type = input.bytes[3];
+ if (data_type === 0x03) {
+ return {
+ // Decoded parameter
+ data: {
+ firmware: input.bytes[5] + '.' + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ ultraDetectInterval: input.bytes[8],
+ magDetectInterval: input.bytes[9],
+ magThreshold: (input.bytes[12] << 8) + input.bytes[13],
+ },
+ };
+ }
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var periodic_interval = input.data.uploadInterval;
+ var periodic_interval_high = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var periodic_interval_low = periodic_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (periodic_interval > 168 || periodic_interval < 1) {
+ return {
+ errors: ['periodic upload interval range 1-168 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x31, periodic_interval_high, periodic_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.ultraDetectionInterval != null && !isNaN(input.data.ultraDetectionInterval)) {
+ var detection_interval = input.data.ultraDetectionInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['ultra detection interval range 1-60 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x33, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.magDetectInterval != null && !isNaN(input.data.magDetectInterval)) {
+ var detection_interval = input.data.magDetectInterval;
+ var detection_interval_high = detection_interval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detection_interval_low = detection_interval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detection_interval > 60 || detection_interval < 1) {
+ return {
+ errors: ['mag detection interval range 1-60 seconds.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x34, detection_interval_high, detection_interval_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 5) {
+ return {
+ errors: ['battery alarm threshold range 5-99 %.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.magThreshold != null && !isNaN(input.data.magThreshold)) {
+ var magThreshold = input.data.magThreshold;
+ var magThreshold_high = magThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var magThreshold_low = magThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (magThreshold > 255 || magThreshold < 1) {
+ return {
+ errors: ['Geomagnet threshold range 1-255 mGs.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x38, 0x38, 0x38, 0x38, 0x30, 0x32, magThreshold_high, magThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x38 ||
+ input.bytes[5] != 0x38 ||
+ input.bytes[6] != 0x38 ||
+ input.bytes[7] != 0x38 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ magThreshold: value,
+ },
+ };
+ case 3:
+ return {
+ data: {
+ ultraDetectInterval: value,
+ },
+ };
+ case 4:
+ return {
+ data: {
+ magDetectInterval: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
diff --git a/vendor/dingtek/do200.png b/vendor/dingtek/do200.png
new file mode 100644
index 0000000000..f59963a3a2
Binary files /dev/null and b/vendor/dingtek/do200.png differ
diff --git a/vendor/dingtek/do200.yaml b/vendor/dingtek/do200.yaml
new file mode 100644
index 0000000000..627dcf9b64
--- /dev/null
+++ b/vendor/dingtek/do200.yaml
@@ -0,0 +1,157 @@
+name: do200
+description: The CNDingtek do200 is parking occupation sensor with combination of ultrasonic and magnetic detection , fire sensor, and accelerometer.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: do200-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: do200-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: do200-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: do200-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: do200-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: do200-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: do200-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - level
+ - magnetometer
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ #- temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 115
+ height: 50
+
+# Weight in grams (optional)
+weight: 150
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: ER26500
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP68
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://dingtek.com/parking-occupation-sensor-do200
+#dataSheetURL: http://www.dingtek.com/documents/23/do200_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: do200.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/wfHHbZIhZMs
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dt311-codec.yaml b/vendor/dingtek/dt311-codec.yaml
new file mode 100644
index 0000000000..648158eda9
--- /dev/null
+++ b/vendor/dingtek/dt311-codec.yaml
@@ -0,0 +1,137 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dt311.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x02, 0x12, 0x01, 0xA4, 0x00, 0x00, 0x26, 0x69, 0x57, 0x62, 0x10, 0x10, 0x00, 0x01, 0x81]
+ output:
+ data:
+ temperature: '26.69'
+ humidity: '57.62'
+ alarmHighTemperature: true
+ alarmLowTemperature: false
+ alarmHighHumidity: true
+ alarmLowHumidity: false
+ alarmBattery: false
+ volt: 4.20
+ frameCounter: 1
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x01, 0x03, 0x11, 0x01, 0x02, 0x18, 0x0A, 0x00, 0x64, 0x01, 0x0A, 0x64, 0x00, 0x00, 0x14, 0x81]
+ output:
+ data:
+ firmware: '1.2'
+ uploadInterval: 24
+ detectInterval: 10
+ highTemperatureThreshold: 100
+ lowTemperatureThreshold: -10
+ highHumidityThreshold: 100
+ lowHumidityThreshold: 0
+ batteryThreshold: 20
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dt311.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: change high temperature alarm threshold to 50℃
+ input:
+ data:
+ highTemperatureThreshold: 50
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x30, 0x33, 0x32, 0x38, 0x31]
+ fPort: 3
+
+ - description: change low temperature alarm threshold to -10℃
+ input:
+ data:
+ lowTemperatureThreshold: -10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+
+ - description: change high humidity alarm threshold to 70%
+ input:
+ data:
+ highHumidityThreshold: 70
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x34, 0x36, 0x38, 0x31]
+ fPort: 3
+
+ - description: change low humidity alarm threshold to 20%
+ input:
+ data:
+ lowHumidityThreshold: 20
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x45, 0x31, 0x34, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dt311.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: change high temperature alarm threshold to 50℃
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x30, 0x33, 0x32, 0x38, 0x31]
+ output:
+ data:
+ highTemperatureThreshold: 50
+
+ - description: change low temperature alarm threshold to -10℃
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, 0x30, 0x31, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ lowTemperatureThreshold: -10
+
+ - description: change high humidity alarm threshold to 70%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, 0x34, 0x36, 0x38, 0x31]
+ output:
+ data:
+ highHumidityThreshold: 70
+
+ - description: change low humidity alarm threshold to 10%
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x45, 0x31, 0x34, 0x38, 0x31]
+ output:
+ data:
+ lowHumidityThreshold: 20
diff --git a/vendor/dingtek/dt311.js b/vendor/dingtek/dt311.js
new file mode 100644
index 0000000000..5824915f08
--- /dev/null
+++ b/vendor/dingtek/dt311.js
@@ -0,0 +1,315 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes[3]) {
+ case 1:
+ case 2:
+ var temp_sign = input.bytes[8];
+ var temp_abs = (input.bytes[9] >> 4) * 10 + (input.bytes[9] & 0x0F) + (input.bytes[10] >> 4) / 10 + (input.bytes[10] & 0x0F) / 100;
+ var humi_abs = (input.bytes[11] >> 4) * 10 + (input.bytes[11] & 0x0F) + (input.bytes[12] >> 4) / 10 + (input.bytes[12] & 0x0F) / 100;
+ var temperature_temp=(temp_sign == 0 )? temp_abs : (0 - temp_abs);
+ return {
+ // Decoded data
+ data: {
+ temperature: temperature_temp.toFixed(2),
+ humidity: humi_abs.toFixed(2),
+ alarmHighTemperature: (input.bytes[13] & 0x10) ? true : false,
+ alarmLowTemperature: (input.bytes[13] & 0x01) ? true : false,
+ alarmHighHumidity: (input.bytes[14] & 0x10) ? true : false,
+ alarmLowHumidity: (input.bytes[14] & 0x01) ? true : false,
+ alarmBattery: (input.bytes[7] & 0x01) ? true : false,
+ volt: ((input.bytes[5] << 8) + input.bytes[6]) / 100,
+ frameCounter: (input.bytes[15] << 8) + input.bytes[16],
+ },
+ };
+ case 3:
+ var high_temp_abs = input.bytes[10];
+ var low_temp_abs = input.bytes[12];
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." + input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ highTemperatureThreshold: input.bytes[9] ? 256 - high_temp_abs : high_temp_abs,
+ lowTemperatureThreshold: input.bytes[11] ? 0 - low_temp_abs : low_temp_abs,
+ highHumidityThreshold: input.bytes[13],
+ lowHumidityThreshold: input.bytes[14],
+ batteryThreshold: input.bytes[16],
+ workMode: input.bytes[15],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 255 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-255 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detectInterval = input.data.detectInterval;
+ var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detectInterval > 255 || detectInterval < 1) {
+ return {
+ errors: ['detection interval range 1-255 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.highTemperatureThreshold != null && !isNaN(input.data.highTemperatureThreshold)) {
+ var highTemperatureThreshold = input.data.highTemperatureThreshold<0?0-input.data.highTemperatureThreshold:input.data.highTemperatureThreshold;
+ var highTemperatureSign=input.data.highTemperatureThreshold<0?0x31:0x30;
+ var highTemperatureThreshold_high = highTemperatureThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var highTemperatureThreshold_low = highTemperatureThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (input.data.highTemperatureThreshold > 85 || input.data.highTemperatureThreshold < -30) {
+ return {
+ errors: ['High temperature alarm threshold range -30~+85.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30,highTemperatureSign,highTemperatureThreshold_high, highTemperatureThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.lowTemperatureThreshold != null && !isNaN(input.data.lowTemperatureThreshold)) {
+ var lowTemperatureThreshold = input.data.lowTemperatureThreshold<0?0-input.data.lowTemperatureThreshold:input.data.lowTemperatureThreshold;
+ var lowTemperatureSign=input.data.lowTemperatureThreshold<0?0x31:0x30;
+ var lowTemperatureThreshold_high = lowTemperatureThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var lowTemperatureThreshold_low = lowTemperatureThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (input.data.lowTemperatureThreshold > 85 || input.data.lowTemperatureThreshold < -30) {
+ return {
+ errors: ['Low temperature alarm threshold range -30~+85.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x33, 0x30,lowTemperatureSign,lowTemperatureThreshold_high, lowTemperatureThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.highHumidityThreshold != null && !isNaN(input.data.highHumidityThreshold)) {
+ var highHumidityThreshold = input.data.highHumidityThreshold<0?0-input.data.highHumidityThreshold:input.data.highHumidityThreshold;
+ var highHumidityThreshold_high = highHumidityThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var highHumidityThreshold_low = highHumidityThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (input.data.highHumidityThreshold > 100 || input.data.highHumidityThreshold < 0) {
+ return {
+ errors: ['High humidity alarm threshold range 0~100.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x34, highHumidityThreshold_high, highHumidityThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.lowHumidityThreshold != null && !isNaN(input.data.lowHumidityThreshold)) {
+ var lowHumidityThreshold = input.data.lowHumidityThreshold<0?0-input.data.lowHumidityThreshold:input.data.lowHumidityThreshold;
+ var lowHumidityThreshold_high = lowHumidityThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var lowHumidityThreshold_low = lowHumidityThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (input.data.lowHumidityThreshold > 100 || input.data.lowHumidityThreshold < 0) {
+ return {
+ errors: ['High humidity alarm threshold range 0~100.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x45, lowHumidityThreshold_high, lowHumidityThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.batteryThreshold != null && !isNaN(input.data.batteryThreshold)) {
+ var batteryThreshold = input.data.batteryThreshold;
+ var batteryThreshold_high = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var batteryThreshold_low = batteryThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (batteryThreshold > 99 || batteryThreshold < 1) {
+ return {
+ errors: ['Battery alarm threshold range 1-99.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, batteryThreshold_high, batteryThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.workMode != null && !isNaN(input.data.workMode)) {
+ var workMode = input.data.workMode;
+ if (workMode === 0) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x35, 0x38, 0x31],
+ };
+ } else if (workMode === 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x36, 0x38, 0x31],
+ };
+ } else {
+ return {
+ errors: ['Work mode range 0-1.'],
+ }
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ var temp_abs = parseInt(String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16);
+ return {
+ data: {
+ highTemperatureThreshold: value > 0 ? 0 - temp_abs : temp_abs,
+ },
+ };
+ case 3:
+ var temp_abs = parseInt(String.fromCharCode(input.bytes[12]) + String.fromCharCode(input.bytes[13]), 16);
+ return {
+ data: {
+ lowTemperatureThreshold: value > 0 ? 0 - temp_abs : temp_abs,
+ },
+ };
+ case 4:
+ return {
+ data: {
+ highHumidityThreshold: value,
+ },
+ };
+ case 5:
+ return {
+ data: {
+ batteryThreshold: value,
+ },
+ };
+ case 14:
+ return {
+ data: {
+ lowHumidityThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/dt311.png b/vendor/dingtek/dt311.png
new file mode 100644
index 0000000000..e03c67db11
Binary files /dev/null and b/vendor/dingtek/dt311.png differ
diff --git a/vendor/dingtek/dt311.yaml b/vendor/dingtek/dt311.yaml
new file mode 100644
index 0000000000..4c303b656d
--- /dev/null
+++ b/vendor/dingtek/dt311.yaml
@@ -0,0 +1,158 @@
+name: dt311
+description: The CNDingtek dt311 is temperature and humidity sensor for indoor using.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dt311-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dt311-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dt311-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dt311-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dt311-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dt311-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dt311-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - humidity
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+ - temperature
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 80
+ height: 38
+
+# Weight in grams (optional)
+weight: 100
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: 1000mAh
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP67
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/temperature-humitidy-sensor-dt311
+#dataSheetURL: http://www.dingtek.com/documents/23/dt311_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: dt311.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/Y1FqgKDrRsc
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/dt320-codec.yaml b/vendor/dingtek/dt320-codec.yaml
new file mode 100644
index 0000000000..2386baff28
--- /dev/null
+++ b/vendor/dingtek/dt320-codec.yaml
@@ -0,0 +1,82 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: dt320.js
+ # Examples (optional)
+ examples:
+ - description: heartbeat upload
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x20, 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x74, 0x00, 0x03, 0x81]
+ output:
+ data:
+ level: 0
+ alarmLevel: false
+ alarmBattery: true
+ temperature: 0
+ volt: 3.72
+ frameCounter: 3
+
+ - description: parameter packet
+ input:
+ fPort: 3
+ bytes: [0x80, 0x00, 0x20, 0x03, 0x0C, 0x01, 0x02, 0x04, 0x1E, 0x01, 0x00, 0x81]
+ output:
+ data:
+ firmware: '1.2'
+ uploadInterval: 4
+ detectInterval: 30
+ levelThreshold: 1
+ workMode: 0
+
+# Downlink encoder encodes JSON object into a binary data downlink (optional)
+downlinkEncoder:
+ fileName: dt320.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ data:
+ uploadInterval: 4
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ fPort: 3
+ - description: change detection interval to 10 minutes
+ input:
+ data:
+ detectInterval: 10
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ fPort: 3
+ - description: set air alarm threshold to 1
+ input:
+ data:
+ levelThreshold: 1
+ output:
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x38, 0x31]
+ fPort: 3
+
+# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+downlinkDecoder:
+ fileName: dt320.js
+ examples:
+ - description: change periodic upload interval to 4 hours
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x30, 0x34, 0x38, 0x31]
+ output:
+ data:
+ uploadInterval: 4
+ - description: change detection interval to 10 minutes
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, 0x30, 0x41, 0x38, 0x31]
+ output:
+ data:
+ detectInterval: 10
+ - description: set air alarm threshold to 1
+ input:
+ fPort: 3
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, 0x30, 0x31, 0x38, 0x31]
+ output:
+ data:
+ levelThreshold: 1
diff --git a/vendor/dingtek/dt320.js b/vendor/dingtek/dt320.js
new file mode 100644
index 0000000000..6353910713
--- /dev/null
+++ b/vendor/dingtek/dt320.js
@@ -0,0 +1,204 @@
+//IEEE754 hex to float convert
+function hex2float(num) {
+ var sign = num & 0x80000000 ? -1 : 1;
+ var exponent = ((num >> 23) & 0xff) - 127;
+ var mantissa = 1 + (num & 0x7fffff) / 0x7fffff;
+ return sign * mantissa * Math.pow(2, exponent);
+}
+
+function decodeUplink(input) {
+ if (input.fPort != 3) {
+ return {
+ errors: ['unknown FPort'],
+ };
+ }
+ switch (input.bytes.length) {
+ case 18:
+ return {
+ // Decoded data
+ data: {
+ level: (input.bytes[5] << 8) + input.bytes[6],
+ alarmLevel: Boolean(input.bytes[11] >> 4),
+ alarmBattery: Boolean(input.bytes[12] & 0x0f),
+ temperature: input.bytes[8],
+ volt: ((input.bytes[13] << 8) + input.bytes[14]) / 100,
+ frameCounter: (input.bytes[15] << 8) + input.bytes[16],
+ },
+ };
+ case 12:
+ return {
+ // Decoded data
+ data: {
+ firmware: input.bytes[5] + "." +input.bytes[6],
+ uploadInterval: input.bytes[7],
+ detectInterval: input.bytes[8],
+ levelThreshold: input.bytes[9],
+ workMode: input.bytes[10],
+ },
+ };
+ default:
+ return {
+ errors: ['wrong length'],
+ };
+ }
+}
+
+// Encode downlink function.
+//
+// Input is an object with the following fields:
+// - data = Object representing the payload that must be encoded.
+// - variables = Object containing the configured device variables.
+//
+// Output must be an object with the following fields:
+// - bytes = Byte array containing the downlink payload.
+function encodeDownlink(input) {
+ if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) {
+ var uploadInterval = input.data.uploadInterval;
+ var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (uploadInterval > 255 || uploadInterval < 1) {
+ return {
+ errors: ['upload interval range 1-255 hours.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) {
+ var detectInterval = input.data.detectInterval;
+ var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (detectInterval > 255 || detectInterval < 1) {
+ return {
+ errors: ['detection interval range 1-255 minutes.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31],
+ };
+ }
+ }
+ if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) {
+ var levelThreshold = input.data.levelThreshold;
+ var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0);
+ var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0);
+ if (levelThreshold > 3 || levelThreshold < 1) {
+ return {
+ errors: ['Air quality alarm threshold range 1-3.'],
+ };
+ } else {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31],
+ };
+ }
+ }
+
+ if (input.data.workMode != null && !isNaN(input.data.workMode)) {
+ var workMode = input.data.workMode;
+ if (workMode === 0) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x35, 0x38, 0x31],
+ };
+ } else if(workMode === 1) {
+ return {
+ // LoRaWAN FPort used for the downlink message
+ fPort: 3,
+ // Encoded bytes
+ bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x36, 0x38, 0x31],
+ };
+ }else{
+ return {
+ errors: ['Work mode range 0-1.'],
+ }
+ }
+ }
+ return {
+ errors: ['invalid downlink parameter.'],
+ };
+}
+
+function decodeDownlink(input) {
+ var input_length = input.bytes.length;
+ if (input.fPort != 3) {
+ return {
+ errors: ['invalid FPort.'],
+ };
+ }
+
+ if (
+ input_length < 12 ||
+ input.bytes[0] != 0x38 ||
+ input.bytes[1] != 0x30 ||
+ input.bytes[2] != 0x30 ||
+ input.bytes[3] != 0x32 ||
+ input.bytes[4] != 0x39 ||
+ input.bytes[5] != 0x39 ||
+ input.bytes[6] != 0x39 ||
+ input.bytes[7] != 0x39 ||
+ input.bytes[input_length - 2] != 0x38 ||
+ input.bytes[input_length - 1] != 0x31
+ ) {
+ return {
+ errors: ['invalid format.'],
+ };
+ }
+ var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16);
+ var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16);
+ switch (option) {
+ case 1:
+ return {
+ data: {
+ uploadInterval: value,
+ },
+ };
+ case 8:
+ return {
+ data: {
+ detectInterval: value,
+ },
+ };
+ case 2:
+ return {
+ data: {
+ levelThreshold: value,
+ },
+ };
+ case 9:
+ switch (value) {
+ case 0x05:
+ return {
+ data: {
+ workMode: 0,
+ },
+ };
+ case 0x06:
+ return {
+ data: {
+ workMode: 1,
+ },
+ };
+ default:
+ return {
+ errors: ['invalid parameter value.'],
+ };
+ }
+ default:
+ return {
+ errors: ['invalid parameter key.'],
+ };
+ }
+}
\ No newline at end of file
diff --git a/vendor/dingtek/dt320.png b/vendor/dingtek/dt320.png
new file mode 100644
index 0000000000..e03c67db11
Binary files /dev/null and b/vendor/dingtek/dt320.png differ
diff --git a/vendor/dingtek/dt320.yaml b/vendor/dingtek/dt320.yaml
new file mode 100644
index 0000000000..661f3018e3
--- /dev/null
+++ b/vendor/dingtek/dt320.yaml
@@ -0,0 +1,157 @@
+name: dt320
+description: The CNDingtek dt320 is air quality sensor monitoring the level of methanal, ammonia, ethanol and cigarette.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 10
+ - version: '1.1'
+ numeric: 11
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+ - '1.1'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dt320-codec
+ US902-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dt320-codec
+ AU915-928:
+ id: dingtek-profile-915
+ lorawanCertified: false
+ codec: dt320-codec
+ AS923:
+ id: dingtek-profile-923
+ lorawanCertified: false
+ codec: dt320-codec
+ IN865-867:
+ id: dingtek-profile-865
+ lorawanCertified: false
+ codec: dt320-codec
+ CN470-510:
+ id: dingtek-profile-470
+ lorawanCertified: false
+ codec: dt320-codec
+ RU864-870:
+ id: dingtek-profile-868
+ lorawanCertified: false
+ codec: dt320-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - iaq
+ #- gps
+ #- motion
+ #- full_alarm
+ #- fire_alarm
+ #- tilt_alarm
+ #- battery_alarm
+ #- angle
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ diameter: 80
+ height: 38
+
+# Weight in grams (optional)
+weight: 100
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: 1000mAh
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 70
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP67
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - serial
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: read protected
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://www.dingtek.com/air-quality-sensor-dt320
+#dataSheetURL: http://www.dingtek.com/documents/23/dt320_Waste_Bin_Detector_LoRaWAN_V1.8.pdf
+
+# Photos
+photos:
+ main: dt320.png
+ #other:
+
+# Youtube or Vimeo Video (optional)
+videos:
+ main: https://youtu.be/T8q0kb5tMXY
+ #other: https://youtu.be/EWrX-4gCLJ4
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 1.9.2
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 1.6.1
diff --git a/vendor/dingtek/index.yaml b/vendor/dingtek/index.yaml
index d0f95c473b..4b191761bc 100644
--- a/vendor/dingtek/index.yaml
+++ b/vendor/dingtek/index.yaml
@@ -1,4 +1,19 @@
endDevices:
+ - df701
- df702
- - dc410
+ - df703
+ - df200
+ - df400
+ #- df520
- df530
+ - df555
+ - df556
+ - dc410
+ - dc413
+ - dc500
+ - dc510
+ - dc600
+ - do200
+ - dt311
+ - dt320
+ #- dt322
diff --git a/vendor/dragino/ldds75.js b/vendor/dragino/ldds75.js
index f5d90c2f0a..aa9cfcfb17 100644
--- a/vendor/dragino/ldds75.js
+++ b/vendor/dragino/ldds75.js
@@ -7,7 +7,7 @@ function decodeUplink(input) {
var interrupt = input.bytes[len-1];
switch (input.fPort) {
case 2:
- if(len==5)
+ if(len==8)
{
data.value=input.bytes[2]<<8 | input.bytes[3];
data.distance=(value);//distance,units:mm
@@ -25,4 +25,4 @@ default:
errors: ["unknown FPort"]
}
}
-}
\ No newline at end of file
+}
diff --git a/vendor/elv/elv-bm-trx1.js b/vendor/elv/elv-bm-trx1.js
index 2ad2af1bf2..3b7d464533 100644
--- a/vendor/elv/elv-bm-trx1.js
+++ b/vendor/elv/elv-bm-trx1.js
@@ -1,7 +1,7 @@
/*
* ELV modular system Payload-Parser
*
- * Version: V1.6.0
+ * Version: V1.7.0
*
* */
@@ -559,11 +559,202 @@ function Decoder(bytes, port) {
}
break;
}
- //case 0x??: // Further Data Type
+ case 0x10: // Absolute angle
+ {
+ // Get the 8 bit value
+ index++; // Set index to data value
+ Temp_Value = bytes[index];
+ switch ( bytes[index] )
+ {
+ case 0xff:
+ {
+ decoded.Absolut_Angle = "Unknown";
+ }
+ break;
+ default:
+ {
+ Temp_Value *= 2.5; // Multiply the value with the angle resolution of 2.5 °
+ decoded.Absolut_Angle = String(Temp_Value.toFixed(1));
+ }
+ break;
+ }
+ break;
+ }
+ case 0x11: // Speed
+ {
+ // Get the 16 bit value
+ index++; // Set index to high byte data value
+ Temp_Value = (bytes[index] * 256);
+ index++; // Set index to low byte data value
+ Temp_Value += bytes[index];
+
+ // Check the wind detection bit
+ if( Temp_Value & 0x0800 )
+ {
+ decoded.Wind_Detection = "1";
+ }
+ else
+ {
+ decoded.Wind_Detection = "0";
+ }
+
+ // Get the unsigned 11 bit speed value
+ Temp_Value &= 0x07ff;
+ switch ( Temp_Value )
+ {
+ case 0x7ff:
+ {
+ decoded.Wind_Speed = "Unknown";
+ }
+ break;
+ case 0x7fe:
+ {
+ decoded.Wind_Speed = "Overflow";
+ }
+ break;
+ default:
+ {
+ Temp_Value *= 0.1; // Multiply the value with the speed resolution of 0.1 km/h
+ decoded.Wind_Speed = String(Temp_Value.toFixed(1));
+ }
+ break;
+ }
+ break;
+ }
+ case 0x12: // Wind
+ {
+ // Get the 16 bit value
+ index++; // Set index to high byte data value
+ Temp_Value = (bytes[index] * 256);
+ index++; // Set index to low byte data value
+ Temp_Value += bytes[index];
+
+ // Check the variation range
+ switch ( ((Temp_Value & 0xf000) / 4096) )
+ {
+ case 0xf:
+ {
+ decoded.Variation_Angle = "Unknown";
+ }
+ break;
+ case 0xe:
+ {
+ decoded.Variation_Angle = "Overflow";
+ }
+ break;
+ default:
+ {
+ decoded.Variation_Angle = String(((11.25 * (Temp_Value & 0xf000) / 4096)).toFixed(2));
+ }
+ break;
+
+ }
+ // Check the wind detection bit
+ if( Temp_Value & 0x0800 )
+ {
+ decoded.Wind_Detection = "1";
+ }
+ else
+ {
+ decoded.Wind_Detection = "0";
+ }
- // break;
+ // Get the unsigned 11 bit speed value
+ Temp_Value &= 0x07ff;
+ switch ( Temp_Value )
+ {
+ case 0x7ff:
+ {
+ decoded.Wind_Speed = "Unknown";
+ }
+ break;
+ case 0x7fe:
+ {
+ decoded.Wind_Speed = "Overflow";
+ }
+ break;
+ default:
+ {
+ Temp_Value *= 0.1; // Multiply the value with the speed resolution of 0.1 km/h
+ decoded.Wind_Speed = String(Temp_Value.toFixed(1));
+ }
+ break;
+ }
+ // Get the 8 bit value
+ index++; // Set index to data value
+ Temp_Value = bytes[index];
+ switch ( bytes[index] )
+ {
+ case 0xff:
+ {
+ decoded.Absolut_Angle = "Unknown";
+ }
+ break;
+ default:
+ {
+ Temp_Value *= 2.5; // Multiply the value with the angle resolution of 2.5 °
+ decoded.Absolut_Angle = String(Temp_Value.toFixed(1));
+ }
+ break;
+ }
+ break;
+ }
+ case 0x13: // Rainfall
+ {
+ // Get the 16 bit value
+ index++; // Set index to high byte data value
+ Temp_Value = (bytes[index] * 256);
+ index++; // Set index to low byte data value
+ Temp_Value += bytes[index];
+
+ // Check the rain detection bit
+ if( Temp_Value & 0x8000 )
+ {
+ decoded.Rain_Detection = "1";
+ }
+ else
+ {
+ decoded.Rain_Detection = "0";
+ }
+
+ // Check the rain counter overflow bit
+ if( Temp_Value & 0x4000 )
+ {
+ decoded.Rain_Counter_Overflow = "1";
+ }
+ else
+ {
+ decoded.Rain_Counter_Overflow = "0";
+ }
+
+ // Get the unsigned 14 bit rain amount value
+ Temp_Value &= 0x3fff;
+ switch ( Temp_Value )
+ {
+ case 0x3fff:
+ {
+ decoded.Rain_Amount = "Unknown";
+ }
+ break;
+ default:
+ {
+ Temp_Value *= 0.1; // Multiply the value with the rainfall resolution of 0.1 l/m²
+ decoded.Rain_Amount = String(Temp_Value.toFixed(1));
+ }
+ break;
+ }
+ break;
+ }
+ // case 0x??: // Further Data Type
+ // {
+ // .
+ // .
+ // .
+ // break;
+ // }
default: // There is something wrong with the data type value
+ {
// Removing all added properties from the "decoded" object with a deep clean
// https://stackoverflow.com/questions/19316857/removing-all-properties-from-a-object/19316873#19316873
// Object.keys(decoded).forEach(function(key){ delete decoded[key]; });
@@ -574,6 +765,7 @@ function Decoder(bytes, port) {
// Add error code propertiy to the "decoded" object
decoded.parser_error = "Data Type Failure --> Please update your payload parser";
break;
+ }
}
} while ((++index < bytes.length) && ('parser_error' in decoded === false));
}
@@ -588,3 +780,4 @@ function Decoder(bytes, port) {
return decoded;
}
+
diff --git a/vendor/elv/elv-lw-mob.yaml b/vendor/elv/elv-lw-mob.yaml
index e555e996a8..5c251b43bb 100644
--- a/vendor/elv/elv-lw-mob.yaml
+++ b/vendor/elv/elv-lw-mob.yaml
@@ -1,5 +1,5 @@
-name: ELV LoRaWAN® Bewegungssensor/1-Tastenfernbedienung ELV-LW-MOB
-description: Compact LoRaWAN® battery radio remote control with acceleration and tilt detection from ELV
+name: ELV Motion Button for LoRaWAN®
+description: Compact LoRaWAN® battery powered radio remote control with acceleration and tilt detection from ELV
# Hardware versions (optional, use when you have revisions)
hardwareVersions:
diff --git a/vendor/elv/elv-lw-omo-backview.png b/vendor/elv/elv-lw-omo-backview.png
new file mode 100644
index 0000000000..1e33e86679
Binary files /dev/null and b/vendor/elv/elv-lw-omo-backview.png differ
diff --git a/vendor/elv/elv-lw-omo-codec.yaml b/vendor/elv/elv-lw-omo-codec.yaml
new file mode 100644
index 0000000000..59b44ab8cb
--- /dev/null
+++ b/vendor/elv/elv-lw-omo-codec.yaml
@@ -0,0 +1,35 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: elv-lw-omo.js
+ # Examples (optional)
+ examples:
+ - description: device status information
+ input:
+ fPort: 10
+ bytes: [0x96, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10]
+ output:
+ data:
+ Supply_Voltage: 1500
+ frame_type: 'Device_State'
+ TX_Reason: 'Button Pressed'
+ Accelerated: false
+ Tilt_Area_0: false
+ Tilt_Area_1: false
+ Tilt_Area_2: false
+ Angle: 0
+ Activation_count: 16
+ - description: device acceleration
+ input:
+ fPort: 10
+ bytes: [0x96, 0x02, 0x05, 0x01, 0x2D]
+ output:
+ data:
+ Supply_Voltage: 1500
+ frame_type: 'Acceleration_Data'
+ TX_Reason: 'Acceleration'
+ Accelerated: true
+ Tilt_Area_0: false
+ Tilt_Area_1: false
+ Tilt_Area_2: false
+ Angle: 45
diff --git a/vendor/elv/elv-lw-omo-components.png b/vendor/elv/elv-lw-omo-components.png
new file mode 100644
index 0000000000..04c6e785ab
Binary files /dev/null and b/vendor/elv/elv-lw-omo-components.png differ
diff --git a/vendor/elv/elv-lw-omo-frontview.png b/vendor/elv/elv-lw-omo-frontview.png
new file mode 100644
index 0000000000..c504175ff6
Binary files /dev/null and b/vendor/elv/elv-lw-omo-frontview.png differ
diff --git a/vendor/elv/elv-lw-omo-housing.png b/vendor/elv/elv-lw-omo-housing.png
new file mode 100644
index 0000000000..adf41922d1
Binary files /dev/null and b/vendor/elv/elv-lw-omo-housing.png differ
diff --git a/vendor/elv/elv-lw-omo.js b/vendor/elv/elv-lw-omo.js
new file mode 100644
index 0000000000..41b9c6980a
--- /dev/null
+++ b/vendor/elv/elv-lw-omo.js
@@ -0,0 +1,125 @@
+/*
+* ELV-LW-OMO Payload Parser
+*
+* Version: V1.0.1
+*
+* */
+
+function decodeUplink(input) {
+ var data = input.bytes;
+ var valid = true;
+
+ if (typeof Decoder === "function") {
+ data = Decoder(data, input.fPort);
+ }
+
+ if (typeof Converter === "function") {
+ data = Converter(data, input.fPort);
+ }
+
+ if (typeof Validator === "function") {
+ valid = Validator(data, input.fPort);
+ }
+
+ if (valid) {
+ return {
+ data: data
+ };
+ } else {
+ return {
+ data: {},
+ errors: ["Invalid data received"]
+ };
+ }
+}
+
+var tx_reason = ["Undefined","Button Pressed", "Heartbeat", "Settings", "Joined", "Acceleration", "Tilt", "Ongoing Acceleration", "Inactivity", "Error"];
+var frame_type = ["Device_Info", "Device_State", "Acceleration_Data", "Button_Pressed", "Config_Data"];
+var device_modes = ["Acceleration", "Tilt"];
+/*
+ * @brief Receives the bytes transmitted from a device of the ELV-LW-OMO
+ * @param bytes: Array with the data stream
+ * @param port: Used TTN/TTS data port
+ * @return Decoded data from a device of the ELV-LW-OMO
+ * */
+function Decoder(bytes, port) {
+ var decoded = {}; // Container with the decoded output
+ var Temp_Value = 0; // Variable for temporarily calculated values
+
+ if (port === 10) { // The default port for app data
+ // Minimum 5 Bytes for Header
+
+ // Collecting header data
+
+ decoded.Supply_Voltage = bytes[0] * 10;
+ decoded.frame_type = frame_type[(bytes[1])]; //Frametype encodes what Kind of Payload is being sent
+ decoded.TX_Reason = tx_reason[(bytes[2])];
+ //Write every reason for sending correspondig to bit n
+ switch (decoded.frame_type)
+ {
+ case "Device_Info":
+ var bl_version_major = bytes[3];
+ var bl_version_minor = bytes[4];
+ var bl_version_patch = bytes[5];
+
+ decoded.Bootloader_Version = `${bl_version_major}.${bl_version_minor}.${bl_version_patch}`; //Build version-String from 3 previous values
+
+ var fw_version_major = bytes[6];
+ var fw_version_minor = bytes[7];
+ var fw_version_patch = bytes[8];
+
+ decoded.Firmware_Version = `${fw_version_major}.${fw_version_minor}.${fw_version_patch}`;//Build version-String from 3 previous values
+
+ decoded.hw_revision = bytes[9] << 8 | bytes[10]; // //HW version is encoded as 16-Bit int
+ break;
+ case "Device_State":
+ decoded.Accelerated = !!(bytes[3] & 0x1);
+ decoded.Tilt_Area_0 = !!(bytes[3] & 0x10);
+ decoded.Tilt_Area_1 = !!(bytes[3] & 0x20);
+ decoded.Tilt_Area_2 = !!(bytes[3] & 0x40);
+
+ decoded.Angle = bytes[4];
+
+ decoded.Activation_count = (bytes[5] << 8 | bytes[6]);
+ break;
+ case "Acceleration_Data":
+ decoded.Accelerated = !!(bytes[3] & 0x1);
+ decoded.Tilt_Area_0 = !!(bytes[3] & 0x10);
+ decoded.Tilt_Area_1 = !!(bytes[3] & 0x20);
+ decoded.Tilt_Area_2 = !!(bytes[3] & 0x40);
+
+ decoded.Angle = bytes[4];
+ break;
+ case "Button_Pressed":
+ decoded.Button_Count = bytes[3];
+ break;
+ case "Config_Data":
+ decoded.device_mode = "";
+ for(let i = 0; i < 8; i++)
+ {
+ if((bytes[3] >> i) & 1)
+ {
+ decoded.device_mode += device_modes[i];
+ }
+ }
+
+ decoded.sensor_threshold = bytes[4];
+
+ decoded.range = bytes[5];
+ decoded.alpha = bytes[6];
+
+ decoded.beta = bytes[7];
+
+ decoded.hysteresis = bytes[8];
+
+ decoded.senc_cycle_minutes = bytes[9] * 6;
+ break;
+ }
+
+ }
+ else {
+ decoded.parser_error = "Wrong Port Number";
+ }
+
+ return decoded;
+}
\ No newline at end of file
diff --git a/vendor/elv/elv-lw-omo.yaml b/vendor/elv/elv-lw-omo.yaml
new file mode 100644
index 0000000000..3a40c70a0d
--- /dev/null
+++ b/vendor/elv/elv-lw-omo.yaml
@@ -0,0 +1,118 @@
+name: ELV Outdoor Motion Sensor for LoRaWAN®
+description: The ELV-LW-OMO is a device to track acceleration, vibration or realtive position changes of an outdoor asset. Fields of application are e.g. the monitoring of garbage cans or the detection of activity at a bird house
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 1
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0.3'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+
+ # Firmware features (optional)
+ # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how
+ # often he device sends a message).
+ features:
+ - remote rejoin
+ - transmission interval
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ # Optional identifier of the vendor of the profile. When you specify the vendorID, the profile is loaded from
+ # the vendorID's folder. This allows you to reuse profiles from module or LoRaWAN end device stack vendors.
+ # If vendorID is empty, the current vendor ID is used. In this example, the vendorID is the current vendor ID,
+ # which is verbose.
+ #vendorID: elv
+ # Identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters)
+ id: trx1-profile
+ lorawanCertified: true
+ codec: elv-lw-omo-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - accelerometer
+ - button
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ width: 18
+ length: 17
+ height: 81
+
+# Weight in grams (optional)
+weight: 43
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: LR03
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -10
+ max: 55
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key programming (optional)
+# Valid values are: bluetooth, nfc, wifi, serial (when the user has a serial interface to set the keys)
+# and firmware (when the user should change the firmware to set the keys).
+keyProgramming:
+ - firmware
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: none
+
+# Firmware programming (optional)
+# Valid values are: serial (when the user has a serial interface to update the firmware), fuota lorawan (when the device
+# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism).
+firmwareProgramming:
+ - serial
+
+# Product and data sheet URLs (optional)
+productURL: https://de.elv.com/
+
+# Commercial information
+resellerURLs:
+ - name: 'ELVshop'
+ region:
+ - European Union
+ url: https://de.elv.com/elv-lorawan-erschuetterungssensor-outdoor-elv-lw-omo-158753
+msrp:
+ EUR: 39.95
+
+# Photos
+photos:
+ main: elv-lw-omo-housing.png
+ other:
+ - elv-lw-omo-frontview.png
+ - elv-lw-omo-backview.png
+ - elv-lw-omo-components.png
diff --git a/vendor/elv/index.yaml b/vendor/elv/index.yaml
index 9782e8fb99..120553dfb9 100644
--- a/vendor/elv/index.yaml
+++ b/vendor/elv/index.yaml
@@ -6,3 +6,4 @@ endDevices:
- elv-lw-esi
- elv-lw-gps1
- elv-lw-mob
+ - elv-lw-omo
diff --git a/vendor/index.yaml b/vendor/index.yaml
index 2f3e36edba..c43833dc36 100644
--- a/vendor/index.yaml
+++ b/vendor/index.yaml
@@ -1702,7 +1702,7 @@ vendors:
- id: dingtek
name: Dingtek
- website: http://dingtek.com/
+ website: https://www.dingtek.com/
logo: dingtek_logo.png
- id: elster
@@ -1966,3 +1966,12 @@ vendors:
name: Agriseen
website: http://www.agriseen.com/
logo: agriseen_logo.png
+
+ - id: koidra
+ name: Koidra Inc.
+ description: Koidra is an intelligent automation company, dedicated to modernizing the automation of manufacturing facilities, with the high-tech greenhouse industry being the core market. Our tiered products deliver a comprehensive solution that enhances industrial efficiency.
+ website: https://www.koidra.ai/
+ logo: koidra-logo.svg
+ social:
+ linkedin: https://www.linkedin.com/company/koidra/
+
diff --git a/vendor/koidra/index.yaml b/vendor/koidra/index.yaml
new file mode 100644
index 0000000000..a7b4593d05
--- /dev/null
+++ b/vendor/koidra/index.yaml
@@ -0,0 +1,8 @@
+# This example contains just one end device: windsensor. It is referenced here in the index.
+
+endDevices:
+ # Unique identifier of the end device (lowercase, alphanumeric with dashes, max 36 characters)
+ - sdi-12-dra # look in sdi-12-dra.yaml for the end device definition
+ # - rs-485-ln # look in windsensor.yaml for the end device definition
+ # - rs-485-bl # look in windsensor.yaml for the end device definition
+ - sdi-12-tek # look in sdi-12-tek.yaml for the end device definition
diff --git a/vendor/koidra/koidra-logo.svg b/vendor/koidra/koidra-logo.svg
new file mode 100644
index 0000000000..2f13ae769f
--- /dev/null
+++ b/vendor/koidra/koidra-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/koidra/sdi-12-dra-codec.yaml b/vendor/koidra/sdi-12-dra-codec.yaml
new file mode 100644
index 0000000000..0b8efa9bb1
--- /dev/null
+++ b/vendor/koidra/sdi-12-dra-codec.yaml
@@ -0,0 +1,65 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: sdi-12-dra.js
+ # Examples (optional)
+ # examples:
+ # - description: 32 knots from the North
+ # input:
+ # fPort: 1
+ # bytes: [0, 32]
+ # output:
+ # data:
+ # direction: 'N'
+ # speed: 32
+ # # Normalized output, uses the normalizeUplink function (optional)
+ # normalizedOutput:
+ # data:
+ # - wind:
+ # speed: 16.4608
+ # direction: 0
+ # - description: 42 knots from the East
+ # input:
+ # fPort: 1
+ # bytes: [1, 42]
+ # output:
+ # data:
+ # direction: 'E'
+ # speed: 42
+ # - description: Unknown FPort
+ # input:
+ # fPort: 42
+ # bytes: [1, 42]
+ # output:
+ # errors:
+ # - unknown FPort
+# # Downlink encoder encodes JSON object into a binary data downlink (optional)
+# downlinkEncoder:
+# fileName: windsensor.js
+# examples:
+# - description: Turn green
+# input:
+# data:
+# led: green
+# output:
+# bytes: [1]
+# fPort: 2
+# - description: Invalid color
+# input:
+# data:
+# led: blue
+# output:
+# errors:
+# - invalid LED color
+
+# # Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+# downlinkDecoder:
+# fileName: windsensor.js
+# examples:
+# - description: Turn green
+# input:
+# fPort: 2
+# bytes: [1]
+# output:
+# data:
+# led: green
diff --git a/vendor/koidra/sdi-12-dra-package.jpg b/vendor/koidra/sdi-12-dra-package.jpg
new file mode 100644
index 0000000000..dcc5d2233a
Binary files /dev/null and b/vendor/koidra/sdi-12-dra-package.jpg differ
diff --git a/vendor/koidra/sdi-12-dra-profile.yaml b/vendor/koidra/sdi-12-dra-profile.yaml
new file mode 100644
index 0000000000..711231155b
--- /dev/null
+++ b/vendor/koidra/sdi-12-dra-profile.yaml
@@ -0,0 +1,52 @@
+# Vendor profile ID, can be freely issued by the vendor
+# This vendor profile ID is also used on the QR code for LoRaWAN devices, see
+# https://lora-alliance.org/sites/default/files/2020-10/LoRa_Alliance_Vendor_ID_for_QR_Code.pdf
+vendorProfileID: 0
+
+# LoRaWAN MAC version: 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 or 1.1
+macVersion: '1.0.3'
+# LoRaWAN Regional Parameters version. Values depend on the LoRaWAN version:
+# 1.0: TS001-1.0
+# 1.0.1: TS001-1.0.1
+# 1.0.2: RP001-1.0.2 or RP001-1.0.2-RevB
+# 1.0.3: RP001-1.0.3-RevA
+# 1.0.4: RP002-1.0.0 or RP002-1.0.1
+# 1.1: RP001-1.1-RevA or RP001-1.1-RevB
+regionalParametersVersion: 'RP001-1.0.3-RevA'
+
+# Whether the end device supports join (OTAA) or not (ABP)
+supportsJoin: true
+# If your device is an ABP device (supportsJoin is false), uncomment the following fields:
+# RX1 delay
+#rx1Delay: 5
+# RX1 data rate offset
+#rx1DataRateOffset: 0
+# RX2 data rate index
+#rx2DataRateIndex: 0
+# RX2 frequency (MHz)
+#rx2Frequency: 869.525
+# Factory preset frequencies (MHz)
+#factoryPresetFrequencies: [868.1, 868.3, 868.5, 867.1, 867.3, 867.5, 867.7, 867.9]
+
+# Maximum EIRP
+maxEIRP: 16
+# Whether the end device supports 32-bit frame counters
+supports32bitFCnt: true
+
+# Whether the end device supports class B
+supportsClassB: false
+# If your device supports class B, uncomment the following fields:
+# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds)
+#classBTimeout: 60
+# Ping slot period (seconds)
+#pingSlotPeriod: 128
+# Ping slot data rate index
+#pingSlotDataRateIndex: 0
+# Ping slot frequency (MHz). Set to 0 if the band supports ping slot frequency hopping.
+#pingSlotFrequency: 869.525
+
+# Whether the end device supports class C
+supportsClassC: false
+# If your device supports class C, uncomment the following fields:
+# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds)
+#classCTimeout: 60
diff --git a/vendor/koidra/sdi-12-dra.jpg b/vendor/koidra/sdi-12-dra.jpg
new file mode 100644
index 0000000000..1c2c2f37e2
Binary files /dev/null and b/vendor/koidra/sdi-12-dra.jpg differ
diff --git a/vendor/koidra/sdi-12-dra.js b/vendor/koidra/sdi-12-dra.js
new file mode 100644
index 0000000000..14f279a999
--- /dev/null
+++ b/vendor/koidra/sdi-12-dra.js
@@ -0,0 +1,123 @@
+// Only for AT+DATAUP=0 & AT+ALLDATAMOD=0
+function Decoder(bytes, port) {
+ if(port==5)
+ {
+ var freq_band;
+ var sub_band;
+ var sensor;
+
+ if(bytes[0]==0x17)
+ sensor= "SDI12-LB";
+
+ var firm_ver= (bytes[1]&0x0f)+'.'+(bytes[2]>>4&0x0f)+'.'+(bytes[2]&0x0f);
+
+ if(bytes[3]==0x01)
+ freq_band="EU868";
+ else if(bytes[3]==0x02)
+ freq_band="US915";
+ else if(bytes[3]==0x03)
+ freq_band="IN865";
+ else if(bytes[3]==0x04)
+ freq_band="AU915";
+ else if(bytes[3]==0x05)
+ freq_band="KZ865";
+ else if(bytes[3]==0x06)
+ freq_band="RU864";
+ else if(bytes[3]==0x07)
+ freq_band="AS923";
+ else if(bytes[3]==0x08)
+ freq_band="AS923_1";
+ else if(bytes[3]==0x09)
+ freq_band="AS923_2";
+ else if(bytes[3]==0x0A)
+ freq_band="AS923_3";
+ else if(bytes[3]==0x0F)
+ freq_band="AS923_4";
+ else if(bytes[3]==0x0B)
+ freq_band="CN470";
+ else if(bytes[3]==0x0C)
+ freq_band="EU433";
+ else if(bytes[3]==0x0D)
+ freq_band="KR920";
+ else if(bytes[3]==0x0E)
+ freq_band="MA869";
+
+ if(bytes[4]==0xff)
+ sub_band="NULL";
+ else
+ sub_band=bytes[4];
+
+ var bat= (bytes[5]<<8 | bytes[6])/1000;
+
+ return {
+ SENSOR_MODEL:sensor,
+ FIRMWARE_VERSION:firm_ver,
+ FREQUENCY_BAND:freq_band,
+ SUB_BAND:sub_band,
+ BAT:bat,
+ }
+ }
+ else if(port==100)
+ {
+ var datas_sum={};
+ for(var j=0;j Suppose_Len) {
+ // ñ\u00170+2574.78+22.2+637JZL\r\n
+ garbage = 1;
+ tempWc = parseFloat(data_sum_infos[1]);
+ decode.wc_Root = 6.771*Math.pow(10, -10) * Math.pow(tempWc, 3) - 5.105*Math.pow(10, -6) * Math.pow(tempWc, 2) + 1.302*Math.pow(10, -2) * tempWc - 10.848;
+ } else {
+ decode.wc_Root = null;
+ }
+
+ if (garbage) {
+ decode.T_Root = !isNaN(parseFloat(data_sum_infos[2])) ? parseFloat(data_sum_infos[2]) : null;
+ const numberRegex = /\d+/g;
+ const numberMatches = data_sum_infos[3].match(numberRegex);
+ tempEc = numberMatches % 100;
+ decode.ec_Root = numberMatches ? (parseInt(tempEc) / 1000) : null;
+ } else {
+ decode.T_Root = !isNaN(parseFloat(data_sum_infos[1])) ? parseFloat(data_sum_infos[1]) : null;
+ const numberRegex = /\d+/g;
+ const numberMatches = data_sum_infos[2].match(numberRegex);
+ decode.ec_Root = numberMatches ? (parseInt(numberMatches.join("")) / 1000) : null;
+ }
+
+ return decode;
+ }
+ }
\ No newline at end of file
diff --git a/vendor/koidra/sdi-12-dra.yaml b/vendor/koidra/sdi-12-dra.yaml
new file mode 100644
index 0000000000..3e06457e51
--- /dev/null
+++ b/vendor/koidra/sdi-12-dra.yaml
@@ -0,0 +1,113 @@
+name: SDI-12-DRA
+description: The Koidra SDI-12 is an SDI-12 to LoRaWAN® converter. It allows the SDI-12 devices to use LoRaWAN wireless protocol which simplifies the IoT installation and reduces the installation/maintaining cost.
+
+# Hardware versions (optional, use when you have revisions)
+# hardwareVersions:
+# - version: '1.0'
+# numeric: 1
+# - version: '1.0-rev-A'
+# numeric: 2
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ # hardwareVersions:
+ # - '1.2'
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, KR920-923, IN865-867, RU864-870
+ profiles:
+ EU863-870:
+ # Unique identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters)
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ US902-928:
+ id: us915-sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ KR920-923:
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ AU915-928:
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ RU864-870:
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ IN865-867:
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+ AS923:
+ id: sdi-12-dra-profile
+ codec: sdi-12-dra-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, snr, solar radiation,
+# sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity, vibration, voltage,
+# water potential, water, weight, wifi ssid, wind direction, wind speed.
+#sensors:
+# - wind direction
+# - wind speed
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ width: 100
+ length: 160
+ height: 60
+
+# Weight in grams (optional)
+weight: 910
+
+# Battery information (optional)
+battery:
+ replaceable: true
+# type: AA
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -30
+ max: 85
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 0.97
+
+# IP rating (optional)
+ipCode: IP67
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+# keySecurity: none
+keyProgramming:
+ - serial
+ - firmware
+
+# Product and data sheet URLs (optional)
+# productURL: http://www.dragino.com/products/lora-lorawan-end-node/item/154-rs485-ln.html
+# dataSheetURL: http://www.dragino.com/products/lora-lorawan-end-node/item/154-rs485-ln.html
+sellerURLs:
+ - name: 'Koidra'
+ region:
+ - Vietnam
+ url: https://www.koidra.ai/
+
+# Photos
+photos:
+ main: sdi-12-dra.jpg
+ other:
+ - sdi-12-dra-package.jpg
diff --git a/vendor/koidra/sdi-12-tek-codec.yaml b/vendor/koidra/sdi-12-tek-codec.yaml
new file mode 100644
index 0000000000..a47b5a3746
--- /dev/null
+++ b/vendor/koidra/sdi-12-tek-codec.yaml
@@ -0,0 +1,65 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: sdi-12-tek.js
+ # Examples (optional)
+ # examples:
+ # - description: 32 knots from the North
+ # input:
+ # fPort: 1
+ # bytes: [0, 32]
+ # output:
+ # data:
+ # direction: 'N'
+ # speed: 32
+ # # Normalized output, uses the normalizeUplink function (optional)
+ # normalizedOutput:
+ # data:
+ # - wind:
+ # speed: 16.4608
+ # direction: 0
+ # - description: 42 knots from the East
+ # input:
+ # fPort: 1
+ # bytes: [1, 42]
+ # output:
+ # data:
+ # direction: 'E'
+ # speed: 42
+ # - description: Unknown FPort
+ # input:
+ # fPort: 42
+ # bytes: [1, 42]
+ # output:
+ # errors:
+ # - unknown FPort
+# # Downlink encoder encodes JSON object into a binary data downlink (optional)
+# downlinkEncoder:
+# fileName: windsensor.js
+# examples:
+# - description: Turn green
+# input:
+# data:
+# led: green
+# output:
+# bytes: [1]
+# fPort: 2
+# - description: Invalid color
+# input:
+# data:
+# led: blue
+# output:
+# errors:
+# - invalid LED color
+
+# # Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
+# downlinkDecoder:
+# fileName: windsensor.js
+# examples:
+# - description: Turn green
+# input:
+# fPort: 2
+# bytes: [1]
+# output:
+# data:
+# led: green
diff --git a/vendor/koidra/sdi-12-tek-package.jpg b/vendor/koidra/sdi-12-tek-package.jpg
new file mode 100644
index 0000000000..f4a1c4072e
Binary files /dev/null and b/vendor/koidra/sdi-12-tek-package.jpg differ
diff --git a/vendor/koidra/sdi-12-tek-profile.yaml b/vendor/koidra/sdi-12-tek-profile.yaml
new file mode 100644
index 0000000000..711231155b
--- /dev/null
+++ b/vendor/koidra/sdi-12-tek-profile.yaml
@@ -0,0 +1,52 @@
+# Vendor profile ID, can be freely issued by the vendor
+# This vendor profile ID is also used on the QR code for LoRaWAN devices, see
+# https://lora-alliance.org/sites/default/files/2020-10/LoRa_Alliance_Vendor_ID_for_QR_Code.pdf
+vendorProfileID: 0
+
+# LoRaWAN MAC version: 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 or 1.1
+macVersion: '1.0.3'
+# LoRaWAN Regional Parameters version. Values depend on the LoRaWAN version:
+# 1.0: TS001-1.0
+# 1.0.1: TS001-1.0.1
+# 1.0.2: RP001-1.0.2 or RP001-1.0.2-RevB
+# 1.0.3: RP001-1.0.3-RevA
+# 1.0.4: RP002-1.0.0 or RP002-1.0.1
+# 1.1: RP001-1.1-RevA or RP001-1.1-RevB
+regionalParametersVersion: 'RP001-1.0.3-RevA'
+
+# Whether the end device supports join (OTAA) or not (ABP)
+supportsJoin: true
+# If your device is an ABP device (supportsJoin is false), uncomment the following fields:
+# RX1 delay
+#rx1Delay: 5
+# RX1 data rate offset
+#rx1DataRateOffset: 0
+# RX2 data rate index
+#rx2DataRateIndex: 0
+# RX2 frequency (MHz)
+#rx2Frequency: 869.525
+# Factory preset frequencies (MHz)
+#factoryPresetFrequencies: [868.1, 868.3, 868.5, 867.1, 867.3, 867.5, 867.7, 867.9]
+
+# Maximum EIRP
+maxEIRP: 16
+# Whether the end device supports 32-bit frame counters
+supports32bitFCnt: true
+
+# Whether the end device supports class B
+supportsClassB: false
+# If your device supports class B, uncomment the following fields:
+# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds)
+#classBTimeout: 60
+# Ping slot period (seconds)
+#pingSlotPeriod: 128
+# Ping slot data rate index
+#pingSlotDataRateIndex: 0
+# Ping slot frequency (MHz). Set to 0 if the band supports ping slot frequency hopping.
+#pingSlotFrequency: 869.525
+
+# Whether the end device supports class C
+supportsClassC: false
+# If your device supports class C, uncomment the following fields:
+# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds)
+#classCTimeout: 60
diff --git a/vendor/koidra/sdi-12-tek.jpg b/vendor/koidra/sdi-12-tek.jpg
new file mode 100644
index 0000000000..bac74d7765
Binary files /dev/null and b/vendor/koidra/sdi-12-tek.jpg differ
diff --git a/vendor/koidra/sdi-12-tek.js b/vendor/koidra/sdi-12-tek.js
new file mode 100644
index 0000000000..25aaf2ac64
--- /dev/null
+++ b/vendor/koidra/sdi-12-tek.js
@@ -0,0 +1,79 @@
+// Only for AT+DATAUP=0 & AT+ALLDATAMOD=0
+// Tekbox format only
+function Decoder(bytes, port) {
+ const Report_Len = 41;
+ const Bat_Len = 25;
+ const Measure_Len = 38;
+
+ if(port==5)
+ {
+ var freq_band;
+ var sub_band;
+ var sensor;
+
+ }
+ else if(port==100)
+ {
+ var datas_sum={};
+ for(var j=0;j bytes[i] = value.toString( 16 ).toUpperCase().length === 1 ? "0" + value.toString( 16 ).toUpperCase() : value.toString( 16 ).toUpperCase())
+ bytes.slice(index+4).forEach((value, i) => bytes[i] = value.toString( 16 ).toUpperCase().length === 1 ? "0" + value.toString( 16 ).toUpperCase() : value.toString( 16 ).toUpperCase())
stdData.value.multimodbus_payload = bytes.join('')
}
tab.push(stdData);
@@ -1098,4 +1098,4 @@ function decodeUplink(input) {
errors: []
};
return decodedInput.data.data
-}
\ No newline at end of file
+}
diff --git a/vendor/nwave/ncc405-codec.yaml b/vendor/nwave/ncc405-codec.yaml
index 5587b1149f..87ef9f9f1d 100644
--- a/vendor/nwave/ncc405-codec.yaml
+++ b/vendor/nwave/ncc405-codec.yaml
@@ -17,7 +17,7 @@ uplinkDecoder:
output:
data:
type: heartbeat
- hw_health_status: 21
+ hw_health_status: 40
battery_voltage: 2.908
battery_voltage_mean_24h: 2.888
diff --git a/vendor/nwave/ncc405.js b/vendor/nwave/ncc405.js
index 2056e6b41b..a43d90f83f 100644
--- a/vendor/nwave/ncc405.js
+++ b/vendor/nwave/ncc405.js
@@ -8,7 +8,7 @@ function decodeUplink(input) {
case 2: // Heartbeat
data.type = "heartbeat";
- data.hw_health_status = input.bytes[0] >> 3;
+ data.hw_health_status = input.bytes[0] & 0x7F;
var batteryVoltageMv = 2500 + input.bytes[1] * 4;
data.battery_voltage = batteryVoltageMv / 1000;
diff --git a/vendor/nwave/ncc405fm.yaml b/vendor/nwave/ncc405fm.yaml
index 8b8bdd9668..ec0f42463a 100644
--- a/vendor/nwave/ncc405fm.yaml
+++ b/vendor/nwave/ncc405fm.yaml
@@ -29,6 +29,8 @@ sensors:
- proximity
dimensions:
diameter: 156
+ width: 156
+ length: 156
height: 20
weight: 405
battery:
diff --git a/vendor/nwave/nps310sm.yaml b/vendor/nwave/nps310sm.yaml
index 9c8ce72ab0..645460466d 100644
--- a/vendor/nwave/nps310sm.yaml
+++ b/vendor/nwave/nps310sm.yaml
@@ -29,6 +29,8 @@ sensors:
- proximity
dimensions:
diameter: 190
+ width: 190
+ length: 190
height: 20
weight: 460
battery:
diff --git a/vendor/nwave/nps405-codec.yaml b/vendor/nwave/nps405-codec.yaml
index a7eb52d889..da9787eefc 100644
--- a/vendor/nwave/nps405-codec.yaml
+++ b/vendor/nwave/nps405-codec.yaml
@@ -4,7 +4,7 @@ uplinkDecoder:
- description: Parking Status
input:
fPort: 1
- bytes: [0xCA]
+ bytes: [0x95]
output:
data:
type: parking_status
@@ -16,7 +16,7 @@ uplinkDecoder:
- description: User Registration
input:
fPort: 10
- bytes: [0xE8, 0x1F, 0x34, 0x56, 0x78]
+ bytes: [0xD1, 0x1F, 0x34, 0x56, 0x78]
output:
data:
type: user_registration
diff --git a/vendor/nwave/nps405.js b/vendor/nwave/nps405.js
index 08c976b0c8..72ff35a2f1 100644
--- a/vendor/nwave/nps405.js
+++ b/vendor/nwave/nps405.js
@@ -28,8 +28,8 @@ function decodeUplink(input) {
switch (input.fPort) {
case 1: // Parking status
data.type = "parking_status";
- data.occupied = (bytes[0] >> 7 & 0x1) === 0x1;
- previousState = calculatePreviousState(bytes[0] & 0x7F);
+ data.occupied = (bytes[0] & 0x1) === 0x1;
+ previousState = calculatePreviousState((bytes[0] >> 1) & 0x7F);
data.previous_state_duration = previousState.previous_state_duration;
data.previous_state_duration_error = previousState.previous_state_duration_error;
data.previous_state_duration_overflow = previousState.previous_state_duration_overflow;
@@ -44,9 +44,11 @@ function decodeUplink(input) {
}
data.type = "heartbeat";
- data.occupied = (bytes[0] >> 7 & 0x1) === 0x1;
+ data.occupied = (bytes[0] & 0x1) === 0x1;
data.hw_health_status = bytes[0] & 0x7F;
- data.temperature = (bytes[2] << 24 >> 24) / 2 + 10;
+
+ var temp_byte = (bytes[2] > 127) ? bytes[2] - 256 : bytes[2]
+ data.temperature = temp_byte / 2 + 10;
var batteryVoltageMv = 2500 + bytes[1] * 4;
data.battery_voltage = batteryVoltageMv / 1000;
@@ -96,9 +98,9 @@ function decodeUplink(input) {
case 10: // SDI tag registration
data.type = "user_registration";
- if ((bytes[0] >> 7 & 0x1) === 0x1) {
+ if ((bytes[0] & 0x1) === 0x1) {
data.occupied = true;
- previousState = calculatePreviousState(bytes[0] & 0x7F);
+ previousState = calculatePreviousState((bytes[0] >> 1) & 0x7F);
data.previous_state_duration = previousState.previous_state_duration;
data.previous_state_duration_error = previousState.previous_state_duration_error;
data.previous_state_duration_overflow = previousState.previous_state_duration_overflow;
diff --git a/vendor/nwave/nps405sm.yaml b/vendor/nwave/nps405sm.yaml
index 0b5decbd47..ecf7d58e3b 100644
--- a/vendor/nwave/nps405sm.yaml
+++ b/vendor/nwave/nps405sm.yaml
@@ -29,6 +29,8 @@ sensors:
- proximity
dimensions:
diameter: 205
+ width: 205
+ length: 205
height: 20
weight: 412
battery:
diff --git a/vendor/radio-bridge/RBS306-US10M.jpg b/vendor/radio-bridge/RBS306-US10M.jpg
index 08e6a230a4..a91739eb3a 100644
Binary files a/vendor/radio-bridge/RBS306-US10M.jpg and b/vendor/radio-bridge/RBS306-US10M.jpg differ
diff --git a/vendor/radio-bridge/rbs101-con.yaml b/vendor/radio-bridge/rbs101-con.yaml
index 956f6225b8..afaa18096d 100644
--- a/vendor/radio-bridge/rbs101-con.yaml
+++ b/vendor/radio-bridge/rbs101-con.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs101-con-profile
lorawanCertified: true
codec: rbs101-con-codec
+# Photos
+photos:
+ main: rbs101-con.png
diff --git a/vendor/radio-bridge/rbs301-abm.yaml b/vendor/radio-bridge/rbs301-abm.yaml
index 70c4a87dd0..06b86f1427 100644
--- a/vendor/radio-bridge/rbs301-abm.yaml
+++ b/vendor/radio-bridge/rbs301-abm.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-abm-profile
lorawanCertified: true
codec: rbs301-abm-codec
+# Photos
+photos:
+ main: rbs301-abm.png
diff --git a/vendor/radio-bridge/rbs301-dws.yaml b/vendor/radio-bridge/rbs301-dws.yaml
index cf67fd9b7b..354bd3cb7f 100644
--- a/vendor/radio-bridge/rbs301-dws.yaml
+++ b/vendor/radio-bridge/rbs301-dws.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-dws-profile
lorawanCertified: true
codec: rbs301-dws-codec
+# Photos
+photos:
+ main: rbs301-dws.png
diff --git a/vendor/radio-bridge/rbs301-temp-ext.yaml b/vendor/radio-bridge/rbs301-temp-ext.yaml
index e899793a0e..4c0f3dd01e 100644
--- a/vendor/radio-bridge/rbs301-temp-ext.yaml
+++ b/vendor/radio-bridge/rbs301-temp-ext.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-temp-ext-profile
lorawanCertified: true
codec: rbs301-temp-ext-codec
+# Photos
+photos:
+ main: rbs301-temp-ext.png
diff --git a/vendor/radio-bridge/rbs301-temp-int.yaml b/vendor/radio-bridge/rbs301-temp-int.yaml
index 7e0511c54b..685aeca2c1 100644
--- a/vendor/radio-bridge/rbs301-temp-int.yaml
+++ b/vendor/radio-bridge/rbs301-temp-int.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-temp-int-profile
lorawanCertified: true
codec: rbs301-temp-int-codec
+# Photos
+photos:
+ main: rbs301-temp-int.png
diff --git a/vendor/radio-bridge/rbs301-tilt.yaml b/vendor/radio-bridge/rbs301-tilt.yaml
index 6d6b9028cc..40b029d4e9 100644
--- a/vendor/radio-bridge/rbs301-tilt.yaml
+++ b/vendor/radio-bridge/rbs301-tilt.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-tilt-profile
lorawanCertified: true
codec: rbs301-tilt-codec
+# Photos
+photos:
+ main: rbs301-tilt.png
diff --git a/vendor/radio-bridge/rbs301-wat.yaml b/vendor/radio-bridge/rbs301-wat.yaml
index 0e9a883d44..4726a628b0 100644
--- a/vendor/radio-bridge/rbs301-wat.yaml
+++ b/vendor/radio-bridge/rbs301-wat.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-wat-profile
lorawanCertified: true
codec: rbs301-wat-codec
+# Photos
+photos:
+ main: rbs301-wat.png
diff --git a/vendor/radio-bridge/rbs301-wr1m.yaml b/vendor/radio-bridge/rbs301-wr1m.yaml
index 7b82199b53..103faeca88 100644
--- a/vendor/radio-bridge/rbs301-wr1m.yaml
+++ b/vendor/radio-bridge/rbs301-wr1m.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs301-wr1m-profile
lorawanCertified: true
codec: rbs301-wr1m-codec
+# Photos
+photos:
+ main: rbs301-wr1m.png
diff --git a/vendor/radio-bridge/rbs305-ath.yaml b/vendor/radio-bridge/rbs305-ath.yaml
index 9ef7450b98..2d36c21dc1 100644
--- a/vendor/radio-bridge/rbs305-ath.yaml
+++ b/vendor/radio-bridge/rbs305-ath.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs305-ath-profile
lorawanCertified: true
codec: rbs305-ath-codec
+# Photos
+photos:
+ main: rbs305-ath.png
diff --git a/vendor/radio-bridge/rbs306-420ma.yaml b/vendor/radio-bridge/rbs306-420ma.yaml
index 502fb20060..f7f02c7f24 100644
--- a/vendor/radio-bridge/rbs306-420ma.yaml
+++ b/vendor/radio-bridge/rbs306-420ma.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-420ma-profile
lorawanCertified: true
codec: rbs306-420ma-codec
+# Photos
+photos:
+ main: rbs306-420ma.png
diff --git a/vendor/radio-bridge/rbs306-abm.yaml b/vendor/radio-bridge/rbs306-abm.yaml
index ef7890ab87..8efbe96920 100644
--- a/vendor/radio-bridge/rbs306-abm.yaml
+++ b/vendor/radio-bridge/rbs306-abm.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-abm-profile
lorawanCertified: true
codec: rbs306-abm-codec
+# Photos
+photos:
+ main: rbs306-abm.png
diff --git a/vendor/radio-bridge/rbs306-ath-ext.yaml b/vendor/radio-bridge/rbs306-ath-ext.yaml
index 822eac8b87..321301fd80 100644
--- a/vendor/radio-bridge/rbs306-ath-ext.yaml
+++ b/vendor/radio-bridge/rbs306-ath-ext.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-ath-ext-profile
lorawanCertified: true
codec: rbs306-ath-ext-codec
+# Photos
+photos:
+ main: rbs306-ath-ext.png
diff --git a/vendor/radio-bridge/rbs306-con.yaml b/vendor/radio-bridge/rbs306-con.yaml
index 2170fdf7a2..e88aa03ff9 100644
--- a/vendor/radio-bridge/rbs306-con.yaml
+++ b/vendor/radio-bridge/rbs306-con.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-con-profile
lorawanCertified: true
codec: rbs306-con-codec
+# Photos
+photos:
+ main: rbs306-con.png
diff --git a/vendor/radio-bridge/rbs306-mbhr.yaml b/vendor/radio-bridge/rbs306-mbhr.yaml
index b774ae8dfb..7fb6599b25 100644
--- a/vendor/radio-bridge/rbs306-mbhr.yaml
+++ b/vendor/radio-bridge/rbs306-mbhr.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-mbhr-profile
lorawanCertified: true
codec: rbs306-mbhr-codec
+# Photos
+photos:
+ main: rbs306-mbhr.jpg
diff --git a/vendor/radio-bridge/rbs306-temp-ext.yaml b/vendor/radio-bridge/rbs306-temp-ext.yaml
index d660b1db2b..b382b24d96 100644
--- a/vendor/radio-bridge/rbs306-temp-ext.yaml
+++ b/vendor/radio-bridge/rbs306-temp-ext.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-temp-ext-profile
lorawanCertified: true
codec: rbs306-temp-ext-codec
+# Photos
+photos:
+ main: rbs306-temp-ext.png
diff --git a/vendor/radio-bridge/rbs306-temp-tc.yaml b/vendor/radio-bridge/rbs306-temp-tc.yaml
index df08ff78bb..501c540279 100644
--- a/vendor/radio-bridge/rbs306-temp-tc.yaml
+++ b/vendor/radio-bridge/rbs306-temp-tc.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-temp-tc-profile
lorawanCertified: true
codec: rbs306-temp-tc-codec
+# Photos
+photos:
+ main: rbs306-temp-tc.png
diff --git a/vendor/radio-bridge/rbs306-tilt-hp.yaml b/vendor/radio-bridge/rbs306-tilt-hp.yaml
index 09a7d9a0f9..702d09d502 100644
--- a/vendor/radio-bridge/rbs306-tilt-hp.yaml
+++ b/vendor/radio-bridge/rbs306-tilt-hp.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-tilt-hp-profile
lorawanCertified: true
codec: rbs306-tilt-hp-codec
+# Photos
+photos:
+ main: rbs306-tilt-hp.png
diff --git a/vendor/radio-bridge/rbs306-us10m.jpg b/vendor/radio-bridge/rbs306-us10m.jpg
index 08e6a230a4..a91739eb3a 100644
Binary files a/vendor/radio-bridge/rbs306-us10m.jpg and b/vendor/radio-bridge/rbs306-us10m.jpg differ
diff --git a/vendor/radio-bridge/rbs306-us10m.yaml b/vendor/radio-bridge/rbs306-us10m.yaml
index 27259d2abb..ca886e4294 100644
--- a/vendor/radio-bridge/rbs306-us10m.yaml
+++ b/vendor/radio-bridge/rbs306-us10m.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-us10m-profile
lorawanCertified: true
codec: rbs306-us10m-codec
+# Photos
+photos:
+ main: rbs306-us10m.jpg
diff --git a/vendor/radio-bridge/rbs306-vm30.yaml b/vendor/radio-bridge/rbs306-vm30.yaml
index 67db9995ce..58118ab80e 100644
--- a/vendor/radio-bridge/rbs306-vm30.yaml
+++ b/vendor/radio-bridge/rbs306-vm30.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-vm30-profile
lorawanCertified: true
codec: rbs306-vm30-codec
+# Photos
+photos:
+ main: rbs306-vm30.jpg
diff --git a/vendor/radio-bridge/rbs306-vshb.yaml b/vendor/radio-bridge/rbs306-vshb.yaml
index 7af783506e..46cbd18d98 100644
--- a/vendor/radio-bridge/rbs306-vshb.yaml
+++ b/vendor/radio-bridge/rbs306-vshb.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-vshb-profile
lorawanCertified: true
codec: rbs306-vshb-codec
+# Photos
+photos:
+ main: rbs306-vshb.jpg
diff --git a/vendor/radio-bridge/rbs306-wr1m.yaml b/vendor/radio-bridge/rbs306-wr1m.yaml
index 2df273cfdb..f74f81d5ce 100644
--- a/vendor/radio-bridge/rbs306-wr1m.yaml
+++ b/vendor/radio-bridge/rbs306-wr1m.yaml
@@ -19,3 +19,6 @@ firmwareVersions:
id: rbs306-wr1m-profile
lorawanCertified: true
codec: rbs306-wr1m-codec
+# Photos
+photos:
+ main: rbs306-wr1m.png
diff --git a/vendor/sensecap/index.yaml b/vendor/sensecap/index.yaml
index f1cb66179d..cae981c0f7 100644
--- a/vendor/sensecap/index.yaml
+++ b/vendor/sensecap/index.yaml
@@ -15,3 +15,4 @@ endDevices:
- sensecaps2105-soll-moisture-temp-ec
- sensecaps2100-data-logger
- sensecaps2120-8-in-1
+ - sensecapt1000-tracker-ab
diff --git a/vendor/sensecap/sensecapt1000-tracker-ab-codec.yaml b/vendor/sensecap/sensecapt1000-tracker-ab-codec.yaml
new file mode 100644
index 0000000000..7fa5b9156f
--- /dev/null
+++ b/vendor/sensecap/sensecapt1000-tracker-ab-codec.yaml
@@ -0,0 +1,5 @@
+# Uplink decoder decodes binary data uplink into a JSON object (optional)
+# For documentation on writing encoders and decoders, see: https://thethingsstack.io/integrations/payload-formatters/javascript/
+uplinkDecoder:
+ fileName: sensecapt1000-tracker-ab-decoder.js
+ # Examples (optional)
diff --git a/vendor/sensecap/sensecapt1000-tracker-ab-decoder.js b/vendor/sensecap/sensecapt1000-tracker-ab-decoder.js
new file mode 100644
index 0000000000..e31df3a1cf
--- /dev/null
+++ b/vendor/sensecap/sensecapt1000-tracker-ab-decoder.js
@@ -0,0 +1,511 @@
+function decodeUplink (input) {
+ var bytes = input['bytes']
+ var bytesString = bytes2HexString(bytes).toLocaleUpperCase()
+ var decoded = {
+ valid: true,
+ err: 0,
+ payload: bytesString,
+ messages: []
+ }
+ let measurement = messageAnalyzed(bytesString)
+ decoded.messages = measurement
+ return { data: decoded }
+}
+
+function messageAnalyzed (messageValue) {
+ try {
+ let frames = unpack(messageValue)
+ let measurementResultArray = []
+ for (let i = 0; i < frames.length; i++) {
+ let item = frames[i]
+ let dataId = item.dataId
+ let dataValue = item.dataValue
+ let measurementArray = deserialize(dataId, dataValue)
+ measurementResultArray.push(measurementArray)
+ }
+ return measurementResultArray
+ } catch (e) {
+ return e.toString()
+ }
+}
+
+function unpack (messageValue) {
+ let frameArray = []
+
+ for (let i = 0; i < messageValue.length; i++) {
+ let remainMessage = messageValue
+ let dataId = remainMessage.substring(0, 2).toUpperCase()
+ let dataValue
+ let dataObj = {}
+ let packageLen
+ switch (dataId) {
+ case '01':
+ packageLen = 94
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '02':
+ packageLen = 32
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '03':
+ packageLen = 64
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ break
+ case '04':
+ packageLen = 20
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '05':
+ packageLen = 10
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '06':
+ packageLen = 44
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '07':
+ packageLen = 84
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '08':
+ packageLen = 70
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '09':
+ packageLen = 36
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '0A':
+ packageLen = 76
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '0B':
+ packageLen = 62
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ case '0C':
+ packageLen = 2
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ break
+ case '0D':
+ packageLen = 10
+ if (remainMessage.length < packageLen) {
+ return frameArray
+ }
+ dataValue = remainMessage.substring(2, packageLen)
+ messageValue = remainMessage.substring(packageLen)
+ dataObj = {
+ 'dataId': dataId, 'dataValue': dataValue
+ }
+ break
+ default:
+ return frameArray
+ }
+ if (dataValue.length < 2) {
+ break
+ }
+ frameArray.push(dataObj)
+ }
+ return frameArray
+}
+
+function deserialize (dataId, dataValue) {
+ let measurementArray = []
+ let eventList = []
+ let collectTime = 0
+ switch (dataId) {
+ case '01':
+ measurementArray = getUpShortInfo(dataValue)
+ break
+ case '02':
+ measurementArray = getUpShortInfo(dataValue)
+ break
+ case '03':
+ break
+ case '04':
+ measurementArray = [
+ {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(0, 2))},
+ {measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getOneWeekInterval(dataValue.substring(4, 8))},
+ {measurementId: '3943', type: 'Periodic Interval', measurementValue: getOneWeekInterval(dataValue.substring(8, 12))},
+ {measurementId: '3944', type: 'Event Interval', measurementValue: getOneWeekInterval(dataValue.substring(12, 16))},
+ {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))}
+ ]
+ break;
+ case '05':
+ measurementArray = [
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))},
+ {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))},
+ {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))}
+ ]
+ break
+ case '06':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '4197', type: 'Longitude', measurementValue: getSensorValue(dataValue.substring(16, 24), 1000000)},
+ {measurementId: '4198', type: 'Latitude', measurementValue: getSensorValue(dataValue.substring(24, 32), 1000000)},
+ {measurementId: '4097', type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)},
+ {measurementId: '4199', type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '07':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '5001', type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))},
+ {measurementId: '4097', type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)},
+ {measurementId: '4199', type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '08':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '5002', type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))},
+ {measurementId: '4097', type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)},
+ {measurementId: '4199', type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '09':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '4197', type: 'Longitude', measurementValue: getSensorValue(dataValue.substring(16, 24), 1000000)},
+ {measurementId: '4198', type: 'Latitude', measurementValue: getSensorValue(dataValue.substring(24, 32), 1000000)},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '0A':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '5001', type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '0B':
+ eventList = this.getEventStatus(dataValue.substring(0, 6))
+ collectTime = this.getUTCTimestamp(dataValue.substring(8, 16))
+ measurementArray = [
+ {measurementId: '4200', type: 'SOS Event', measurementValue: eventList[6]},
+ {measurementId: '5002', type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))},
+ {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))},
+ {type: 'Timestamp', measurementValue: collectTime}
+ ]
+ break
+ case '0D':
+ let errorCode = this.getInt(dataValue)
+ let error = ''
+ switch (errorCode) {
+ case 0:
+ error = 'THE GNSS SCAN TIME OUT'
+ break
+ case 1:
+ error = 'THE WI-FI SCAN TIME OUT'
+ break
+ case 2:
+ error = 'THE WI-FI+GNSS SCAN TIME OUT'
+ break
+ case 3:
+ error = 'THE GNSS+WI-FI SCAN TIME OUT'
+ break
+ case 4:
+ error = 'THE BEACON SCAN TIME OUT'
+ break
+ case 5:
+ error = 'THE BEACON+WI-FI SCAN TIME OUT'
+ break
+ case 6:
+ error = 'THE BEACON+GNSS SCAN TIME OUT'
+ break
+ case 7:
+ error = 'THE BEACON+WI-FI+GNSS SCAN TIME OUT'
+ break
+ case 8:
+ error = 'FAILED TO OBTAIN THE UTC TIMESTAMP'
+ break
+ }
+ measurementArray.push({errorCode, error})
+ }
+ return measurementArray
+}
+
+function getUpShortInfo (messageValue) {
+ return [
+ {
+ measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2))
+ }, {
+ measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6))
+ }, {
+ measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10))
+ }, {
+ measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12))
+ }, {
+ measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getOneWeekInterval(messageValue.substring(14, 18))
+ }, {
+ measurementId: '3943', type: 'Periodic Interval', measurementValue: getOneWeekInterval(messageValue.substring(18, 22))
+ }, {
+ measurementId: '3944', type: 'Event Interval', measurementValue: getOneWeekInterval(messageValue.substring(22, 26))
+ }, {
+ measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30))
+ }
+ ]
+}
+function getBattery (batteryStr) {
+ return loraWANV2DataFormat(batteryStr)
+}
+function getSoftVersion (softVersion) {
+ return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}`
+}
+function getHardVersion (hardVersion) {
+ return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}`
+}
+
+function getOneWeekInterval (str) {
+ return loraWANV2DataFormat(str) * 60
+}
+function getSensorValue (str, dig) {
+ if (str === '8000') {
+ return null
+ } else {
+ return loraWANV2DataFormat(str, dig)
+ }
+}
+
+function bytes2HexString (arrBytes) {
+ var str = ''
+ for (var i = 0; i < arrBytes.length; i++) {
+ var tmp
+ var num = arrBytes[i]
+ if (num < 0) {
+ tmp = (255 + num + 1).toString(16)
+ } else {
+ tmp = num.toString(16)
+ }
+ if (tmp.length === 1) {
+ tmp = '0' + tmp
+ }
+ str += tmp
+ }
+ return str
+}
+function loraWANV2DataFormat (str, divisor = 1) {
+ let strReverse = bigEndianTransform(str)
+ let str2 = toBinary(strReverse)
+ if (str2.substring(0, 1) === '1') {
+ let arr = str2.split('')
+ let reverseArr = arr.map((item) => {
+ if (parseInt(item) === 1) {
+ return 0
+ } else {
+ return 1
+ }
+ })
+ str2 = parseInt(reverseArr.join(''), 2) + 1
+ return '-' + str2 / divisor
+ }
+ return parseInt(str2, 2) / divisor
+}
+
+function bigEndianTransform (data) {
+ let dataArray = []
+ for (let i = 0; i < data.length; i += 2) {
+ dataArray.push(data.substring(i, i + 2))
+ }
+ return dataArray
+}
+
+function toBinary (arr) {
+ let binaryData = arr.map((item) => {
+ let data = parseInt(item, 16)
+ .toString(2)
+ let dataLength = data.length
+ if (data.length !== 8) {
+ for (let i = 0; i < 8 - dataLength; i++) {
+ data = `0` + data
+ }
+ }
+ return data
+ })
+ return binaryData.toString().replace(/,/g, '')
+}
+
+function getSOSMode (str) {
+ return loraWANV2DataFormat(str)
+}
+
+function getMacAndRssiObj (pair) {
+ let pairs = []
+ if (pair.length % 14 === 0) {
+ for (let i = 0; i < pair.length; i += 14) {
+ let mac = getMacAddress(pair.substring(i, i + 12))
+ if (mac) {
+ let rssi = getInt8RSSI(pair.substring(i + 12, i + 14))
+ pairs.push({mac: mac, rssi: rssi})
+ } else {
+ continue
+ }
+ }
+ }
+ return pairs
+}
+
+function getMacAddress (str) {
+ if (str.toLowerCase() === 'ffffffffffff') {
+ return null
+ }
+ let macArr = []
+ for (let i = 1; i < str.length; i++) {
+ if (i % 2 === 1) {
+ macArr.push(str.substring(i - 1, i + 1))
+ }
+ }
+ let mac = ''
+ for (let i = 0; i < macArr.length; i++) {
+ mac = mac + macArr[i]
+ if (i < macArr.length - 1) {
+ mac = mac + ':'
+ }
+ }
+ return mac
+}
+
+function getInt8RSSI (str) {
+ return this.loraWANV2DataFormat(str)
+}
+
+function getInt (str) {
+ return parseInt(str)
+}
+
+/**
+ * 1.MOVING_STARTING
+ * 2.MOVING_END
+ * 3.DEVICE_STATIC
+ * 4.SHOCK_EVENT
+ * 5.TEMP_EVENT
+ * 6.LIGHTING_EVENT
+ * 7.SOS_EVENT
+ * 8.CUSTOMER_EVENT
+ * */
+function getEventStatus (str) {
+ let bitStr = this.getByteArray(str)
+ let event = []
+ for (let i = bitStr.length; i >= 0; i--) {
+ if (i === 0) {
+ event[i] = bitStr.substring(0)
+ } else {
+ event[i] = bitStr.substring(i - 1, i)
+ }
+ }
+ return event.reverse()
+}
+
+function getByteArray (str) {
+ let bytes = []
+ for (let i = 0; i < str.length; i += 2) {
+ bytes.push(str.substring(i, i + 2))
+ }
+ return toBinary(bytes)
+}
+
+function getWorkingMode (workingMode) {
+ return getInt(workingMode)
+}
+
+function getUTCTimestamp(str){
+ return parseInt(this.loraWANV2PositiveDataFormat(str)) * 1000
+}
+
+function loraWANV2PositiveDataFormat (str, divisor = 1) {
+ let strReverse = this.bigEndianTransform(str)
+ let str2 = this.toBinary(strReverse)
+ return parseInt(str2, 2) / divisor
+}
\ No newline at end of file
diff --git a/vendor/sensecap/sensecapt1000-tracker-ab.yaml b/vendor/sensecap/sensecapt1000-tracker-ab.yaml
new file mode 100644
index 0000000000..ae72e3577b
--- /dev/null
+++ b/vendor/sensecap/sensecapt1000-tracker-ab.yaml
@@ -0,0 +1,136 @@
+name: SenseCAP T1000 Tracker A/B
+description: SenseCAP T1000 A/B is a credit card-sized tracker, which is designed for asset and personal tracking. By utilizing GNSS/Wi-Fi/Bluetooth, it covers both outdoor and indoor positioning scenarios with high accuracy.
+
+# Hardware versions (optional, use when you have revisions)
+hardwareVersions:
+ - version: '1.0'
+ numeric: 1
+
+# Firmware versions (at least one is mandatory)
+firmwareVersions:
+ - # Firmware version
+ version: '1.0'
+ numeric: 1
+ # Corresponding hardware versions (optional)
+ hardwareVersions:
+ - '1.0'
+
+ # LoRaWAN Device Profiles per region
+ # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867,
+ # RU864-870
+ profiles:
+ EU863-870:
+ # Unique identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters)
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ US902-928:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ AU915-928:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ KR920-923:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ IN865-867:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ AS923:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+ RU864-870:
+ id: sensecap-profile
+ lorawanCertified: true
+ codec: sensecapt1000-tracker-ab-codec
+
+# Sensors that this device features (optional)
+# Valid values are:
+# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity,
+# current, digital input, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, humidity, iaq, level, light,
+# lightning, link, magnetometer, moisture, motion, no, no2, o3, particulate matter, ph, pir, pm2.5, pm10, potentiometer,
+# power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, rssi, smart valve, snr, so2,
+# solar radiation, sound, strain, surface temperature, temperature, tilt, time, tvoc, uv, vapor pressure, velocity,
+# vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed.
+sensors:
+ - temperature
+ - light
+ #- longitude
+ #- latitude
+
+# Dimensions in mm (optional)
+# Use width, height, length and/or diameter
+dimensions:
+ width: 6.5
+ length: 55
+ height: 85
+
+# Weight in grams (optional)
+weight: 32
+
+# Battery information (optional)
+battery:
+ replaceable: true
+ type: Rechargeable lithium battery, 700mAh
+
+# Operating conditions (optional)
+operatingConditions:
+ # Temperature (Celsius)
+ temperature:
+ min: -20
+ max: 60
+ # Relative humidity (fraction of 1)
+ relativeHumidity:
+ min: 0
+ max: 1
+
+# IP rating (optional)
+ipCode: IP65
+
+# Key provisioning (optional)
+# Valid values are: custom (user can configure keys), join server and manifest.
+keyProvisioning:
+ - custom
+ - join server
+
+# Key security (optional)
+# Valid values are: none, read protected and secure element.
+keySecurity: none
+
+# Product and data sheet URLs (optional)
+productURL: https://files.seeedstudio.com/products/SenseCAP/SenseCAP_Tracker/SenseCAP_Tracker_T1000-AB_User_Guide.pdf
+dataSheetURL: https://files.seeedstudio.com/products/SenseCAP/SenseCAP_Tracker/SenseCAP_Tracker_T1000_Datasheet.pdf
+
+# Commercial information
+resellerURLs:
+ - name: 'Seeed'
+ region:
+ - Other
+ url: https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html
+
+# Photos
+photos:
+ main: sensecapt1000.png
+
+video: https://youtu.be/jj6XN8IcchI
+
+# Regulatory compliances (optional)
+compliances:
+ safety:
+ - body: IEC
+ norm: EN
+ standard: 62368-1
+ radioEquipment:
+ - body: ETSI
+ norm: EN
+ standard: 301 489-1
+ version: 2.2.0
+ - body: ETSI
+ norm: EN
+ standard: 301 489-3
+ version: 2.1.0
diff --git a/vendor/sensecap/sensecapt1000.png b/vendor/sensecap/sensecapt1000.png
new file mode 100644
index 0000000000..0a0af2f01a
Binary files /dev/null and b/vendor/sensecap/sensecapt1000.png differ
diff --git a/website/yarn.lock b/website/yarn.lock
index de5bdc141a..c46ece09c3 100644
--- a/website/yarn.lock
+++ b/website/yarn.lock
@@ -3764,10 +3764,12 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
-lru-cache@^7.4.0:
- version "7.8.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.8.0.tgz#649aaeb294a56297b5cbc5d70f198dcc5ebe5747"
- integrity sha512-AmXqneQZL3KZMIgBpaPTeI6pfwh+xQ2vutMsyqOu1TBdEXFZgpG/80wuJ531w2ZN7TI0/oc8CPxzh/DKQudZqg==
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
make-dir@^2.0.0, make-dir@^2.1.0:
version "2.1.0"
@@ -5159,9 +5161,9 @@ selfsigned@^1.10.8:
node-forge "^0.10.0"
"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@7.0.0:
version "7.0.0"
@@ -5169,16 +5171,16 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.4:
- version "7.3.6"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.6.tgz#5d73886fb9c0c6602e79440b97165c29581cbb2b"
- integrity sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
- lru-cache "^7.4.0"
+ lru-cache "^6.0.0"
send@0.17.2:
version "0.17.2"
@@ -6212,6 +6214,11 @@ yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
yaml@^1.10.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"