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