Merge pull request #513 from cyberman54/sdcard

add sdcard support to branch development
This commit is contained in:
Verkehrsrot 2019-12-28 17:16:31 +01:00 committed by GitHub
commit 4e1472caae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 183 additions and 7 deletions

View File

@ -20,7 +20,7 @@ Paxcounter is a proof-of-concept device for metering passenger flows in realtime
Intention of this project is to do this without intrusion in privacy: You don't need to track people owned devices, if you just want to count them. Therefore, Paxcounter does not persistenly store MAC adresses and does no kind of fingerprinting the scanned devices. Intention of this project is to do this without intrusion in privacy: You don't need to track people owned devices, if you just want to count them. Therefore, Paxcounter does not persistenly store MAC adresses and does no kind of fingerprinting the scanned devices.
Data is transferred to a server via a LoRaWAN network, and/or a wired SPI slave interface. Data is transferred to a server via a LoRaWAN network, and/or a wired SPI slave interface. It can also be stored on a local SD-card.
You can build this project battery powered and reach a full day uptime with a single 18650 Li-Ion cell. You can build this project battery powered and reach a full day uptime with a single 18650 Li-Ion cell.
@ -33,7 +33,7 @@ This can all be done with a single small and cheap ESP32 board for less than $20
*LoRa & SPI*: *LoRa & SPI*:
- Heltec: LoRa-32 v1 and v2 - Heltec: LoRa-32 v1 and v2
- TTGO: T1, T2, T3, T-Beam, T-Fox - TTGO: T1*, T2*, T3*, T-Beam, T-Fox (* supports microSD-card)
- Pycom: LoPy, LoPy4, FiPy - Pycom: LoPy, LoPy4, FiPy
- Radioshuttle.de: [ECO Power Board](https://www.radioshuttle.de/esp32-eco-power/esp32-eco-power-board/) - Radioshuttle.de: [ECO Power Board](https://www.radioshuttle.de/esp32-eco-power/esp32-eco-power-board/)
- WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora), - WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora),
@ -60,6 +60,7 @@ Depending on board hardware following features are supported:
- IF482 (serial) and DCF77 (gpio) time telegram generator - IF482 (serial) and DCF77 (gpio) time telegram generator
- Switch external power / battery - Switch external power / battery
- LED Matrix display (similar to [this 64x16 model](https://www.instructables.com/id/64x16-RED-LED-Marquee/), can be ordered on [Aliexpress](https://www.aliexpress.com/item/P3-75-dot-matrix-led-module-3-75mm-high-clear-top1-for-text-display-304-60mm/32616683948.html)) - LED Matrix display (similar to [this 64x16 model](https://www.instructables.com/id/64x16-RED-LED-Marquee/), can be ordered on [Aliexpress](https://www.aliexpress.com/item/P3-75-dot-matrix-led-module-3-75mm-high-clear-top1-for-text-display-304-60mm/32616683948.html))
- SD-card (see section SD-card here)
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br> Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.<br> Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.<br>
@ -196,6 +197,43 @@ Follow all steps so far for preparing the device, use the packed payload format.
There in the sensor configuration select "TheThingsNetwork" and set Decoding Profil to "LoRa serialization", enter your TTN Application and Device Id. Decoding option has to be There in the sensor configuration select "TheThingsNetwork" and set Decoding Profil to "LoRa serialization", enter your TTN Application and Device Id. Decoding option has to be
[{"decoder":"latLng"},{"decoder":"uint16","sensor_id":"yoursensorid"}] [{"decoder":"latLng"},{"decoder":"uint16","sensor_id":"yoursensorid"}]
# SD-card
Data can be stored on an SD-card if one is availabe. Simply choose the file in src/hal and add the following lines to your hal-file:
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13) // fill in the correct numbers for your board
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
Please choose the correct number for the connection of the reader/writer.
This is an example of a board with SD-card: https://www.aliexpress.com/item/32990008126.html
In this case you take the file src/hal/ttgov21new.h and add the lines given above (numbers given are for this board).
Another approach would be this tiny board: https://www.aliexpress.com/item/32424558182.html (needs 5V).
In this case you choose the correct file for your ESP32-board in the src/hal-directory and add the lines given above to the correct h-file. Please correct the numbers given in the example to the numbers used corresponding to your wiring.
Some hints:
These cheap devices often handle SD-cards up to 32GB, not bigger ones. They can handle files in the old DOS-way, to say the filenames are in the 8.3-format. And they often cannot handle subdirectories.
The software included here writes data in a file named PAXCOUNT.xx, where xx can range from 00 to 99. The software starts with 00, checks to see if such a file already exists and if yes it will continue with the next number (up to 99 - in this case it will return no sd-card). So an existing file will not be overwritten.
The data is written to the card and after 3 write-operations the data is flushed to the disk. So maybe the last 3 minutes of data get lost when you disconnect the PAXCOUNTER from power.
And finally: this is the data written to the disk:
date, time, wifi, bluet
00.00.1970,00:01:09,2,0
00.00.1970,00:02:09,1,0
00.00.1970,00:03:09,2,0
Format of the data is CSV, which can easily imported into LibreOffice, Excel, .....
If you want to change this please look into src/sdcard.cpp and include/sdcard.h.
# Payload format # Payload format
You can select different payload formats in [paxcounter.conf](src/paxcounter.conf#L12): You can select different payload formats in [paxcounter.conf](src/paxcounter.conf#L12):

16
include/sdcard.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _SDCARD_H
#define _SDCARD_H
#include <globals.h>
#include <stdio.h>
#include <SPI.h>
#include <mySD.h>
#define SDCARD_FILE_NAME "paxcount.%02d"
#define SDCARD_FILE_HEADER "date, time, wifi, bluet"
bool sdcardInit( void );
void sdcardWriteData( uint16_t, uint16_t);
#endif

View File

@ -12,6 +12,10 @@
#include "display.h" #include "display.h"
#endif #endif
#ifdef HAS_SDCARD
#include "sdcard.h"
#endif
extern Ticker sendcycler; extern Ticker sendcycler;
void SendPayload(uint8_t port, sendprio_t prio); void SendPayload(uint8_t port, sendprio_t prio);

View File

@ -7,7 +7,7 @@
; ---> SELECT THE TARGET PLATFORM HERE! <--- ; ---> SELECT THE TARGET PLATFORM HERE! <---
[board] [board]
halfile = generic.h ;halfile = generic.h
;halfile = ebox.h ;halfile = ebox.h
;halfile = eboxtube.h ;halfile = eboxtube.h
;halfile = ecopower.h ;halfile = ecopower.h
@ -16,7 +16,7 @@ halfile = generic.h
;halfile = ttgov1.h ;halfile = ttgov1.h
;halfile = ttgov2.h ;halfile = ttgov2.h
;halfile = ttgov21old.h ;halfile = ttgov21old.h
;halfile = ttgov21new.h halfile = ttgov21new.h
;halfile = ttgofox.h ;halfile = ttgofox.h
;halfile = ttgobeam.h ;halfile = ttgobeam.h
;halfile = ttgobeam10.h ;halfile = ttgobeam10.h
@ -76,6 +76,7 @@ lib_deps_basic =
274@>=2.3.3 ; #274 RTC by Michael Miller 274@>=2.3.3 ; #274 RTC by Michael Miller
SimpleButton SimpleButton
AXP202X_Library@>=1.1.0 ; AXP202 PMU lib by Lewis He AXP202X_Library@>=1.1.0 ; AXP202 PMU lib by Lewis He
esp32-micro-sdcard
lib_deps_all = lib_deps_all =
${common.lib_deps_basic} ${common.lib_deps_basic}
${common.lib_deps_lora} ${common.lib_deps_lora}

View File

@ -18,6 +18,14 @@
#define SPI_SCLK GPIO_NUM_18 #define SPI_SCLK GPIO_NUM_18
#define SPI_CS GPIO_NUM_5 #define SPI_CS GPIO_NUM_5
// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
// enable only if device has these sensors, otherwise comment these lines // enable only if device has these sensors, otherwise comment these lines
// tutorial to connect BME sensor see here: // tutorial to connect BME sensor see here:
// https://sbamueller.wordpress.com/2019/02/26/paxcounter-mit-umweltsensor/ // https://sbamueller.wordpress.com/2019/02/26/paxcounter-mit-umweltsensor/

View File

@ -18,6 +18,14 @@
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
#define HAS_BUTTON KEY_BUILTIN #define HAS_BUTTON KEY_BUILTIN
// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
// Pins for I2C interface of OLED Display // Pins for I2C interface of OLED Display
#define MY_OLED_SDA (4) #define MY_OLED_SDA (4)
#define MY_OLED_SCL (15) #define MY_OLED_SCL (15)

View File

@ -19,6 +19,14 @@
// disable brownout detection (needed on TTGOv2 for battery powered operation) // disable brownout detection (needed on TTGOv2 for battery powered operation)
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
// Pins for I2C interface of OLED Display // Pins for I2C interface of OLED Display
#define MY_OLED_SDA (21) #define MY_OLED_SDA (21)
#define MY_OLED_SCL (22) #define MY_OLED_SCL (22)

View File

@ -15,6 +15,14 @@
#define HAS_LORA 1 // comment out if device shall not send data via LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC #define CFG_sx1276_radio 1 // HPD13A LoRa SoC
// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
// enable only if device has these sensors, otherwise comment these lines // enable only if device has these sensors, otherwise comment these lines
// BME280 sensor on I2C bus // BME280 sensor on I2C bus
//#define HAS_BME 1 // Enable BME sensors in general //#define HAS_BME 1 // Enable BME sensors in general

View File

@ -19,6 +19,14 @@
#define HAS_LED NOT_A_PIN // no usable LED on board #define HAS_LED NOT_A_PIN // no usable LED on board
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
#define HAS_DISPLAY 1 #define HAS_DISPLAY 1
#define DISPLAY_FLIP 1 // rotated display #define DISPLAY_FLIP 1 // rotated display
//#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7 //#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7

View File

@ -323,6 +323,11 @@ void setup() {
assert(spi_init() == ESP_OK); assert(spi_init() == ESP_OK);
#endif #endif
#ifdef HAS_SDCARD
if (sdcardInit())
strcat_P(features, " SD");
#endif
#if (VENDORFILTER) #if (VENDORFILTER)
strcat_P(features, " FILTER"); strcat_P(features, " FILTER");
#endif #endif

67
src/sdcard.cpp Normal file
View File

@ -0,0 +1,67 @@
// routines for writing data to an SD-card, if present
// Local logging tag
static const char TAG[] = __FILE__;
#include "sdcard.h"
static bool useSDCard;
static void createFile(void);
File fileSDCard;
bool sdcardInit() {
ESP_LOGD(TAG, "looking for SD-card...");
useSDCard = SD.begin(SDCARD_CS, SDCARD_MOSI, SDCARD_MISO, SDCARD_SCLK);
if (useSDCard)
createFile();
return useSDCard;
}
void sdcardWriteData(uint16_t noWifi, uint16_t noBle) {
static int counterWrites = 0;
char tempBuffer[12 + 1];
time_t t = now();
if (!useSDCard)
return;
ESP_LOGD(TAG, "writing to SD-card");
sprintf(tempBuffer, "%02d.%02d.%4d,", day(t), month(t), year(t));
fileSDCard.print(tempBuffer);
sprintf(tempBuffer, "%02d:%02d:%02d,", hour(t), minute(t), second(t));
fileSDCard.print(tempBuffer);
sprintf(tempBuffer, "%d,%d", noWifi, noBle);
fileSDCard.println(tempBuffer);
if (++counterWrites > 2) {
// force writing to SD-card
ESP_LOGD(TAG, "flushing data to card");
fileSDCard.flush();
counterWrites = 0;
}
}
void createFile(void) {
char bufferFilename[8 + 1 + 3 + 1];
useSDCard = false;
for (int i = 0; i < 100; i++) {
sprintf(bufferFilename, SDCARD_FILE_NAME, i);
ESP_LOGD(TAG, "SD: looking for file <%s>", bufferFilename);
bool fileExists = SD.exists(bufferFilename);
if (!fileExists) {
ESP_LOGD(TAG, "SD: file does not exist: opening");
fileSDCard = SD.open(bufferFilename, FILE_WRITE);
if (fileSDCard) {
ESP_LOGD(TAG, "SD: name opended: <%s>", bufferFilename);
fileSDCard.println(SDCARD_FILE_HEADER);
useSDCard = true;
break;
}
}
}
return;
}

View File

@ -51,6 +51,11 @@ void SendPayload(uint8_t port, sendprio_t prio) {
spi_enqueuedata(&SendBuffer); spi_enqueuedata(&SendBuffer);
#endif #endif
// write data to sdcard, if present
#ifdef HAS_SDCARD
sdcardWriteData(macs_wifi, macs_ble);
#endif
} // SendPayload } // SendPayload
// interrupt triggered function to prepare payload to send // interrupt triggered function to prepare payload to send