Insights
Directories:
src/containers/Insights
src/components/Insights
Front End
Components
InsightsInfoComponent
Props Used:
title: string
value: string
valueLabel: string
percent: number (0-100)
Used In:
People Fed
Soil Organic Matter
Labour Happiness
Biodiversity
BalanceBarComponent
Props used:
value: number
unit: string
Used In:
Water Balance
Nitrogen Balance
FrequencySelectorComponent
Props used:
None
Used In:
Nitrogen Balance
InfoBoxComponent
Props used:
title: string
body: string
showSave: boolean
showDelete: boolean
Used In:
All of the Insights Containers
LabourHappinessTask
Props used:
title: string
mood: number
Used In:
Labour Happiness
NitrogenBalanceInfo
Props used:
title: string
PriceCropContainer
Props used:
cropData: Crop Object
PriceDistanceComponent
Props Used:
None
Saga Calls
Saga Call | Description |
---|---|
getCropsSoldNutrition | Get Crops Sold for Farm |
getSoilOMData | Get Soil OM for Farm |
getLabourHappinessData | Get Labour Happiness for Farm |
getBiodiversityData | Get Biodiversity Data for Farm |
getPricesData | Get All Prices Data for Farm (Excluding Distance) |
getPricesWithDistanceData | Get Prices including distances for Farm |
getWaterBalanceData | Get Water Balance Data for Farm |
getNitrogenBalanceData | Get Nitrogen Balance Data for Farm |
createWaterBalanceSchedule | Create Water Balance Schedule for Farm |
getNitrogenBalanceFrequency | Get Nitrogen Balance Schedule for Farm |
postNitrogenBalanceFrequency | Create Nitrogen Balance Schedule for Farm |
deleteNitrogenBalanceFrequency | Delete Nitrogen Balance Schedule for Farm |
Back End
API Endpoints:
Method | Endpoint | Information |
---|---|---|
GET | /people_fed/:farm_id | Grabs People Fed Info based on a FarmID |
GET | /labour_happiness/:farm_id | Grabs Labour Happiness based on a FarmID |
GET | /biodiversity/:farm_id | Grabs Biodiversity based on a FarmID |
GET | /prices/distance/:farm_id | Grabs a persons prices based on FarmID |
GET | /waterbalance/:farm_id | Grabs a persons water balance based on FarmID |
GET | /waterbalance/schedule/:farm_id | Grabs a persons water balance schedule based on FarmID |
GET | /nitrogenbalance/:farm_id | Grabs a persons nitrogen balance data based on FarmID |
GET | /nitrogenbalance/schedule/:farm_id | Grabs a persons nitrogen balance scheduled based on FarmID |
POST | /waterbalance | Adds a water balance calculation |
POST | /waterbalance/schedule | Adds a water balance schedule |
POST | /nitrogenbalance/schedule | Adds a nitrogen balance schedule |
DEL | /nitrogenbalance/schedule/:id | Deletes a nitrogen balance schedule based on the nitrogen schedule ID |
Submodules:
People Fed
In People Fed, we calculate how many meals the farmer has fed based off their cropSale and crop nutritional data
This equation is derived from ./src/controllers/insightHelpers.js
A persons expected intake for nutrition: - Calories: 2500 kcal - Protein: 52g - Fat: 750g - Vitamin C: 90mg - Vitamin A: 900mg
For every crop that the farmer has sold: percentLeft = 1 - crop.percentRefuse Calculate the nutritional value by taking each crop nutritional value: crop.Calories = (crop.energy * 10) * crop.quantity_kg * percentLeft crop.Protein = (crop.protein * 10) * crop.quantity_kg * percentLeft crop.Fat = (crop.lipid * 10) * crop.quantity_kg * percentLeft crop.VitaminC = (crop.vitc * 10) * crop.quantity_kg * percentLeft crop.VitaminA = (crop.vita_rae * 10) * crop.quantity_kg * percentLeft Take each of these values: crop.MEAL = crop.NUTRITION / (expectedIntake.NUTRITION / MEALS_PER_DAY) Assume Nutrition is one of: Calories, Protein, Fat, VitC, VitA Assume Meals Per Day is 3
Prices
In Prices, we compare the farms sales with the rest of the sales in the network based on their proximity setting in the app.
The algorithm organizes the sales into its crop and month/year and displays it as a graph on the front end
This equation is derived from ./src/controllers/insightHelpers.js
For each crop the algorithm grabs: quantity sold, quantity value, date sold The algorithm first checks if the crop is a cropSale in my farm. It then keeps two running sums, one for the farmers crops, and another for the network crops After, it totals the quantity sold, quantity value based off the date sold. Finally, it takes totalQuantity / totalValue as well as networkQuantity / networkValue
Water Balance
In Water Balance, we use soil data logs, weather data, and crop nutritional data to make an estimate on the crops plant available water.
This equation is derived from ./src/jobs/waterBalance/waterBalance.js
There are <b>two</b> types of cron jobs that are run everyday
Hourly Weather Calculations
Daily Water Balance Calculation
Hourly Calculation
The algorithm is run hourly pulling weather data from OpenWeatherMap API
The algorithm saves these values into the database based on each field registered
The algorithm pulls these data: - min_degrees: Minimum temperature at the time - max_degrees: Maximum temperature at the time - precipitation: Accumulated rain at the time - wind_speed: Accumulated wind speed at the time - field_id: the field id for this weather - min_humidity: Minimum humidity at the time - max_humidity: Maximum humidity at the time - data_points: Amount of data points (should be 24 at the end of the day)
Daily Calculation
The algorithm runs a daily calculation based off equations from cited sources below
This algorithm calculates the water balance for each crop
This algorithm then puts a number in our backend DB in the Water Balance Table
References:
Plant Available Water
Plant Available Water = Soil Water Content - Calculate Wilting Point
Soil Water Content
Variables: - fieldCapacity: How much water the field can hold - oldSoilWaterContent: Previous days soil water content (if present) - precipitation: How much rain was present during the day based on a farmers field location - evapotranspiration: How much water is transferred from the land to the atmosphere by evaporation if (oldSolWaterContent + precipitation > fieldCapacity) soilWaterContent = fieldCapacity - ET else soilWaterContent = (oldSoilWaterContent + precipitation) - ET
Field Capacity
Variables: - texture - organic matter - rooting depth fieldCapacity_1 = (-0.251 * textureObject.sand) + (0.195 * textureObject.clay) + (0.011 * organicMatter) + 0.006 * (textureObject.sand * organicMatter) - 0.027 * (textureObject.clay * organicMatter) + 0.452 * (textureObject.sand * textureObject.clay) + 0.299 fieldCapacity_2 = fieldCapacity_1 + (1.283 * Math.pow(fieldCapacity_1, 2) - 0.374 * fieldCapacity_1 - 0.015); field capacity = fieldCapacity_2 * rooting depth
Precipitation
The algorithm uses OpenWeatherMap API to grab the amount of rain that occurred within the hour If no rain is present, OpenWeatherMap API does not give back the key 'rain' In the code, this behaviour defaults to 0 precipitation Added onto precipitation, are the irrigation logs: - The algorithm grabs the irrigation logs for the day, organized by crop - The log contains "hours" which is converted first to minutes - irrigation = (flow_rate_l/min) / minutes / area_used Now we sum the precipitation that was accumulated from the day and the irrigation calculated.
Evapotranspiration
Variables and Assumptions: - Clear Sky Transmissivity = 1 - Albedo = 0.23 - Average Temperature = (max_temp - min_temp) / 2 - Elevation Data - Wind Speed - ExtraT Solar Radiation - Solar Radiation - Slope - Psychometric Constant - Saturated Vapour Pressure - Actual Vapour Pressure - RNL - RNS ET = 0.408 * slope * (rns - rnl) + psychometricConstant * (900 / (averageTemperature + 273)) * windSpeed * (saturatedVP - actualVP)) / (slope + psychometricConstant * (1 + 0.34 * windSpeed))
Elevation Data
In the app, the algorithm calls the Google Maps API to get elevation data based on a farms field location
Wind Speed
In the app, the algorithm calls the Google Maps API to get wind speed data based on a farms field location
Extra T Solar Radiation
Variables: - Latitude of Location (In Radian) - Current day of the year - corr Earth and Sun Distance: 1 + 0.0334 * Math.cos(0.01721 * dayOfYear - 0.0552) - Solar Declination: 0.4093 * Math.sin((2 * Math.PI * (284 + dayOfYear)) / 365) - Daylight Time Factor: Math.acos(-Math.tan(latitudeInRadian) * Math.tan(solarDecl)) ExtraTSolar = 4.921 * 24 / Math.PI * corrEarthSunDist * (Math.sin(latitudeInRadian) * Math.sin(solarDecl) * daylightTimeFactor + Math.cos(latitudeInRadian) * Math.cos(solarDecl)) * Math.sin(daylightTimeFactor)
Solar Radiation
Variables: - weatherData = Weather Data based on Field weatherData = 0.16 * extraTSolar * (weatherData['max_degrees'] - weatherData['min_degrees'])
Slope
Variables: - Temperature = average temperature of the day slope = (4098 * (0.6108 * Math.exp(17.27 * temperature / (temperature + 237.3)))) / Math.pow(temperature + 237.3, 2)
Psychometric Constant
const p = 101.3 * (Math.pow((293 - 0.0065 * elevation) / 293, 5.26)); psychometricConstant = (1.013e-03 * p) / (0.622 * (2.501 - 0.002361 * averageTemperature));
Saturated Vapour Pressure
Variables: - temperature = mean temperature of the day Saturated Vapour Pressure = 0.6108 * Math.exp((17.27 * temperature) / (temperature + 237.3))
Actual Vapour Pressure
Variables: - temperature = mean temperature of the day - humidity = mean humidity of the day - Saturated Vapour Presure = See equation just above Actual Vapour Pressure = Saturated Vapour Pressure * humidity / 100
RNL
Variables: - min temperature - max temperature - solar radiation - actual vapour pressure - extraT - tal = 1 RNL = 4.903e-09 * ((Math.pow(maxTemp + 273.16, 4) + Math.pow(minTemp + 273.16, 4)) / 2) * (0.34 - 0.14 * Math.sqrt(actualVapourPressure)) * (1.35 * solarRadiation / (extraT * tal) - 0.35)
RNS
Variables: - Solar Radiation - Albedo RNS = (1- albedo) * solar radiation
Nitrogen Balance
In Nitrogen Balance, it is very similar to Water Balance as there one daily job.
References:
Daily Calculation
Nitrogen In: the amount of nitrogen that is put into the soil Nitrogen Out: the amount of nitrogen that is dissipated nitrogen balance = nitrogen in - nitrogen out
Nitrogen In
Variables: Current Total Nitrogen: Crop Quantity * Nitrogen_Percent / 100 Current NH3 = Total NH3 in the crop Current NH4 = Total NH4 in the crop Nitrogen Credits = field nutrient credits in the soil mineralization rate = mineralization rate of the crop Total Nitrogen for Fertilizer = nitrogenCredits + ((currentTotalNitrogen - currentNH3 - currentNH4) * mineralizationRate) + currentNH4 + currentNH3;
Nitrogen Out
Variables: Quantity Harvested: How much harvested crops in a farm Refuse: % Refuse for each crop Protein Content: Crop Protein Factor to Convert From Protein to Nitrogen = 0.16 Moisture Factor = 1 Total Nitrogen In Crop = quantityHarvested * (1 - refuse) * proteinContent * factorToConvertFromProteinToNitrogen * moistureFactor;
Labour Happiness
Variables: Shifts based on a persons farm - Mood (1-5) The algorithm parses each mood from 1-5 if the worker decided to not submit their task, it is not weighted in this system The algorithm uses a "weighted sum" determined on the duration of the workers shift For example: If a worker does two tasks: Harvesting: 5 mins Plowing: 20 mins Rating: 3/5 The rating is shifted more in favour of plowing (As the worker spent more time plowing)
Soil Organic Matter
The algorithm calls SoilGridsAPI to grab organic matter data for the soil. This API accepts a latitude and longitude input and returns an integer for soil OM (e.g. 9).
Variables: Field - Grab organic matter based on the soil - Logs based in their farm The algorithm adds the logs organic matter. If none is present, the algorithm calls soilgridsAPI in order to retrieve the organic matter. SoilGrids Organic Matter = SoilGridsAPI Organic Matter * 2 * 0.01