3#include <ArduinoJson.h>
15static unsigned long last_check_time = 0;
19static float current_moisture_value = -1.0f;
22 type = Esp32Command_irrigation_command_tag;
30 if (cmd.which_command != Esp32Command_irrigation_command_tag) {
34 switch (cmd.command.irrigation_command.type) {
35 case IrrigationCommand_Type_CHECK:
44 memcpy(
buffer, request_buffer, request_buffer_len);
45 return request_buffer_len;
53 unsigned long current_time = millis();
58 last_check_time = current_time;
60 Log.noticeln(
"Fetching soil moisture from API...");
63 if (new_moisture >= 0) {
64 current_moisture_value = new_moisture;
65 Log.noticeln(
"Moisture reading: %.1f%%", new_moisture);
68 Log.errorln(
"Failed to get moisture from API");
69 current_moisture_value = -1.0f;
73void ModuleIrrigation::Check(
const Esp32Command& cmd) {
74 IrrigationCommand resp = IrrigationCommand_init_zero;
88 Log.noticeln(
"Moisture low (%.1f%% < %.1f%%) - Opening valve",
92 Log.noticeln(
"Moisture adequate (%.1f%% > %.1f%%) - Closing valve",
100 struct tm* tm_info = gmtime(×tamp);
102 strftime(buf,
sizeof(buf),
"%a, %d %b %Y %H:%M:%S GMT", tm_info);
109 float moisture_value = -1.0f;
113 if (gettimeofday(&tv, NULL) == 0) {
114 time_t now = tv.tv_sec;
115 time_t start_time = now - 30;
121 String url =
"http://dirtviz.jlab.ucsc.edu/api/sensor/";
122 url +=
"?name=sen0308";
123 url +=
"&measurement=humidity";
124 url +=
"&cellId=1448";
125 url +=
"&startTime=" + start_time_str;
126 url +=
"&endTime=" + end_time_str;
127 url +=
"&stream=true";
129 Log.traceln(
"API URL: %s", url.c_str());
131 if (http.begin(url)) {
132 Log.traceln(
"Requesting data from last 30 seconds...");
133 int httpCode = http.GET();
134 Log.traceln(
"HTTP response code: %d", httpCode);
136 if (httpCode == HTTP_CODE_OK) {
137 String payload = http.getString();
138 Log.traceln(
"Payload: %s", payload.c_str());
140 DynamicJsonDocument doc(2048);
141 DeserializationError error = deserializeJson(doc, payload);
145 if (doc.containsKey(
"data") && doc[
"data"].is<JsonArray>()) {
146 JsonArray data_array = doc[
"data"];
148 if (data_array.size() > 0) {
150 moisture_value = data_array[data_array.size() - 1].as<
float>();
152 Log.errorln(
"Data array is empty");
155 Log.errorln(
"No 'data' array in API response");
157 for (JsonPair kv : doc.as<JsonObject>()) {
158 if (kv.value().is<JsonArray>()) {
159 Log.traceln(
"Key: %s (Array)", kv.key().c_str());
161 Log.traceln(
"Key: %s, Value: %s", kv.key().c_str(),
162 kv.value().as<String>().c_str());
167 Log.errorln(
"JSON parse error: %s", error.c_str());
170 Log.errorln(
"HTTP request failed: %d", httpCode);
174 Log.errorln(
"Failed to begin HTTP connection");
177 Log.errorln(
"Failed to get current time");
180 return moisture_value;
188 Log.noticeln(
"Auto irrigation enabled: Min=%.1f%%, Max=%.1f%%", min_thresh,
194 Log.noticeln(
"Auto irrigation disabled");
size_t OnRequest(uint8_t *buffer)
void OnReceive(const Esp32Command &cmd)
void CheckAutoIrrigation()
size_t EncodeIrrigationCommand(const IrrigationCommand *irrigation_cmd, uint8_t *buffer, size_t size)
Encodes an IrrigationCommand.
void SetCheckInterval(unsigned long interval_ms)
bool auto_irrigation_enabled
void EnableAutoIrrigation(float min_thresh, float max_thresh)
bool IsAutoIrrigationEnabled()
float GetCurrentMoistureFromCache()
float GetSimpleSoilMoisture()
unsigned long GetCheckInterval()
void CheckIrrigationConditions()
String formatTimeRFC1123(time_t timestamp)
void DisableAutoIrrigation()
Module for controling irrigation valve.
bool Check(void)
Check API health.
unsigned long check_interval
bool auto_irrigation_enabled
float moisture_min_threshold
float moisture_max_threshold
IrrigationCommand_State GetSolenoidState()
Get the current solenoid state.
void SetSolenoidState(IrrigationCommand_State newState)
Set the solenoid state.
float GetSimpleSoilMoisture()
void CheckIrrigationConditions()