refactor: 删除 ESP Config WeChat 项目

This commit is contained in:
duruofu
2025-08-04 19:55:09 +08:00
parent a356de9d73
commit ef991fe9f1
93 changed files with 389 additions and 10656 deletions
@@ -1,2 +0,0 @@
node_modules/
miniprogram_npm/
@@ -1,5 +0,0 @@
# ESP Config WeChat
A WeChat application for provisioning ESP smart devices.
## Implemented modules
[BluFi](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/blufi)
@@ -1,22 +0,0 @@
//app.js
App({
data: {
service_uuid: "0000FFFF-0000-1000-8000-00805F9B34FB",
characteristic_write_uuid: "0000FF01-0000-1000-8000-00805F9B34FB",
characteristic_read_uuid: "0000FF02-0000-1000-8000-00805F9B34FB",
name: "BLUFI",
mtu: 19,
constMtu: 128,
md5Key: "",
platform: '',
sequenceControl: -1,
sequenceNumber: -1
},
onLaunch: function () {
},
globalData: {
userInfo: null
}
})
@@ -1,15 +0,0 @@
{
"pages": [
"pages/index/index",
"pages/blueDevices/blueDevices",
"pages/blueWifi/blueWifi",
"pages/blueConnect/blueConnect"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#4d9efb",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "white"
},
"sitemapLocation": "sitemap.json"
}
@@ -1,119 +0,0 @@
/**app.wxss**/
.container {
height: 100%;
display: flex;
padding: 0 10px;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
.item {
display: flex;
height: 130rpx;
width: 100%;
align-items: center;
border-bottom: 1px solid #eee;
}
.item-img {
flex: 0 0 100rpx;
height: 100rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 100%;
}
.bluetooth-img {
height: 80rpx;
width: 80rpx;
}
.item-name {
flex: 1;
padding-left: 10px;
display: flex;
flex-direction: column;
font-size: 32rpx;
}
.text-rssi {
font-size: 28rpx;
color: #999;
}
.btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #4d9efb;
border: none;
margin-bottom: 30rpx;
font-size: 14px;
color: #fff;
}
.font14 {
font-size: 14px;
}
.font16 {
font-size: 16px;
}
.textcenter {
text-align: center;
}
.width100 {
width: 100%;
}
.margintop20 {
margin-top: 20px;
}
.margintop10 {
margin-top: 10px;
}
.modal-mask{
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba(0,0,0,.7);
overflow: hidden;
color: #ffffff;
z-index:900;
}
.modal-dialog{
background-color: #f9f9f9;
/*background: rgba(0,0,0,.7);*/
opacity: 0.95;
position: fixed;
z-index: 999;
top: 20%;
left: 10%;
overflow: hidden;
width: 80%;
color: #000;
border-radius: 26rpx;
}
.modal-dialog input{
margin: 15px 0;
padding: 0 20px;
font-size: 32rpx;
}
.modal-btn-wrapper{
display: flex;
flex-direction: row;
height: 100rpx;
line-height:90rpx;
border-top: 2rpx solid rgba(7,17,27,0.1);
}
.cancel-btn, .confirm-btn{
flex: 1;
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-size: 32rpx;
}
.cancel-btn{
border-right: 2rpx solid rgba(7,17,27,0.1);
}
.modal-title{
text-align: center;
padding-top: 10px;
}
File diff suppressed because it is too large Load Diff
@@ -1,42 +0,0 @@
var generatePrime = require('./lib/generatePrime')
var DH = require('./lib/dh')
var Buffer = require('./lib/safe-buffer').Buffer
function getDiffieHellman(mod) {
var prime = new Buffer(primes[mod].prime, 'hex')
var gen = new Buffer(primes[mod].gen, 'hex')
return new DH(prime, gen)
}
var ENCODINGS = {
'binary': true, 'hex': true, 'base64': true
}
function createDiffieHellman(prime, enc, generator, genc) {
if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) {
return createDiffieHellman(prime, 'binary', enc, generator)
}
enc = enc || 'binary'
genc = genc || 'binary'
generator = generator || new Buffer([2])
if (!Buffer.isBuffer(generator)) {
generator = new Buffer(generator, genc)
}
if (typeof prime === 'number') {
return new DH(generatePrime(prime, generator), generator, true)
}
if (!Buffer.isBuffer(prime)) {
prime = new Buffer(prime, enc)
}
return new DH(prime, generator, true)
}
exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman
exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman
@@ -1,151 +0,0 @@
'use strict'
exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray
var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i]
revLookup[code.charCodeAt(i)] = i
}
// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function getLens (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
var validLen = b64.indexOf('=')
if (validLen === -1) validLen = len
var placeHoldersLen = validLen === len
? 0
: 4 - (validLen % 4)
return [validLen, placeHoldersLen]
}
// base64 is 4/3 + up to two characters of the original data
function byteLength (b64) {
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function _byteLength (b64, validLen, placeHoldersLen) {
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function toByteArray (b64) {
var tmp
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
var curByte = 0
// if there are placeholders, only get up to the last complete 4 chars
var len = placeHoldersLen > 0
? validLen - 4
: validLen
for (var i = 0; i < len; i += 4) {
tmp =
(revLookup[b64.charCodeAt(i)] << 18) |
(revLookup[b64.charCodeAt(i + 1)] << 12) |
(revLookup[b64.charCodeAt(i + 2)] << 6) |
revLookup[b64.charCodeAt(i + 3)]
arr[curByte++] = (tmp >> 16) & 0xFF
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 2) {
tmp =
(revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 1) {
tmp =
(revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
return arr
}
function tripletToBase64 (num) {
return lookup[num >> 18 & 0x3F] +
lookup[num >> 12 & 0x3F] +
lookup[num >> 6 & 0x3F] +
lookup[num & 0x3F]
}
function encodeChunk (uint8, start, end) {
var tmp
var output = []
for (var i = start; i < end; i += 3) {
tmp =
((uint8[i] << 16) & 0xFF0000) +
((uint8[i + 1] << 8) & 0xFF00) +
(uint8[i + 2] & 0xFF)
output.push(tripletToBase64(tmp))
}
return output.join('')
}
function fromByteArray (uint8) {
var tmp
var len = uint8.length
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
var parts = []
var maxChunkLength = 16383 // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
parts.push(encodeChunk(
uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
))
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1) {
tmp = uint8[len - 1]
parts.push(
lookup[tmp >> 2] +
lookup[(tmp << 4) & 0x3F] +
'=='
)
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
parts.push(
lookup[tmp >> 10] +
lookup[(tmp >> 4) & 0x3F] +
lookup[(tmp << 2) & 0x3F] +
'='
)
}
return parts.join('')
}
File diff suppressed because it is too large Load Diff
@@ -1,52 +0,0 @@
var r;
module.exports = function rand(len) {
if (!r)
r = new Rand(null);
return r.generate(len);
};
function Rand(rand) {
this.rand = rand;
}
module.exports.Rand = Rand;
Rand.prototype.generate = function generate(len) {
return this._rand(len);
};
// Emulate crypto API using randy
Rand.prototype._rand = function _rand(n) {
console.log(this);
if (this.rand.getBytes)
return this.rand.getBytes(n);
var res = new Uint8Array(n);
for (var i = 0; i < res.length; i++)
res[i] = this.rand.getByte();
return res;
};
if (typeof self === 'object') {
Rand.prototype._rand = function _rand(n) {
var list = [];
for (var i = 0; i < n; i++) {
list.push(Math.ceil(Math.random() * 255))
}
var arr = new Uint8Array(list);
return arr;
};
} else {
// Node.js or Web worker with no crypto support
try {
var crypto = require('crypto');
if (typeof crypto.randomBytes !== 'function')
throw new Error('Not supported');
Rand.prototype._rand = function _rand(n) {
return crypto.randomBytes(n);
};
} catch (e) {
}
}
File diff suppressed because it is too large Load Diff
@@ -1,165 +0,0 @@
var BN = require('bn');
var MillerRabin = require('miller-rabin');
var millerRabin = new MillerRabin();
var TWENTYFOUR = new BN(24);
var ELEVEN = new BN(11);
var TEN = new BN(10);
var THREE = new BN(3);
var SEVEN = new BN(7);
var Buffer = require('safe-buffer').Buffer
var primes = require('./generatePrime');
var randomBytes = require('randombytes');
module.exports = DH;
function setPublicKey(pub, enc) {
enc = enc || 'utf8';
if (!Buffer.isBuffer(pub)) {
pub = new Buffer(pub, enc);
}
this._pub = new BN(pub);
return this;
}
function setPrivateKey(priv, enc) {
enc = enc || 'utf8';
if (!Buffer.isBuffer(priv)) {
priv = new Buffer(priv, enc);
}
this._priv = new BN(priv);
return this;
}
var primeCache = {};
function checkPrime(prime, generator) {
var gen = generator.toString('hex');
var hex = [gen, prime.toString(16)].join('_');
if (hex in primeCache) {
return primeCache[hex];
}
var error = 0;
if (prime.isEven() ||
!primes.simpleSieve ||
!primes.fermatTest(prime) ||
!millerRabin.test(prime)) {
//not a prime so +1
error += 1;
if (gen === '02' || gen === '05') {
// we'd be able to check the generator
// it would fail so +8
error += 8;
} else {
//we wouldn't be able to test the generator
// so +4
error += 4;
}
primeCache[hex] = error;
return error;
}
if (!millerRabin.test(prime.shrn(1))) {
//not a safe prime
error += 2;
}
var rem;
switch (gen) {
case '02':
if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) {
// unsuidable generator
error += 8;
}
break;
case '05':
rem = prime.mod(TEN);
if (rem.cmp(THREE) && rem.cmp(SEVEN)) {
// prime mod 10 needs to equal 3 or 7
error += 8;
}
break;
default:
error += 4;
}
primeCache[hex] = error;
return error;
}
function DH(prime, generator, malleable) {
this.setGenerator(generator);
this.__prime = new BN(prime);
this._prime = BN.mont(this.__prime);
this._primeLen = 128;
this._pub = undefined;
this._priv = undefined;
this._primeCode = undefined;
if (malleable) {
this.setPublicKey = setPublicKey;
this.setPrivateKey = setPrivateKey;
} else {
this._primeCode = 8;
}
}
Object.defineProperty(DH.prototype, 'verifyError', {
enumerable: true,
get: function () {
if (typeof this._primeCode !== 'number') {
this._primeCode = checkPrime(this.__prime, this.__gen);
}
return this._primeCode;
}
});
DH.prototype.generateKeys = function () {
if (!this._priv) {
this._priv = new BN(randomBytes(this._primeLen));
}
this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed();
return this.getPublicKey();
};
DH.prototype.computeSecret = function (other) {
other = new BN(other);
other = other.toRed(this._prime);
var secret = other.redPow(this._priv).fromRed();
var out = new Buffer(secret.toArray());
var prime = this.getPrime();
if (out.length < prime.length) {
var front = new Buffer(prime.length - out.length);
front.fill(0);
out = Buffer.concat([front, out]);
}
return out;
};
DH.prototype.getPublicKey = function getPublicKey(enc) {
return formatReturnValue(this._pub, enc);
};
DH.prototype.getPrivateKey = function getPrivateKey(enc) {
return formatReturnValue(this._priv, enc);
};
DH.prototype.getPrime = function (enc) {
return formatReturnValue(this.__prime, enc);
};
DH.prototype.getGenerator = function (enc) {
return formatReturnValue(this._gen, enc);
};
DH.prototype.setGenerator = function (gen, enc) {
enc = enc || 'utf8';
if (!Buffer.isBuffer(gen)) {
gen = new Buffer(gen, enc);
}
this.__gen = gen;
this._gen = new BN(gen);
return this;
};
function formatReturnValue(bn, enc) {
var buf = new Buffer(bn.toArray());
if (!enc) {
return buf;
} else {
return buf.toString(enc);
}
}
@@ -1,105 +0,0 @@
var randomBytes = require('randombytes');
module.exports = findPrime;
findPrime.simpleSieve = simpleSieve;
findPrime.fermatTest = fermatTest;
var BN = require('bn.js');
var TWENTYFOUR = new BN(24);
var MillerRabin = require('miller-rabin');
var millerRabin = new MillerRabin();
var ONE = new BN(1);
var TWO = new BN(2);
var FIVE = new BN(5);
var SIXTEEN = new BN(16);
var EIGHT = new BN(8);
var TEN = new BN(10);
var THREE = new BN(3);
var SEVEN = new BN(7);
var ELEVEN = new BN(11);
var FOUR = new BN(4);
var TWELVE = new BN(12);
var primes = null;
function _getPrimes() {
if (primes !== null)
return primes;
var limit = 0x100000;
var res = [];
res[0] = 2;
for (var i = 1, k = 3; k < limit; k += 2) {
var sqrt = Math.ceil(Math.sqrt(k));
for (var j = 0; j < i && res[j] <= sqrt; j++)
if (k % res[j] === 0)
break;
if (i !== j && res[j] <= sqrt)
continue;
res[i++] = k;
}
primes = res;
return res;
}
function simpleSieve(p) {
var primes = _getPrimes();
for (var i = 0; i < primes.length; i++)
if (p.modn(primes[i]) === 0) {
if (p.cmpn(primes[i]) === 0) {
return true;
} else {
return false;
}
}
return true;
}
function fermatTest(p) {
var red = BN.mont(p);
return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0;
}
function findPrime(bits, gen) {
if (bits < 16) {
// this is what openssl does
if (gen === 2 || gen === 5) {
return new BN([0x8c, 0x7b]);
} else {
return new BN([0x8c, 0x27]);
}
}
gen = new BN(gen);
var num, n2;
while (true) {
num = new BN(randomBytes(Math.ceil(bits / 8)));
while (num.bitLength() > bits) {
num.ishrn(1);
}
if (num.isEven()) {
num.iadd(ONE);
}
if (!num.testn(1)) {
num.iadd(TWO);
}
if (!gen.cmp(TWO)) {
while (num.mod(TWENTYFOUR).cmp(ELEVEN)) {
num.iadd(FOUR);
}
} else if (!gen.cmp(FIVE)) {
while (num.mod(TEN).cmp(THREE)) {
num.iadd(FOUR);
}
}
n2 = num.shrn(1);
if (simpleSieve(n2) && simpleSieve(num) &&
fermatTest(n2) && fermatTest(num) &&
millerRabin.test(n2) && millerRabin.test(num)) {
return num;
}
}
}
@@ -1,84 +0,0 @@
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
var e, m
var eLen = (nBytes * 8) - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var nBits = -7
var i = isLE ? (nBytes - 1) : 0
var d = isLE ? -1 : 1
var s = buffer[offset + i]
i += d
e = s & ((1 << (-nBits)) - 1)
s >>= (-nBits)
nBits += eLen
for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
m = e & ((1 << (-nBits)) - 1)
e >>= (-nBits)
nBits += mLen
for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
if (e === 0) {
e = 1 - eBias
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity)
} else {
m = m + Math.pow(2, mLen)
e = e - eBias
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
}
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
var e, m, c
var eLen = (nBytes * 8) - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
var i = isLE ? 0 : (nBytes - 1)
var d = isLE ? 1 : -1
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
value = Math.abs(value)
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0
e = eMax
} else {
e = Math.floor(Math.log(value) / Math.LN2)
if (value * (c = Math.pow(2, -e)) < 1) {
e--
c *= 2
}
if (e + eBias >= 1) {
value += rt / c
} else {
value += rt * Math.pow(2, 1 - eBias)
}
if (value * c >= 2) {
e++
c /= 2
}
if (e + eBias >= eMax) {
m = 0
e = eMax
} else if (e + eBias >= 1) {
m = ((value * c) - 1) * Math.pow(2, mLen)
e = e + eBias
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
e = 0
}
}
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
e = (e << mLen) | m
eLen += mLen
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
buffer[offset + i - d] |= s * 128
}
@@ -1,115 +0,0 @@
var bn = require('bn.js');
var brorand = require('brorand');
function MillerRabin(rand) {
this.rand = rand || new brorand.Rand();
}
module.exports = MillerRabin;
MillerRabin.create = function create(rand) {
return new MillerRabin(rand);
};
MillerRabin.prototype._randbelow = function _randbelow(n) {
var len = n.bitLength();
var min_bytes = Math.ceil(len / 8);
// Generage random bytes until a number less than n is found.
// This ensures that 0..n-1 have an equal probability of being selected.
do
var a = new bn(this.rand.generate(min_bytes));
while (a.cmp(n) >= 0);
return a;
};
MillerRabin.prototype._randrange = function _randrange(start, stop) {
// Generate a random number greater than or equal to start and less than stop.
var size = stop.sub(start);
return start.add(this._randbelow(size));
};
MillerRabin.prototype.test = function test(n, k, cb) {
var len = n.bitLength();
var red = bn.mont(n);
var rone = new bn(1).toRed(red);
if (!k)
k = Math.max(1, (len / 48) | 0);
// Find d and s, (n - 1) = (2 ^ s) * d;
var n1 = n.subn(1);
for (var s = 0; !n1.testn(s); s++) {}
var d = n.shrn(s);
var rn1 = n1.toRed(red);
var prime = true;
for (; k > 0; k--) {
var a = this._randrange(new bn(2), n1);
if (cb)
cb(a);
var x = a.toRed(red).redPow(d);
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
continue;
for (var i = 1; i < s; i++) {
x = x.redSqr();
if (x.cmp(rone) === 0)
return false;
if (x.cmp(rn1) === 0)
break;
}
if (i === s)
return false;
}
return prime;
};
MillerRabin.prototype.getDivisor = function getDivisor(n, k) {
var len = n.bitLength();
var red = bn.mont(n);
var rone = new bn(1).toRed(red);
if (!k)
k = Math.max(1, (len / 48) | 0);
// Find d and s, (n - 1) = (2 ^ s) * d;
var n1 = n.subn(1);
for (var s = 0; !n1.testn(s); s++) {}
var d = n.shrn(s);
var rn1 = n1.toRed(red);
for (; k > 0; k--) {
var a = this._randrange(new bn(2), n1);
var g = n.gcd(a);
if (g.cmpn(1) !== 0)
return g;
var x = a.toRed(red).redPow(d);
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
continue;
for (var i = 1; i < s; i++) {
x = x.redSqr();
if (x.cmp(rone) === 0)
return x.fromRed().subn(1).gcd(n);
if (x.cmp(rn1) === 0)
break;
}
if (i === s) {
x = x.redSqr();
return x.fromRed().subn(1).gcd(n);
}
}
return false;
};
@@ -1,31 +0,0 @@
'use strict'
function oldBrowser() {
throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11')
}
var Buffer = require('safe-buffer').Buffer
module.exports = randomBytes
function randomBytes(size, cb) {
// phantomjs needs to throw
if (size > 65536) throw new Error('requested too many random bytes')
// in case browserify isn't using the Uint8Array version
var arr = [];
for (var i = 0; i < size; i++) {
arr.push(Math.ceil(Math.random() * 255))
}
var rawBytes = new Uint8Array(arr)
// XXX: phantomjs doesn't like a buffer being passed here
var bytes = Buffer.from(rawBytes.buffer)
if (typeof cb === 'function') {
return process.nextTick(function () {
cb(null, bytes)
})
}
return bytes
}
@@ -1,62 +0,0 @@
/* eslint-disable node/no-deprecated-api */
var buffer = require('buffer')
var Buffer = buffer.Buffer
// alternative to using Object.keys for old browsers
function copyProps (src, dst) {
for (var key in src) {
dst[key] = src[key]
}
}
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
module.exports = buffer
} else {
// Copy properties from require('buffer')
copyProps(buffer, exports)
exports.Buffer = SafeBuffer
}
function SafeBuffer (arg, encodingOrOffset, length) {
return Buffer(arg, encodingOrOffset, length)
}
// Copy static methods from Buffer
copyProps(Buffer, SafeBuffer)
SafeBuffer.from = function (arg, encodingOrOffset, length) {
if (typeof arg === 'number') {
throw new TypeError('Argument must not be a number')
}
return Buffer(arg, encodingOrOffset, length)
}
SafeBuffer.alloc = function (size, fill, encoding) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
var buf = Buffer(size)
if (fill !== undefined) {
if (typeof encoding === 'string') {
buf.fill(fill, encoding)
} else {
buf.fill(fill)
}
} else {
buf.fill(0)
}
return buf
}
SafeBuffer.allocUnsafe = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return Buffer(size)
}
SafeBuffer.allocUnsafeSlow = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return buffer.SlowBuffer(size)
}
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

@@ -1,28 +0,0 @@
{
"name": "ESP-Config-WeChat",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ESP-Config-WeChat",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"crypto-js": "^4.0.0"
}
},
"node_modules/crypto-js": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
}
},
"dependencies": {
"crypto-js": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
}
}
}
@@ -1,23 +0,0 @@
{
"name": "ESP-Config-WeChat",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/EspressifApps/ESP-Config-WeChat.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/EspressifApps/ESP-Config-WeChat/issues"
},
"homepage": "https://github.com/EspressifApps/ESP-Config-WeChat#readme",
"dependencies": {
"crypto-js": "^4.0.0"
}
}
@@ -1,29 +0,0 @@
<!--pages/blueConnect/blueConnect.wxml-->
<view class="container">
<block wx:if="{{!failure}}">
<view class="schedule">
<view class="schedule-result schedule-success">
<image class='schedule-img' mode='aspectFit' src='../../images/round.gif'></image>
<view class="desc-wrapper">
<view class="text-value"><text>{{value}}</text><text class="text-samll">%</text></view>
<view class="text-desc">{{desc}}</view>
</view>
</view>
</view>
</block>
<block wx:else>
<view class="schedule fail">
<view class="schedule-result schedule-fail">
<image class='schedule-img' mode='aspectFit' src='../../images/failure.png'></image>
<view class="desc-wrapper">
<view class="text-sigh"><text>!</text></view>
<view class="text-desc">{{desc}}</view>
</view>
</view>
</view>
</block>
<view class="process-wrapper">
<text class="text-process" wx:for="{{processList}}" wx:key="*this">{{item}}</text>
<text>{{vConsoleV}}</text>
</view>
</view>
@@ -1,68 +0,0 @@
/* pages/blueConnect/blueConnect.wxss */
.container {
padding: 0;
}
.schedule {
background: #4d9efb;
height: 46vh;
width: 100%;
padding: 50rpx;
}
.schedule-result {
position: relative;
display: flex;
justify-content: center;
align-items: center;
border-radius: 100%;
background: transparent;
height: 55vw;
width: 55vw;
margin: 0 auto;
color: #fff;
}
.schedule-img {
height: 55vw;
width: 55vw;
}
.fail{
background: #737d89;
}
.desc-wrapper {
position: absolute;
}
.text-value {
text-align: center;
font-size: 20px;
}
.text-desc {
font-size: 14px;
}
.text-samll {
font-size: 16px;
}
.text-sigh {
height: 80rpx;
width: 80rpx;
background: #fff;
border-radius: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
color: #737d89;
margin: 0 auto 10px;
}
.process-wrapper {
display: flex;
flex-direction: column;
width: 100%;
text-align: left;
margin-top: 20px;
padding-left: 30px;
font-size: 14px;
color: #999;
}
.text-process {
margin: 3px 0;
}
@@ -1,105 +0,0 @@
//获取应用实例
const app = getApp();
const util = require('../../utils/util.js');
Page({
data: {
deviceList: [],
deviceId: "",
},
bindViewConnect: function (event) {
var self = this,
deviceId = event.currentTarget.dataset.value;
self.setData({
deviceId: deviceId
});
wx.navigateTo({
url: '/pages/blueWifi/blueWifi?deviceId=' + deviceId,
})
},
getBluDevice: function () {
var self = this;
wx.getBluetoothDevices({
success: function (res) {
var list = util.filterDevice(res.devices, "name");
if (list.length > 0) {
wx.hideLoading();
}
self.setData({
deviceList: list
})
}
})
wx.onBluetoothDeviceFound(function (res) {
console.log(res.devices[0].name);
var list = util.filterDevice(res.devices, "name");
if (list.length > 0) {
wx.hideLoading();
}
self.setData({
deviceList: self.data.deviceList.concat(list)
})
})
},
onLoad: function () {
var self = this;
wx.setNavigationBarTitle({
title: 'BluFi扫描'
});
wx.showLoading({
title: '设备扫描中...',
})
self.getBluDevice();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
var self = this,
deviceId = self.data.deviceId;
if (!util._isEmpty(deviceId)) {
wx.closeBLEConnection({
deviceId: deviceId,
})
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
})
@@ -1,13 +0,0 @@
<!--index.wxml-->
<view class="container">
<view data-value="{{item.deviceId}}" bindtap="bindViewConnect" wx:for="{{deviceList}}" class="item" wx:key="*this">
<view class="item-img">
<image class='bluetooth-img' mode='aspectFit' src='../../images/bluetooth.png'></image>
</view>
<view class="item-name">
<text class="text-name">{{item.name}}</text>
<text class="text-rssi">Rssi: {{item.RSSI}}</text>
<text class="text-rssi">deviceId: {{item.deviceId}}</text>
</view>
</view>
</view>
@@ -1,11 +0,0 @@
/* pages/blueDevices/blueDevices.wxss */
.prompt-title {
height: 50rpx;
border-top: 1px solid #999;
border-bottom: 1px solid #999;
width: 100%;
}
.item {
height: auto;
padding: 8rpx 0;
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +0,0 @@
{
"backgroundTextStyle": "dark",
"enablePullDownRefresh": true
}
@@ -1,19 +0,0 @@
<view class="container">
<view data-bssid="" data-ssid="{{item.SSID}}" bindtap="bindViewWifi" wx:for="{{wifiList}}" class="item" wx:key="*this">
<view class="item-name">
<text class="text-name">{{item.SSID}}</text>
</view>
<view class="item-icon">
<image class='wifi-img' mode='aspectFit' src='../../images/wifi.png'></image>
</view>
</view>
<view class='modal-mask' hidden="{{hiddenModal}}"></view>
<view class='modal-dialog' hidden="{{hiddenModal}}">
<view class='modal-title'>{{ssid}}</view>
<input type='text' password='true' bindinput='bindViewInput' placeholder="请输入密码"/>
<view class='modal-btn-wrapper'>
<view class='cancel-btn' style='color:rgba(7,17,27,0.6)' bindtap='bindViewCancel'>取消</view>
<view class='confirm-btn' style='color:#4d9efb' bindtap='bindViewConfirm'>开始配网</view>
</view>
</view>
</view>
@@ -1,12 +0,0 @@
/* pages/blueWifi/blueWifi.wxss */
.item-icon {
flex: 0 0 80rpx;
height: 100%;
display: flex;
justify-items: center;
align-items: center;
}
.wifi-img {
width: 60rpx;
height: 60rpx;
}
@@ -1,57 +0,0 @@
//index.js
//获取应用实例
const app = getApp();
const util = require('../../utils/util.js');
Page({
data: {
},
//事件处理函数
bindViewBlue: function() {
wx.closeBluetoothAdapter({
success: function () {
}
});
wx.openBluetoothAdapter({
success: function (res) {
wx.startBluetoothDevicesDiscovery({
success: function (res) {
wx.navigateTo({
url: '/pages/blueDevices/blueDevices',
})
}
})
},
fail: function (res) {
wx.showToast({
title: '请打开蓝牙',
icon: 'none',
duration: 2000
})
}
})
},
bindViewWifi: function () {
wx.navigateTo({
url: '/pages/wifiDevices/wifiDevices',
})
},
onLoad: function () {
wx.setNavigationBarTitle({
title: '配网方式'
})
wx.getSystemInfo({
success (res) {
try {
app.data.platform = res.platform.toLocaleLowerCase()
} catch(e) {
console.log(e)
}
}
})
},
getUserInfo: function(e) {
}
})
@@ -1,19 +0,0 @@
<!--index.wxml-->
<view class="container">
<view class='header-wrapper'>
<image class="header-image" src="../../images/network.png"></image>
</view>
<view class='content-wrapper'>
<view class="title">配网方式</view>
<view class="btn-info">
<view bindtap="bindViewBlue" class="select-way">
<image class="btn-image" src="../../images/bluetooth-way.png"></image>
<text class="name">BluFi 配网</text>
</view>
<!-- <view bindtap="bindViewWifi" class="select-way">
<image class="btn-image" src="../../images/wifi-way.png"></image>
<text class="name">WiFi配网</text>
</view> -->
</view>
</view>
</view>
@@ -1,60 +0,0 @@
.container {
display: block;
padding: 0;
height: 100vh;
background: #eee;
}
.header-wrapper {
display: flex;
justify-content: center;
align-items: center;
height: 45vh;
width: 100%;
background: #4d9efb;
border-bottom-right-radius: 40px;
border-bottom-left-radius: 40px;
}
.header-image {
width: 29vh;
height: 29vh;
position: relative;
top: -5vh;
}
.content-wrapper {
position: absolute;
top: 38vh;
left: 15px;
height: 50vh;
width: calc(100% - 30px);
padding: 20px;
box-sizing: border-box;
background: #fff;
border-radius: 10px;
box-shadow: 0px 0px 3px #fff;
color: #818181;
}
.title {
margin: 10px 0;
text-align: center;
font-size: 16px;
}
.btn-info {
display: flex;
margin-top: 10vh;
}
.btn-image {
width: 50px;
height: 50px;
}
.select-way {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.name {
margin: 10px 0;
font-size: 14px;
}
@@ -1,72 +0,0 @@
// pages/wifiConfig/wifiConfig.js
Page({
/**
* 页面的初始数据
*/
data: {
},
next: function () {
wx.navigateTo({
url: "/pages/wifiList/wifiList"
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.setNavigationBarTitle({
title: 'WiFi配网'
});
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
@@ -1,20 +0,0 @@
<!--pages/wifi3/wifi3.wxml-->
<view class='container'>
<view class='textcenter'>
<view><text class='font14'>第二步</text></view>
<view class="margintop10"><text class='font16'>将手机连接设备,请前往手机设置,进入无线局域网</text></view>
</view>
<!-- wifi -->
<view>
<image class="wifi-img" src="../../images/wifi.jpg"></image>
</view>
<view class="width100 margintop20">
<button class="btn" bindtap='setWifi'>去设置 </button>
</view>
<view class="width100" bindtap='next'>
<button class="btn" > 下一步 </button>
</view>
</view>
@@ -1,9 +0,0 @@
/* pages/wifiConfig/wifiConfig.wxss */
.container{
padding-top: 50rpx;
}
.wifi-img {
width:300px;
height:234px;
margin-top:20px;
}
@@ -1,166 +0,0 @@
// pages/wifiConnect/wifiConnect.js
Page({
/**
* 页面的初始数据
*/
data: {
failStatus: false,
sucStatus: false,
progress: 0,
},
getStatus: function() {
var self = this;
wx.request({
url: 'https://www.alavening.com/wifi/connstatus.cgi',
data: {
},
header: {
'content-type': 'application/json' // 默认值
},
success: function (res) {
console.log(res.data);
var data = res.data;
console.log(data.status);
if (data.status == "success") {
self.setData({
progress: 100,
failStatus: false,
sucStatus: true,
})
self.setResult("success");
} else if (data.status == "fail") {
self.setData({
failStatus: true,
sucStatus: false,
})
self.setResult("fail");
} else {
if (self.data.progress <= 90) {
self.setData({
progress: (self.data.progress + 5),
failStatus: false,
sucStatus: false,
})
}
self.getStatus();
}
},
fail: function (res) {
self.setData({
failStatus: true,
sucStatus: false,
})
}
})
},
setResult: function(result) {
var self = this;
wx.request({
url: 'https://www.alavening.com/wifi/configsuccess.cgi',
method: "post",
data: {
configstatus: result
},
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function (res) {
},
fail: function () {
}
})
},
setConnect: function(ssid, password) {
var self = this;
wx.request({
url: 'https://alavening.com/wifi/connect.cgi',
method: "post",
data: {
essid: ssid,
password: password
},
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function (res) {
},
fail: function () {
}
})
self.getStatus();
},
successwifi: function() {
wx.reLaunch({
url: '/pages/index/index'
})
},
failwifi: function() {
wx.navigateBack({
delta: 2
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var self = this;
wx.setNavigationBarTitle({
title: 'WiFi配网'
});
self.setConnect(options.ssid, options.password);
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
@@ -1,13 +0,0 @@
<!--pages/wifi4/wifi4.wxml-->
<view class='container'>
<view class='textcenter'>
<view><text class='font16'>配网中...</text></view>
</view>
<view class="progress-wrapper">
<progress percent="{{progress}}" stroke-width="12" activeColor="#4d9efb"/>
</view>
<view class='width100 margintop20'>
<button hidden='{{failStatus || !sucStatus}}' class="btn" bindtap='successwifi'>配网成功 </button>
<button hidden='{{!failStatus || sucStatus}}' class="btn" bindtap='failwifi'>配网失败 </button>
</view>
</view>
@@ -1,13 +0,0 @@
/* pages/wifiConnect/wifiConnect.wxss */
.container {
padding-top: 50rpx;
}
.progress-wrapper {
width: 100%;
height: 40px;
display: flex;
align-items: center;
}
progress {
flex: 1;
}
@@ -1,67 +0,0 @@
// pages/wifiDevices/wifiDevices.js
Page({
/**
* 页面的初始数据
*/
data: {
},
next: function () {
wx.navigateTo({
url: "/pages/wifiConfig/wifiConfig"
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.setNavigationBarTitle({
title: 'WiFi配网'
});
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
})
@@ -1,23 +0,0 @@
<!--pages/wifi/wifi.wxml-->
<view class='container'>
<view class='textcenter'>
<view><text class='font14'>第一步</text></view>
<view class="margintop10"><text class='font16'>双击设备按键</text></view>
</view>
<!-- 图片 -->
<view>
<image></image>
</view>
<view class='textcenter font14'>
<checkbox-group>
<label class="checkbox">
<checkbox color="#4d9efb" value=""/>我已双击设备按钮
</label>
</checkbox-group>
</view>
<view class='width100 margintop20' bindtap='next'>
<button class="btn" >下一步</button>
</view>
<!-- <button class='font14 back' >返回上一步</button> -->
</view>
@@ -1,20 +0,0 @@
/* pages/wifi/wifi.wxss */
.container {
padding-top: 50rpx;
}
.checkbox{
color: #333
}
.back{
width: 40%;
margin: 0 auto
}
.colored{
color: red;
}
.hide{
display: none;
}
.show{
display: block;
}
@@ -1,142 +0,0 @@
// pages/wifiList/wifiList.js
Page({
/**
* 页面的初始数据
*/
data: {
password: '',
hiddenmodal: true,//可以通过hidden是否掩藏弹出框的属性,来指定那个弹出框
wifiList: [],
ssid: '',
},
//点击按钮弹出指定的hiddenmodalput弹出框
bindViewWifi: function (e) {
var list = this.data.wifiList;
var index = e.currentTarget.dataset.index;
//console.log(list[index])
this.setData({
ssid: list[index].essid,
hiddenmodal: !this.data.hiddenmodal,
})
},
bindViewInput: function (e) {
this.setData({ password: e.detail.value })
},
getWifiList: function() {
var self = this;
wx.request({
url: 'https://www.alavening.com/wifi/wifiscan.cgi',
data: {
},
header: {
'content-type': 'application/json' // 默认值
},
success: function (res) {
console.log(res);
var data = res.data.result;
console.log(data);
if (data.inProgress == "0") {
wx.hideLoading();
self.setData({
wifiList: data.APs
})
} else {
self.getWifiList();
}
},
fail: function(res) {
console.log(res);
wx.hideLoading();
}
})
},
//取消按钮
cancel: function () {
this.setData({
hiddenmodal: true
});
},
//确认
confirm: function () {
var self = this;
// this.setData({
// hiddenmodal: true
// })
if (!self.data.password.length < 8) {
// 这里修改成跳转的页面
wx.redirectTo({
url: '/pages/wifiConnect/wifiConnect?password=' + self.data.password + "&ssid=" + self.data.ssid
})
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var self = this;
wx.setNavigationBarTitle({
title: 'WiFi配网'
});
setTimeout(function() {
wx.showLoading({
title: 'WiFi加载中...',
});
self.getWifiList();
console.log("WiFi加载中...");
}, 500);
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
@@ -1,35 +0,0 @@
<!--pages/wifi2/wifi2.wxml-->
<view class='container'>
<view class='textcenter'>
<view><text class='font14'>第三步</text></view>
<view class="margintop10"><text class='font16'>请选择您的WiFi</text></view>
</view>
<!-- wifi -->
<view class="width100 margintop20">
<view data-index="{{index}}" bindtap="bindViewWifi" wx:for="{{wifiList}}" class="item" wx:key="*this">
<view class="item-name">
<text class="text-name">{{item.essid}}</text>
</view>
<view class="item-icon">
<image class='wifi-img' mode='aspectFit' src='../../images/wifi.png'></image>
</view>
</view>
</view>
<view class='modal-mask' hidden="{{hiddenmodal}}"></view>
<!-- 弹窗 -->
<view class='modal-dialog' hidden="{{hiddenmodal}}" data-index="{{index}}">
<view class='modal-title'>{{ssid}}</view>
<input type='text' password='true' bindinput='bindViewInput' placeholder="请输入密码"/>
<view class='modal-btn-wrapper'>
<view class='cancel-btn' style='color:rgba(7,17,27,0.6)' bindtap='cancel'>取消</view>
<view class='confirm-btn' style='color:#4d9efb' bindtap='confirm'>确定</view>
</view>
</view>
</view>
@@ -1,35 +0,0 @@
.container{
position: relative;
padding-top: 50rpx;
}
.weui-cell__bd{
padding: 0 20px;
}
.wifi-list{
margin-top: 30px;
}
.main-content{
flex: 1;
height: 100%;
overflow-y: hidden;
}
.item-wifi{
border-bottom:2rpx solid #eee;
height:100rpx;
line-height:100rpx;
margin-top:0;
padding: 0 20px;
}
.item-icon {
flex: 0 0 80rpx;
height: 100%;
display: flex;
justify-items: center;
align-items: center;
}
.wifi-img {
width: 60rpx;
height: 60rpx;
}
@@ -1,54 +0,0 @@
{
"description": "项目配置文件",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"urlCheck": true,
"es6": true,
"enhance": false,
"postcss": true,
"preloadBackgroundData": false,
"minified": true,
"newFeature": true,
"coverView": true,
"nodeModules": true,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"scopeDataCheck": false,
"uglifyFileName": false,
"checkInvalidKey": true,
"checkSiteMap": true,
"uploadWithSourceMap": true,
"compileHotReLoad": false,
"useMultiFrameRuntime": false,
"useApiHook": false,
"useApiHostProcess": false,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"useIsolateContext": false,
"userConfirmedBundleSwitch": false,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"disableUseStrict": false,
"minifyWXML": true,
"showES6CompileOption": false,
"useCompilerPlugins": false
},
"compileType": "miniprogram",
"libVersion": "2.3.0",
"appid": "wx3ff81ef68814b084",
"projectname": "ESPConfig",
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
@@ -1,7 +0,0 @@
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "ESPConfig",
"setting": {
"compileHotReLoad": true
}
}
@@ -1,7 +0,0 @@
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
File diff suppressed because it is too large Load Diff
@@ -1,6 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(blufi_demo)
@@ -1,84 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
# ESP-IDF Blufi Example
This demo shows how to use the *Blufi* to configurate the Wi-Fi connection to AP.
The BluFi for ESP32 is a Wi-Fi network configuration function via Bluetooth channel. It provides a secure protocol to pass Wi-Fi configuration and credentials to the ESP32.
## How to Use Example
Before project configuration and build, be sure to set the correct chip target using:
```bash
idf.py set-target <chip_name>
```
To test this demo, you need to prepare a mobile phone with blufi application installed. You can download the blufi application from [Android version](https://github.com/EspressifApp/EspBlufi) and [iOS version](https://itunes.apple.com/cn/app/espblufi/id1450614082?mt=8).
Blufi is completely open source, here is the download link:
* [Blufi source code](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/blufi)
* [BluFi protocol](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ble/blufi.html)
* [iOS source code](https://github.com/EspressifApp/EspBlufiForiOS)
* [Android source code](https://github.com/EspressifApp/EspBlufi)
* [Bluetooth Network User Guide CN](https://www.espressif.com/sites/default/files/documentation/esp32_bluetooth_networking_user_guide_cn.pdf)
### Hardware Required
* A development board with ESP32/ESP32-C3/ESP32-S3/ESP32-C2 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (0) cpu_start: Starting scheduler on APP CPU.
I (708) wifi:wifi driver task: 3ffbb118, prio:23, stack:6656, core=0
I (708) system_api: Base MAC address is not set
I (708) system_api: read default base MAC address from EFUSE
I (718) wifi:wifi firmware version: 44799ff
I (718) wifi:wifi certification version: v7.0
I (718) wifi:config NVS flash: enabled
I (718) wifi:config nano formatting: disabled
I (728) wifi:Init data frame dynamic rx buffer num: 32
I (728) wifi:Init management frame dynamic rx buffer num: 32
I (738) wifi:Init management short buffer num: 32
I (738) wifi:Init dynamic tx buffer num: 32
I (748) wifi:Init static rx buffer size: 1600
I (748) wifi:Init static rx buffer num: 10
I (748) wifi:Init dynamic rx buffer num: 32
I (758) wifi_init: rx ba win: 6
I (758) wifi_init: tcpip mbox: 32
I (768) wifi_init: udp mbox: 6
I (768) wifi_init: tcp mbox: 6
I (768) wifi_init: tcp tx win: 5744
I (778) wifi_init: tcp rx win: 5744
I (778) wifi_init: tcp mss: 1440
I (788) wifi_init: WiFi IRAM OP enabled
I (788) wifi_init: WiFi RX IRAM OP enabled
I (798) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (908) wifi:mode : sta (fc:f5:c4:3c:62:90)
I (908) wifi:enable tsf
I (908) BTDM_INIT: BT controller compile version [1342a48]
I (1198) BLUFI_EXAMPLE: BD ADDR: fc:f5:c4:3c:62:92
I (1198) BLUFI_EXAMPLE: BLUFI VERSION 0102
I (1198) BLUFI_EXAMPLE: BLUFI init finish
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
@@ -1,4 +0,0 @@
idf_component_register(SRCS "blufi_example_main.c"
"blufi_security.c"
"blufi_init.c"
INCLUDE_DIRS ".")
@@ -1,10 +0,0 @@
menu "Example Configuration"
config EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY
int "WiFi connection maximum retry"
range 0 255
default 2
help
WiFi connection maximum retry, from 0 to 255.
endmenu
@@ -1,26 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#define BLUFI_EXAMPLE_TAG "BLUFI_EXAMPLE"
#define BLUFI_INFO(fmt, ...) ESP_LOGI(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__)
#define BLUFI_ERROR(fmt, ...) ESP_LOGE(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__)
void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free);
int blufi_aes_encrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len);
int blufi_security_init(void);
void blufi_security_deinit(void);
int esp_blufi_gap_register_callback(void);
esp_err_t esp_blufi_host_init(void);
esp_err_t esp_blufi_host_and_cb_init(esp_blufi_callbacks_t *callbacks);
esp_err_t esp_blufi_host_deinit(void);
esp_err_t esp_blufi_controller_init(void);
esp_err_t esp_blufi_controller_deinit(void);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,18 +0,0 @@
# Override some defaults so BT stack is enabled
# in this example
#
# Partition Table
# (It's possible to fit Blufi in 1MB app partition size with some other optimizations, but
# default config is close to 1MB.)
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
#
# BT config
#
CONFIG_BT_ENABLED=y
CONFIG_BT_GATTC_ENABLE=n
CONFIG_BT_BLE_SMP_ENABLE=n
CONFIG_BT_BLE_BLUFI_ENABLE=y
CONFIG_MBEDTLS_HARDWARE_MPI=n
CONFIG_MBEDTLS_DHM_C=y
@@ -1,7 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32"
CONFIG_BT_ENABLED=y
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
@@ -1,18 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_BLUFI_ENABLE=y
# CONFIG_BT_GATTC_ENABLE is not set
# CONFIG_BT_BLE_SMP_ENABLE is not set
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
CONFIG_MBEDTLS_DHM_C=y
# The config items for NIMBLE HOST
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_ROLE_CENTRAL=n
CONFIG_BT_NIMBLE_ROLE_OBSERVER=n
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n
CONFIG_BT_NIMBLE_SECURITY_ENABLE=n
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n
@@ -1,7 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32c3"
CONFIG_BT_ENABLED=y
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
@@ -1,18 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_BLUFI_ENABLE=y
# CONFIG_BT_GATTC_ENABLE is not set
# CONFIG_BT_BLE_SMP_ENABLE is not set
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
CONFIG_MBEDTLS_DHM_C=y
# The config items for NIMBLE HOST
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_ROLE_CENTRAL=n
CONFIG_BT_NIMBLE_ROLE_OBSERVER=n
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n
CONFIG_BT_NIMBLE_SECURITY_ENABLE=n
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n
@@ -1,7 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32s3"
CONFIG_BT_ENABLED=y
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
+38 -27
View File
@@ -4,22 +4,22 @@
"type": "split",
"children": [
{
"id": "dbcfd28f34b2a13b",
"id": "8ff7430257e8e5f4",
"type": "tabs",
"children": [
{
"id": "ba89e06e4ba5dcbd",
"id": "c787cb3c2720eaca",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md",
"file": "10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/42步进电机.md",
"mode": "source",
"source": false,
"backlinks": false
},
"icon": "lucide-file",
"title": "SG90舵机"
"title": "42步进电机"
}
}
]
@@ -69,7 +69,7 @@
}
],
"direction": "horizontal",
"width": 300
"width": 240.5
},
"right": {
"id": "5efe8913089ec8d6",
@@ -85,13 +85,13 @@
"state": {
"type": "outline",
"state": {
"file": "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md",
"file": "10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/42步进电机.md",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "SG90舵机 的大纲"
"title": "42步进电机 的大纲"
}
}
]
@@ -107,23 +107,39 @@
"templates:插入模板": false
}
},
"active": "ba89e06e4ba5dcbd",
"active": "70853e127a5d7008",
"lastOpenFiles": [
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md",
"04.外设学习/4.1-基础外设/4.1.6-LED_PWM/LED_PWM控制.md",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152414.png",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152307.png",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527165130.png",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527163637.png",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527163522.png",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527162100.png",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527161829.png",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块/rc522模块.md",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/42步进电机.md",
"目录.md",
"04.外设学习/4.1-基础外设/4.1.1-GPIO/GPIO入门.md",
"attachments/Templates.md",
"attachments/20250202192226.png",
"04.外设学习/4.3-其他外设/4.3.3-RMT/RMT.md",
"04.外设学习/4.3-其他外设/4.3.2-TWAI/TWAI.md",
"04.外设学习/4.3-其他外设/4.3.3-RMT",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块/attachments/Pasted image 20250624174842.png",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块/attachments/Pasted image 20250624174733.png",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块/attachments/Pasted image 20250624165127.png",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块/attachments",
"04.外设学习/4.1-基础外设/4.1.9-I2S/I2S入门.md",
"10.项目实战/10.1-模块驱动案例/10.1.4-rc522模块",
"04.外设学习/4.1-基础外设/4.1.7-I2C/I2C通信.md",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md",
"04.外设学习/4.3-其他外设/4.3.1-MCPWM/MCPWM.md",
"04.外设学习/4.3-其他外设/4.3.2-TWAI",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604165352.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604164929.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604164852.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604162407.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604162227.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments/Pasted image 20250604162038.png",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机/attachments",
"10.项目实战/10.1-模块驱动案例/10.1.3-42步进电机",
"04.外设学习/4.1-基础外设/4.1.6-LED_PWM/LED_PWM控制.md",
"10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments",
"04.外设学习/4.1-基础外设/4.1.1-GPIO/GPIO入门.md",
"04.外设学习/4.1-基础外设/4.1.4-ADC/ADC模数转换.md",
"01.认识ESP32/1.1-ESP32介绍/ESP32介绍.md",
"00.常见问题及解决方案/常见问题及解决方案.md",
@@ -131,12 +147,7 @@
"10.项目实战/10.1-模块驱动案例/未命名.md",
"10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机",
"04.外设学习/4.4-外设使用案例/未命名.md",
"04.外设学习/4.4-外设使用案例/未命名",
"10.项目实战/10.1-模块驱动案例",
"00.常见问题及解决方案/attachments/20250210094506.png",
"attachments/20250202192226.png",
"01.认识ESP32/1.2-ESP32开发环境搭建/1.环境搭建-Windows.md",
"03.FreeRTOS基础/3.4-FreeRTOS软件定时器/FreeRTOS软件定时器.md",
"00.常见问题及解决方案/attachments/20250506154522.png"
"03.FreeRTOS基础/3.4-FreeRTOS软件定时器/FreeRTOS软件定时器.md"
]
}
@@ -29,10 +29,8 @@ Inter-IC Sount Bus(I2S)是飞利浦半导体公司(现为恩智浦半导体公
**SCK: (continuous serial clock) 串行时钟**:标准名称为“连续串列主频”
**WS: (word select) 字段(声道)选择:** 也称为“帧同步线”
**SD: (serial data) 串行数据 :** 也可称为SDATA,SDIN,SDOUT,DACDAT,ADCDAT等
@@ -0,0 +1,99 @@
# 双线汽车接口 (TWAI) -(CAN)
> [!TIP] 🚀 ESP32 外设之双线汽车接口 (TWAI) |
> - 💡 **碎碎念**😎:本节将介绍 ESP32 的双线汽车接口 (TWAI) ,他是是一种适用于汽车和工业应用的实时串行通信协议。
> - 📺 **视频教程**:🚧 *开发中*
> - 💾 **示例代码**:🚧 *开发中*
双线汽车接口 (TWAI) 是一种适用于汽车和工业应用的实时串行通信协议。它兼容 ISO11898-1 经典帧,因此可以支持标准帧格式(11 位 ID)和扩展帧格式(29 位 ID)。ESP32 包含 1 个 TWAI 控制器,经配置可以在 TWAI 总线上使用外部收发器通信。
注意:TWAI 控制器不兼容 ISO11898-1 FD 格式帧,并会将这些帧解析为错误。
## 一、前言简介
- 简介:TWAI(Two-Wire Automotive Interface)是 ESP32 提供的 CAN 协议兼容实现。
- 协议兼容性:支持 ISO11898-1 标准帧和扩展帧格式,不支持 CAN-FD。
- 应用场景:
- 车载设备通信
- 工业自动化系统
- 多主多从嵌入式网络
---
## 二、协议基础
- TWAI = Classic CAN(兼容)
- 帧格式:
- 标准帧(11 位 ID)
- 扩展帧(29 位 ID)
- 数据帧、远程帧、错误帧
- 仲裁机制与优先级
- 位定时与波特率选择(如 500kbps)
---
## 三、硬件准备
- ESP32 模块(推荐 WROOM/WROVER 系列)
- CAN 收发器(如 SN65HVD230、TJA1050)
- 接线说明:
- ESP32 TX ➝ 收发器 TXD
- ESP32 RX ➝ 收发器 RXD
- CANH、CANL ➝ 总线
- 加 120Ω 终端电阻于总线两端
- 电源要求与隔离建议(如长距离通信建议使用隔离型收发器)
---
## 四、软件环境配置(ESP-IDF)
- 驱动初始化步骤:
- `twai_driver_install()`
- `twai_start()`
- 主要结构体:
- `twai_message_t`:数据帧定义
- `twai_general_config_t`、`twai_timing_config_t`、`twai_filter_config_t`
- 示例配置波特率、引脚、模式等参数
- 使用 FreeRTOS 任务接收数据(推荐)
---
## 五、发送与接收示例
- ✅ 发送帧示例(标准帧、扩展帧)
- ✅ 接收帧示例(阻塞与非阻塞)
- 🔁 循环发送测试数据
- 🛑 超时处理和帧校验
- 🚦 使用中断或轮询方式收发
---
## 六、调试与验证
- 使用逻辑分析仪/示波器查看 CANH/CANL 波形
- 多设备组网互通验证(例如连接另一个 STM32/开发板)
- 常见问题排查:
- 没有数据 ➝ 检查终端电阻、电压、接线
- 接收错误 ➝ 检查帧格式、波特率一致性
- 控制器状态 ➝ 使用 `twai_get_status_info()` 查看错误码
---
## 七、高级应用(可选)
- 设置 ID 过滤器(精确匹配 / 范围匹配)
- 发送优先级控制(低 ID = 高优先级)
- 状态监测:总线关闭、错误计数
- 灵活切换正常模式 / 回环模式 / 监听模式
---
## 八、总结与资料
- 官方文档:
- [ESP-IDF TWAI 文档](https://docs.espressif.com/projects/esp-idf/zh/latest/esp32/api-reference/peripherals/twai.html)
- 推荐资料:
- CAN 协议详解(推荐阅读 Bosch CAN spec)
- 收发器芯片选型参考
- 视频教程:🚧 *开发中*
- 示例代码:🚧 *开发中*
@@ -0,0 +1,4 @@
# 红外遥控 (RMT)
红外遥控 (RMT) 外设是一个红外发射和接收控制器。其数据格式灵活,可进一步扩展为多功能的通用收发器,发送或接收多种类型的信号。就网络分层而言,RMT 硬件包含物理层和数据链路层。物理层定义通信介质和比特信号的表示方式,数据链路层定义 RMT 帧的格式。
@@ -0,0 +1,108 @@
# ESP32驱动42步进电机
> [!TIP] 🚀 ESP32驱动42步进电机 | XXXXX
> - 💡 **碎碎念**😎:本节将介绍XXXXXXXXXXXXXXXXXXX
> - 📺 **视频教程**:🚧 *开发中*
> - 💾 **示例代码**:🚧 *开发中*
>
## 一、介绍
### 1.1 什么是42步进电机?
42步进电机是一种常见的小型两相步进电机,因其电机外壳边长为 42mm 而得名(即 NEMA 17 尺寸标准)。该类电机广泛应用于 3D打印机、激光雕刻机、CNC加工设备、机器人 等对位置控制要求较高的场景。
常见参数如下:
- 步距角:1.8°(每转200步)或 0.9°(每转400步)
- 工作电压:一般为 12V 或 24V
- 峰值电流:0.8A ~ 2A
### 1.2 步进电机工作原理
步进电机是一种将电脉冲信号转换为角位移的电机。当控制器发出一个脉冲信号,电机就按照设定角度旋转一步。通过调节脉冲频率,可以控制电机的转速;通过控制脉冲数量,可以精准控制角位移。
具体的工作原理在此不再赘述,大家可自行上网查阅。由于其不需要编码器即可进行位置控制,特别适合需要开环控制的系统。
下面简单对比步进电机与直流电机 / 伺服电机的区别:
| 特性 | 步进电机 | 直流电机 | 伺服电机 |
| ---- | --------------- | --------- | ---------- |
| 控制方式 | 开环(可闭环) | 电压/电流控制 | 闭环(带编码器) |
| 精度 | 高(0.9°\~1.8°/步) | 低 | 非常高(编码器支持) |
| 启停性能 | 好 | 中 | 非常好 |
| 振动噪音 | 较大(尤其低速) | 小 | 极小 |
| 价格 | 便宜 | 更便宜 | 昂贵 |
| 适合应用 | 中低速定位控制 | 普通旋转/风扇/泵 | 高速高精定位控制 |
值得注意的是,我们需要了解一下细分技术:
传统步进电机的步距角通常为 1.8°(每圈 200 步),在一些对平稳性和精度要求更高的场合,1.8° 的步进角可能仍然过大,运行过程中会出现抖动、不平滑等问题。为此,引入了 细分驱动(Microstepping) 技术。
细分驱动器不是简单地控制电机绕组全电流通断,而是通过 PWM 控制 或 电流恒流分级控制,将每个完整步细分为若干个微小步。比如:
- 半步细分:每步 0.9°,一圈 400 步;
- 1/8 细分:每步 0.225°,一圈 1600 步;
- 1/16 细分:每步 0.1125°,一圈 3200 步;
细分的优势在于提高分辨率和控制精度,运行更平滑、减少共振,降低噪音和震动和改善电机低速运行性能。虽然细分技术能提高控制平滑度,但并不能无限提高“实际定位精度”,因为电机本身的机械和磁滞误差仍然存在。高细分主要用于改善运动特性,而不是绝对定位精度。并且市面上常见的步进电机驱动器基本都支持细分。
### 1.3 常用驱动器
步进电机无法直接由电源驱动,必须通过驱动器精确控制线圈的电流方向与大小。以下是几种常用驱动器及其特点:
#### 1. A4988 驱动芯片
A4988 是一种体积小、成本低的双极步进电机驱动模块,广泛应用于 3D 打印机、桌面级 CNC 等入门级设备。它支持全步、半步、1/4、1/8 和 1/16 微步细分,并带有可调电流限制功能。模块自带过热保护和欠压保护,接口简单、体积小巧,适合面包板快速开发。但需要注意的是,该模块在高电流下易发热,接线错误或通电顺序错误容易烧毁,因此在使用时要特别注意接线安全与散热。
![](attachments/Pasted%20image%2020250604162038.png)
#### 2. tb6600 驱动器
TB6600 驱动器是面向工业级场景设计的中功率步进电机驱动器,支持工作电压 9V 到 42V,最大输出电流可达 4.5A,常用于控制较大扭矩的 42、57、86 步进电机。它支持的细分模式从全步到 32步,用户可通过拨码开关手动配置。TB6600 驱动器通常带有铝合金壳体和散热片,接口清晰,安装方便,适用于 CNC 雕刻机、激光切割、机械臂等中大型场合。相比 A4988,TB6600 功率更大、稳定性更好,但体积较大,不适合空间受限的设计,且价格略高。
![](attachments/Pasted%20image%2020250604162227.png)
#### 3.DRV8825驱动芯片
DRV8825 是德州仪器推出的一款高性能步进电机驱动器,与 A4988 引脚兼容但性能更强。其支持最多 1/32 步细分。相比 A4988,它支持更高的工作电压,能够在更高速度下提供更大的扭矩,同时运行更安静,抖动更小。它适用于对噪音和稳定性有更高要求的项目,如中高端 3D 打印机或机器人项目。不过也需注意散热问题,可以在模块上添加散热片。
![](attachments/Pasted%20image%2020250604162407.png)
## 二、使用
下面简单介绍一下使用ESP32配合DRV8825驱动芯片驱动42步进电机:
首先介绍DRV8825驱动模块,我们买到的DRV8825步进驱动模块一般如下图:
![](attachments/Pasted%20image%2020250604162407.png)
DRV8825 是德州仪器设计的集成电机驱动芯片。 芯片内部集成了2个H桥电路和1/32微步进分度器, 可以驱动一个双极型电机或两个直流有刷电机。主要有如下特点:
1. 适合驱动8.2V~45V2.5A以下的步进电机:
2. 只有简单的步进和方向控制接口;
3. 六个不同的步进模式:全、半、1/4、1/8、1/16、1/32;
4. 可调电位器可以调节最大电流输出,从而获得更高的步进率;
5. 自动电流衰减模式检测/选择;
6. 过热关闭电路、欠压锁定、交叉电流保护;
它的引脚定义是这样的:
![](attachments/Pasted%20image%2020250604164929.png)
这是芯片手册中的简化控制示意图:
![](attachments/Pasted%20image%2020250604164852.png)
## 三、示例
# 参考链接
@@ -0,0 +1,140 @@
# ESP32驱动RC522模块与 RFID / NFC 卡通信
> [!TIP] 🚀 ESP32驱动RC522射频IC卡识别模块 | 轻松实现 RFID / NFC 卡通信
>
> * 💡 **碎碎念**😎:本节将介绍如何使用 ESP32 驱动 RC522 模块,快速实现 RFID/NFC 卡片的检测和读取。
> * 📺 **视频教程**:🚧 *开发中*
> * 💾 **示例代码**:🚧 *开发中*
## 一、介绍
![](attachments/Pasted%20image%2020250624165127.png)
RC522 是一款常见的 RFID 读卡器模块,工作在 **13.56MHz** 频段,支持对标准 NFC / IC 卡片进行检测和通信。结合 ESP32 可快速构建:
* 门禁控制器
* NFC 标签检测器
* RFID 学生证管理器
* 简单的考勤、登录、支付等应用场景
RC522 通常通过 **SPI 接口** 与 ESP32 通信,库和示例代码完善,适合入门和快速验证。
## 二、使用
### 1️⃣ 硬件连接
| ESP32引脚 | RC522引脚 | 功能 |
| ------- | ------- | -------- |
| 3V3 | 3.3V | 供电 |
| GND | GND | 地线 |
| GPIO18 | SCK | SPI时钟 |
| GPIO19 | MISO | SPI MISO |
| GPIO23 | MOSI | SPI MOSI |
| GPIO5 | RST | 重置 |
| GPIO4 | SDA | SPI片选 |
### 2️⃣ 配套库
* ESP-IDF: https://components.espressif.com/components/abobija/rc522/versions/3.3.2/versions?language=en
### 3️⃣ 通信流程
1. ESP32 通过 SPI 与 RC522 通信。
2. 检测是否有 RFID/NFC 标签进入。
3. 获取 UID。
4. 可选:读取或写入 IC 卡数据。
## 三、示例
接线:
``` c
#define RC522_SPI_BUS_GPIO_MISO (25)
#define RC522_SPI_BUS_GPIO_MOSI (23)
#define RC522_SPI_BUS_GPIO_SCLK (19)
#define RC522_SPI_SCANNER_GPIO_SDA (22)
```
![](attachments/Pasted%20image%2020250624174733.png)
代码:
```cpp
#include <esp_log.h>
#include "rc522.h"
#include "driver/rc522_spi.h"
#include "rc522_picc.h"
static const char *TAG = "rc522-basic-example";
#define RC522_SPI_BUS_GPIO_MISO (25)
#define RC522_SPI_BUS_GPIO_MOSI (23)
#define RC522_SPI_BUS_GPIO_SCLK (19)
#define RC522_SPI_SCANNER_GPIO_SDA (22)
#define RC522_SCANNER_GPIO_RST (-1)
static rc522_spi_config_t driver_config = {
.host_id = SPI2_HOST,
.bus_config = &(spi_bus_config_t){
.miso_io_num = RC522_SPI_BUS_GPIO_MISO,
.mosi_io_num = RC522_SPI_BUS_GPIO_MOSI,
.sclk_io_num = RC522_SPI_BUS_GPIO_SCLK,
},
.dev_config = {
.spics_io_num = RC522_SPI_SCANNER_GPIO_SDA,
},
.rst_io_num = RC522_SCANNER_GPIO_RST,
};
static rc522_driver_handle_t driver;
static rc522_handle_t scanner;
static void on_picc_state_changed(void *arg, esp_event_base_t base, int32_t event_id, void *data)
{
rc522_picc_state_changed_event_t *event = (rc522_picc_state_changed_event_t *)data;
rc522_picc_t *picc = event->picc;
if (picc->state == RC522_PICC_STATE_ACTIVE) {
rc522_picc_print(picc);
}
else if (picc->state == RC522_PICC_STATE_IDLE && event->old_state >= RC522_PICC_STATE_ACTIVE) {
ESP_LOGI(TAG, "Card has been removed");
}
}
void app_main()
{
rc522_spi_create(&driver_config, &driver);
rc522_driver_install(driver);
rc522_config_t scanner_config = {
.driver = driver,
};
rc522_create(&scanner_config, &scanner);
rc522_register_events(scanner, RC522_EVENT_PICC_STATE_CHANGED, on_picc_state_changed, NULL);
rc522_start(scanner);
}
```
效果:
![](attachments/Pasted%20image%2020250624174842.png)
### 其他
在使用esp-idf-rc522这个库时,发现通信引脚不能随意配置
对于ESP32来说,能够正常使用的配置如下:
```
#define RC522_SPI_BUS_GPIO_MISO (25)
#define RC522_SPI_BUS_GPIO_MOSI (23)
#define RC522_SPI_BUS_GPIO_SCLK (19)
#define RC522_SPI_SCANNER_GPIO_SDA (22)
#define RC522_SCANNER_GPIO_RST (-1)
```
具体见: https://github.com/abobija/esp-idf-rc522/issues/71