• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266 и sqlite3

Народ, нашел на ютубе видео про это сочетание и решил попробовать прикрутить на свое устройство. Собственно с SQL, который Microsoft хорошо знаком и выборку на HTML + JavaScript умею делать. Осталось чтобы датчики писали данные в базу sqlite3. А вот это и не получается. Вот такой код получился на первое время, если есть баги не по sqlite3 просто не замечайте, обвес хватался из разных скетчей.

Базу я создал на компе, положил ее на ESP по FTP и пытаюсь писать в нее. Так вот когда вызывается sqlite3_exec еспешка перегружается. И когда я делаю INSERT пишет, что такой таблицы нет. А когда SELECT из этой таблицы, то не ругается на запрос. Может кто чего увидит?
Код ниже приложу. ЧТо-то не дал создать тему, мол символов много.
 
Код:
#include <sqlite3.h>
#include <vfs.h>
#include <FS.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266FtpServer.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

#define GMT 3              // смещение (москва 3)
#define NTP_ADDRESS  "europe.pool.ntp.org"    // сервер времени
#define NTP_INTERVAL 60 * 1000    // обновление (1 минута)

const byte relay = 4;
const char *ssid     = "MYWIFI"; // Для хранения SSID
const char *password = "MYPASSWORD"; // Для хранения пароля сети
const char *ssidAP = "MyESP";

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, GMT * 3600, NTP_INTERVAL);
ESP8266WebServer HTTP(80);                                              // Определяем объект и порт сервера для работы с HTTP
FtpServer ftpSrv; 
sqlite3 *db;

byte days, hs, ms, ss, my, dm;
int yy;

void setup() {
   Serial.begin(9600);
   pinMode(relay,OUTPUT);
  
WiFi.mode(WIFI_STA);
  byte tries = 50;
  WiFi.begin(ssid, password);
  while (--tries && WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("");
    Serial.println("WiFi up AP");
    WiFi.softAP(ssidAP);                                                    // Создаём точку доступа
  }
  else {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
 
  system_update_cpu_freq(SYS_CPU_160MHZ); 
  SPIFFS.begin();
  HTTP.begin(); 
  ftpSrv.begin("relay","relay");

  Serial.print("\nMy IP to connect via Web-Browser or FTP: ");
  Serial.println(WiFi.softAPIP());
  Serial.println("\n");

  timeClient.begin();

// Обработка HTTP-запросов
  HTTP.on("/relay_switch", [](){
      HTTP.send(200, "text/plain", relay_switch());
  });
  HTTP.on("/relay_status", [](){
      HTTP.send(200, "text/plain", relay_status());
  });
  HTTP.onNotFound([](){
  if(!handleFileRead(HTTP.uri()))
      HTTP.send(404, "text/plain", "Not Found");
  });


//   SPIFFS.remove("/db.db");

   sqlite3_initialize();
}

void loop() {
  timeClient.update();
  hs = timeClient.getHours();
  ms = timeClient.getMinutes();
  ss = timeClient.getSeconds();
  getDTString();
//  Serial.println(String(hs) + ":" + String(ms) + ":" + String(ss) + " " + String(dm) + "/" + String(my) + "/" + String(yy));
  if (Serial.available() > 0) {
    String str = Serial.readString();
    if (str != "")
    {
      char query[str.length() + 1];
      strcpy(query, str.c_str());
      str = "";
      db_exec(db, query);
     }
  }
  delay(10);
  HTTP.handleClient();
  ftpSrv.handleFTP();
}

void db_exec(sqlite3 *db, const char *sql) {
   const char *dbf = "/weather.sql3";
   char *ErrMsg = 0;
   const char* data = 0;
   Serial.println(sql);
   File db_file_obj;
   vfs_set_spiffs_file_obj(&db_file_obj);
   if (sqlite3_open(dbf, &db)) {
       Serial.print(F("Can't open database: "));
       Serial.println(sqlite3_errmsg(db));
       return;
   }
   else {Serial.println("DB opened");}
   Serial.println(sql);
   long start = millis();
   int rc = sqlite3_exec(db, sql, callback, (void*)data, &ErrMsg);
   if (rc != SQLITE_OK) {
       Serial.print(F("SQL error: "));
       Serial.println(ErrMsg);
       sqlite3_free(ErrMsg);
   } else {
      Serial.print(F("Done. Time taken: "));
       Serial.print(millis()-start);
       Serial.println(F(" ms"));
       Serial.println();
   }
   Serial.println(rc);
   sqlite3_close(db); 
}

static int callback(void *data, int argc, char **argv, char **azColName) {
   for (int i = 0; i < argc; i++){
//  Serial.printf("%s = %s\n", azColName[i], argv[i]);
    if (i > 0)
      Serial.print(" | ");
    Serial.print(argv[i]); 
   }
   Serial.println();
   return 0;
}

String relay_switch() {
  byte state;
  if (digitalRead(relay))
    state = 0;
  else
    state = 1;
  digitalWrite(relay, state);
  Serial.println(String(hs) + ":" + String(ms) + ":" + String(ss) + " " + String(dm) + "/" + String(my - 1) + "/" + String(yy));
//  String str = "INSERT INTO pokazaniya (cday, cmonth, cyear, chour, tin, tout, vlag, davl) VALUES (" + String(dm) + ", " + String(my) + ", " + String(yy) + ", " + String(hs) + ", 29.4, -4.5, 15, 745)";
//  String str = "INSERT INTO pokazaniya VALUES (" + String(dm) + ", " + String(my) + ", " + String(yy) + ", " + String(hs) + ", 29.4, -4.5, 15, 745)";
  String str = "SELECT * FROM pokazaniya WHERE cday = 21";
  char query[str.length() + 1];
  db_exec(db, str.c_str());
  return String(state);
}

String relay_status() {
  byte state;
  if (digitalRead(relay))
    state = 1;
  else
    state = 0;
  return String(state);
}

bool handleFileRead(String path){
  if(path.endsWith("/")) path += "index.html";
  String contentType = getContentType(path);
  if(SPIFFS.exists(path)){
    File file = SPIFFS.open(path, "r");
    size_t sent = HTTP.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false; 
}

String getContentType(String filename){
  if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".jpg")) return "image/jpeg";
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  return "text/plain";
}

void getDTString() {
  unsigned long rawTime = (timeClient.getEpochTime()) / 86400L;  // in days
  unsigned long days = 0, yr = 1970;
  uint8_t month;

  while((days += (LEAP_YEAR(yr) ? 366 : 365)) <= rawTime)
    yr++;
  rawTime -= days - (LEAP_YEAR(yr) ? 366 : 365); // now it is days in this year, starting at 0
  days=0;
  for (month=0; month<12; month++) {
    uint8_t monthLength;
    if (month==1) { // february
      monthLength = LEAP_YEAR(yr) ? 29 : 28;
    } else {
      //monthLength = monthDays[month];
    }
    if (rawTime < monthLength) break;
    rawTime -= monthLength;
  }
  yy = yr;
  my = month+1;
  dm = rawTime+1;
//  DayOfWeek = weekDays[timeClient.getDay()];
//  MonthOfYear = monthNames[my-1];
 
//  String monthStr = ++month < 10 ? "0" + String(month) : String(month); // jan is month 1 
//  String dayStr = ++rawTime < 10 ? "0" + String(rawTime) : String(rawTime); // day of month 
//  return String(yr) + "-" + monthStr + "-" + dayStr + "T" + timeClient.getFormattedTime(ss ? ss : 0) + "Z";
}

int openDb(const char *filename, sqlite3 **db) {
  int rc = sqlite3_open(filename, db);
  if (rc) {
      Serial.printf("Can't open database: %s\n", sqlite3_errmsg(*db));
      return rc;
  } else {
      Serial.printf("Opened database successfully\n");
  }
  return rc;
}
Вот код. МОжет тут лишнее осталось.
 

pvvx

Активный участник сообщества
"Размер стека ядра ESP8266 Arduino должен быть увеличен как минимум до 6144 байта для извлечения данных из образцов баз данных, поскольку они довольно большие."
 
"Размер стека ядра ESP8266 Arduino должен быть увеличен как минимум до 6144 байта для извлечения данных из образцов баз данных, поскольку они довольно большие."
Вот спасибо! Только прочитал ваш пост, сразу вспомнил, что в видео об этом говорили. Увеличил. Теперь не перегружается. Но теперь просто пишет:
DB opened
SELECT * FROM pokazaniya WHERE cday = 21
SQL error: no such table: pokazaniya
Хотя на компе запрос срабатывает.
 
Заработало. Видно кодировки чтоль разные. Когда создал таблицу в Arduino ide все заработало. Осталось разобраться с автоинкрементным ключем, что-то не приняло при создании таблицы это значение. А так можно работать.
 
Разобрался с автоинкрементом. Напишу, если кому будет интересно.
1. AUTOINCREMENT вообще не указывается. Надо просто указать _id INTEGER PRIMARY KEY NOT NUL и оно будет автоинкрементом.
2. Конструкция INSERT INTO tbl VALUES (1, 2, 3) не работает. Ругается, что полей больше чем указано (ну мы же не пишем значение которое будет автоинкрементно записано). Только полностью писать надо
INSERT INTO tbl (fld1, fld2, fld3) VALUES (1,2,3). Так работает.
 
Теперь все бы хорошо, но пытаюсь открыть эту базу sqlite3 из html страницы с помощью javascript и нифига не получается. Нет, можно конечно считать данные с помощью скетча и потом уже передать их на обработку в html страницу и построить из них таблицу или график, но хочется напрямую из html обратиться к БД. Может кто подскажет как это можно сделать? Я работал только с PHP, но тут то это не прокатит.
 

CodeNameHawk

Moderator
Команда форума
Теперь все бы хорошо, но пытаюсь открыть эту базу sqlite3 из html страницы с помощью javascript и нифига не получается.
Напишите скетч, что бы JS работал на есп, может что и получится.
но хочется напрямую из html обратиться к БД.
Что значит напрямую, мимо самой есп, мимо прошивки есп(скетча), как вы это себе представляете?
 
Что значит напрямую, мимо самой есп, мимо прошивки есп(скетча), как вы это себе представляете?
Ну скажем если бы я хотел, чтобы просто на странице под текущими показаниями автоматом по событию On Open сама html страничка обращалась к базе и рисовала табличку.
 

CodeNameHawk

Moderator
Команда форума
я хотел, чтобы просто на странице под текущими показаниями автоматом по событию On Open сама html страничка обращалась к базе и рисовала табличку.
Если страничка а самой есп, по идее ничего не мешает вам это сделать.
 
раничка а самой есп, по идее ничего не мешает вам это сделать.
Наверное. Только как? Лазаю со вчерашнего дня. Везде только подключение с помощью node.js. Просто JavaScript такое ощущение, что не может к базе обратится. Я во всяком случае ни одного примера не нашел.
Есть еще PHP, там все просто, но это серверная платформа.
 

CodeNameHawk

Moderator
Команда форума

pvvx

Активный участник сообщества
js + websocket2sqlite наверно самое простое...

В HTML5 вроде нет и не будет sql

Есть такое:
 
Всем привет! Практически закончил курсы! :ROFLMAO: Проходил их на ютубе. Там два товарища подробные уроки по управлению веб страницами выложили. Вот тут. Рассказывает хорошо. Но минус в том, что пропал где-то год назад и он и товарищь с которым он работал. Ответов на вопросы не получишь. Ну на сколько я понял WebSocket для непосредственного обмена данными с дейвайса и веб страницы. А мне надо как-то прочитать таблицу sqlite3. еще мне понравились у них живые графики. Хорошо, подошло бы, но мне хочется брать историю из базы, а там график строится начиная с момента захода на страницу.
 
Народ, столкнулся с проблемой. Посмотрел тут видео и подумал, может JSON использовать вместо sqlite3. Но почему-то не могусо страницы, с помощью javascript прочитать файлю Нашел кучу примеров, даже смог прочитать файл выложеный в инете, а вот локально никак. При чем на тех курсах, что я смотрел, и в их примерах, все прекрасно читается. Но у них там своя система какая-то. Ковыряю их исходники, но пока глухо. Можете пример чтения JSON файла в JavaScript выложить?
 
JSON прочитал. 😁 Оказалось, что простого имени файла недостаточно. Нужно именно как полную WEB ссылку писать, тогда все читается.
Теперь надо по нажатию кнопки на странице сохранить в JSON файл изменения. Опять торможу. День сегодня сижу и не могу сделать. Хотя в тех курсах все работало. Но в их исходниках тяжко разбираться, а автары пропали и молчат. Может кто сдесь поможет? Хотя надежды мало. По чтению никто не подсказал, а запись по сложнее будет.
 
Сверху Снизу