commit
cb07ad4414
@ -13,6 +13,8 @@ Tutorial (in german language): https://www.heise.de/select/make/2019/1/155109923
|
||||
<img src="img/TTGO-curves.jpg">
|
||||
<img src="img/Paxcounter-LEDmatrix.jpg">
|
||||
<img src="img/Paxcounter-Clock.png">
|
||||
<img src="img/Paxcounter-ttgo-twristband.jpg">
|
||||
|
||||
|
||||
# Use case
|
||||
|
||||
@ -47,6 +49,7 @@ LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-L
|
||||
- WeMos: LoLin32, LoLin32 Lite, WeMos D32, [Wemos32 Oled](https://www.instructables.com/id/ESP32-With-Integrated-OLED-WEMOSLolin-Getting-Star/)
|
||||
- Crowdsupply: [TinyPICO](https://www.crowdsupply.com/unexpected-maker/tinypico)
|
||||
- TTGO: [T-Display](https://www.aliexpress.com/item/33048962331.html)
|
||||
- TTGO: [T-Wristband](https://www.aliexpress.com/item/4000527495064.html)
|
||||
- Generic ESP32
|
||||
|
||||
Depending on board hardware following features are supported:
|
||||
@ -604,6 +607,7 @@ Thanks to
|
||||
- [Oliver Brandmüller](https://github.com/spmrider) for idea and initial setup of this project
|
||||
- [Charles Hallard](https://github.com/hallard) for major code contributions to this project
|
||||
- [robbi5](https://github.com/robbi5) for the payload converter
|
||||
- [Caspar Armster](https://www.dasdigidings.de/) for the The Things Stack V3 payload converter
|
||||
- [terrillmoore](https://github.com/mcci-catena) for maintaining the LMIC for arduino LoRaWAN stack
|
||||
- [sbamueller](https://github.com/sbamueller) for writing the tutorial in Make Magazine
|
||||
- [Stefan](https://github.com/nerdyscout) for paxcounter opensensebox integration
|
||||
|
BIN
img/Paxcounter-ttgo-twristband.jpg
Normal file
BIN
img/Paxcounter-ttgo-twristband.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 229 KiB |
@ -2,8 +2,8 @@
|
||||
#define _POWER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <driver/adc.h>
|
||||
#include <esp_adc_cal.h>
|
||||
//#include <esp32-hal-adc.h>
|
||||
|
||||
#include "i2c.h"
|
||||
#include "reset.h"
|
||||
@ -34,6 +34,20 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EXT_POWER_SW
|
||||
#ifndef EXT_POWER_ON
|
||||
#define EXT_POWER_ON 1
|
||||
#endif
|
||||
#ifndef EXT_POWER_OFF
|
||||
#define EXT_POWER_OFF (!EXT_POWER_ON)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BAT_MEASURE_ADC_UNIT // ADC2 wifi bug workaround
|
||||
extern RTC_NOINIT_ATTR uint64_t RTC_reg_b;
|
||||
#include "soc/sens_reg.h" // needed for adc pin reset
|
||||
#endif
|
||||
|
||||
typedef uint8_t (*mapFn_t)(uint16_t, uint16_t, uint16_t);
|
||||
|
||||
uint16_t read_voltage(void);
|
||||
|
@ -13,6 +13,7 @@
|
||||
;halfile = ecopower.h
|
||||
;halfile = heltec.h
|
||||
;halfile = heltecv2.h
|
||||
;halfile = heltecv21.h
|
||||
;halfile = ttgov1.h
|
||||
;halfile = ttgov2.h
|
||||
;halfile = ttgov21old.h
|
||||
@ -21,6 +22,7 @@
|
||||
;halfile = ttgobeam.h
|
||||
halfile = ttgobeam10.h
|
||||
;halfile = ttgotdisplay.h
|
||||
;halfile = ttgotwristband.h
|
||||
;halfile = fipy.h
|
||||
;halfile = lopy.h
|
||||
;halfile = lopy4.h
|
||||
|
330
src/TTNv3/packed_decodeUplink.js
Normal file
330
src/TTNv3/packed_decodeUplink.js
Normal file
@ -0,0 +1,330 @@
|
||||
// Decoder for device payload encoder "PACKED"
|
||||
// copy&paste to TTN Console V3 -> Applications -> Payload formatters -> Uplink -> Javascript
|
||||
// modified for The Things Stack V3 by Caspar Armster, dasdigidings e.V.
|
||||
|
||||
function decodeUplink(input) {
|
||||
var data = {};
|
||||
|
||||
if (input.fPort === 1) {
|
||||
// only wifi counter data, no gps
|
||||
if (input.bytes.length === 2) {
|
||||
data = decode(input.bytes, [uint16], ['wifi']);
|
||||
}
|
||||
// wifi + ble counter data, no gps
|
||||
if (input.bytes.length === 4) {
|
||||
data = decode(input.bytes, [uint16, uint16], ['wifi', 'ble']);
|
||||
}
|
||||
// combined wifi + ble + SDS011
|
||||
if (input.bytes.length === 8) {
|
||||
data = decode(input.bytes, [uint16, uint16, uint16, uint16], ['wifi', 'ble', 'PM10', 'PM25']);
|
||||
}
|
||||
// combined wifi counter and gps data, used by https://opensensemap.org
|
||||
if (input.bytes.length === 10) {
|
||||
data = decode(input.bytes, [latLng, latLng, uint16], ['latitude', 'longitude', 'wifi']);
|
||||
}
|
||||
// combined wifi + ble counter and gps data, used by https://opensensemap.org
|
||||
if (input.bytes.length === 12) {
|
||||
data = decode(input.bytes, [latLng, latLng, uint16, uint16], ['latitude', 'longitude', 'wifi', 'ble']);
|
||||
}
|
||||
// combined wifi counter and gps data
|
||||
if (input.bytes.length === 15) {
|
||||
data = decode(input.bytes, [uint16, latLng, latLng, uint8, hdop, altitude], ['wifi', 'latitude', 'longitude', 'sats', 'hdop', 'altitude']);
|
||||
}
|
||||
// combined wifi + ble counter and gps data
|
||||
if (input.bytes.length === 17) {
|
||||
data = decode(input.bytes, [uint16, uint16, latLng, latLng, uint8, hdop, altitude], ['wifi', 'ble', 'latitude', 'longitude', 'sats', 'hdop', 'altitude']);
|
||||
}
|
||||
|
||||
data.pax = 0;
|
||||
if ('wifi' in data) {
|
||||
data.pax += data.wifi;
|
||||
}
|
||||
if ('ble' in data) {
|
||||
data.pax += data.ble;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 2) {
|
||||
// device status data
|
||||
if (input.bytes.length === 17) {
|
||||
data = decode(input.bytes, [uint16, uptime, uint8, uint32, uint8, uint8], ['voltage', 'uptime', 'cputemp', 'memory', 'reset0', 'reset1']);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 3) {
|
||||
// device config data
|
||||
data = decode(input.bytes, [uint8, uint8, int16, uint8, uint8, uint8, uint8, bitmap1, bitmap2, version], ['loradr', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'payloadmask', 'version']);
|
||||
}
|
||||
|
||||
if (input.fPort === 4) {
|
||||
// gps data
|
||||
if (input.bytes.length === 8) {
|
||||
data = decode(input.bytes, [latLng, latLng], ['latitude', 'longitude']);
|
||||
} else {
|
||||
data = decode(input.bytes, [latLng, latLng, uint8, hdop, altitude], ['latitude', 'longitude', 'sats', 'hdop', 'altitude']);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 5) {
|
||||
// button pressed
|
||||
data = decode(input.bytes, [uint8], ['button']);
|
||||
}
|
||||
|
||||
if (input.fPort === 6) {
|
||||
// beacon proximity alarm
|
||||
data = decode(input.bytes, [int8, uint8], ['rssi', 'beacon']);
|
||||
}
|
||||
|
||||
if (input.fPort === 7) {
|
||||
// BME680 sensor data
|
||||
data = decode(input.bytes, [float, pressure, ufloat, ufloat], ['temperature', 'pressure', 'humidity', 'air']);
|
||||
}
|
||||
|
||||
if (input.fPort === 8) {
|
||||
// battery voltage
|
||||
data = decode(input.bytes, [uint16], ['voltage']);
|
||||
}
|
||||
|
||||
if (input.fPort === 9) {
|
||||
// timesync request
|
||||
if (input.bytes.length === 1) {
|
||||
data.timesync_seqno = input.bytes[0];
|
||||
}
|
||||
// epoch time answer
|
||||
if (input.bytes.length === 5) {
|
||||
data = decode(input.bytes, [uint32, uint8], ['time', 'timestatus']);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 10) {
|
||||
// ENS count
|
||||
data = decode(input.bytes, [uint16], ['ens']);
|
||||
}
|
||||
|
||||
data.bytes = input.bytes; // comment out if you do not want to include the original payload
|
||||
data.port = input.fPort; // comment out if you do not want to inlude the port
|
||||
|
||||
return {
|
||||
data: data,
|
||||
warnings: [],
|
||||
errors: []
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ----- contents of /src/decoder.js --------------------------------------------
|
||||
// https://github.com/thesolarnomad/lora-serialization/blob/master/src/decoder.js
|
||||
|
||||
var bytesToInt = function (bytes) {
|
||||
var i = 0;
|
||||
for (var x = 0; x < bytes.length; x++) {
|
||||
i |= (bytes[x] << (x * 8));
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
var version = function (bytes) {
|
||||
if (bytes.length !== version.BYTES) {
|
||||
throw new Error('version must have exactly 10 bytes');
|
||||
}
|
||||
return String.fromCharCode.apply(null, bytes).split('\u0000')[0];
|
||||
};
|
||||
version.BYTES = 10;
|
||||
|
||||
var uint8 = function (bytes) {
|
||||
if (bytes.length !== uint8.BYTES) {
|
||||
throw new Error('uint8 must have exactly 1 byte');
|
||||
}
|
||||
return bytesToInt(bytes);
|
||||
};
|
||||
uint8.BYTES = 1;
|
||||
|
||||
var uint16 = function (bytes) {
|
||||
if (bytes.length !== uint16.BYTES) {
|
||||
throw new Error('uint16 must have exactly 2 bytes');
|
||||
}
|
||||
return bytesToInt(bytes);
|
||||
};
|
||||
uint16.BYTES = 2;
|
||||
|
||||
var uint32 = function (bytes) {
|
||||
if (bytes.length !== uint32.BYTES) {
|
||||
throw new Error('uint32 must have exactly 4 bytes');
|
||||
}
|
||||
return bytesToInt(bytes);
|
||||
};
|
||||
uint32.BYTES = 4;
|
||||
|
||||
var uint64 = function (bytes) {
|
||||
if (bytes.length !== uint64.BYTES) {
|
||||
throw new Error('uint64 must have exactly 8 bytes');
|
||||
}
|
||||
return bytesToInt(bytes);
|
||||
};
|
||||
uint64.BYTES = 8;
|
||||
|
||||
var int8 = function (bytes) {
|
||||
if (bytes.length !== int8.BYTES) {
|
||||
throw new Error('int8 must have exactly 1 byte');
|
||||
}
|
||||
var value = +(bytesToInt(bytes));
|
||||
if (value > 127) {
|
||||
value -= 256;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
int8.BYTES = 1;
|
||||
|
||||
var int16 = function (bytes) {
|
||||
if (bytes.length !== int16.BYTES) {
|
||||
throw new Error('int16 must have exactly 2 bytes');
|
||||
}
|
||||
var value = +(bytesToInt(bytes));
|
||||
if (value > 32767) {
|
||||
value -= 65536;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
int16.BYTES = 2;
|
||||
|
||||
var int32 = function (bytes) {
|
||||
if (bytes.length !== int32.BYTES) {
|
||||
throw new Error('int32 must have exactly 4 bytes');
|
||||
}
|
||||
var value = +(bytesToInt(bytes));
|
||||
if (value > 2147483647) {
|
||||
value -= 4294967296;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
int32.BYTES = 4;
|
||||
|
||||
var latLng = function (bytes) {
|
||||
return +(int32(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
latLng.BYTES = int32.BYTES;
|
||||
|
||||
var uptime = function (bytes) {
|
||||
return uint64(bytes);
|
||||
};
|
||||
uptime.BYTES = uint64.BYTES;
|
||||
|
||||
var hdop = function (bytes) {
|
||||
return +(uint16(bytes) / 100).toFixed(2);
|
||||
};
|
||||
hdop.BYTES = uint16.BYTES;
|
||||
|
||||
var altitude = function (bytes) {
|
||||
// Option to increase altitude resolution (also on encoder side)
|
||||
// return +(int16(bytes) / 4 - 1000).toFixed(1);
|
||||
return +(int16(bytes));
|
||||
};
|
||||
altitude.BYTES = int16.BYTES;
|
||||
|
||||
|
||||
var float = function (bytes) {
|
||||
if (bytes.length !== float.BYTES) {
|
||||
throw new Error('Float must have exactly 2 bytes');
|
||||
}
|
||||
var isNegative = bytes[0] & 0x80;
|
||||
var b = ('00000000' + Number(bytes[0]).toString(2)).slice(-8)
|
||||
+ ('00000000' + Number(bytes[1]).toString(2)).slice(-8);
|
||||
if (isNegative) {
|
||||
var arr = b.split('').map(function (x) { return !Number(x); });
|
||||
for (var i = arr.length - 1; i > 0; i--) {
|
||||
arr[i] = !arr[i];
|
||||
if (arr[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
b = arr.map(Number).join('');
|
||||
}
|
||||
var t = parseInt(b, 2);
|
||||
if (isNegative) {
|
||||
t = -t;
|
||||
}
|
||||
return +(t / 100).toFixed(2);
|
||||
};
|
||||
float.BYTES = 2;
|
||||
|
||||
var ufloat = function (bytes) {
|
||||
return +(uint16(bytes) / 100).toFixed(2);
|
||||
};
|
||||
ufloat.BYTES = uint16.BYTES;
|
||||
|
||||
var pressure = function (bytes) {
|
||||
return +(uint16(bytes) / 10).toFixed(1);
|
||||
};
|
||||
pressure.BYTES = uint16.BYTES;
|
||||
|
||||
var bitmap1 = function (byte) {
|
||||
if (byte.length !== bitmap1.BYTES) {
|
||||
throw new Error('Bitmap must have exactly 1 byte');
|
||||
}
|
||||
var i = bytesToInt(byte);
|
||||
var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean);
|
||||
return ['adr', 'screensaver', 'screen', 'countermode', 'blescan', 'antenna', 'filter', 'alarm']
|
||||
.reduce(function (obj, pos, index) {
|
||||
obj[pos] = +bm[index];
|
||||
return obj;
|
||||
}, {});
|
||||
};
|
||||
bitmap1.BYTES = 1;
|
||||
|
||||
var bitmap2 = function (byte) {
|
||||
if (byte.length !== bitmap2.BYTES) {
|
||||
throw new Error('Bitmap must have exactly 1 byte');
|
||||
}
|
||||
var i = bytesToInt(byte);
|
||||
var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean);
|
||||
return ['battery', 'sensor3', 'sensor2', 'sensor1', 'gps', 'bme', 'alarm', 'counter']
|
||||
.reduce(function (obj, pos, index) {
|
||||
obj[pos] = +bm[index];
|
||||
return obj;
|
||||
}, {});
|
||||
};
|
||||
bitmap2.BYTES = 1;
|
||||
|
||||
var decode = function (bytes, mask, names) {
|
||||
|
||||
var maskLength = mask.reduce(function (prev, cur) {
|
||||
return prev + cur.BYTES;
|
||||
}, 0);
|
||||
if (bytes.length < maskLength) {
|
||||
throw new Error('Mask length is ' + maskLength + ' whereas input is ' + bytes.length);
|
||||
}
|
||||
|
||||
names = names || [];
|
||||
var offset = 0;
|
||||
return mask
|
||||
.map(function (decodeFn) {
|
||||
var current = bytes.slice(offset, offset += decodeFn.BYTES);
|
||||
return decodeFn(current);
|
||||
})
|
||||
.reduce(function (prev, cur, idx) {
|
||||
prev[names[idx] || idx] = cur;
|
||||
return prev;
|
||||
}, {});
|
||||
};
|
||||
|
||||
if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
||||
module.exports = {
|
||||
uint8: uint8,
|
||||
uint16: uint16,
|
||||
uint32: uint32,
|
||||
int8: int8,
|
||||
int16: int16,
|
||||
int32: int32,
|
||||
uptime: uptime,
|
||||
float: float,
|
||||
ufloat: ufloat,
|
||||
pressure: pressure,
|
||||
latLng: latLng,
|
||||
hdop: hdop,
|
||||
altitude: altitude,
|
||||
bitmap1: bitmap1,
|
||||
bitmap2: bitmap2,
|
||||
version: version,
|
||||
decode: decode
|
||||
};
|
||||
}
|
114
src/TTNv3/plain_decodeUplink.js
Normal file
114
src/TTNv3/plain_decodeUplink.js
Normal file
@ -0,0 +1,114 @@
|
||||
// Decoder for device payload encoder "PLAIN"
|
||||
// copy&paste to TTN Console V3 -> Applications -> Payload formatters -> Uplink -> Javascript
|
||||
// modified for The Things Stack V3 by Caspar Armster, dasdigidings e.V.
|
||||
|
||||
function decodeUplink(input) {
|
||||
var data = {};
|
||||
|
||||
if (input.fPort === 1) {
|
||||
var i = 0;
|
||||
|
||||
if (input.bytes.length >= 2) {
|
||||
data.wifi = (input.bytes[i++] << 8) | input.bytes[i++];
|
||||
}
|
||||
|
||||
if (input.bytes.length === 4 || input.bytes.length > 15) {
|
||||
data.ble = (input.bytes[i++] << 8) | input.bytes[i++];
|
||||
}
|
||||
|
||||
if (input.bytes.length > 4) {
|
||||
data.latitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.longitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.sats = input.bytes[i++];
|
||||
data.hdop = (input.bytes[i++] << 8) | (input.bytes[i++]);
|
||||
data.altitude = ((input.bytes[i++] << 8) | (input.bytes[i++]));
|
||||
}
|
||||
data.pax = 0;
|
||||
if ('wifi' in data) {
|
||||
data.pax += data.wifi;
|
||||
}
|
||||
if ('ble' in data) {
|
||||
data.pax += data.ble;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 2) {
|
||||
var i = 0;
|
||||
data.voltage = ((input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.uptime = ((input.bytes[i++] << 56) | (input.bytes[i++] << 48) | (input.bytes[i++] << 40) | (input.bytes[i++] << 32) | (input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.cputemp = input.bytes[i++];
|
||||
data.memory = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.reset0 = input.bytes[i++];
|
||||
data.reset1 = input.bytes[i++];
|
||||
}
|
||||
|
||||
if (input.fPort === 4) {
|
||||
var i = 0;
|
||||
data.latitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.longitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.sats = input.bytes[i++];
|
||||
data.hdop = (input.bytes[i++] << 8) | (input.bytes[i++]);
|
||||
data.altitude = ((input.bytes[i++] << 8) | (input.bytes[i++]));
|
||||
}
|
||||
|
||||
if (input.fPort === 5) {
|
||||
var i = 0;
|
||||
data.button = input.bytes[i++];
|
||||
}
|
||||
|
||||
if (input.fPort === 6) {
|
||||
var i = 0;
|
||||
data.rssi = input.bytes[i++];
|
||||
data.beacon = input.bytes[i++];
|
||||
}
|
||||
|
||||
if (input.fPort === 7) {
|
||||
var i = 0;
|
||||
data.temperature = ((input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.pressure = ((input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.humidity = ((input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.air = ((input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
}
|
||||
|
||||
if (input.fPort === 8) {
|
||||
var i = 0;
|
||||
if (input.bytes.length >= 2) {
|
||||
data.voltage = (input.bytes[i++] << 8) | input.bytes[i++];
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 9) {
|
||||
// timesync request
|
||||
if (input.bytes.length === 1) {
|
||||
data.timesync_seqno = input.bytes[0];
|
||||
}
|
||||
// epoch time answer
|
||||
if (input.bytes.length === 5) {
|
||||
var i = 0;
|
||||
data.time = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
|
||||
data.timestatus = input.bytes[i++];
|
||||
}
|
||||
}
|
||||
|
||||
if (input.fPort === 10) {
|
||||
var i = 0;
|
||||
if (input.bytes.length >= 2) {
|
||||
data.ens = (input.bytes[i++] << 8) | input.bytes[i++];
|
||||
}
|
||||
}
|
||||
|
||||
if (data.hdop) {
|
||||
data.hdop /= 100;
|
||||
data.latitude /= 1000000;
|
||||
data.longitude /= 1000000;
|
||||
}
|
||||
|
||||
data.bytes = input.bytes; // comment out if you do not want to include the original payload
|
||||
data.port = input.fPort; // comment out if you do not want to include the port
|
||||
|
||||
return {
|
||||
data: data,
|
||||
warnings: [],
|
||||
errors: []
|
||||
};
|
||||
}
|
@ -20,7 +20,6 @@
|
||||
|
||||
#define EXT_POWER_SW 15 // Switch VDD on pin JP10, needed for RTC DS3231
|
||||
#define EXT_POWER_ON 0
|
||||
#define EXT_POWER_OFF 1
|
||||
|
||||
#define HAS_LED (2) // on board green LED
|
||||
#define HAS_TWO_LED (12) // on board red LED
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for Heltec V1 LoRa-32 Board
|
||||
// see https://heltec-automation-docs.readthedocs.io/en/latest/esp32/wifi_lora_32/hardware_update_log.html#v1
|
||||
|
||||
//#define HAS_BME 1 // Enable BME sensors in general
|
||||
//#define HAS_BME680 GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for Heltec V2 LoRa-32 Board
|
||||
// see https://heltec-automation-docs.readthedocs.io/en/latest/esp32/wifi_lora_32/hardware_update_log.html#v2
|
||||
|
||||
//#define HAS_BME 1 // Enable BME sensors in general
|
||||
//#define HAS_BME680 GPIO_NUM_4, GPIO_NUM_15 // SDA, SCL
|
||||
@ -22,16 +23,13 @@
|
||||
#define HAS_LED LED_BUILTIN // white LED on board
|
||||
#define HAS_BUTTON KEY_BUILTIN // button "PROG" on board
|
||||
|
||||
// caveat: activating ADC2 conflicts with Wifi in current arduino-esp32
|
||||
// see https://github.com/espressif/arduino-esp32/issues/3222
|
||||
// thus we must waiver of battery monitoring
|
||||
//#define BAT_MEASURE_ADC ADC2_GPIO13_CHANNEL // battery probe GPIO pin
|
||||
//#define BAT_MEASURE_ADC_UNIT 2 // ADC 2
|
||||
//#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 220k/100k on board
|
||||
#define BAT_MEASURE_ADC ADC2_GPIO13_CHANNEL // battery probe GPIO pin
|
||||
#define BAT_MEASURE_ADC_UNIT 2 // ADC 2
|
||||
#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 220k/100k on board
|
||||
|
||||
#define EXT_POWER_SW Vext // switches battery power, Vext control 0 = on / 1 = off
|
||||
#define EXT_POWER_ON 0
|
||||
//#define EXT_POWER_OFF 1
|
||||
// switches battery power and Vext, switch logic 0 = on / 1 = off
|
||||
#define EXT_POWER_SW Vext
|
||||
#define EXT_POWER_ON 0
|
||||
|
||||
// Pins for I2C interface of OLED Display
|
||||
#define MY_DISPLAY_SDA SDA_OLED
|
||||
@ -43,7 +41,7 @@
|
||||
#define LORA_IRQ DIO0
|
||||
#define LORA_IO1 DIO1
|
||||
#define LORA_IO2 DIO2
|
||||
#define LORA_SCK GPIO_NUM_5
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_MISO MISO
|
||||
#define LORA_MOSI MOSI
|
||||
#define LORA_RST RST_LoRa
|
||||
|
49
src/hal/heltecv21.h
Normal file
49
src/hal/heltecv21.h
Normal file
@ -0,0 +1,49 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board heltec_wifi_lora_32_V2
|
||||
|
||||
#ifndef _HELTECV21_H
|
||||
#define _HELTECV21_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for Heltec V2.1 LoRa-32 Board
|
||||
// see https://heltec-automation-docs.readthedocs.io/en/latest/esp32/wifi_lora_32/hardware_update_log.html#v2-1
|
||||
|
||||
//#define HAS_BME 1 // Enable BME sensors in general
|
||||
//#define HAS_BME680 GPIO_NUM_4, GPIO_NUM_15 // SDA, SCL
|
||||
//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
|
||||
//#define HAS_BMP180
|
||||
//#define BMP180_ADDR 0x77
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
#define HAS_DISPLAY 1 // OLED-Display on board
|
||||
#define HAS_LED LED_BUILTIN // white LED on board
|
||||
#define HAS_BUTTON KEY_BUILTIN // button "PROG" on board
|
||||
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO37_CHANNEL // battery probe GPIO pin
|
||||
#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 220k/100k on board
|
||||
|
||||
// switches battery power and Vext, switch logic 0 = on / 1 = off
|
||||
#define EXT_POWER_SW Vext
|
||||
#define EXT_POWER_ON 0
|
||||
|
||||
// Pins for I2C interface of OLED Display
|
||||
#define MY_DISPLAY_SDA SDA_OLED
|
||||
#define MY_DISPLAY_SCL SCL_OLED
|
||||
#define MY_DISPLAY_RST RST_OLED
|
||||
|
||||
// Pins for LORA chip SPI interface come from board file, we need some
|
||||
// additional definitions for LMIC
|
||||
#define LORA_IRQ DIO0
|
||||
#define LORA_IO1 DIO1
|
||||
#define LORA_IO2 DIO2
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_MISO MISO
|
||||
#define LORA_MOSI MOSI
|
||||
#define LORA_RST RST_LoRa
|
||||
#define LORA_CS SS
|
||||
|
||||
#endif
|
@ -15,7 +15,6 @@
|
||||
|
||||
#define EXT_POWER_SW GPIO_NUM_25 // switches power for LoRa chip
|
||||
#define EXT_POWER_ON 0
|
||||
#define EXT_POWER_OFF 1
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL
|
||||
#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board
|
||||
#define HAS_BUTTON GPIO_NUM_36 // on board button (next to reset)
|
||||
|
58
src/hal/ttgotwristband.h
Normal file
58
src/hal/ttgotwristband.h
Normal file
@ -0,0 +1,58 @@
|
||||
// clang-format off
|
||||
// upload_speed 1500000
|
||||
// board pico32
|
||||
|
||||
#ifndef _TTGOTWRISTBAND_H
|
||||
#define _TTGOTWRISTBAND_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
#define HAS_DISPLAY 2 // TFT-LCD, support work in progess, not ready yet
|
||||
#define MY_DISPLAY_FLIP 1 // use if display is rotated
|
||||
|
||||
#define HAS_LED NOT_A_PIN // no on board LED (?)
|
||||
#define HAS_BUTTON (33) // on board button A
|
||||
|
||||
// power management settings
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BAT_VOLTAGE_DIVIDER 2.605f // voltage divider
|
||||
|
||||
// Display Settings
|
||||
#define MY_DISPLAY_WIDTH 80
|
||||
#define MY_DISPLAY_HEIGHT 160
|
||||
#define MY_DISPLAY_INVERT 1
|
||||
|
||||
// setting for TTGO T-display
|
||||
#define USER_SETUP_LOADED 1
|
||||
#define ST7735_DRIVER 1
|
||||
|
||||
#define CGRAM_OFFSET
|
||||
|
||||
#define TFT_MISO -1
|
||||
#define TFT_MOSI GPIO_NUM_19 // SPI
|
||||
#define TFT_SCLK GPIO_NUM_18 // SPI
|
||||
#define TFT_CS GPIO_NUM_5 // Chip select control
|
||||
#define TFT_DC GPIO_NUM_23 // Data Command control
|
||||
#define TFT_RST GPIO_NUM_26 // Reset
|
||||
#define TFT_BL GPIO_NUM_27 // LED back-light
|
||||
#define TFT_BACKLIGHT_ON 1
|
||||
#define ST7735_GREENTAB160x80
|
||||
|
||||
#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
|
||||
|
||||
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
|
||||
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
|
||||
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
|
||||
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
|
||||
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
|
||||
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
|
||||
#define SMOOTH_FONT
|
||||
|
||||
#define SPI_FREQUENCY 27000000
|
||||
#define SPI_READ_FREQUENCY 6000000
|
||||
|
||||
#endif
|
||||
|
@ -64,7 +64,7 @@ void lora_setupForNetwork(bool preJoin) {
|
||||
#elif CFG_LMIC_EU_like
|
||||
// settings for TheThingsNetwork
|
||||
// Enable link check validation
|
||||
LMIC_setLinkCheckMode(true);
|
||||
LMIC_setLinkCheckMode(1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
@ -541,7 +541,7 @@ void SaveLMICToRTC(int deepsleep_sec) {
|
||||
unsigned long now = millis();
|
||||
|
||||
// EU Like Bands
|
||||
#if defined(CFG_LMIC_EU_like)
|
||||
#if CFG_LMIC_EU_like
|
||||
for (int i = 0; i < MAX_BANDS; i++) {
|
||||
ostime_t correctedAvail =
|
||||
RTC_LMIC.bands[i].avail -
|
||||
|
14
src/ota.cpp
14
src/ota.cpp
@ -189,6 +189,8 @@ int do_ota_update() {
|
||||
|
||||
while (client.available()) {
|
||||
String line = client.readStringUntil('\n');
|
||||
String lineLowerCase = line;
|
||||
lineLowerCase.toLowerCase();
|
||||
// Check if the line is end of headers by removing space symbol
|
||||
line.trim();
|
||||
// if the the line is empty, this is the end of the headers
|
||||
@ -213,8 +215,8 @@ int do_ota_update() {
|
||||
}
|
||||
|
||||
// Extracting new redirect location
|
||||
if (line.startsWith("Location: ")) {
|
||||
String newUrl = getHeaderValue(line, "Location: ");
|
||||
if (lineLowerCase.startsWith("location: ")) {
|
||||
String newUrl = getHeaderValue(line, "location: ");
|
||||
ESP_LOGI(TAG, "Got new url: %s", newUrl.c_str());
|
||||
newUrl.remove(0, newUrl.indexOf("//") + 2);
|
||||
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
|
||||
@ -224,14 +226,14 @@ int do_ota_update() {
|
||||
}
|
||||
|
||||
// Checking headers
|
||||
if (line.startsWith("Content-Length: ")) {
|
||||
if (lineLowerCase.startsWith("content-length: ")) {
|
||||
contentLength =
|
||||
atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
||||
atoi((getHeaderValue(line, "content-length: ")).c_str());
|
||||
ESP_LOGI(TAG, "Got %d bytes from server", contentLength);
|
||||
}
|
||||
|
||||
if (line.startsWith("Content-Type: ")) {
|
||||
String contentType = getHeaderValue(line, "Content-Type: ");
|
||||
if (lineLowerCase.startsWith("content-type: ")) {
|
||||
String contentType = getHeaderValue(line, "content-type: ");
|
||||
ESP_LOGI(TAG, "Got %s payload", contentType.c_str());
|
||||
if (contentType == "application/octet-stream") {
|
||||
isValidContentType = true;
|
||||
|
@ -14,6 +14,7 @@ esp_adc_cal_characteristics_t *adc_characs =
|
||||
static const adc1_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||
#else // ADC2
|
||||
static const adc2_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||
RTC_NOINIT_ATTR uint64_t RTC_reg_b;
|
||||
#endif
|
||||
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
static const adc_unit_t unit = ADC_UNIT_1;
|
||||
@ -171,9 +172,9 @@ void AXP192_init(void) {
|
||||
#endif // PMU_INT
|
||||
|
||||
// set charging parameterss according to user settings if we have (see power.h)
|
||||
#ifdef PMU_CHARGE_CURRENT
|
||||
pmu.setChargeControlCur(PMU_CHARGE_CURRENT);
|
||||
pmu.setChargingTargetVoltage(PMU_CHARGE_CUTOFF);
|
||||
#ifdef PMU_CHG_CURRENT
|
||||
pmu.setChargeControlCur(PMU_CHG_CURRENT);
|
||||
pmu.setChargingTargetVoltage(PMU_CHG_CUTOFF);
|
||||
pmu.enableChargeing(true);
|
||||
#endif
|
||||
|
||||
@ -193,8 +194,10 @@ void calibrate_voltage(void) {
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
adc1_config_channel_atten(adc_channel, atten);
|
||||
#else // ADC2
|
||||
// adc2_config_width(ADC_WIDTH_BIT_12);
|
||||
adc2_config_channel_atten(adc_channel, atten);
|
||||
// ADC2 wifi bug workaround, see
|
||||
// https://github.com/espressif/arduino-esp32/issues/102
|
||||
RTC_reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
|
||||
#endif
|
||||
// calibrate ADC
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(
|
||||
@ -229,6 +232,10 @@ uint16_t read_voltage(void) {
|
||||
#else // ADC2
|
||||
int adc_buf = 0;
|
||||
for (int i = 0; i < NO_OF_SAMPLES; i++) {
|
||||
// ADC2 wifi bug workaround, see
|
||||
// https://github.com/espressif/arduino-esp32/issues/102
|
||||
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
|
||||
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
|
||||
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
|
||||
adc_reading += adc_buf;
|
||||
}
|
||||
|
@ -73,11 +73,11 @@ void wifi_sniffer_init(void) {
|
||||
esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler);
|
||||
|
||||
// setup wifi channel hopping timer
|
||||
WifiChanTimer =
|
||||
xTimerCreate("WifiChannelTimer",
|
||||
(cfg.wifichancycle > 0) ? pdMS_TO_TICKS(cfg.wifichancycle)
|
||||
: pdMS_TO_TICKS(50),
|
||||
pdTRUE, (void *)0, switchWifiChannel);
|
||||
WifiChanTimer = xTimerCreate("WifiChannelTimer",
|
||||
(cfg.wifichancycle > 0)
|
||||
? pdMS_TO_TICKS(cfg.wifichancycle * 10)
|
||||
: pdMS_TO_TICKS(50),
|
||||
pdTRUE, (void *)0, switchWifiChannel);
|
||||
}
|
||||
|
||||
void switch_wifi_sniffer(uint8_t state) {
|
||||
|
Loading…
Reference in New Issue
Block a user