demeter
Autonomous Hydroponic Intelligencegit clone https://github.com/maydayv7/demeter
frontend/src/data/mockData.js (10165B)
1// MOCK DATA
2// -- Set USE_MOCK_DATA = true to use local test data
3// -- Set USE_MOCK_DATA = false to connect to the real backend API
4export const USE_MOCK_DATA = false;
5
6// HELPERS
7const ts = (daysAgo, hour = 10, min = 0) => {
8 const d = new Date();
9 d.setDate(d.getDate() - daysAgo);
10 d.setHours(hour, min, 0, 0);
11 return d.toISOString();
12};
13
14const plantedTs = (daysAgo) => {
15 const d = new Date();
16 d.setDate(d.getDate() - daysAgo);
17 return d.toISOString();
18};
19
20// Explanation log samples
21const EXPLANATION_LOGS = {
22 lettuce: `1. **Observation**: Sensors show pH 6.1, EC 1.4 dS/m, Temp 23.5°C, Humidity 68%.
23 All parameters are within acceptable range for Vegetative Lettuce.
24
252. **Precedent**: 3 similar past states found. In 2 of those cases, a slight EC boost
26 improved growth rate by +12%. No disease was detected in the last 5 cycles.
27
283. **Logic**: EC at 1.4 is slightly below the 1.5-1.8 target for late vegetative.
29 A small nutrient dosage increase will push it into the optimal window.
30 Fan speed is adequate; no VPD concerns at current temp/humidity.
31
324. **Conclusion**: Dosing 2.5ml nutrients is the safest, most targeted intervention.
33 No pH correction needed. Maintain current atmospheric settings.`,
34
35 tomato: `1. **Observation**: pH 5.8, EC 2.1 dS/m, Temp 26°C, Humidity 58%.
36 EC is elevated for flowering stage - approaching upper safe limit of 2.2.
37
382. **Precedent**: 2 similar flowering Tomato states found. In one prior case,
39 EC > 2.2 triggered blossom drop. Acid dosage was effective in 1 case.
40
413. **Logic**: pH 5.8 is at the lower end for Tomato flowering (optimal 6.0-6.5).
42 A controlled acid dose of 1.5ml will bring pH down slightly to 5.9,
43 while nutrient top-up at 4ml maintains bloom support without pushing EC over limit.
44
454. **Conclusion**: Targeted acid dosage + nutrient boost is the correct intervention.
46 Increased fan speed to 60% to manage VPD in warm conditions.`,
47
48 basil: `1. **Observation**: CRITICAL - pH 7.8 (target 5.5-6.5), EC 0.6 (very low), Temp 29.5°C.
49 Multiple out-of-range parameters detected simultaneously.
50
512. **Precedent**: 1 similar critical Basil state found. Previous corrective action
52 required 8ml acid dosage to restore pH. Recovery took 2 cycles.
53
543. **Logic**: pH 7.8 indicates severe alkalinity - likely nutrient lockout.
55 At this pH, iron and manganese become unavailable causing yellowing.
56 EC 0.6 confirms nutrient starvation. Aggressive correction required.
57 High temp (29.5°C) increases risk of bolting.
58
594. **Conclusion**: Emergency acid dosage (8ml) is necessary. Fan at 80% to cool.
60 Nutrient addition deferred until pH stabilizes to avoid compounding stress.`,
61
62 strawberry: `1. **Observation**: pH 6.2, EC 1.8 dS/m, Temp 22°C, Humidity 65%.
63 All parameters within optimal range for Strawberry Vegetative stage.
64
652. **Precedent**: 4 similar states found, all showing positive outcomes.
66 Gentle interventions in this range historically improve runner production by 10-18%.
67
683. **Logic**: Conditions are near-ideal. pH 6.2 is perfect for Strawberry (optimal 6.0-6.5).
69 Light nutrient boost (1.5ml) maintains EC momentum. Water refill supports
70 root zone hydration without diluting nutrients significantly.
71
724. **Conclusion**: Minimal intervention strategy. 1.5ml nutrient + 1.5L water refill.
73 Fan at 40% maintains gentle airflow - adequate for cooler Strawberry environment.`,
74};
75
76/**
77 * MOCK_DASHBOARD - Raw MongoDB document shape
78 * (sensors as arrays, planted_at, cycle_duration_hours, sensor_ids, location)
79 */
80export const MOCK_DASHBOARD = [
81 {
82 _id: "mongo-001",
83 crop_id: "Batch_Lettuce_2025A",
84 crop: "Lettuce",
85 stage: "vegetative",
86 sequence_number: 14,
87 cycle_duration_hours: 1,
88 planted_at: plantedTs(10),
89 last_updated: ts(0, 9, 30),
90 location: "Rack A - Shelf 1",
91 notes: "Fast-growing batch, increased EC slightly on day 7.",
92 image_url: "",
93 sensors: {
94 pH: [5.9, 6.0, 6.1, 6.1],
95 EC: [1.3, 1.4, 1.4, 1.4],
96 temp: [23.0, 23.5, 23.5, 23.5],
97 humidity: [66, 67, 68, 68],
98 },
99 sensor_ids: {
100 ph_sensor: "PH-SEN-A1F3",
101 ec_sensor: "EC-SEN-B2D7",
102 temp_sensor: "TMP-SEN-C4E9",
103 humidity_sensor: "HUM-SEN-D6F1",
104 },
105 action_taken: JSON.stringify({
106 acid_dosage_ml: 0,
107 base_dosage_ml: 0,
108 nutrient_dosage_ml: 2.5,
109 fan_speed_pct: 45,
110 water_refill_l: 0,
111 }),
112 outcome: "IMPROVED | Reward: 0.8",
113 strategic_intent: "MAINTAIN_CURRENT",
114 bandit_action_id: 0,
115 reward_score: 0.8,
116 explanation_log: EXPLANATION_LOGS.lettuce,
117 },
118 {
119 _id: "mongo-002",
120 crop_id: "Batch_Tomato_2025B",
121 crop: "Tomato",
122 stage: "flowering",
123 sequence_number: 22,
124 cycle_duration_hours: 2,
125 planted_at: plantedTs(45),
126 last_updated: ts(0, 8, 15),
127 location: "Rack B - Shelf 2",
128 notes: "",
129 image_url: "",
130 sensors: {
131 pH: [5.7, 5.8, 5.8, 5.8],
132 EC: [2.0, 2.1, 2.1, 2.1],
133 temp: [25.5, 26.0, 26.0, 26.0],
134 humidity: [57, 58, 58, 58],
135 },
136 sensor_ids: {
137 ph_sensor: "PH-SEN-E5A2",
138 ec_sensor: "EC-SEN-F3C8",
139 temp_sensor: "TMP-SEN-G7D1",
140 humidity_sensor: "HUM-SEN-H9B4",
141 },
142 action_taken: JSON.stringify({
143 acid_dosage_ml: 1.5,
144 base_dosage_ml: 0,
145 nutrient_dosage_ml: 4.0,
146 fan_speed_pct: 60,
147 water_refill_l: 0,
148 }),
149 outcome: "STABLE | Reward: 0.4",
150 strategic_intent: "INCREASE_EC_BLOOM",
151 bandit_action_id: 6,
152 reward_score: 0.4,
153 explanation_log: EXPLANATION_LOGS.tomato,
154 },
155 {
156 _id: "mongo-003",
157 crop_id: "Batch_Basil_2025C",
158 crop: "Basil",
159 stage: "seedling",
160 sequence_number: 5,
161 cycle_duration_hours: 1,
162 planted_at: plantedTs(3),
163 last_updated: ts(0, 11, 0),
164 location: "Rack A - Shelf 3",
165 notes: "New batch - watching pH closely.",
166 image_url: "",
167 sensors: {
168 pH: [7.5, 7.7, 7.8, 7.8],
169 EC: [0.7, 0.6, 0.6, 0.6],
170 temp: [28.5, 29.0, 29.5, 29.5],
171 humidity: [80, 81, 82, 82],
172 },
173 sensor_ids: {
174 ph_sensor: "PH-SEN-I2K6",
175 ec_sensor: "EC-SEN-J4L9",
176 temp_sensor: "TMP-SEN-K1M3",
177 humidity_sensor: "HUM-SEN-L8N7",
178 },
179 action_taken: JSON.stringify({
180 acid_dosage_ml: 8.0,
181 base_dosage_ml: 0,
182 nutrient_dosage_ml: 3.0,
183 fan_speed_pct: 80,
184 water_refill_l: 0,
185 }),
186 outcome: "DETERIORATED | Reward: -0.6",
187 strategic_intent: "AGGRESSIVE_PH_DOWN",
188 bandit_action_id: 2,
189 reward_score: -0.6,
190 explanation_log: EXPLANATION_LOGS.basil,
191 },
192 {
193 _id: "mongo-004",
194 crop_id: "Batch_Strawberry_2025D",
195 crop: "Strawberry",
196 stage: "vegetative",
197 sequence_number: 9,
198 cycle_duration_hours: 2,
199 planted_at: plantedTs(18),
200 last_updated: ts(1, 14, 45),
201 location: "Rack C - Shelf 1",
202 notes: "Runner training started on day 12.",
203 image_url: "",
204 sensors: {
205 pH: [6.1, 6.2, 6.2, 6.2],
206 EC: [1.7, 1.8, 1.8, 1.8],
207 temp: [21.5, 22.0, 22.0, 22.0],
208 humidity: [63, 64, 65, 65],
209 },
210 sensor_ids: {
211 ph_sensor: "PH-SEN-M5P2",
212 ec_sensor: "EC-SEN-N7Q4",
213 temp_sensor: "TMP-SEN-O3R8",
214 humidity_sensor: "HUM-SEN-P1S6",
215 },
216 action_taken: JSON.stringify({
217 acid_dosage_ml: 0,
218 base_dosage_ml: 0,
219 nutrient_dosage_ml: 1.5,
220 fan_speed_pct: 40,
221 water_refill_l: 1.5,
222 }),
223 outcome: "IMPROVED | Reward: 0.7",
224 strategic_intent: "GENTLE_PH_BALANCING",
225 bandit_action_id: 4,
226 reward_score: 0.7,
227 explanation_log: EXPLANATION_LOGS.strawberry,
228 },
229];
230
231// Detailed history per crop (multiple snapshots - keeps Qdrant/payload shape for analytics)
232function makeHistory(cropId, cropName, stage, n, baseVals, explanationLog) {
233 return Array.from({ length: n }, (_, i) => {
234 const jitter = (range) => (Math.random() - 0.5) * range;
235 return {
236 id: `${cropId}-seq-${i + 1}`,
237 payload: {
238 crop_id: cropId,
239 crop: cropName,
240 stage,
241 sequence_number: i + 1,
242 timestamp: ts(Math.floor((n - i) / 3), (i * 2) % 24, (i * 7) % 60),
243 sensors: {
244 pH: +(baseVals.ph + jitter(0.4)).toFixed(2),
245 EC: +(baseVals.ec + jitter(0.3)).toFixed(2),
246 temp: +(baseVals.temp + jitter(2)).toFixed(1),
247 humidity: +(baseVals.humidity + jitter(8)).toFixed(1),
248 },
249 action_taken: JSON.stringify({
250 acid_dosage_ml: +(Math.random() * 2).toFixed(1),
251 base_dosage_ml: 0,
252 nutrient_dosage_ml: +(Math.random() * 3 + 1).toFixed(1),
253 fan_speed_pct: Math.round(30 + Math.random() * 40),
254 water_refill_l: +(Math.random() * 2).toFixed(1),
255 }),
256 outcome: [
257 "IMPROVED | Reward: 0.7",
258 "STABLE | Reward: 0.4",
259 "DETERIORATED | Reward: -0.3",
260 ][i % 3],
261 strategic_intent: [
262 "MAINTAIN_CURRENT",
263 "GENTLE_PH_BALANCING",
264 "INCREASE_EC_VEG",
265 ][i % 3],
266 reward_score: [0.7, 0.4, -0.3][i % 3],
267 explanation_log: explanationLog,
268 },
269 };
270 });
271}
272
273export const MOCK_HISTORY = [
274 ...makeHistory(
275 "Batch_Lettuce_2025A",
276 "Lettuce",
277 "vegetative",
278 14,
279 { ph: 6.1, ec: 1.4, temp: 23.5, humidity: 68 },
280 EXPLANATION_LOGS.lettuce,
281 ),
282 ...makeHistory(
283 "Batch_Tomato_2025B",
284 "Tomato",
285 "flowering",
286 22,
287 { ph: 5.8, ec: 2.1, temp: 26.0, humidity: 58 },
288 EXPLANATION_LOGS.tomato,
289 ),
290 ...makeHistory(
291 "Batch_Basil_2025C",
292 "Basil",
293 "seedling",
294 5,
295 { ph: 7.8, ec: 0.6, temp: 29.5, humidity: 82 },
296 EXPLANATION_LOGS.basil,
297 ),
298 ...makeHistory(
299 "Batch_Strawberry_2025D",
300 "Strawberry",
301 "vegetative",
302 9,
303 { ph: 6.2, ec: 1.8, temp: 22.0, humidity: 65 },
304 EXPLANATION_LOGS.strawberry,
305 ),
306];
307
308// Mock search result (for FarmIntelligence)
309export const MOCK_SEARCH_RESULT = {
310 status: "success",
311 results: MOCK_DASHBOARD.slice(0, 2).map((d, i) => ({
312 id: d._id,
313 score: 0.95 - i * 0.08,
314 payload: { ...d, sensors: { pH: 6.1, EC: 1.4, temp: 23.5, humidity: 68 } },
315 })),
316 query_logic: { must: [{ key: "crop", match: "Lettuce" }] },
317};