csv_writer.cpp 5 KB
Newer Older
1
2
#include "csv_writer.h"

Eric Duminil's avatar
TODO    
Eric Duminil committed
3
4
//TODO: Allow CSV download via USB Serial, when requested (e.g. via a Python script)

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
namespace config {
  // Values should be defined in config.h
  uint16_t csv_interval = CSV_INTERVAL; // [s]
}
namespace csv_writer {
  unsigned long last_written_at = 0;
  String last_successful_write = "";

#if defined(ESP8266)
  /**
   * SPECIFIC FUNCTIONS FOR LITTLEFS
   */
  FSInfo fs_info;

  bool mountFS() {
    return LittleFS.begin(); // format if needed.
  }

  void updateFsInfo() {
    FS_LIB.info(fs_info);
  }

  int getTotalSpace() {
    return fs_info.totalBytes;
  }

  int getUsedSpace() {
    return fs_info.usedBytes;
  }

  void showFilesystemContent() {
    Dir dir = FS_LIB.openDir("/");
    while (dir.next()) {
      Serial.print("  ");
      Serial.print(dir.fileName());
      Serial.print(" - ");
      if (dir.fileSize()) {
        File f = dir.openFile("r");
        Serial.println(f.size());
        f.close();
      } else {
        Serial.println("0");
      }
    }
  }
Eric Duminil's avatar
Eric Duminil committed
50
#elif defined(ESP32)
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  /**
   * SPECIFIC FUNCTIONS FOR SPIFFS
   */
  bool mountFS() {
    return SPIFFS.begin(true); // format if needed.
  }

  void updateFsInfo() {
    // Nothing to do.
  }

  int getTotalSpace() {
    return SPIFFS.totalBytes();
  }

  int getUsedSpace() {
    return SPIFFS.usedBytes();
  }

  void showFilesystemContent() {
    File root = SPIFFS.open("/");
    File file = root.openNextFile();
    while (file) {
      Serial.print("  ");
      Serial.print(file.name());
      Serial.print(" - ");
      Serial.println(file.size());
      file = root.openNextFile();
    }
  }
#endif

  const String filename = "/" + SENSOR_ID + ".csv";

  int getAvailableSpace() {
    return getTotalSpace() - getUsedSpace();
  }

  void initialize() {
    Serial.print(F("Initializing FS..."));
    if (mountFS()) {
      Serial.println(F("done."));
    } else {
      Serial.println(F("fail."));
      return;
    }

    updateFsInfo();

    Serial.println(F("File system info:"));

    Serial.print(F("  Total space    : "));
    Serial.print(getTotalSpace() / 1024);
    Serial.println("kB");

    Serial.print(F("  Used space     : "));
    Serial.print(getUsedSpace() / 1024);
    Serial.println("kB");

    Serial.print(F("  Available space: "));
    Serial.print(getAvailableSpace() / 1024);
    Serial.println("kB");
    Serial.println();

    // Open dir folder
Eric Duminil's avatar
Eric Duminil committed
116
    Serial.println(F("Filesystem content:"));
117
    showFilesystemContent();
Eric Duminil's avatar
Eric Duminil committed
118
    Serial.println();
Eric Duminil's avatar
Eric Duminil committed
119

Eric Duminil's avatar
Eric Duminil committed
120
    sensor_commands::defineIntCallback("csv", setCSVinterval, " 60 (Sets CSV writing interval, in s)");
Eric Duminil's avatar
Eric Duminil committed
121
122
123
124
125
126
127
128
129
    sensor_commands::defineIntCallback("double", [](int32_t x) {
      Serial.print("2 * ");
      Serial.print(x);
      Serial.print(" = ");
      Serial.println(2 * x);
    }, " (Say Hello;)");
    sensor_commands::defineCallback("hello", []() {
      Serial.println("SAY HELLO");
    }, " (Say Hello;)");
Eric Duminil's avatar
Eric Duminil committed
130
    sensor_commands::defineCallback("format_filesystem", formatFilesystem, " (Deletes the whole filesystem)");
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  }

  File openOrCreate() {
    File csv_file;
    if (FS_LIB.exists(filename)) {
      csv_file = FS_LIB.open(filename, "a+");
    } else {
      csv_file = FS_LIB.open(filename, "w");
      csv_file.print(F("Sensor time;CO2 concentration;Temperature;Humidity\r\n"));
      csv_file.print(F("YYYY-MM-DD HH:MM:SS+ZZ;ppm;degC;%\r\n"));
    }
    return csv_file;
  }

Eric Duminil's avatar
Eric Duminil committed
145
  void log(const String &timeStamp, const int16_t &co2, const float &temperature, const float &humidity) {
146
    led_effects::onBoardLEDOn();
Eric Duminil's avatar
Eric Duminil committed
147
148
149
150
151
152
153
154
155
    File csv_file = openOrCreate();
    char csv_line[42];
    snprintf(csv_line, sizeof(csv_line), "%s;%d;%.1f;%.1f\r\n", timeStamp.c_str(), co2, temperature, humidity);
    if (csv_file) {
      size_t written_bytes = csv_file.print(csv_line);
      csv_file.close();
      if (written_bytes == 0) {
        Serial.println(F("Nothing written. Disk full?"));
      } else {
Eric Duminil's avatar
Eric Duminil committed
156
        Serial.print(F("CSV - Wrote : "));
Eric Duminil's avatar
Eric Duminil committed
157
158
159
160
161
162
163
164
165
        Serial.print(csv_line);
        last_successful_write = ntp::getLocalTime();
      }
      updateFsInfo();
      delay(50);
    } else {
      //NOTE: Can it ever happen that outfile is false?
      Serial.println(F("Problem on create file!"));
    }
166
    led_effects::onBoardLEDOff();
Eric Duminil's avatar
Eric Duminil committed
167
168
169
  }

  void logIfTimeHasCome(const String &timeStamp, const int16_t &co2, const float &temperature, const float &humidity) {
170
171
172
    unsigned long now = seconds();
    if (now - last_written_at > config::csv_interval) {
      last_written_at = now;
Eric Duminil's avatar
Eric Duminil committed
173
      log(timeStamp, co2, temperature, humidity);
174
175
    }
  }
176
177
178
179
180
181
182
183
184
185
186

  /*****************************************************************
   * Callbacks for sensor commands                                 *
   *****************************************************************/
  void setCSVinterval(int32_t csv_interval) {
    config::csv_interval = csv_interval;
    Serial.print(F("Setting CSV Interval to : "));
    Serial.print(config::csv_interval);
    Serial.println("s.");
    led_effects::showKITTWheel(color::green, 1);
  }
187
188
189
190
191

  void formatFilesystem() {
    FS_LIB.format();
    led_effects::showKITTWheel(color::blue, 2);
  }
192
}