mirror of
https://github.com/SasaKaranovic/HousePlantMonitoringSystem.git
synced 2026-07-08 17:52:37 +02:00
Merge pull request #2 from SasaKaranovic/AdjustableFlow
Adding adjustable flow and logging.
This commit is contained in:
@@ -1,15 +1,27 @@
|
||||
#include <EEPROM.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include "WiFi.h"
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#include <esp_task_wdt.h>
|
||||
#include "CentralUnit_cfg.h"
|
||||
#include "wifi_credentials.h"
|
||||
#include "PlantSystem.h"
|
||||
#include "Wire.h"
|
||||
#include "time.h"
|
||||
#include <WiFiUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
|
||||
#define WDT_TIMEOUT 20000
|
||||
#define EEPROM_SIZE 4
|
||||
|
||||
const char* ntpServer = "pool.ntp.org";
|
||||
const long gmtOffset_sec = -18000;
|
||||
const int daylightOffset_sec = 3600;
|
||||
|
||||
AsyncWebServer server(80);
|
||||
int WiFi_status = WL_IDLE_STATUS;
|
||||
volatile uint32_t nFlowSensorCount = 0;
|
||||
@@ -17,12 +29,37 @@ volatile uint32_t nFlowSensorCount_last = 0;
|
||||
|
||||
char dbgBuff[4024] = {0};
|
||||
uint32_t dbgBuffPos = 0;
|
||||
float fImpulsePerML = 0;
|
||||
float fImpulsePerML = WATERING_FLOW_EDGES_PER_mL;
|
||||
|
||||
void IRAM_ATTR ISR_flowSensor() {
|
||||
nFlowSensorCount++;
|
||||
}
|
||||
|
||||
// Function prototypes
|
||||
void ps_debug_log_reset_Reason(RESET_REASON reason);
|
||||
void ps_debug_log_verbose_reset_reason(RESET_REASON reason);
|
||||
int vprintf_into_spiffs(const char* szFormat, va_list args);
|
||||
void printLocalTime();
|
||||
void LOG_Timestamp(void);
|
||||
void setupWebServer(void);
|
||||
void flowInterruptEnabled(bool state);
|
||||
void LED_Blink(uint8_t nTimes, uint16_t n_delayPeriod);
|
||||
void PlantSystem_tick(void);
|
||||
void PlantSystem_ScanBus(void);
|
||||
void PlantSystem_debugShowDevicesOnBus(void);
|
||||
void PlantSystem_getDeviceInfo(uint8_t devID);
|
||||
bool PlantSystem_SetSolenoidState(uint32_t I2CAddress, bool energized);
|
||||
void PlantSystem_UpdateSensors(void);
|
||||
void I2C_SendBuffer(uint8_t address, uint8_t *pBuffer, uint8_t nLen);
|
||||
bool I2C_ReadFrom(uint8_t address, uint8_t nLen, uint8_t *pData, uint8_t nPos, uint8_t nBytes);
|
||||
bool PlantSystem_WaterPlant(uint8_t solenoidAddress, uint32_t n_volume_in_mL);
|
||||
void PlantSystem_RequestPrimeSystem(void);
|
||||
bool PlantSystem_PrimeSystemWithWater(void);
|
||||
bool PlantSystem_WAPI_GetDevices(char *pBuff, uint32_t nMaxLen);
|
||||
bool PlantSystem_WAPI_SensorData(char *pBuff, uint32_t nMaxLen);
|
||||
bool PlantSystem_WAPI_SolenoidList(char *pBuff, uint32_t nMaxLen);
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
@@ -41,6 +78,35 @@ void setup()
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup Logging
|
||||
if (!SPIFFS.begin(true)) {
|
||||
Serial.println("An Error has occurred while mounting SPIFFS");
|
||||
while(1)
|
||||
{
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("SPIFFS mounted");
|
||||
|
||||
}
|
||||
|
||||
delay(500);
|
||||
esp_log_set_vprintf(&vprintf_into_spiffs);
|
||||
esp_log_level_set("*", ESP_LOG_DEBUG);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- SPIFFS Boot up\n");
|
||||
|
||||
// Log reset reason
|
||||
Serial.println("Storing reason in log.txt");
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- CPU0 ");
|
||||
ps_debug_log_verbose_reset_reason(rtc_get_reset_reason(0));
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- CPU1 ");
|
||||
ps_debug_log_verbose_reset_reason(rtc_get_reset_reason(1));
|
||||
|
||||
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
|
||||
|
||||
// EEPROM begin
|
||||
@@ -56,6 +122,7 @@ void setup()
|
||||
// Debug EEPROM after read
|
||||
Serial.println("After read: fImpulsePerML");
|
||||
Serial.println((float)(fImpulsePerML),4);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- fImpulsePerML: %f\n", fImpulsePerML);
|
||||
|
||||
|
||||
// Configure WDT
|
||||
@@ -64,25 +131,105 @@ void setup()
|
||||
esp_task_wdt_add(NULL); //add current thread to WDT watch
|
||||
|
||||
// Connect to WiFi
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Configuring WiFi.\n");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setHostname("sk_watering_system");
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Connecting to WiFi...\n");
|
||||
while ( WiFi_status != WL_CONNECTED) {
|
||||
Serial.print("Connecting to SSID: ");
|
||||
Serial.println(ssid);
|
||||
WiFi_status = WiFi.begin(ssid, password);
|
||||
|
||||
// wait 5 seconds for connection:
|
||||
esp_task_wdt_reset();
|
||||
delay(5000);
|
||||
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(500);
|
||||
}
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Connected.\n");
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
Serial.print("WiFi IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.print("Hostname: ");
|
||||
Serial.println(WiFi.getHostname());
|
||||
|
||||
char cIP_buff[50] = {0};
|
||||
String sIP = WiFi.localIP().toString();
|
||||
sIP.toCharArray(cIP_buff, 50);
|
||||
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- WiFi IP: %s\n", cIP_buff);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- WiFi hostname: %s\n",WiFi.getHostname());
|
||||
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- mDNS started\n");
|
||||
|
||||
// Update time
|
||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||
printLocalTime();
|
||||
LOG_Timestamp();
|
||||
|
||||
// Config printout
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "\n-- I2C_BUS_RESCAN_ENABLED=%d\n", I2C_BUS_RESCAN_ENABLED);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- PERIOD_RESCAN_BUS=%d\n", PERIOD_RESCAN_BUS);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- PERIOD_RELOAD_SENSORS=%d\n", PERIOD_RELOAD_SENSORS);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- FLOW_RATE_DEBUG_ENABLED=%d\n", FLOW_RATE_DEBUG_ENABLED);
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- PERIOD_FLOW_RATE_DEBUG=%d\n\n", PERIOD_FLOW_RATE_DEBUG);
|
||||
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
setupWebServer();
|
||||
server.begin();
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Started web server.\n");
|
||||
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
|
||||
ArduinoOTA.setHostname("WateringSystem");
|
||||
ArduinoOTA.setPassword("Tr6spEh1");
|
||||
|
||||
ArduinoOTA
|
||||
.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||
{
|
||||
type = "sketch";
|
||||
}
|
||||
else // U_SPIFFS
|
||||
{
|
||||
type = "filesystem";
|
||||
SPIFFS.end();
|
||||
}
|
||||
|
||||
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
||||
Serial.println("Start updating " + type);
|
||||
})
|
||||
.onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
})
|
||||
.onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
|
||||
ArduinoOTA.begin();
|
||||
|
||||
flowInterruptEnabled(true);
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Leaving setup.\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -101,10 +248,8 @@ void flowInterruptEnabled(bool state)
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
PlantSystem_tick();
|
||||
}
|
||||
ArduinoOTA.handle();
|
||||
PlantSystem_tick();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +271,39 @@ void setupWebServer(void)
|
||||
});
|
||||
|
||||
|
||||
// Read log.txt
|
||||
server.on("/log.txt", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if(SPIFFS.exists("/log.txt"))
|
||||
{
|
||||
Serial.println("Log.txt request received");
|
||||
request->send(SPIFFS, "/log.txt", "text/plain");
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(200, "text/plain", "log.txt not found.");
|
||||
}
|
||||
});
|
||||
|
||||
// Delete /log.txt
|
||||
server.on("/delete_log", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
Serial.println("Delete Log.txt request received");
|
||||
if(SPIFFS.exists("/log.txt"))
|
||||
{
|
||||
File writeLog = SPIFFS.open("/log.txt", FILE_WRITE);
|
||||
if(!writeLog) Serial.println("Couldn't open log.txt");
|
||||
delay(50);
|
||||
LOG_Timestamp();
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- Log wiped.\n");
|
||||
writeLog.close();
|
||||
request->send(200, "text/plain", "log.txt reset");
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(200, "text/plain", "log.txt not found.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Get sensors on the bus
|
||||
server.on("/sensorData", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
Serial.println("Sensor data");
|
||||
@@ -181,7 +359,7 @@ void setupWebServer(void)
|
||||
}
|
||||
});
|
||||
|
||||
// Get devices on the bus
|
||||
// Get number of flow sensor ticks for last watering action
|
||||
server.on("/flowSensor", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
Serial.println("Flow sensor data");
|
||||
|
||||
@@ -203,7 +381,7 @@ void setupWebServer(void)
|
||||
});
|
||||
|
||||
|
||||
// Get devices on the bus
|
||||
// Set solenoid state
|
||||
server.on("/setSolenoid", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
Serial.println("Set solenoid to state");
|
||||
|
||||
@@ -261,11 +439,12 @@ void setupWebServer(void)
|
||||
if(PlantSystem_WaterPlant(nAddress, nVolume) == true)
|
||||
{
|
||||
char buff[200] = {0};
|
||||
int len;
|
||||
int len = 0;
|
||||
|
||||
len = snprintf(buff, 200, "{ \"result\": OK, \"Address\":%d, \"Volume\":%d }",
|
||||
nAddress, nVolume);
|
||||
request->send(200, "text/plain", buff);
|
||||
UNUSED(len);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -292,10 +471,12 @@ void setupWebServer(void)
|
||||
return;
|
||||
});
|
||||
|
||||
// Calibrate flow sensor
|
||||
// Calibrate flow sensor or read current value
|
||||
server.on("/calibrateFlowSensor", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
Serial.println("Calibrate edges per mL");
|
||||
|
||||
char buff[200] = {0};
|
||||
|
||||
if ( request->hasParam("edges") )
|
||||
{
|
||||
String xEdges;
|
||||
@@ -312,12 +493,14 @@ void setupWebServer(void)
|
||||
Serial.print("Changing fImpulsePerML to ");
|
||||
Serial.println((float)(fImpulsePerML),4);
|
||||
|
||||
request->send(200, "text/plain", "OK");
|
||||
snprintf(buff, 200, "New value set to %f", fEdges);
|
||||
request->send(200, "text/plain", buff);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(404, "text/plain", "MISSING_ARGUMENT");
|
||||
snprintf(buff, 200, "Current value is %f\r\nLast impulse count was: %d", fImpulsePerML, nFlowSensorCount_last);
|
||||
request->send(200, "text/plain", buff);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,4 +10,59 @@
|
||||
#define WATER_PUMP_EN_PIN 12
|
||||
#define FLOW_SENSOR_PIN 26
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(x) ((void)(x))
|
||||
#endif
|
||||
|
||||
// Typedefs to allow us easier tracking on devices on the bus and storing received data
|
||||
typedef struct I2C_Device_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
uint8_t deviceType;
|
||||
} I2C_Device_TypeDef;
|
||||
|
||||
typedef struct I2C_Sensor_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
float temperature;
|
||||
uint32_t soilMoisture;
|
||||
uint32_t ambienLight;
|
||||
} I2C_Sensor_TypeDef;
|
||||
|
||||
typedef struct I2C_Solenoid_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
uint8_t lastState;
|
||||
} I2C_Solenoid_TypeDef;
|
||||
|
||||
// I2C bus config
|
||||
#define I2C_MAX_SENSORS_ON_BUS 20
|
||||
#define I2C_MAX_SOLENOIDS_ON_BUS 20
|
||||
#define I2C_MAX_DEVICES_ON_BUS (I2C_MAX_SENSORS_ON_BUS + I2C_MAX_SOLENOIDS_ON_BUS)
|
||||
#define I2C_ADDRESS_LIMIT_LOWER 0x08
|
||||
#define I2C_ADDRESS_LIMIT_UPPER 0x7F
|
||||
|
||||
// Plant watering definitions
|
||||
#define WATERING_VOLUME_MINIMUM 10
|
||||
#define WATERING_VOLUME_MAXIMUM 550
|
||||
#define WATERING_FLOW_EDGES_PER_mL 4
|
||||
|
||||
// Sanity checks
|
||||
#if (WATERING_VOLUME_MINIMUM <= 0)
|
||||
#error "WATERING_VOLUME_MINIMUM has to be non-zero positive (unsigned int) value!"
|
||||
#endif
|
||||
#if (WATERING_VOLUME_MAXIMUM <= 0)
|
||||
#error "WATERING_VOLUME_MAXIMUM has to be non-zero positive (unsigned int) value!"
|
||||
#endif
|
||||
#if (WATERING_FLOW_EDGES_PER_mL <= 0)
|
||||
#error "WATERING_FLOW_EDGES_PER_mL has to be non-zero positive (float) value!"
|
||||
#endif
|
||||
|
||||
// PlantSystem_tick periods and debug
|
||||
#define I2C_BUS_RESCAN_ENABLED 0 // Define to enable I2C bus periodic rescan
|
||||
#define PERIOD_RESCAN_BUS 24*3600*1000 // Every PERIOD_RESCAN_BUS miliseconds perform I2C bus rescan
|
||||
#define PERIOD_RELOAD_SENSORS 15*1000 // Every PERIOD_RELOAD_SENSORS miliseconds poll data from sensors
|
||||
#define FLOW_RATE_DEBUG_ENABLED 0 // Define to enable periodic flow rate debug serial printouts
|
||||
#define PERIOD_FLOW_RATE_DEBUG 2*1000 // Every PERIOD_FLOW_RATE_DEBUG print out flow rate values (used for debug)
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,20 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
// CMD (1byte) + DATATYPE (1byte) + DATALEN (2bytes)
|
||||
#define PLANTSYSTEM_MIN_HEADER_LENGHT 4
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
static char log_print_buffer[512];
|
||||
|
||||
int vprintf_into_spiffs(const char* szFormat, va_list args) {
|
||||
//write evaluated format string into buffer
|
||||
int ret = vsnprintf (log_print_buffer, sizeof(log_print_buffer), szFormat, args);
|
||||
|
||||
//output is now in buffer. write to file.
|
||||
if(ret >= 0) {
|
||||
if(!SPIFFS.exists("/log.txt"))
|
||||
{
|
||||
File writeLog = SPIFFS.open("/log.txt", FILE_WRITE);
|
||||
if(!writeLog) Serial.println("Couldn't open log.txt");
|
||||
delay(50);
|
||||
writeLog.close();
|
||||
}
|
||||
|
||||
File spiffsLogFile = SPIFFS.open("/log.txt", FILE_APPEND);
|
||||
//debug output
|
||||
//printf("[Writing to SPIFFS] %.*s", ret, log_print_buffer);
|
||||
spiffsLogFile.write((uint8_t*) log_print_buffer, (size_t) ret);
|
||||
//to be safe in case of crashes: flush the output
|
||||
spiffsLogFile.flush();
|
||||
spiffsLogFile.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printLocalTime(){
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo)){
|
||||
Serial.println("Failed to obtain time");
|
||||
return;
|
||||
}
|
||||
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
|
||||
}
|
||||
|
||||
|
||||
void LOG_Timestamp(void)
|
||||
{
|
||||
time_t now;
|
||||
char strftime_buf[64];
|
||||
struct tm timeinfo;
|
||||
|
||||
time(&now);
|
||||
// Set timezone to China Standard Time
|
||||
setenv("TZ", "CST-8", 1);
|
||||
tzset();
|
||||
|
||||
localtime_r(&now, &timeinfo);
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Date/time is: %s", strftime_buf);
|
||||
}
|
||||
|
||||
void ps_debug_log_reset_Reason(RESET_REASON reason)
|
||||
{
|
||||
switch ( reason)
|
||||
{
|
||||
case 1 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: POWERON_RESET\n");break; /**<1, Vbat power on reset*/
|
||||
case 3 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: SW_RESET\n");break; /**<3, Software reset digital core*/
|
||||
case 4 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: OWDT_RESET\n");break; /**<4, Legacy watch dog reset digital core*/
|
||||
case 5 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: DEEPSLEEP_RESET\n");break; /**<5, Deep Sleep reset digital core*/
|
||||
case 6 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: SDIO_RESET\n");break; /**<6, Reset by SLC module, reset digital core*/
|
||||
case 7 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: TG0WDT_SYS_RESET\n");break; /**<7, Timer Group0 Watch dog reset digital core*/
|
||||
case 8 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: TG1WDT_SYS_RESET\n");break; /**<8, Timer Group1 Watch dog reset digital core*/
|
||||
case 9 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTCWDT_SYS_RESET\n");break; /**<9, RTC Watch dog Reset digital core*/
|
||||
case 10 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: INTRUSION_RESET\n");break; /**<10, Instrusion tested to reset CPU*/
|
||||
case 11 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: TGWDT_CPU_RESET\n");break; /**<11, Time Group reset CPU*/
|
||||
case 12 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: SW_CPU_RESET\n");break; /**<12, Software reset CPU*/
|
||||
case 13 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTCWDT_CPU_RESET\n");break; /**<13, RTC Watch dog Reset CPU*/
|
||||
case 14 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: EXT_CPU_RESET\n");break; /**<14, for APP CPU, reseted by PRO CPU*/
|
||||
case 15 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTCWDT_BROWN_OUT_RESET\n");break;/**<15, Reset when the vdd voltage is not stable*/
|
||||
case 16 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTCWDT_RTC_RESET\n");break; /**<16, RTC Watch dog reset digital core and rtc module*/
|
||||
default : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: NO_MEAN\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ps_debug_log_verbose_reset_reason(RESET_REASON reason)
|
||||
{
|
||||
switch ( reason)
|
||||
{
|
||||
case 1 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Vbat power on reset\n");break;
|
||||
case 3 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Software reset digital core\n");break;
|
||||
case 4 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Legacy watch dog reset digital core\n");break;
|
||||
case 5 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Deep Sleep reset digital core\n");break;
|
||||
case 6 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Reset by SLC module, reset digital core\n");break;
|
||||
case 7 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Timer Group0 Watch dog reset digital core\n");break;
|
||||
case 8 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Timer Group1 Watch dog reset digital core\n");break;
|
||||
case 9 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTC Watch dog Reset digital core\n");break;
|
||||
case 10 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Instrusion tested to reset CPU\n");break;
|
||||
case 11 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Time Group reset CPU\n");break;
|
||||
case 12 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Software reset CPU\n");break;
|
||||
case 13 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTC Watch dog Reset CPU\n");break;
|
||||
case 14 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: for APP CPU, reseted by PRO CPU\n");break;
|
||||
case 15 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: Reset when the vdd voltage is not stable\n");break;
|
||||
case 16 : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: RTC Watch dog reset digital core and rtc module\n");break;
|
||||
default : esp_log_write(ESP_LOG_INFO, "SKWS", "Reset: NO_MEAN\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,18 @@
|
||||
// Plant system note
|
||||
// CMD (1byte) + DATATYPE (1byte) + DATALEN (2bytes)
|
||||
#include "CentralUnit_cfg.h"
|
||||
|
||||
|
||||
// Typedefs to allow us easier tracking on devices on the bus and storing received data
|
||||
typedef struct I2C_Device_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
uint8_t deviceType;
|
||||
} I2C_Device_TypeDef;
|
||||
|
||||
typedef struct I2C_Sensor_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
float temperature;
|
||||
uint32_t soilMoisture;
|
||||
uint32_t ambienLight;
|
||||
} I2C_Sensor_TypeDef;
|
||||
|
||||
typedef struct I2C_Solenoid_TypeDef
|
||||
{
|
||||
uint8_t i2cAddress;
|
||||
uint8_t lastState;
|
||||
} I2C_Solenoid_TypeDef;
|
||||
|
||||
// Every device that we saw on the bus
|
||||
I2C_Device_TypeDef gDevicesOnBus[250] = { {.i2cAddress=0, .deviceType=0} };
|
||||
I2C_Device_TypeDef gDevicesOnBus[I2C_MAX_DEVICES_ON_BUS] = { {.i2cAddress=0, .deviceType=0} };
|
||||
uint8_t gDevicesOnBusCount = 0;
|
||||
|
||||
// All sensors that are registered on the bus
|
||||
I2C_Sensor_TypeDef gSensorsOnBus[20] = { {.i2cAddress=0, .temperature=0.0, .soilMoisture=0, .ambienLight=0} };
|
||||
I2C_Sensor_TypeDef gSensorsOnBus[I2C_MAX_SENSORS_ON_BUS] = { {.i2cAddress=0, .temperature=0.0, .soilMoisture=0, .ambienLight=0} };
|
||||
uint8_t gnSensorsOnBusCnt = 0;
|
||||
|
||||
// All solenoids that are on the bus
|
||||
I2C_Solenoid_TypeDef gSolenoidsOnBus[20] = { {.i2cAddress=0, .lastState=0} };
|
||||
I2C_Solenoid_TypeDef gSolenoidsOnBus[I2C_MAX_SOLENOIDS_ON_BUS] = { {.i2cAddress=0, .lastState=0} };
|
||||
uint8_t gnSolenoidsOnBusCnt = 0;
|
||||
|
||||
// I2C bus config
|
||||
#define I2C_ADDRESS_LIMIT_LOWER 0x08
|
||||
#define I2C_ADDRESS_LIMIT_UPPER 0x7F
|
||||
|
||||
// Plant watering definitions
|
||||
#define WATERING_VOLUME_MINIMUM 10
|
||||
#define WATERING_VOLUME_MAXIMUM 550
|
||||
#define WATERING_FLOW_EDGES_PER_L 5880 //98
|
||||
|
||||
// PlantSystem_tick periods
|
||||
#define PERIOD_RESCAN_BUS 24*3600*1000 // Every 24h
|
||||
#define PERIOD_RELOAD_SENSORS 15*1000 // Every 5sec
|
||||
#define PERIOD_FLOW_RATE 2*1000 // Every 2sec
|
||||
|
||||
// PlantSystem_tick global variables
|
||||
uint32_t nPeriod_Rescanbus=0;
|
||||
uint32_t nPeriod_ReloadSensors=0;
|
||||
@@ -59,6 +23,7 @@ bool bPrimeSystem_requestPending=false;
|
||||
bool bWatering_requestPending=false;
|
||||
bool bWatering_inProgress=false;
|
||||
bool bCloseValvesOnPowerUp=false;
|
||||
bool bI2CBusScanned=false;
|
||||
uint32_t nWatering_volume=0;
|
||||
uint8_t nWatering_i2cAddress=0;
|
||||
uint32_t nTimeout = 0;
|
||||
@@ -69,16 +34,25 @@ void PlantSystem_tick(void)
|
||||
bool bWateringError = false;
|
||||
esp_task_wdt_reset();
|
||||
|
||||
// -- Rescan I2C bus
|
||||
if(nPeriod_Rescanbus <= millis())
|
||||
// -- Initial I2C scan
|
||||
if(bI2CBusScanned == false)
|
||||
{
|
||||
esp_task_wdt_reset();
|
||||
PlantSystem_ScanBus();
|
||||
PlantSystem_debugShowDevicesOnBus();
|
||||
bI2CBusScanned = true;
|
||||
}
|
||||
|
||||
// -- I2C periodic rescan
|
||||
#if (I2C_BUS_RESCAN_ENABLED != 0)
|
||||
if(nPeriod_Rescanbus <= millis())
|
||||
{
|
||||
esp_task_wdt_reset();
|
||||
PlantSystem_ScanBus();
|
||||
#if 1
|
||||
PlantSystem_debugShowDevicesOnBus();
|
||||
#endif
|
||||
nPeriod_Rescanbus = millis() + PERIOD_RESCAN_BUS;
|
||||
}
|
||||
#endif
|
||||
|
||||
// -- Reload sensor data
|
||||
if(nPeriod_ReloadSensors <= millis())
|
||||
@@ -112,13 +86,13 @@ void PlantSystem_tick(void)
|
||||
bCloseValvesOnPowerUp = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if (FLOW_RATE_DEBUG_ENABLED != 0)
|
||||
// -- Flow sensor debug
|
||||
if(nPeriod_FlowRate <= millis())
|
||||
{
|
||||
Serial.print("nFlowSensorCount: ");
|
||||
Serial.println(nFlowSensorCount, DEC);
|
||||
nPeriod_FlowRate = millis() + PERIOD_FLOW_RATE;
|
||||
nPeriod_FlowRate = millis() + PERIOD_FLOW_RATE_DEBUG;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -150,14 +124,15 @@ void PlantSystem_tick(void)
|
||||
digitalWrite(WATER_PUMP_EN_PIN, LOW);
|
||||
Serial.println("Turning pump OFF");
|
||||
Serial.println("Failed to open solenoid. Aborting...");
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- Failed to open solenoid 0x%02X. Aborting...\n", nWatering_i2cAddress);
|
||||
LED_Blink(4, 250);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
delay(2000);
|
||||
// - Reset flow counter
|
||||
nFlowSensorCount = 0;
|
||||
nFlowSensorCount_last = 0;
|
||||
flowInterruptEnabled(true);
|
||||
|
||||
// - Turn ON pump
|
||||
@@ -166,12 +141,12 @@ void PlantSystem_tick(void)
|
||||
digitalWrite(WATER_PUMP_EN_PIN, HIGH);
|
||||
|
||||
esp_task_wdt_reset();
|
||||
nTimeout = millis() + 10000; // 10sec time-out for watering
|
||||
nTimeout = millis() + 20000; // 20sec time-out for watering
|
||||
|
||||
// Calculate water flow
|
||||
uint32_t nWaterFlow_millis_timestamp = millis();
|
||||
float flowMilliLitres = 0.0;
|
||||
unsigned long totalMilliLitres = 0;
|
||||
uint32_t totalMilliLitres = 0;
|
||||
|
||||
// Wait until target mL or timeout is reached
|
||||
while(millis() < nTimeout)
|
||||
@@ -183,6 +158,12 @@ void PlantSystem_tick(void)
|
||||
flowInterruptEnabled(false);
|
||||
|
||||
// Update mL
|
||||
if(fImpulsePerML <= 0)
|
||||
{
|
||||
Serial.println("Invalid fImpulsePerML value! Please calibrate flow sensor!");
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- Invalid fImpulsePerML value (fImpulsePerML=%f)! Please calibrate flow sensor!\n", fImpulsePerML);
|
||||
fImpulsePerML = 100;
|
||||
}
|
||||
flowMilliLitres = nFlowSensorCount/fImpulsePerML;
|
||||
totalMilliLitres += flowMilliLitres;
|
||||
|
||||
@@ -213,7 +194,10 @@ void PlantSystem_tick(void)
|
||||
|
||||
|
||||
// Store last flow data and prepare for new request
|
||||
nFlowSensorCount_last = 0;
|
||||
|
||||
|
||||
|
||||
nFlowSensorCount_last = nFlowSensorCount;
|
||||
nFlowSensorCount = 0;
|
||||
nWatering_volume = 0;
|
||||
|
||||
@@ -243,7 +227,18 @@ void PlantSystem_tick(void)
|
||||
|
||||
void PlantSystem_ScanBus(void)
|
||||
{
|
||||
// Clear/reset data from previous scan
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- Resetting internal I2C bus state.\n");
|
||||
Serial.println ("Resetting internal I2C bus state.");
|
||||
gDevicesOnBusCount = 0;
|
||||
gnSensorsOnBusCnt = 0;
|
||||
gnSolenoidsOnBusCnt = 0;
|
||||
memset(gDevicesOnBus, 0 , sizeof(gDevicesOnBus));
|
||||
memset(gSensorsOnBus, 0 , sizeof(gSensorsOnBus));
|
||||
memset(gSolenoidsOnBus, 0 , sizeof(gSolenoidsOnBus));
|
||||
|
||||
Serial.println ("Scanning I2C bus...");
|
||||
esp_log_write(ESP_LOG_DEBUG, "SKWS", "-- Resetting internal I2C bus state.\n");
|
||||
for (uint8_t i=I2C_ADDRESS_LIMIT_LOWER; i<I2C_ADDRESS_LIMIT_UPPER; i++)
|
||||
{
|
||||
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
|
||||
@@ -252,9 +247,11 @@ void PlantSystem_ScanBus(void)
|
||||
gDevicesOnBus[gDevicesOnBusCount++].i2cAddress = i;
|
||||
// gDevicesOnBusCount++;
|
||||
}
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
esp_task_wdt_reset();
|
||||
Serial.print ("Found ");
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- I2C bus rescan found %d devices.\n", gDevicesOnBusCount);
|
||||
Serial.print ("Found ");
|
||||
Serial.print (gDevicesOnBusCount, DEC); // numbers of devices
|
||||
Serial.println (" device(s).");
|
||||
|
||||
@@ -269,12 +266,11 @@ void PlantSystem_ScanBus(void)
|
||||
|
||||
void PlantSystem_debugShowDevicesOnBus(void)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
|
||||
// -- Print all devices
|
||||
Serial.print ("There are total of ");
|
||||
Serial.print (gDevicesOnBusCount, DEC); // numbers of devices
|
||||
Serial.println (" device(s) on I2C bus.");
|
||||
Serial.println (" device(s) on I2C bus.");
|
||||
|
||||
|
||||
for (uint8_t i = 0; i< gDevicesOnBusCount; i++)
|
||||
{
|
||||
@@ -303,6 +299,7 @@ void PlantSystem_debugShowDevicesOnBus(void)
|
||||
Serial.print ("There are total of ");
|
||||
Serial.print (gnSensorsOnBusCnt, DEC); // numbers of devices
|
||||
Serial.println (" SENSORS on I2C bus.");
|
||||
esp_log_write(ESP_LOG_INFO, "SKWS", "-- Reporting %d sensors and %d solenoids\n", gnSensorsOnBusCnt, gnSolenoidsOnBusCnt);
|
||||
for (uint8_t i = 0; i< gnSensorsOnBusCnt; i++)
|
||||
{
|
||||
Serial.print("Sensor @ 0x");
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
extern I2C_Device_TypeDef gDevicesOnBus[250];
|
||||
#include "CentralUnit_cfg.h"
|
||||
|
||||
extern I2C_Device_TypeDef gDevicesOnBus[I2C_MAX_DEVICES_ON_BUS];
|
||||
extern uint8_t gDevicesOnBusCount;
|
||||
|
||||
extern I2C_Sensor_TypeDef gSensorsOnBus[20];
|
||||
extern I2C_Sensor_TypeDef gSensorsOnBus[I2C_MAX_SENSORS_ON_BUS];
|
||||
extern uint8_t gnSensorsOnBusCnt;
|
||||
|
||||
extern I2C_Solenoid_TypeDef gSolenoidsOnBus[20];
|
||||
extern I2C_Solenoid_TypeDef gSolenoidsOnBus[I2C_MAX_SOLENOIDS_ON_BUS];
|
||||
extern uint8_t gnSolenoidsOnBusCnt;
|
||||
|
||||
// -- Format char buffer to return data as JSON object
|
||||
@@ -34,6 +36,7 @@ bool PlantSystem_WAPI_GetDevices(char *pBuff, uint32_t nMaxLen)
|
||||
gDevicesOnBusCount);
|
||||
if(len<0)
|
||||
{
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- PlantSystem_WAPI_GetDevices: Buffer too short (e:%d)\n", len);
|
||||
Serial.println("Buffer too short");
|
||||
return false;
|
||||
}
|
||||
@@ -68,6 +71,7 @@ bool PlantSystem_WAPI_GetDevices(char *pBuff, uint32_t nMaxLen)
|
||||
}
|
||||
else
|
||||
{
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- PlantSystem_WAPI_GetDevices: Len issue (e:%d)\n", len);
|
||||
Serial.println("Len issue");
|
||||
Serial.println(len, DEC);
|
||||
return false;
|
||||
@@ -77,7 +81,7 @@ bool PlantSystem_WAPI_GetDevices(char *pBuff, uint32_t nMaxLen)
|
||||
// Close JSON string
|
||||
len = snprintf(&pBuff[currentPos-1], (nMaxLen-currentPos), "]}");
|
||||
|
||||
if(len >0 && currentPos <nMaxLen)
|
||||
if(len>0 && currentPos<nMaxLen)
|
||||
{
|
||||
#if 0
|
||||
Serial.println("Printing pBuff");
|
||||
@@ -87,6 +91,7 @@ bool PlantSystem_WAPI_GetDevices(char *pBuff, uint32_t nMaxLen)
|
||||
}
|
||||
else
|
||||
{
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- (len>0 && currentPos<nMaxLen) fail (%d >0 && %d<%d)\n", len, currentPos, nMaxLen);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -116,6 +121,7 @@ bool PlantSystem_WAPI_SensorData(char *pBuff, uint32_t nMaxLen)
|
||||
gnSensorsOnBusCnt);
|
||||
if(len<0)
|
||||
{
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- PlantSystem_WAPI_SensorData: Buffer too short (e:%d)\n", len);
|
||||
Serial.println("Buffer too short");
|
||||
return false;
|
||||
}
|
||||
@@ -162,10 +168,12 @@ bool PlantSystem_WAPI_SensorData(char *pBuff, uint32_t nMaxLen)
|
||||
Serial.println(len, DEC);
|
||||
|
||||
Serial.print("nMaxLen: ");
|
||||
Serial.println(len, DEC);
|
||||
Serial.println(nMaxLen, DEC);
|
||||
|
||||
Serial.print("currentPos :");
|
||||
Serial.println(len, DEC);
|
||||
Serial.println(currentPos, DEC);
|
||||
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- PlantSystem_WAPI_SensorData: Buffer too short. snprintf ret:%d, nMaxLen:%d currentPos:%d\n", len, nMaxLen, currentPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -179,6 +187,7 @@ bool PlantSystem_WAPI_SensorData(char *pBuff, uint32_t nMaxLen)
|
||||
}
|
||||
else
|
||||
{
|
||||
esp_log_write(ESP_LOG_ERROR, "SKWS", "-- PlantSystem_WAPI_SensorData fail (len:%d)\n", len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user