Fixing missing files: Adding adjustable flow and logging.

This commit is contained in:
Sasa Karanovic
2021-10-22 00:30:08 -04:00
parent 1a4afa199b
commit bb8a212ccb
6 changed files with 435 additions and 74 deletions
@@ -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;
}
}