Merge branch 'dev' into feature_guiOverhaul_M3
This commit is contained in:
commit
dd09fad581
|
@ -26,7 +26,7 @@ tasks.withType(JavaCompile) {
|
|||
|
||||
application {
|
||||
mainModule = 'ch.zhaw.gartenverwaltung'
|
||||
mainClass = 'ch.zhaw.gartenverwaltung.HelloApplication'
|
||||
mainClass = 'ch.zhaw.gartenverwaltung.Main'
|
||||
}
|
||||
|
||||
javafx {
|
||||
|
@ -42,6 +42,8 @@ dependencies {
|
|||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4'
|
||||
testImplementation 'org.mockito:mockito-core:4.3.+'
|
||||
implementation 'com.sun.mail:javax.mail:1.6.2'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HelloApplication extends Application {
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
AppLoader appLoader = new AppLoader();
|
||||
|
||||
appLoader.loadSceneToStage("MainFXML.fxml", stage);
|
||||
|
||||
stage.setTitle("Gartenverwaltung");
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
|
||||
import ch.zhaw.gartenverwaltung.backgroundtasks.BackgroundTasks;
|
||||
import ch.zhaw.gartenverwaltung.io.CropList;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.TaskList;
|
||||
import ch.zhaw.gartenverwaltung.models.Garden;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Timer;
|
||||
|
||||
public class Main extends Application {
|
||||
Timer backGroundTaskTimer = new Timer();
|
||||
BackgroundTasks backgroundTasks;
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
AppLoader appLoader = new AppLoader();
|
||||
|
||||
backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class));
|
||||
// TODO reduce period
|
||||
backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 1000);
|
||||
|
||||
appLoader.loadSceneToStage("MainFXML.fxml", stage);
|
||||
|
||||
stage.setTitle("Gartenverwaltung");
|
||||
stage.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(){
|
||||
backGroundTaskTimer.cancel();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
}
|
|
@ -1,13 +1,23 @@
|
|||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.backgroundtasks.email.SmtpCredentials;
|
||||
import ch.zhaw.gartenverwaltung.types.HardinessZone;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Settings {
|
||||
private static final Settings instance;
|
||||
private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A;
|
||||
private static Settings instance;
|
||||
private final BooleanProperty showTutorial = new SimpleBooleanProperty(false);
|
||||
private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true);
|
||||
// Gmail Address: pm3.hs22.it21b.win.team1@gmail.com
|
||||
// Gmail Passwort: Gartenverwaltung.PM3.2022
|
||||
// E-Mail Inbox: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1
|
||||
private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com";
|
||||
private String mailNotificationSubjectTemplate = "Task %s is due!"; // {0} = Task Name
|
||||
private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s"; // {0} = Task Name, {1} = plantname, {2} = nextExecution, {3} = Task description
|
||||
|
||||
private String location = "";
|
||||
|
||||
|
@ -48,4 +58,20 @@ public class Settings {
|
|||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public SmtpCredentials getSmtpCredentials() {
|
||||
return smtpCredentials;
|
||||
}
|
||||
|
||||
public String getMailNotificationReceivers() {
|
||||
return mailNotificationReceivers;
|
||||
}
|
||||
|
||||
public String getMailNotificationSubjectTemplate() {
|
||||
return mailNotificationSubjectTemplate;
|
||||
}
|
||||
|
||||
public String getMailNotificationTextTemplate() {
|
||||
return mailNotificationTextTemplate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.CropDetailController;
|
||||
import ch.zhaw.gartenverwaltung.backgroundtasks.weather.WeatherGradenTaskPlanner;
|
||||
import ch.zhaw.gartenverwaltung.io.CropList;
|
||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.TaskList;
|
||||
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.TimerTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BackgroundTasks extends TimerTask {
|
||||
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
|
||||
private final TaskList taskList;
|
||||
private final Notifier notifier;
|
||||
private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
|
||||
|
||||
private void movePastTasks() throws IOException {
|
||||
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN, LocalDate.now().minusDays(1));
|
||||
taskList.forEach(task -> {
|
||||
if (!task.isDone()) {
|
||||
task.setNextExecution(LocalDate.now());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
|
||||
this.taskList = taskList;
|
||||
notifier = new Notifier(taskList, plantList, cropList);
|
||||
weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
movePastTasks();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LOG.log(Level.SEVERE, "Could not execute Background Task: move past Tasks ", e.getCause());
|
||||
}
|
||||
try {
|
||||
weatherGardenTaskPlaner.refreshTasks();
|
||||
} catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
LOG.log(Level.SEVERE, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause());
|
||||
}
|
||||
try {
|
||||
notifier.sendNotifications();
|
||||
} catch (IOException | MessagingException | HardinessZoneNotSetException e) {
|
||||
e.printStackTrace();
|
||||
LOG.log(Level.SEVERE, "Could not execute Background Task: send Notification for due Tasks", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.Settings;
|
||||
import ch.zhaw.gartenverwaltung.backgroundtasks.email.EMailSender;
|
||||
import ch.zhaw.gartenverwaltung.io.CropList;
|
||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.TaskList;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class Notifier {
|
||||
private final TaskList taskList;
|
||||
private final CropList cropList;
|
||||
private final PlantList plantList;
|
||||
private final EMailSender eMailSender = new EMailSender();
|
||||
|
||||
public Notifier(TaskList taskList, PlantList plantList, CropList cropList) {
|
||||
this.taskList = taskList;
|
||||
this.cropList = cropList;
|
||||
this.plantList = plantList;
|
||||
}
|
||||
|
||||
private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||
String plantName = "unkown plant";
|
||||
if(cropList.getCropById((task.getCropId())).isPresent()){
|
||||
Crop crop = cropList.getCropById(task.getCropId()).get();
|
||||
if(plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).isPresent()) {
|
||||
plantName = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get().name();
|
||||
}
|
||||
}
|
||||
String messageSubject = String.format(Settings.getInstance().getMailNotificationSubjectTemplate(), task.getName());
|
||||
String messageText = String.format(Settings.getInstance().getMailNotificationTextTemplate(), task.getName(), plantName, task.getNextExecution(), task.getDescription());
|
||||
eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
|
||||
}
|
||||
|
||||
public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||
for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
|
||||
if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
|
||||
sendNotification(task);
|
||||
task.setNextNotification(LocalDate.now().plusDays(1));
|
||||
taskList.saveTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks.email;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.Settings;
|
||||
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class EMailSender {
|
||||
|
||||
|
||||
public EMailSender(){
|
||||
|
||||
}
|
||||
|
||||
public void sendMails(String recipients, String subject, String text) throws MessagingException {
|
||||
// TODO replace printMail with implementation
|
||||
printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it
|
||||
MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
|
||||
message.addHeader("Content-type", "text/HTML; charset=UTF-8");
|
||||
message.addHeader("format", "flowed");
|
||||
message.addHeader("Content-Transfer-Encoding", "8bit");
|
||||
message.setFrom(new InternetAddress(Settings.getInstance().getSmtpCredentials().fromAddress()));
|
||||
message.setReplyTo(InternetAddress.parse(Settings.getInstance().getSmtpCredentials().fromAddress(), false));
|
||||
message.setSubject(subject);
|
||||
message.setText(text);
|
||||
message.setSentDate(new Date());
|
||||
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients, false));
|
||||
Transport.send(message);
|
||||
}
|
||||
|
||||
private void printMail(String receiver, String subject, String text){
|
||||
System.out.printf("\nSending E-Mail:\nTo: %s\nSubject: %s\nMessage:\n%s\n", receiver, subject, text);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks.email;
|
||||
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import java.net.Authenticator;
|
||||
import java.util.Properties;
|
||||
|
||||
public record SmtpCredentials(
|
||||
String host,
|
||||
String port,
|
||||
String fromAddress,
|
||||
String username,
|
||||
String password,
|
||||
boolean startTLS
|
||||
) {
|
||||
|
||||
private Properties getProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.put("mail.smtp.host", host);
|
||||
properties.put("mail.smtp.port", port);
|
||||
properties.put("mail.smtp.auth", "true");
|
||||
properties.put("mail.smtp.starttls.enable", startTLS ? "true" : "false");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private javax.mail.Authenticator getAuthenticator() {
|
||||
return new javax.mail.Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return Session.getInstance(getProperties(), getAuthenticator());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
|
||||
public enum SevereWeather {
|
||||
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.io.CropList;
|
||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.TaskList;
|
||||
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
|
||||
import ch.zhaw.gartenverwaltung.types.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
|
||||
*
|
||||
*/
|
||||
public class WeatherGradenTaskPlanner {
|
||||
private final TaskList taskList;
|
||||
private final PlantList plantList;
|
||||
private final CropList cropList;
|
||||
WeatherService weatherService;
|
||||
private final LocalDate dateSevereWeather = LocalDate.of(2022,12,15);
|
||||
|
||||
public WeatherGradenTaskPlanner(TaskList taskList, PlantList plantList, CropList cropList) {
|
||||
this.taskList = taskList;
|
||||
this.plantList = plantList;
|
||||
this.cropList = cropList;
|
||||
weatherService = new WeatherService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to refresh watering tasks and severe weather tasks
|
||||
* @throws IOException If the database cannot be accessed
|
||||
* @throws HardinessZoneNotSetException If the hardiness zone is not available
|
||||
* @throws PlantNotFoundException if the plant is not available for the watering task
|
||||
*/
|
||||
public void refreshTasks() throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
|
||||
getSevereWeatherEvents();
|
||||
getRainAmount();
|
||||
}
|
||||
|
||||
private void getSevereWeatherEvents() throws IOException {
|
||||
SevereWeather actualWeather = weatherService.causeSevereWeather(1);
|
||||
if (SevereWeather.HAIL.equals(actualWeather)) {
|
||||
createPreHailTask();
|
||||
} else if (SevereWeather.FROST.equals(actualWeather)) {
|
||||
createPreFrostTask();
|
||||
} else if (SevereWeather.SNOW.equals(actualWeather)) {
|
||||
createPreSnowTask();
|
||||
}
|
||||
}
|
||||
|
||||
private void getRainAmount() throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
|
||||
int rainAmount = weatherService.causeRainAmount(3);
|
||||
adjustWateringTask(rainAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a PreHailTask
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void createPreHailTask() throws IOException {
|
||||
|
||||
Task preHailTask = new Task("Hail",
|
||||
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preHailTask);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a PreFrosttask
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void createPreFrostTask() throws IOException {
|
||||
Task preFrostTask = new Task("Frost",
|
||||
"The temperatur falls below zero degrees, cover especially the root with wool",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preFrostTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a PreSnowTask
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void createPreSnowTask() throws IOException {
|
||||
Task preSnowTask = new Task("Snow",
|
||||
"The weather brings little snowfall. Cover your crops",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preSnowTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to adjust the water plant tasks
|
||||
* @param rainAmount Amount of rain from the last 7 days
|
||||
* @throws IOException If the database cannot be accessed
|
||||
* @throws HardinessZoneNotSetException If the hardiness zone is not available
|
||||
* @throws PlantNotFoundException if the plant is not available for the watering task
|
||||
*/
|
||||
private void adjustWateringTask(int rainAmount) throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
|
||||
|
||||
for (Crop crop : cropList.getCrops()) {
|
||||
Plant plant = plantList.getPlantById(HardinessZone.ZONE_8A,crop.getPlantId()).orElseThrow(PlantNotFoundException::new);
|
||||
|
||||
if(plant.wateringCycle().litersPerSqM() < rainAmount){
|
||||
adjustNextExecutionOfWateringTasks(taskList.getTaskList(LocalDate.now(), LocalDate.now().plusDays(7)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set next execution date of the water plant tasks
|
||||
* @param cropTaskList List with tasks from crops
|
||||
* @throws IOException If the database cannot be accessed
|
||||
* @throws HardinessZoneNotSetException If the hardiness zone is not available
|
||||
* @throws PlantNotFoundException if the plant is not available for the watering task
|
||||
*/
|
||||
private void adjustNextExecutionOfWateringTasks(List<Task> cropTaskList){
|
||||
for(Task task : cropTaskList){
|
||||
if(task.getName().equals("water plant")){
|
||||
task.setNextExecution(task.getNextExecution().plusDays(task.getInterval().orElse(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
/**
|
||||
* The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
|
||||
*
|
||||
*/
|
||||
public class WeatherService {
|
||||
private static final int NO_RAIN = 0;
|
||||
private static final int LITTLE_RAIN = 15;
|
||||
private static final int RAIN = 25;
|
||||
private static final int HEAVY_RAIN = 50;
|
||||
|
||||
public SevereWeather causeSevereWeather(int randomWeather) {
|
||||
return switch (randomWeather) {
|
||||
case 1 -> SevereWeather.HAIL;
|
||||
case 2 -> SevereWeather.SNOW;
|
||||
case 3 -> SevereWeather.FROST;
|
||||
default -> null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public int causeRainAmount(int randomRainAmount) {
|
||||
return switch (randomRainAmount) {
|
||||
case 1 -> NO_RAIN;
|
||||
case 2 -> LITTLE_RAIN;
|
||||
case 3 -> RAIN;
|
||||
case 4 -> HEAVY_RAIN;
|
||||
default -> -1;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,12 +1,7 @@
|
|||
package ch.zhaw.gartenverwaltung.bootstrap;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.HelloApplication;
|
||||
import ch.zhaw.gartenverwaltung.io.CropList;
|
||||
import ch.zhaw.gartenverwaltung.io.JsonCropList;
|
||||
import ch.zhaw.gartenverwaltung.io.JsonPlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.JsonTaskList;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.TaskList;
|
||||
import ch.zhaw.gartenverwaltung.Main;
|
||||
import ch.zhaw.gartenverwaltung.io.*;
|
||||
import ch.zhaw.gartenverwaltung.models.Garden;
|
||||
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
|
||||
import ch.zhaw.gartenverwaltung.models.PlantListModel;
|
||||
|
@ -82,7 +77,7 @@ public class AppLoader {
|
|||
* @throws IOException if the file could not be loaded
|
||||
*/
|
||||
public Object loadSceneToStage(String fxmlFile, Stage appendee) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile)));
|
||||
Pane root = loader.load();
|
||||
Scene scene = new Scene(root);
|
||||
String css = Objects.requireNonNull(this.getClass().getResource("styles.css")).toExternalForm();
|
||||
|
@ -104,7 +99,7 @@ public class AppLoader {
|
|||
* @throws IOException if the file could not be loaded
|
||||
*/
|
||||
public Object loadPaneToDialog(String fxmlFile, DialogPane appendee) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile)));
|
||||
appendee.setContent(loader.load());
|
||||
Object controller = loader.getController();
|
||||
annotationInject(controller);
|
||||
|
@ -119,7 +114,7 @@ public class AppLoader {
|
|||
* @throws IOException if the file could not be loaded
|
||||
*/
|
||||
public void loadAndCacheFxml(String fxmlFile) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile)));
|
||||
Pane pane = loader.load();
|
||||
panes.put(fxmlFile, pane);
|
||||
annotationInject(loader.getController());
|
||||
|
@ -157,7 +152,7 @@ public class AppLoader {
|
|||
});
|
||||
}
|
||||
|
||||
private Object getAppDependency(Class<?> type) {
|
||||
public Object getAppDependency(Class<?> type) {
|
||||
return dependencies.get(type.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,9 @@ public class PlantImageDeserializer extends JsonDeserializer<Image> {
|
|||
@Override
|
||||
public Image deserialize(JsonParser parser, DeserializationContext context) throws IOException {
|
||||
Image result = null;
|
||||
URL imageUrl = PlantList.class.getResource(String.format("images/%s", parser.getText()));
|
||||
if (imageUrl != null) {
|
||||
try (InputStream is = new FileInputStream(new File(imageUrl.toURI()))) {
|
||||
result = new Image(is);
|
||||
} catch (IllegalArgumentException | URISyntaxException e) {
|
||||
throw new IOException(String.format("Cannot find Image \"%s\"\n", imageUrl.getFile()));
|
||||
}
|
||||
InputStream is = PlantList.class.getResourceAsStream(String.format("images/%s", parser.getText()));
|
||||
if (is != null) {
|
||||
result = new Image(is);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.time.LocalDate;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GardenSchedule {
|
||||
|
@ -49,6 +48,10 @@ public class GardenSchedule {
|
|||
public void planTasksForCrop(Crop crop) throws PlantNotFoundException, HardinessZoneNotSetException, IOException {
|
||||
Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).orElseThrow(PlantNotFoundException::new);
|
||||
int growPhaseGroup = plant.getGrowphaseGroupForDate(crop.getStartDate());
|
||||
addTask(new Task("watering Task", "pour water over the plant circa : "+ plant.wateringCycle().litersPerSqM() +" per square meter",
|
||||
crop.getStartDate(), crop.getStartDate().plusDays(plant.timeToHarvest(0)),
|
||||
plant.wateringCycle().interval(), crop.getCropId().orElse(0L)));
|
||||
|
||||
for (GrowthPhase growthPhase : plant.lifecycleForGroup(growPhaseGroup)) {
|
||||
for (TaskTemplate taskTemplate : growthPhase.taskTemplates()) {
|
||||
addTask(taskTemplate.generateTask(crop.getStartDate(), crop.getCropId().orElse(0L)));
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package ch.zhaw.gartenverwaltung.types;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.io.JsonPlantList;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
|
|
@ -12,7 +12,6 @@ public record GrowthPhase(
|
|||
MonthDay startDate,
|
||||
MonthDay endDate,
|
||||
int group,
|
||||
WateringCycle wateringCycle,
|
||||
@JsonDeserialize(using = GrowthPhaseTypeDeserializer.class) GrowthPhaseType type,
|
||||
@JsonDeserialize(using = HardinessZoneDeserializer.class) HardinessZone zone,
|
||||
List<TaskTemplate> taskTemplates) {
|
||||
|
|
|
@ -18,6 +18,7 @@ public record Plant(
|
|||
int light,
|
||||
String soil,
|
||||
List<Pest> pests,
|
||||
WateringCycle wateringCycle,
|
||||
List<GrowthPhase> lifecycle) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,6 +41,16 @@ public class Task {
|
|||
this.cropId = cropId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for weather events
|
||||
*/
|
||||
public Task(String name, String description, LocalDate startDate, LocalDate endDate) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public Task(String name, String description, LocalDate startDate, LocalDate endDate, int interval, long cropId) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
|
@ -72,8 +82,10 @@ public class Task {
|
|||
public void done(){
|
||||
if(interval != null && interval != 0 && !nextExecution.plusDays(interval).isAfter(endDate)){
|
||||
nextExecution = nextExecution.plusDays(interval);
|
||||
nextNotification = nextExecution;
|
||||
} else {
|
||||
nextExecution = null;
|
||||
nextNotification = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ module ch.zhaw.gartenverwaltung {
|
|||
requires com.fasterxml.jackson.datatype.jsr310;
|
||||
requires com.fasterxml.jackson.datatype.jdk8;
|
||||
requires java.logging;
|
||||
requires java.mail;
|
||||
|
||||
|
||||
opens ch.zhaw.gartenverwaltung to javafx.fxml;
|
||||
opens ch.zhaw.gartenverwaltung.types to com.fasterxml.jackson.databind;
|
||||
|
@ -13,4 +15,8 @@ module ch.zhaw.gartenverwaltung {
|
|||
exports ch.zhaw.gartenverwaltung.types;
|
||||
exports ch.zhaw.gartenverwaltung.models;
|
||||
exports ch.zhaw.gartenverwaltung.json;
|
||||
exports ch.zhaw.gartenverwaltung.backgroundtasks;
|
||||
opens ch.zhaw.gartenverwaltung.backgroundtasks to javafx.fxml;
|
||||
exports ch.zhaw.gartenverwaltung.backgroundtasks.email;
|
||||
opens ch.zhaw.gartenverwaltung.backgroundtasks.email to javafx.fxml;
|
||||
}
|
|
@ -14,6 +14,11 @@
|
|||
"measures": "Less water."
|
||||
}
|
||||
],
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-10",
|
||||
|
@ -21,11 +26,6 @@
|
|||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Germinate",
|
||||
|
@ -42,11 +42,6 @@
|
|||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 7,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -63,11 +58,6 @@
|
|||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvest",
|
||||
|
@ -85,6 +75,11 @@
|
|||
"name": "Early Carrot",
|
||||
"description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
|
||||
"image": "carrot.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 3,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "02-20",
|
||||
|
@ -92,11 +87,7 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "SOW",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 3,
|
||||
"notes": []
|
||||
},
|
||||
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -113,13 +104,6 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "PLANT",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 3,
|
||||
"notes": [
|
||||
"Be careful not to pour water over the leaves, as this will lead to sunburn."
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -136,11 +120,6 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "HARVEST",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
|
@ -167,6 +146,12 @@
|
|||
"name": "Summertime Onion",
|
||||
"description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
|
||||
"image": "onion.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 4,
|
||||
"notes": [
|
||||
]
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-15",
|
||||
|
@ -174,12 +159,6 @@
|
|||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 4,
|
||||
"notes": [
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Plant Sets",
|
||||
|
@ -196,13 +175,6 @@
|
|||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 3,
|
||||
"notes": [
|
||||
""
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -219,12 +191,6 @@
|
|||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": [
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
|
@ -261,6 +227,11 @@
|
|||
"measures": "Less water."
|
||||
}
|
||||
],
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "12-01",
|
||||
|
@ -268,11 +239,7 @@
|
|||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Germinate",
|
||||
|
@ -289,11 +256,6 @@
|
|||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 7,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -310,11 +272,6 @@
|
|||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvest",
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
"id": 2,
|
||||
"name": "water plant",
|
||||
"description": "water the plant, so that the soil is wet around the plant.",
|
||||
"startDate": "2022-05-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"startDate": "2022-10-29",
|
||||
"nextExecution": "2022-11-30",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate": "2022-09-01",
|
||||
"endDate": "2022-12-31",
|
||||
"interval": 2,
|
||||
"cropId": 0
|
||||
},
|
||||
|
|
|
@ -49,11 +49,12 @@ public class GardenPlanModelTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())));
|
||||
new WateringCycle(15, 0, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())));
|
||||
|
||||
exampleCropOnion = new Crop(examplePlantOnion.id(), LocalDate.of(2023, 3, 1))
|
||||
.withId(3);
|
||||
|
@ -66,7 +67,8 @@ public class GardenPlanModelTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())));
|
||||
new WateringCycle(25, 0, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())));
|
||||
exampleCropCarrot = new Crop(examplePlantCarrot.id(), LocalDate.now())
|
||||
.withId(5);
|
||||
|
||||
|
|
|
@ -7,8 +7,14 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
@ -88,14 +94,19 @@ class GardenScheduleTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
new WateringCycle(15, 0, null),
|
||||
List.of(
|
||||
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, List.of(
|
||||
|
||||
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, List.of(
|
||||
exampleTaskTemplateList.get(0),
|
||||
exampleTaskTemplateList.get(1)
|
||||
)),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, List.of(
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, List.of(
|
||||
exampleTaskTemplateList.get(2),
|
||||
exampleTaskTemplateList.get(3)
|
||||
)),
|
||||
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, List.of(
|
||||
|
||||
))
|
||||
)));
|
||||
}
|
||||
|
@ -187,8 +198,7 @@ class GardenScheduleTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void planTasksForCrop() throws HardinessZoneNotSetException, PlantNotFoundException, IOException {
|
||||
assertThrows(PlantNotFoundException.class,()-> model.planTasksForCrop(new Crop()));
|
||||
void planTasksForCrop() throws HardinessZoneNotSetException, PlantNotFoundException, IOException, URISyntaxException {
|
||||
model.planTasksForCrop(new Crop(20, exampleStartDate).withId(30));
|
||||
verify(exampleTaskTemplateList.get(0), times(1)).generateTask(exampleStartDate, 30);
|
||||
verify(exampleTaskTemplateList.get(1), times(1)).generateTask(exampleStartDate, 30);
|
||||
|
@ -198,5 +208,18 @@ class GardenScheduleTest {
|
|||
verify(taskList, times(1)).saveTask(exampleTaskList.get(1));
|
||||
verify(taskList, times(1)).saveTask(exampleTaskList.get(2));
|
||||
verify(taskList, times(1)).saveTask(exampleTaskList.get(3));
|
||||
|
||||
final URL dbDataSource = this.getClass().getResource("test-taskdb.json");
|
||||
final URL testFile = this.getClass().getResource("template-taskdb.json");
|
||||
|
||||
Files.copy(Path.of(testFile.toURI()), Path.of(dbDataSource.toURI()), StandardCopyOption.REPLACE_EXISTING);
|
||||
JsonTaskList testTaskList = new JsonTaskList(dbDataSource);
|
||||
|
||||
model = spy(new GardenSchedule(testTaskList,plantList));
|
||||
model.planTasksForCrop(new Crop(20, exampleStartDate).withId(30));
|
||||
assertEquals(5,testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).size());
|
||||
testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).get(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -49,11 +49,12 @@ class PlantListModelTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
new WateringCycle(25, 0, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
);
|
||||
examplePlantList.add(new Plant(
|
||||
0,
|
||||
|
@ -64,8 +65,9 @@ class PlantListModelTest {
|
|||
6,
|
||||
"sandy",
|
||||
new ArrayList<>(),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
new WateringCycle(0, 0, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
);
|
||||
examplePlantList.add(new Plant(
|
||||
1,
|
||||
|
@ -76,7 +78,8 @@ class PlantListModelTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
new WateringCycle(25, 0, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,16 +20,16 @@ class PlantTest {
|
|||
@BeforeEach
|
||||
void setUp() {
|
||||
List<GrowthPhase> growthPhases = new ArrayList<>();
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(2, 1), MonthDay.of(4, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(4, 2), MonthDay.of(6, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(6, 3), MonthDay.of(8, 6), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(3, 1), MonthDay.of(5, 4), 1, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(5, 2), MonthDay.of(7, 5), 1, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(7, 3), MonthDay.of(9, 6), 1, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(4, 1), MonthDay.of(6, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(6, 2), MonthDay.of(8, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(7, 2), MonthDay.of(9, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(8, 3), MonthDay.of(10, 6), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(2, 1), MonthDay.of(4, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(4, 2), MonthDay.of(6, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(6, 3), MonthDay.of(8, 6), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(3, 1), MonthDay.of(5, 4), 1, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(5, 2), MonthDay.of(7, 5), 1, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(7, 3), MonthDay.of(9, 6), 1, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(4, 1), MonthDay.of(6, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(6, 2), MonthDay.of(8, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(7, 2), MonthDay.of(9, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
growthPhases.add(new GrowthPhase(MonthDay.of(8, 3), MonthDay.of(10, 6), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_1A, new ArrayList<>()));
|
||||
|
||||
testPlant = new Plant(
|
||||
20,
|
||||
|
@ -40,6 +40,7 @@ class PlantTest {
|
|||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
new WateringCycle(25, 0, null),
|
||||
growthPhases);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
[
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Potato",
|
||||
"description": "The potato is a tuber, round or oval, with small white roots called 'eyes', that are growth buds. The size varies depending on the variety; the colour of the skin can be white, yellow or even purple.",
|
||||
"light": 6,
|
||||
"spacing": "35",
|
||||
"soil": "sandy",
|
||||
"image": "potato.jpg",
|
||||
"pests": [
|
||||
{
|
||||
"name": "Rot",
|
||||
"description": "Rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
|
||||
"measures": "Less water."
|
||||
}
|
||||
],
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-10",
|
||||
"endDate": "04-10",
|
||||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Germinate",
|
||||
"relativeStartDate": -14,
|
||||
"relativeEndDate": null,
|
||||
"description": "Take an egg carton and fill it with soil. Put the seedling deep enough so its half covered with soil. Keep it in 10-15 * Celsius with lots of light.",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "04-10",
|
||||
"endDate": "07-10",
|
||||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": null,
|
||||
"description": "When the plants are 20 cm tall, begin hilling the potatoes by gently mounding the soil from the center of your rows around the stems of the plant. Mound up the soil around the plant until just the top few leaves show above the soil. Two weeks later, hill up the soil again when the plants grow another 20 cm.",
|
||||
"interval": 21
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "06-10",
|
||||
"endDate": "08-10",
|
||||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvest",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": null,
|
||||
"description": "Once the foliage has wilted and dried completely, harvest on a dry day. Store in a dark and cool location.",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Early Carrot",
|
||||
"description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
|
||||
"image": "carrot.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 3,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "02-20",
|
||||
"endDate": "03-10",
|
||||
"zone": "ZONE_8A",
|
||||
"type": "SOW",
|
||||
"group": 0,
|
||||
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": 0,
|
||||
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "03-10",
|
||||
"endDate": "05-10",
|
||||
"zone": "ZONE_8A",
|
||||
"type": "PLANT",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": null,
|
||||
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
|
||||
"interval": 15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "05-10",
|
||||
"endDate": "05-20",
|
||||
"zone": "ZONE_8A",
|
||||
"type": "HARVEST",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": 14,
|
||||
"description": "When the leaves turn to a yellowish brown. Do not harvest earlier. The plant will show when it's ready.",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"soil": "sandy to loamy, loose soil, free of stones",
|
||||
"spacing": "5,35,2.5",
|
||||
"pests": [
|
||||
{
|
||||
"name": "Rot",
|
||||
"description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
|
||||
"measures": "less water"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Summertime Onion",
|
||||
"description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
|
||||
"image": "onion.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 4,
|
||||
"notes": [
|
||||
]
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-15",
|
||||
"endDate": "04-10",
|
||||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Plant Sets",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": 0,
|
||||
"description": "Plant the sets about 5cm deep into the soil.",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "04-10",
|
||||
"endDate": "07-10",
|
||||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": null,
|
||||
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
|
||||
"interval": 15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"startDate": "07-10",
|
||||
"endDate": "09-20",
|
||||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": 14,
|
||||
"description": "When ready for harvest, the leaves on your onion plants will start to flop over. This happens at the \"neck\" of the onion and it signals that the plant has stopped growing and is ready for storage. Onions should be harvested soon thereafter",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"soil": "sandy to loamy, loose soil, free of stones",
|
||||
"spacing": "15,30,2",
|
||||
"pests": [
|
||||
{
|
||||
"name": "Rot",
|
||||
"description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
|
||||
"measures": "less water"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -4,6 +4,8 @@
|
|||
"name" : "sow plant",
|
||||
"description": "Plant the seeds, crops in de bed.",
|
||||
"startDate" : "2022-05-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-05-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 0
|
||||
|
@ -13,6 +15,8 @@
|
|||
"name" : "water plant",
|
||||
"description": "water the plant, so that the soil is wet around the plant.",
|
||||
"startDate" : "2022-05-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-09-01",
|
||||
"interval" : 2,
|
||||
"cropId" : 0
|
||||
|
@ -22,6 +26,8 @@
|
|||
"name" : "fertilize plant",
|
||||
"description": "The fertilizer has to be mixed with water. Then fertilize the plants soil with the mixture",
|
||||
"startDate" : "2022-06-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-08-01",
|
||||
"interval" : 28,
|
||||
"cropId" : 0
|
||||
|
@ -31,6 +37,8 @@
|
|||
"name" : "covering plant",
|
||||
"description": "Take a big enough coverage for the plants. Cover the whole plant with a bit space between the plant and the coverage",
|
||||
"startDate" : "2022-07-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-07-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 0
|
||||
|
@ -40,6 +48,8 @@
|
|||
"name" : "look after plant",
|
||||
"description": "Look for pest or illness at the leaves of the plant. Check the soil around the plant, if the roots are enough covered with soil",
|
||||
"startDate" : "2022-05-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-09-01",
|
||||
"interval" : 5,
|
||||
"cropId" : 0
|
||||
|
@ -49,6 +59,8 @@
|
|||
"name" : "harvest plant",
|
||||
"description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ",
|
||||
"startDate" : "2022-09-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"endDate" : "2022-09-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 0
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
"measures": "Less water."
|
||||
}
|
||||
],
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-10",
|
||||
|
@ -21,11 +26,6 @@
|
|||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Germinate",
|
||||
|
@ -42,11 +42,6 @@
|
|||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 7,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -63,11 +58,6 @@
|
|||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvest",
|
||||
|
@ -85,6 +75,11 @@
|
|||
"name": "Early Carrot",
|
||||
"description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
|
||||
"image": "carrot.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 3,
|
||||
"notes": []
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "02-20",
|
||||
|
@ -92,11 +87,7 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "SOW",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 3,
|
||||
"notes": []
|
||||
},
|
||||
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -113,13 +104,6 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "PLANT",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 3,
|
||||
"notes": [
|
||||
"Be careful not to pour water over the leaves, as this will lead to sunburn."
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -136,11 +120,6 @@
|
|||
"zone": "ZONE_8A",
|
||||
"type": "HARVEST",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": []
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
|
@ -167,6 +146,12 @@
|
|||
"name": "Summertime Onion",
|
||||
"description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
|
||||
"image": "onion.jpg",
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 4,
|
||||
"notes": [
|
||||
]
|
||||
},
|
||||
"lifecycle": [
|
||||
{
|
||||
"startDate": "03-15",
|
||||
|
@ -174,19 +159,12 @@
|
|||
"type": "SOW",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 15,
|
||||
"interval": 4,
|
||||
"notes": [
|
||||
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
"name": "Plant Sets",
|
||||
"relativeStartDate": 0,
|
||||
"relativeEndDate": 0,
|
||||
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
|
||||
"description": "Plant the sets about 5cm deep into the soil.",
|
||||
"interval": null
|
||||
}
|
||||
]
|
||||
|
@ -197,13 +175,6 @@
|
|||
"type": "PLANT",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 25,
|
||||
"interval": 3,
|
||||
"notes": [
|
||||
""
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "hilling",
|
||||
|
@ -220,13 +191,6 @@
|
|||
"type": "HARVEST",
|
||||
"zone": "ZONE_8A",
|
||||
"group": 0,
|
||||
"wateringCycle": {
|
||||
"litersPerSqM": 0,
|
||||
"interval": null,
|
||||
"notes": [
|
||||
|
||||
]
|
||||
},
|
||||
"taskTemplates": [
|
||||
{
|
||||
"name": "Harvesting",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
Loading…
Reference in New Issue