From a83cc44bf881d3997052626f7261f0357e7669e5 Mon Sep 17 00:00:00 2001 From: Eden Kirin Date: Mon, 19 May 2025 10:12:53 +0200 Subject: [PATCH] Initial --- .gitignore | 8 + .pio/build/structure.hash | 1 + doc/soba - cvrčci.svg | 470 ++++++++++++++++++++++++++++++++++++++ include/readme.txt | 39 ++++ lib/readme.txt | 36 +++ platformio.ini | 18 ++ src/comm.cpp | 150 ++++++++++++ src/comm.h | 28 +++ src/defs.h | 35 +++ src/dht_measure.cpp | 98 ++++++++ src/dht_measure.h | 20 ++ src/disp.cpp | 206 +++++++++++++++++ src/disp.h | 22 ++ src/hw.cpp | 42 ++++ src/hw.h | 35 +++ src/measure.cpp | 286 +++++++++++++++++++++++ src/measure.h | 63 +++++ src/teleinsektarij.ino | 84 +++++++ test/main.cpp | 48 ++++ test/makefile | 10 + 20 files changed, 1699 insertions(+) create mode 100644 .gitignore create mode 100644 .pio/build/structure.hash create mode 100644 doc/soba - cvrčci.svg create mode 100644 include/readme.txt create mode 100644 lib/readme.txt create mode 100644 platformio.ini create mode 100644 src/comm.cpp create mode 100644 src/comm.h create mode 100644 src/defs.h create mode 100644 src/dht_measure.cpp create mode 100644 src/dht_measure.h create mode 100644 src/disp.cpp create mode 100644 src/disp.h create mode 100644 src/hw.cpp create mode 100644 src/hw.h create mode 100644 src/measure.cpp create mode 100644 src/measure.h create mode 100644 src/teleinsektarij.ino create mode 100644 test/main.cpp create mode 100644 test/makefile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d00ed5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json + +/.vscode +/test/a.out +/test/o diff --git a/.pio/build/structure.hash b/.pio/build/structure.hash new file mode 100644 index 0000000..c7f7b54 --- /dev/null +++ b/.pio/build/structure.hash @@ -0,0 +1 @@ +63daa49347a7d1f33ca50cf95705163a684f2e55 \ No newline at end of file diff --git a/doc/soba - cvrčci.svg b/doc/soba - cvrčci.svg new file mode 100644 index 0000000..3fd4c81 --- /dev/null +++ b/doc/soba - cvrčci.svg @@ -0,0 +1,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + T1 + T2 + + + T3 + T4 + T6/H1 + + + T5 + + + T8 + T7 + ESP + Soba 1 - Cvrčci + + diff --git a/include/readme.txt b/include/readme.txt new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/readme.txt @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/readme.txt b/lib/readme.txt new file mode 100644 index 0000000..dbadc3d --- /dev/null +++ b/lib/readme.txt @@ -0,0 +1,36 @@ + +This directory is intended for the project specific (private) libraries. +PlatformIO will compile them to static libraries and link to executable file. + +The source code of each library should be placed in separate directory, like +"lib/private_lib/[here are source files]". + +For example, see how can be organized `Foo` and `Bar` libraries: + +|--lib +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| |--Foo +| | |- Foo.c +| | |- Foo.h +| |- readme.txt --> THIS FILE +|- platformio.ini +|--src + |- main.c + +Then in `src/main.c` you should use: + +#include +#include + +// rest H/C/CPP code + +PlatformIO will find your libraries automatically, configure preprocessor's +include paths and build them. + +More information about PlatformIO Library Dependency Finder +- http://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..27f6cda --- /dev/null +++ b/platformio.ini @@ -0,0 +1,18 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:espduino] +platform = espressif8266 +board = espduino +;board = nodemcuv2 +framework = arduino +upload_speed = 230400 +;upload_speed = 460800 +upload_port = /dev/ttyUSB0 diff --git a/src/comm.cpp b/src/comm.cpp new file mode 100644 index 0000000..aa5f58a --- /dev/null +++ b/src/comm.cpp @@ -0,0 +1,150 @@ +#include +#include +#include "defs.h" +#include "comm.h" +#include "hw.h" +#include "measure.h" +#include "disp.h" + + +uint8_t last_server_comm_status = STATUS_UNKNOWN; + + +//--------------------------------------------------------------------------------------- + +void init_comm() +{ + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + + +//--------------------------------------------------------------------------------------- + + +bool comm_is_connected() { + return WiFi.status() == WL_CONNECTED; +} + + +//--------------------------------------------------------------------------------------- + + +void connect_comm() +{ + uint8_t retry = 0; + + while (!comm_is_connected() && retry <= 3) + { + disp_indicate_status(STATUS_CONNECTING_TO_WIFI, true); + SERIAL_PRINTLN("Connecting to WiFi..."); + blink_led(LED_BLUE, 500); + disp_indicate_status(STATUS_CONNECTING_TO_WIFI, false); + + delay(1000); + retry++; + } + + if (!comm_is_connected()) + last_server_comm_status = STATUS_ERR; +} + + +//--------------------------------------------------------------------------------------- + + +unsigned long get_uptime() +{ + static unsigned int _rollover_cnt = 0; + static unsigned long _last_millis = 0; + unsigned long current_millis = millis(); + + if (current_millis < _last_millis) + _rollover_cnt++; + + _last_millis = current_millis; + + return (0xFFFFFFFF / 1000) * _rollover_cnt + (_last_millis / 1000); +} + + +//--------------------------------------------------------------------------------------- + + +void post_data_to_server() +{ + int http_response_code; + HTTPClient http; + String post_data; + String measurement_data; + char buff[100]; + + unsigned long uptime = get_uptime(); + + set_led(LED_GREEN, true); + disp_indicate_status(STATUS_SENDING_DATA, true); + + http.begin(API_URL); + + measurement_data = format_measurement_data(); + + sprintf( + buff, + "cmd=set_sensors&api_key=%s&uptime=%ld&", + API_KEY, + uptime + ); + + post_data = String(buff) + measurement_data; + + // content type must be included with POST method + http.addHeader("Content-Type", "application/x-www-form-urlencoded"); + + SERIAL_PRINT("[HTTP POST] to "); + SERIAL_PRINTLN(API_URL); + SERIAL_PRINT("[HTTP POST] data: "); + SERIAL_PRINTLN(post_data); + + http_response_code = http.POST(post_data); + + // http_response_code will be negative on error + if (http_response_code > 0) + { + // HTTP header has been sent and server response header has been handled + SERIAL_PRINTF("[HTTP POST] response code: %d\n", http_response_code); + + if (http_response_code == HTTP_CODE_OK) + { + last_server_comm_status = STATUS_OK; + String payload = http.getString(); + SERIAL_PRINT("[HTTP response] "); + SERIAL_PRINTLN(payload); + } else { + last_server_comm_status = STATUS_ERR; + } + } else { + last_server_comm_status = STATUS_ERR; + + SERIAL_PRINTF( + "[HTTP] Failed, response code: %d, error: %s\n", + http_response_code, + http.errorToString(http_response_code).c_str() + ); + blink_led(LED_RED, 500); + } + http.end(); + + set_led(LED_GREEN, false); + disp_indicate_status(STATUS_SENDING_DATA, false); +} + + +//--------------------------------------------------------------------------------------- + + +uint8_t get_last_server_comm_status() { + return last_server_comm_status; +} + + +//--------------------------------------------------------------------------------------- diff --git a/src/comm.h b/src/comm.h new file mode 100644 index 0000000..38aea59 --- /dev/null +++ b/src/comm.h @@ -0,0 +1,28 @@ +#ifndef COMM_H +#define COMM_H + +#include "defs.h" + +#ifdef LOCAL_SERVER + #define API_URL "http://192.168.1.5:8000/api/" + #define WIFI_SSID "" + #define WIFI_PASSWORD "" + #define API_KEY "" +#else + #define API_URL "" + #define WIFI_SSID "" + #define WIFI_PASSWORD "" + #define API_KEY "" +#endif + + +//--------------------------------------------------------------------------------------- + + +void init_comm(); +void post_data_to_server(); +void connect_comm(); +bool comm_is_connected(); +uint8_t get_last_server_comm_status(); + +#endif diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 0000000..7fb7c44 --- /dev/null +++ b/src/defs.h @@ -0,0 +1,35 @@ +#ifndef DEFS_H +#define DEFS_H + +#define LOCAL_SERVER +#define SERIAL_DEBUG + +#ifdef SERIAL_DEBUG + #define SERIAL_PRINT(x) Serial.print(x) + #define SERIAL_PRINTDEC(x) Serial.print(x, DEC) + #define SERIAL_PRINTLN(x) Serial.println(x) + #define SERIAL_PRINTF(fmt, ...) Serial.printf(fmt, ##__VA_ARGS__) +#else + #define SERIAL_PRINT(x) + #define SERIAL_PRINTDEC(x) + #define SERIAL_PRINTLN(x) + #define SERIAL_PRINTF(fmt, ...) +#endif + +#define SIGNAL_LED_BLINK_INTERVAL 2000 // ms +#define DS_MEASURE_INTERVAL 1000 // ms +#define DHT_MEASURE_INTERVAL 2000 // ms + +#define SERIAL_BAUD_RATE 115200 + +#ifdef LOCAL_SERVER + #define SEND_DATA_TO_SERVER_INTERVAL 5000 // ms +#else + #define SEND_DATA_TO_SERVER_INTERVAL 20000 // ms +#endif + +#define STATUS_UNKNOWN 0 +#define STATUS_OK 1 +#define STATUS_ERR 2 + +#endif diff --git a/src/dht_measure.cpp b/src/dht_measure.cpp new file mode 100644 index 0000000..a7f7ca5 --- /dev/null +++ b/src/dht_measure.cpp @@ -0,0 +1,98 @@ +#include "defs.h" +#include "measure.h" +#include "dht_measure.h" +#include "disp.h" + +DHTSensorData dht_sensors[DHT_SENSOR_COUNT]; +uint8_t current_sensor = 0; + +DHT dht_sensor_0(DHT_SENSOR_PINS[0], DHTTYPE); +// DHT dht_sensor_1(DHT_SENSOR_PINS[1], DHTTYPE); + + +//--------------------------------------------------------------------------------------- + + +void dht_init_measure() +{ + dht_sensors[0].sensor = &dht_sensor_0; + // dht_sensors[1].sensor = &dht_sensor_1; + + for (uint8_t i = 0; i < DHT_SENSOR_COUNT; i++) + { + dht_sensors[i].sensor->begin(); + SERIAL_PRINTF("Setting up sensor %d on pin %d.\n", i, DHT_SENSOR_PINS[i]); + } +} + + +//--------------------------------------------------------------------------------------- + + +float dht_read_sensor(uint8_t index) +{ + DHTSensorData* sd = &dht_sensors[index]; + + float humidity = sd->sensor->readHumidity(); + float temperature = sd->sensor->readTemperature(); + + disp_indicate_status(STATUS_SENSOR_READ, false); + + if (!isnan(humidity) && !isnan(temperature)) + { + assign_sensor_value(&sd->humidity, humidity); + assign_sensor_value(&sd->temperature, temperature); + return true; + } else { + sd->humidity.valid = false; + sd->temperature.valid = false; + return false; + } +} + + +//--------------------------------------------------------------------------------------- + + +void dht_read_next_sensor() +{ + if (DHT_SENSOR_COUNT == 0) + return; + + if (current_sensor >= DHT_SENSOR_COUNT) + current_sensor = 0; + + DHTSensorData* sensor_data = &dht_sensors[current_sensor]; + + set_led(LED_YELLOW, true); + disp_indicate_status(STATUS_SENSOR_READ, true); + + if (dht_read_sensor(current_sensor)) + { + SERIAL_PRINTF( + "Reading DHT sensor %d: Temperature: %0.2f, humidity: %0.2f\n", + current_sensor, + sensor_data->temperature.value, + sensor_data->humidity.value + ); + } else { + SERIAL_PRINTF("Error reading DHT sensor %d.\n", current_sensor); + }; + + set_led(LED_YELLOW, false); + disp_indicate_status(STATUS_SENSOR_READ, false); + + current_sensor++; +} + + +//--------------------------------------------------------------------------------------- + + +pDHTSensorData dht_get_sensors_data() +{ + return (pDHTSensorData)&dht_sensors; +} + + +//--------------------------------------------------------------------------------------- diff --git a/src/dht_measure.h b/src/dht_measure.h new file mode 100644 index 0000000..f0f3221 --- /dev/null +++ b/src/dht_measure.h @@ -0,0 +1,20 @@ +#ifndef DHT_MEASURE_H +#define DHT_MEASURE_H + +#include "hw.h" +#include "measure.h" + +#define DHT_SENSOR_COUNT 1 +#define DHTTYPE DHT22 + +static uint8_t DHT_SENSOR_PINS[] = {D12, D13}; + + +//--------------------------------------------------------------------------------------- + + +void dht_init_measure(); +void dht_read_next_sensor(); +pDHTSensorData dht_get_sensors_data(); + +#endif diff --git a/src/disp.cpp b/src/disp.cpp new file mode 100644 index 0000000..97f4296 --- /dev/null +++ b/src/disp.cpp @@ -0,0 +1,206 @@ +#include +#include +#include "disp.h" +#include "defs.h" +#include "measure.h" +#include "dht_measure.h" +#include "comm.h" + + +U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0); + +#define GLYPH_OK 0x25a0 +#define GLYPH_ERR 0x2612 +#define GLYPH_UNKNOWN 0x2610 +#define GLYPH_STATUS_ACTIVE 0x25CF + +#define STATUS_Y_OFFS 36 +#define STATUS_X_OFFS_GLYPH 34 +#define STATUS_Y_OFFS_GLYPH STATUS_Y_OFFS - 2 +#define STATUS_X_OFFS_STATUS_GLYPH 24 +#define STATUS_Y_OFFS_STATUS_GLYPH STATUS_Y_OFFS_GLYPH + 2 + + +//--------------------------------------------------------------------------------------- + + +void init_disp() { + display.begin(); + display.setFontPosTop(); +} + + +//--------------------------------------------------------------------------------------- + + +void display_sensor_value(const char* caption, SensorData* sd) { + if (sd != NULL && sd->valid) { + display.printf("%s %0.1f", caption, sd->value); + } else { + display.printf("%s ERR", caption); + } +} + + +//--------------------------------------------------------------------------------------- + + +void display_ds_sensor_value(const char* caption, const char* sensor_address) { + display_sensor_value(caption, get_ds_sensor_data(sensor_address)); +} + + +//--------------------------------------------------------------------------------------- + + +uint16_t get_status_glyph(uint8_t status) { + switch (status) { + case STATUS_OK: + return GLYPH_OK; + case STATUS_ERR: + return GLYPH_ERR; + default: + return GLYPH_UNKNOWN; + } +} + + +//--------------------------------------------------------------------------------------- + + +void show_display_page(uint8_t index) { + pDHTSensorData dht_sensors_data; + char caption[8]; + uint8_t values_x_offs = 50; + uint8_t lh; + + display.clearBuffer(); + display.setFontMode(1); // activate transparent font mode + display.setFont(u8g2_font_t0_22_mf); + lh = 16; + + switch (index) { + case 0: + strcpy(caption, "P1"); + display.setCursor(values_x_offs, 0 * lh); + display_ds_sensor_value("T1", T1_ADDRESS); + display.setCursor(values_x_offs, 1 * lh); + display_ds_sensor_value("T2", T2_ADDRESS); + display.setCursor(values_x_offs, 2 * lh); + display_ds_sensor_value("T3", T3_ADDRESS); + display.setCursor(values_x_offs, 3 * lh); + display_ds_sensor_value("T4", T4_ADDRESS); + break; + case 1: + dht_sensors_data = dht_get_sensors_data(); + strcpy(caption, "P2"); + display.setCursor(values_x_offs, 0 * lh); + display_ds_sensor_value("T5", T5_ADDRESS); + display.setCursor(values_x_offs, 1 * lh); + display_sensor_value("T6", &dht_sensors_data->temperature); + display.setCursor(values_x_offs, 2 * lh); + display_sensor_value("H1", &dht_sensors_data->humidity); + break; + case 2: + strcpy(caption, "P3"); + display.setCursor(values_x_offs, 0 * lh); + display_ds_sensor_value("T7", T7_ADDRESS); + display.setCursor(values_x_offs, 1 * lh); + display_ds_sensor_value("T8", T8_ADDRESS); + break; + } + + // print page caption + display.setFont(u8g2_font_profont29_mf); + display.drawStr(0, 0, caption); + + // print status captions + display.setFont(u8g2_font_victoriamedium8_8u); + lh = 8; + display.setCursor(0, STATUS_Y_OFFS + lh * 0); + display.print("NET"); + display.setCursor(0, STATUS_Y_OFFS + lh * 1); + display.print("COM"); + display.setCursor(0, STATUS_Y_OFFS + lh * 2); + display.print("SNS"); + + display.setFont(u8g2_font_unifont_t_symbols); + + // wifi connection status + display.drawGlyph( + STATUS_X_OFFS_GLYPH, + STATUS_Y_OFFS_GLYPH + lh * 0, + get_status_glyph(comm_is_connected()) + ); + // server communication status + display.drawGlyph( + STATUS_X_OFFS_GLYPH, + STATUS_Y_OFFS_GLYPH + lh * 1, + get_status_glyph(get_last_server_comm_status()) + ); + + display.sendBuffer(); +} + + +//--------------------------------------------------------------------------------------- + + +void disp_indicate_status(uint8_t status, bool value) { + uint8_t line; + uint8_t lh = 8; + + display.setFont(u8g2_font_unifont_t_symbols); + display.setFontMode(1); // activate transparent font mode + + switch (status) { + case STATUS_CONNECTING_TO_WIFI: + line = 0; + break; + case STATUS_SENDING_DATA: + line = 1; + break; + case STATUS_SENSOR_READ: + line = 2; + break; + default: + return; + } + + if (value) + display.setDrawColor(1); + else + display.setDrawColor(0); + + display.drawGlyph( + STATUS_X_OFFS_STATUS_GLYPH, + STATUS_Y_OFFS_STATUS_GLYPH + lh * line, + GLYPH_STATUS_ACTIVE + ); + + display.sendBuffer(); + display.setDrawColor(1); +} + + +//--------------------------------------------------------------------------------------- + + +void handle_disp() { + unsigned long current_millis = millis(); + static unsigned long timestamp_display_page_switch = 0; + static uint8_t display_page_index = 0; + + if (current_millis - timestamp_display_page_switch > DISPLAY_PAGE_SWITCH_INTERVAL) { + show_display_page(display_page_index); + + display_page_index++; + if (display_page_index >= DISPLAY_PAGE_COUNT) + display_page_index = 0; + + timestamp_display_page_switch = current_millis; + } +} + + +//--------------------------------------------------------------------------------------- diff --git a/src/disp.h b/src/disp.h new file mode 100644 index 0000000..1025611 --- /dev/null +++ b/src/disp.h @@ -0,0 +1,22 @@ +#ifndef DISP_H +#define DISP_H + +#include + +#define DISPLAY_PAGE_SWITCH_INTERVAL 5000 +#define DISPLAY_PAGE_COUNT 3 + +#define STATUS_CONNECTING_TO_WIFI 0 +#define STATUS_SENSOR_READ 1 +#define STATUS_SENDING_DATA 2 + + +//--------------------------------------------------------------------------------------- + + +void init_disp(); +void handle_disp(); +void disp_indicate_status(uint8_t status, bool value); + + +#endif diff --git a/src/hw.cpp b/src/hw.cpp new file mode 100644 index 0000000..561a143 --- /dev/null +++ b/src/hw.cpp @@ -0,0 +1,42 @@ +#include +#include "hw.h" + + +//--------------------------------------------------------------------------------------- + + +void init_hw() +{ + pinMode(LED_BLUE, OUTPUT); + pinMode(LED_RED, OUTPUT); + pinMode(LED_YELLOW, OUTPUT); + pinMode(LED_GREEN, OUTPUT); +} + + +//--------------------------------------------------------------------------------------- + + +void set_led(int led, bool value) +{ + bool invert = led == LED_BLUE; + + if (!invert) + digitalWrite(led, value ? HIGH : LOW); + else + digitalWrite(led, value ? LOW : HIGH); +} + + +//--------------------------------------------------------------------------------------- + + +void blink_led(int led, int duration) +{ + set_led(led, true); + delay(duration); + set_led(led, false); +} + + +//--------------------------------------------------------------------------------------- diff --git a/src/hw.h b/src/hw.h new file mode 100644 index 0000000..ad914a0 --- /dev/null +++ b/src/hw.h @@ -0,0 +1,35 @@ +#ifndef HW_H +#define HW_H + + +#define D0 0 +#define D1 1 +#define D2 2 +#define D3 3 +#define D4 4 +#define D5 5 +#define D6 6 +#define D7 7 +#define D8 8 +#define D9 9 +#define D10 10 +#define D11 11 +#define D12 12 +#define D13 13 +#define D14 14 +#define D15 15 + +#define LED_RED D3 +#define LED_YELLOW D4 +#define LED_GREEN D5 +#define LED_BLUE LED_BUILTIN + + +//--------------------------------------------------------------------------------------- + + +void init_hw(); +void set_led(int led, bool value); +void blink_led(int led, int duration); + +#endif diff --git a/src/measure.cpp b/src/measure.cpp new file mode 100644 index 0000000..7426430 --- /dev/null +++ b/src/measure.cpp @@ -0,0 +1,286 @@ +#include +#include +#include "defs.h" +#include "measure.h" +#include "dht_measure.h" +#include "comm.h" +#include "disp.h" + + +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature ds_sensors(&oneWire); +DallasSensorData sensor_data[MAX_SENSORS_COUNT]; +int ds_sensor_count = 0; +int ds_current_sensor = 0; + + +//--------------------------------------------------------------------------------------- + + +void assign_sensor_value(SensorData* sd, float value) +{ + // calculate average + sd->cumulative_value += value; + sd->count++; + sd->value = sd->cumulative_value / sd->count; + sd->timestamp = millis(); + sd->sent = false; + sd->valid = true; +} + + +//--------------------------------------------------------------------------------------- + + +void sensor_value_sent(SensorData* sd) +{ + sd->cumulative_value = 0; + sd->count = 0; + sd->sent = true; +} + + +//--------------------------------------------------------------------------------------- + + +void ds_address_to_str(DeviceAddress address, char *out_buff) +{ + char *p = out_buff; + + for (uint8_t i = 0; i < 8; i++, p += 2) + sprintf(p, "%02x", address[i]); +} + + +//--------------------------------------------------------------------------------------- + + +void str_to_ds_address(char* str, DeviceAddress* address) +{ + char* p_str = str; + uint8_t* p_out = address[0]; + char buff[3]; + + memset(buff, 0, sizeof(buff)); + + for (int i = 0; i < 8; i++) { + buff[0] = *p_str++; + buff[1] = *p_str++; + *p_out++ = (uint8_t)strtol(buff, NULL, 16); + } +} + + +//--------------------------------------------------------------------------------------- + + +float ds_get_sensor_value(DeviceAddress deviceAddress) +{ + return ds_sensors.getTempC(deviceAddress); +} + + +//--------------------------------------------------------------------------------------- + + +void ds_discover_sensors() +{ + int i; + char buff[100]; + DallasSensorData* sd; + + // locate devices on the bus + SERIAL_PRINT("Discovering sensors..."); + ds_sensor_count = ds_sensors.getDeviceCount(); + SERIAL_PRINT(ds_sensor_count); + SERIAL_PRINTLN(" sensors."); + // report parasite power requirements + SERIAL_PRINT("Parasite power: "); + SERIAL_PRINTLN(ds_sensors.isParasitePowerMode() ? "ON" : "OFF"); + + for (i = 0; i < ds_sensor_count; i++) + { + sd = &sensor_data[i]; + + ds_sensors.getAddress(sd->address, i); + ds_sensors.setResolution(sd->address, TEMPERATURE_PRECISION); + + ds_address_to_str(sd->address, buff); + SERIAL_PRINTF("Sensor %d, address: %s\n", i, buff); + delay(1000); + } +} + + +//--------------------------------------------------------------------------------------- + + +void init_measure() +{ + ds_sensors.begin(); + + delay(500); + ds_discover_sensors(); + delay(500); + + dht_init_measure(); + delay(500); +} + + +//--------------------------------------------------------------------------------------- + + +bool ds_is_value_valid(float value) +{ + // value == -127 -> sensor disconnected + // value == 85 -> sensor comm error, probably bad wiring + return !(value == -127 || value == 85); +} + + +//--------------------------------------------------------------------------------------- + + +void measure_next_sensor() +{ + float value; + char buff[100]; + DallasSensorData* sd; + + if (ds_sensor_count == 0) + return; + + set_led(LED_YELLOW, true); + disp_indicate_status(STATUS_SENSOR_READ, true); + + if (ds_current_sensor >= ds_sensor_count) + { + // request sensors to measure temperatures only once + ds_sensors.requestTemperatures(); + ds_current_sensor = 0; + } + + sd = &sensor_data[ds_current_sensor]; + + ds_address_to_str(sd->address, buff); + SERIAL_PRINTF("Reading sensor %d [address %s]... ", ds_current_sensor, buff); + + value = ds_get_sensor_value(sd->address); + SERIAL_PRINTF("Value: %0.2f\r\n", value); + + if (ds_is_value_valid(value)) + { + assign_sensor_value(&sd->data, value); + } else { + sd->data.valid = false; + blink_led(LED_RED, 200); + } + + ds_current_sensor++; + + set_led(LED_YELLOW, false); + disp_indicate_status(STATUS_SENSOR_READ, false); +} + + +//--------------------------------------------------------------------------------------- + + +String format_measurement_data() +{ + String res; + char address[MAX_ADDRESS_STR_LENGTH]; + char buff[200]; + int i; + DallasSensorData *sd; + int cnt = 0; + + for (i = 0; i < ds_sensor_count; i++) + { + sd = &sensor_data[i]; + + if (sd->data.valid && !sd->data.sent) + { + ds_address_to_str(sd->address, address); + sprintf( + buff, + "s%daddr=%s&s%dval=%0.2f&", + cnt, + address, + cnt, + sd->data.value + ); + // reset average calc + sensor_value_sent(&sd->data); + res += buff; + cnt++; + } + } + + pDHTSensorData dht_data = dht_get_sensors_data(); + for (i = 0; i < DHT_SENSOR_COUNT; i++) + { + // format temperature + if (dht_data->temperature.valid) { + sprintf( + buff, + "s%daddr=dht%dtemp&s%dval=%0.2f&", + cnt, + i, + cnt, + dht_data->temperature.value + ); + // reset average calc + sensor_value_sent(&dht_data->temperature); + res += buff; + cnt++; + } + + // format humidity + if (dht_data->humidity.valid) { + sprintf( + buff, + "s%daddr=dht%dhumidity&s%dval=%0.2f&", + cnt, + i, + cnt, + dht_data->humidity.value + ); + // reset average calc + sensor_value_sent(&dht_data->humidity); + res += buff; + cnt++; + } + + dht_data++; + } + + sprintf(buff, "sensor_count=%d", cnt); + res += buff; + + return res; +} + + +//--------------------------------------------------------------------------------------- + + +pSensorData get_ds_sensor_data(const char* sensor_address) { + DeviceAddress address; + DallasSensorData *sd; + + str_to_ds_address((char*)sensor_address, &address); + + for (uint8_t i = 0; i < ds_sensor_count; i++) { + sd = &sensor_data[i]; + if (memcmp(address, sd->address, sizeof(DeviceAddress)) == 0) { + return &sd->data; + } + } + + return NULL; +} + + +//--------------------------------------------------------------------------------------- diff --git a/src/measure.h b/src/measure.h new file mode 100644 index 0000000..def3863 --- /dev/null +++ b/src/measure.h @@ -0,0 +1,63 @@ +#ifndef MEASURE_H +#define MEASURE_H + +#include "hw.h" +#include +#include +#include + +#define ONE_WIRE_BUS D13 +#define TEMPERATURE_PRECISION 11 // can be 9, 10, 11 or 12 bits +#define MAX_SENSORS_COUNT 10 +#define MEASUREMENT_TIMEOUT 60000 // ms + +#define MAX_ADDRESS_STR_LENGTH 20 +#define INVALID_SENSOR_VALUE -127 + +// Sensor addresses +#define T1_ADDRESS "28ffbb19841704c3" +#define T2_ADDRESS "28ff112ca01705d0" +#define T3_ADDRESS "28ffde61a01705e0" +#define T4_ADDRESS "28ff3c09a017046b" +#define T5_ADDRESS "28ff4459a01704e0" +#define T6_ADDRESS "28ffbb19841704c3" +#define T7_ADDRESS "28ff3e69a0170478" +#define T8_ADDRESS "28ffcb4ba0170525" + + +typedef struct { + float value = INVALID_SENSOR_VALUE; + float cumulative_value = 0; + int count = 0; + long timestamp = 0; + bool sent = false; + bool valid = false; +} SensorData; + +typedef struct { + DeviceAddress address; + SensorData data; +} DallasSensorData; + +typedef struct { + DHT* sensor; + SensorData temperature; + SensorData humidity; +} DHTSensorData; + +typedef SensorData* pSensorData; +typedef DallasSensorData* pDallasSensorData; +typedef DHTSensorData* pDHTSensorData; + + +//--------------------------------------------------------------------------------------- + + +void init_measure(); +void measure_next_sensor(); +String format_measurement_data(); +void assign_sensor_value(SensorData* sensor_data, float value); +pSensorData get_ds_sensor_data(const char* sensor_address); +void str_to_ds_address(char* str, DeviceAddress* address); + +#endif diff --git a/src/teleinsektarij.ino b/src/teleinsektarij.ino new file mode 100644 index 0000000..7777afc --- /dev/null +++ b/src/teleinsektarij.ino @@ -0,0 +1,84 @@ +#include "hw.h" +#include "comm.h" +#include "measure.h" +#include "dht_measure.h" +#include "defs.h" +#include "disp.h" + +unsigned long timestamp_blink = 0; +unsigned long timestamp_http_request = 0; +unsigned long timestamp_ds_measure = 0; +unsigned long timestamp_dht_measure = 0; +bool first_loop = true; + + +//--------------------------------------------------------------------------------------- + + +void setup() +{ + init_hw(); + + #ifdef SERIAL_DEBUG + Serial.begin(SERIAL_BAUD_RATE); + Serial.setDebugOutput(true); + #endif + + init_comm(); + init_measure(); + init_disp(); + + first_loop = true; +} + + +//--------------------------------------------------------------------------------------- + + +void loop() +{ + unsigned long current_millis = millis(); + + // connect WiFi + connect_comm(); + + if (first_loop) + { + // don't allow sending data to server in the first loop + timestamp_http_request = current_millis; + first_loop = false; + } + + // indicate program run + if (current_millis - timestamp_blink > SIGNAL_LED_BLINK_INTERVAL) + { + blink_led(LED_BLUE, 50); + delay(50); + blink_led(LED_BLUE, 50); + timestamp_blink = current_millis; + } + + if (current_millis - timestamp_ds_measure > DS_MEASURE_INTERVAL) + { + measure_next_sensor(); + timestamp_ds_measure = current_millis; + } + + if (current_millis - timestamp_dht_measure > DHT_MEASURE_INTERVAL) + { + dht_read_next_sensor(); + timestamp_dht_measure = current_millis; + } + + // post data to server + if (comm_is_connected() && current_millis - timestamp_http_request > SEND_DATA_TO_SERVER_INTERVAL) + { + post_data_to_server(); + timestamp_http_request = current_millis; + } + + handle_disp(); +} + + +//--------------------------------------------------------------------------------------- diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..17115cd --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + + +#define T1_ADDRESS "28ffbb19841704c3" +#define T2_ADDRESS "28ff112ca01705d0" +#define T3_ADDRESS "28ffde61a01705e0" +#define T4_ADDRESS "28ff3c09a017046b" +#define T5_ADDRESS "28ff4459a01704e0" +#define T6_ADDRESS "28ffbb19841704c3" +#define T7_ADDRESS "28ff3e69a0170478" +#define T8_ADDRESS "28ffcb4ba0170525" + + +typedef unsigned char uint8_t; +typedef uint8_t DeviceAddress[8]; + + +int main() { + char str_address[20]; + char* p_str = str_address; + DeviceAddress out; + uint8_t* p_out = out; + char buff[3]; + + strcpy(str_address, T2_ADDRESS); + memset(buff, 0, sizeof(buff)); + + for (int i = 0; i < 8; i++) { + buff[0] = *p_str++; + buff[1] = *p_str++; + *p_out++ = (uint8_t)strtol(buff, NULL, 16); + + } + + printf("%s\n", str_address); + + for(int i = 0; i < sizeof(out); i++) { + printf("%X ", out[i]); + } + + printf("\n"); +} \ No newline at end of file diff --git a/test/makefile b/test/makefile new file mode 100644 index 0000000..cd61568 --- /dev/null +++ b/test/makefile @@ -0,0 +1,10 @@ +OOUTDIR = o/ + +output: main.o + g++ -std=c++0x -Wall $(OOUTDIR)main.o -o a.out + +main.o: main.cpp + g++ -c main.cpp -o $(OOUTDIR)main.o + +clean: + rm $(OOUTDIR)*.o a.out