A low cost DIY sound pressure level sensor for enabling environmental noise awareness. https://lukasschwarz.org/noise-sensor
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

269 Zeilen
7.4 KiB

  1. // vim: noai:sw=2:tw=88
  2. #include "NoiseSensor.h"
  3. #include "time.h"
  4. #include <ESP32Time.h>
  5. #include <TimeLib.h>
  6. ESP32Time t;
  7. bool NoiseSensorClass::begin() {
  8. _PACKET_SIZE = ( _tick_count + LORA_HEADER_LENGTH + BATTERY_FIELD_SIZE );
  9. _REQUEST_SIZE = ( PACKET_COUNT * _PACKET_SIZE * 2 ); // * 2, it's 16 bit.
  10. for (int i = 0; i < PACKET_COUNT; i++) {
  11. _nodes[i] = new NoiseSensorNode(i, _PACKET_SIZE * 2);
  12. }
  13. if (this->_tick_duration < 2) {
  14. Serial.println("--> Using a tick duration of less than two seconds. This "
  15. "will fail unless you've increased the MCUs SYSCLK!");
  16. }
  17. if (this->_tick_count >= 100) {
  18. Serial.println(
  19. "--> Using a tick count of more than 100 gets dangerously close to the "
  20. "LoRa transmission limitations and is not supported as of now.");
  21. }
  22. if (!setupNTPClient()) {
  23. Serial.println("!!!-------------------------!!!");
  24. Serial.println("NTPClient couldn't be started.");
  25. Serial.println("!!!-------------------------!!!");
  26. return false;
  27. }
  28. Wire.begin(21, 22, 400000);
  29. sendSyncBeacon();
  30. this->_first_sync = 1;
  31. }
  32. bool NoiseSensorClass::begin(uint8_t tick_count) {
  33. this->_tick_count = tick_count;
  34. this->begin();
  35. }
  36. bool NoiseSensorClass::begin(uint8_t tick_count, uint8_t tick_duration) {
  37. this->_tick_count = tick_count;
  38. this->_tick_duration = tick_duration;
  39. this->begin();
  40. }
  41. bool NoiseSensorClass::begin(uint8_t tick_count, uint8_t tick_duration,
  42. uint8_t tx_offset) {
  43. this->_tick_count = tick_count;
  44. this->_tick_duration = tick_duration;
  45. this->_tx_offset = tx_offset;
  46. this->begin();
  47. }
  48. void NoiseSensorClass::setIds(const char* sensebox_ids[], const char* sensor_ids[]) {
  49. for (int i = 0; i < PACKET_COUNT; i++) {
  50. char tmp[24] = {0};
  51. _nodes[i]->sensebox_id = sensebox_ids[i];
  52. _nodes[i]->sensor_id = sensor_ids[i];
  53. }
  54. }
  55. bool NoiseSensorClass::beaconReady() {
  56. if (t.getEpoch() - _last_sync_time ==
  57. (this->_tick_count * this->_tick_duration)) {
  58. Serial.println("---->Beacon ready");
  59. return true;
  60. }
  61. return false;
  62. }
  63. bool NoiseSensorClass::requestReady() {
  64. // 1 second as tolerance
  65. if (!this->_first_sync &&
  66. t.getEpoch() - _last_sync_time ==
  67. (5 * this->_tx_offset * this->_tick_duration + 1)) {
  68. Serial.println("---->Request ready");
  69. return true;
  70. }
  71. return false;
  72. }
  73. bool NoiseSensorClass::read() {
  74. for (int pkt = 0; pkt < PACKET_COUNT; pkt++) {
  75. NoiseSensorNode* node = _nodes[pkt];
  76. // Calculate the time of the sync message that triggered this packet.
  77. uint32_t time_offset = (_tick_count * _tick_duration); // TODO Move
  78. node->_sync_message_ts = this->_last_sync_time - time_offset;
  79. /*
  80. Serial.print("Last sync time: ");
  81. Serial.println(_last_sync_time);
  82. Serial.print("Offset: ");
  83. Serial.println(time_offset);
  84. Serial.print("TS: ");
  85. Serial.println(_nodes[pkt]->_sync_message_ts);
  86. Serial.print(minute(_nodes[pkt]->_sync_message_ts));
  87. Serial.print(":");
  88. Serial.println(second(_nodes[pkt]->_sync_message_ts));
  89. */
  90. /*
  91. if (node->missing_answers > 0) {
  92. node->_sync_message_ts -= time_offset * node->missing_answers;
  93. }
  94. */
  95. Wire.requestFrom(_i2c_address, _PACKET_SIZE * 2);
  96. char req_buf[_PACKET_SIZE * 2] = {0};
  97. uint8_t count = 0;
  98. while (Wire.available()) {
  99. char c = Wire.read();
  100. req_buf[count] = c;
  101. count++;
  102. }
  103. // TODO There's probably a neater way than doing these low level operations.
  104. for (int i = 0; i < _PACKET_SIZE * 2; i+=2) {
  105. uint16_t n = req_buf[i+1] << 8;
  106. n |= req_buf[i];
  107. node->_measurements[i/2] = n;
  108. Serial.print(n);
  109. Serial.print(" ");
  110. }
  111. Serial.println();
  112. }
  113. // Skip 0, it has no battery.
  114. for (int pkt = 1; pkt < PACKET_COUNT; pkt++) {
  115. // TODO Move this to a sane place (own function).
  116. if (_nodes[pkt]->_measurements[_PACKET_SIZE - 1]) {
  117. Serial.print("Battery low on device");
  118. Serial.println(pkt);
  119. }
  120. }
  121. Serial.println("Reading done.");
  122. return true;
  123. }
  124. void NoiseSensorClass::printMeasurements(uint8_t node_id) {
  125. uint32_t ts = this->_nodes[node_id]->_sync_message_ts;
  126. char printbuf[32];
  127. sprintf(printbuf, "- ID %u - ", node_id);
  128. Serial.println(printbuf);
  129. for (int i = 2; i < (this->_PACKET_SIZE - BATTERY_FIELD_SIZE); i++) {
  130. // TODO Timestamps
  131. Serial.println(this->_nodes[node_id]->_measurements[i]);
  132. ts += this->_tick_duration;
  133. }
  134. }
  135. bool NoiseSensorClass::sendSyncBeacon() {
  136. uint8_t setup_values[4];
  137. setup_values[0] = 1;
  138. setup_values[1] = this->_tick_count;
  139. setup_values[2] = this->_tick_duration;
  140. setup_values[3] = this->_tx_offset;
  141. Serial.println("Sent beacon");
  142. Wire.beginTransmission(_i2c_address);
  143. Wire.write((uint8_t *) setup_values, sizeof(setup_values));
  144. Wire.endTransmission();
  145. this->_first_sync = 0;
  146. _last_sync_time = t.getEpoch();
  147. Serial.println(_last_sync_time);
  148. }
  149. String NoiseSensorClass::buildSenseBoxJSON(uint8_t device_id) {
  150. NoiseSensorNode* node = _nodes[device_id];
  151. uint32_t ts = node->_sync_message_ts;
  152. // Each measurement line is max. 94 chars long + 2 curly brackets.
  153. uint16_t bufsize = _tick_count * 94 + 2;
  154. char json_buf[bufsize] = {0};
  155. char sensor_id[25] = {0};
  156. node->sensor_id.toCharArray(sensor_id, 25);
  157. // Build a json string in a very comprehensible way...
  158. strcat(json_buf, "[\n");
  159. for (int i = 2; i < (_PACKET_SIZE - BATTERY_FIELD_SIZE); i++) {
  160. char tmpbuf[1024] = {0};
  161. char timestamp[24] = {0};
  162. float m = node->_measurements[i] / 10.0; // From fixed point to float.
  163. if (m >= 29 && m <= 120) {
  164. sprintf(timestamp, "%i-%02i-%02iT%02i:%02i:%02iZ", year(ts), month(ts),
  165. day(ts), hour(ts), minute(ts), second(ts));
  166. sprintf(tmpbuf, "{\"sensor\":\"%s\", \"value\":\"%.1f\", \"createdAt\":\"%s\"}", sensor_id, m, timestamp);
  167. // No trailing comma on the last entry.
  168. if (i != _PACKET_SIZE - BATTERY_FIELD_SIZE - 1) {
  169. strcat(tmpbuf, ",");
  170. }
  171. strcat(json_buf, tmpbuf);
  172. strcat(json_buf, "\n");
  173. }
  174. ts += this->_tick_duration;
  175. }
  176. /*
  177. if (strlen(json_buf) > 2) {
  178. node->missing_answers = 0;
  179. Serial.println("Missing answers reset.");
  180. } else {
  181. node->missing_answers++;
  182. Serial.print("Missing answers: ");
  183. Serial.println(node->missing_answers);
  184. }
  185. */
  186. strcat(json_buf, "]");
  187. return json_buf;
  188. }
  189. String NoiseSensorClass::buildHTTPHeader(uint8_t device_id, const char* server, uint16_t content_length) {
  190. char sb_id[25] = {0};
  191. _nodes[device_id]->sensebox_id.toCharArray(sb_id, 25);
  192. char uploadbuf[2048] = {0};
  193. sprintf(uploadbuf, "POST /boxes/%s/data HTTP/1.1\n"
  194. "Host: %s\n"
  195. "content-type: application/json\n"
  196. "Connection: close\n"
  197. "Content-Length: %u", sb_id, server, content_length);
  198. return String(uploadbuf);
  199. }
  200. // Private functions
  201. bool NoiseSensorClass::setupNTPClient() {
  202. configTime(0, 0, "de.pool.ntp.org");
  203. // Allow processing of the package.
  204. delay(1000);
  205. struct tm timeinfo;
  206. if(!getLocalTime(&timeinfo)){
  207. Serial.println("Failed to obtain time");
  208. return false;
  209. }
  210. char timestamp[24];
  211. uint32_t ts = t.getEpoch();
  212. sprintf(timestamp, "%i-%02i-%02iT%02i:%02i:%02iZ", year(ts), month(ts),
  213. day(ts), hour(ts), minute(ts), second(ts));
  214. Serial.println(timestamp);
  215. return true;
  216. }
  217. NoiseSensorClass NoiseSensor;