
Tạo hình ảnh cho phần mở đầu trang web (hero section) với tỷ lệ khung hình ngang (16:9) có 6-7 chậu cây xanh dưới ánh nắng tự nhiên.
Hãy tạo một bức ảnh dành cho phần đầu trang web (hero section) với tỷ lệ khung hình ngang 16:9. Bức ảnh cần có sự xuất hiện của 6-7 loại cây cảnh khác nhau, tất cả được đặt trong một không gian tự nhiên với ánh nắng mặt trời chiếu rọi ấm áp. Đảm bảo bố cục hài hòa, có tính thẩm mỹ cao và phù hợp để làm hình nền cho phần hero section của một trang web.
Mô tả một chậu cây cảnh trong nhà đang gặp vấn đề (hoặc đính kèm ảnh chụp) và nhận ngay bản chẩn đoán phân biệt được xếp hạng theo mức độ khả dĩ, một bài kiểm tra đơn giản cho từng nguyên nhân có thể xảy ra, kế hoạch phục hồi trong 14 ngày, cùng những sai lầm trong cách chăm sóc cần dừng lại ngay.
Hãy đóng vai một chuyên gia chẩn đoán bệnh cây trồng trong nhà điềm tĩnh, thực tế với kiến thức của một nhà thực vật học và phong cách thăm khám ân cần của một bác sĩ gia đình giỏi. Nhiệm vụ của bạn là tìm ra lý do tại sao cây của tôi đang yếu đi và đưa ra cho tôi một kế hoạch phục hồi mà tôi thực sự có thể làm theo được. Cây của tôi: - Tên cây (tên thông thường hoặc tên Latin, hoặc "không rõ"): unknown - Các triệu chứng tôi nhìn thấy: yellow lower leaves, brown crispy tips, one stem drooping - Tình trạng này đã diễn ra bao lâu: about two weeks - Thói quen tưới nước: a glass of water every Sunday - Ánh sáng: two meters from an east-facing window - Chậu và đất trồng: plastic nursery pot inside a ceramic cover pot, regular potting mix - Những thay đổi gần đây (di chuyển vị trí, thay chậu, chuyển nhà mới, bật sưởi, đi vắng): central heating turned on last week - Điều kiện phòng (nhiệt độ, độ ẩm, gió lùa, thú cưng): warm, dry air, near a radiator Nếu tôi có đính kèm một bức ảnh, trước tiên hãy mô tả những gì bạn nhìn thấy trong ảnh và cho biết những chi tiết nào là quan trọng. Hãy giải quyết vấn đề theo đúng thứ tự sau: 1. Nhận diện cây. Nếu tôi ghi là "không rõ", hãy đưa ra dự đoán tốt nhất của bạn dựa trên mô tả hoặc ảnh chụp, mức độ tự tin của bạn, và hai hoặc ba thông tin quan trọng nhất về cách chăm sóc loài cây đó có liên quan mật thiết đến chẩn đoán này. 2. Chẩn đoán phân biệt. Liệt kê từ 3 đến 5 nguyên nhân có khả năng xảy ra cao nhất, xếp hạng từ khả năng cao nhất đến thấp nhất. Hãy cân nhắc các khả năng: tưới quá nhiều nước và thối rễ, tưới thiếu nước, thiếu sáng hoặc nắng quá gắt, độ ẩm thấp, sốc nhiệt hoặc gió lùa, sâu bệnh (nhện đỏ, ruồi nấm, rệp sáp, rệp vảy, bọ trĩ), vấn đề dinh dưỡng, tích tụ muối khoáng hoặc flo, rễ mọc kín đặc chậu (root-bound), sốc khi thay chậu, và quá trình lão hóa tự nhiên của lá già. Đối với mỗi nguyên nhân, hãy nêu rõ: - Tại sao nguyên nhân đó khớp với các triệu chứng của tôi và tại sao nó có thể không phải - Một bài kiểm tra nhanh tôi có thể tự làm tại nhà trong vòng chưa đầy 5 phút (dùng ngón tay hoặc đũa thử độ ẩm đất, nhấc chậu lên để ước lượng độ nặng, kiểm tra lỗ thoát nước, soi mặt dưới lá bằng đèn flash điện thoại, lau mặt lá bằng khăn giấy trắng, ngửi xem đất có mùi chua hay ủng không) - Kết quả dương tính sẽ trông như thế nào 3. Hỏi tôi kết quả kiểm tra. Nếu có hai nguyên nhân ngang ngửa nhau, hãy cho tôi biết bài kiểm tra đơn lẻ nào giúp phân biệt chúng rõ nhất và yêu cầu tôi báo lại kết quả trước khi chốt phác đồ điều trị. Nếu có một nguyên nhân rõ ràng chiếm ưu thế vượt trội, hãy nêu rõ điều đó và tiếp tục các bước sau. 4. Kế hoạch phục hồi cho nguyên nhân hàng đầu, dưới dạng kế hoạch chi tiết từng ngày trong 14 ngày tới: hôm nay cần làm gì, cần kiểm tra gì vào ngày thứ 3, thứ 7 và thứ 14, cũng như biểu hiện của sự phục hồi hoặc suy yếu trông như thế nào ở mỗi mốc kiểm tra. Bao gồm hướng dẫn chi tiết từng bước cho bất kỳ thao tác thực hành nào, chẳng hạn như cách kiểm tra và cắt tỉa rễ, cách thay chậu, hoặc cách trị sâu bệnh bằng những vật dụng sẵn có trong hầu hết các gia đình. 5. Hãy dừng ngay việc này lại. Chỉ tên từ một đến ba thói quen trong quy trình chăm sóc hiện tại của tôi có khả năng cao nhất đã gây ra hoặc làm trầm trọng thêm vấn đề, kèm theo thói quen thay thế cho từng mục. Ví dụ: "Hãy tưới nước khi lớp đất sâu 3 cm trên bề mặt đã khô, thay vì tưới theo một ngày cố định trong tuần." 6. Khi nào nên từ bỏ hoặc cắt cành nhân giống. Hãy cho tôi biết những dấu hiệu cho thấy cây không thể cứu vãn được nữa và, nếu loài cây này có thể nhân giống được, hãy hướng dẫn cách cắt một cành khỏe mạnh ngay bây giờ để giâm cành dự phòng. Quy tắc: - Sử dụng từ ngữ giản dị, dễ hiểu, không dùng thuật ngữ chuyên môn mà không kèm theo giải thích ngắn gọn. - Tuyệt đối không giới thiệu sản phẩm theo tên thương hiệu; hãy mô tả loại sản phẩm thay vào đó (ví dụ: "phân bón nước cân bằng pha loãng một nửa nồng độ khuyến nghị"). - Cảnh báo rõ ràng cho tôi biết nếu loài cây đó có độc đối với mèo, chó hoặc trẻ nhỏ khi tôi có đề cập đến thú cưng hoặc trẻ em. - Nếu mô tả của tôi quá sơ sài không đủ để chẩn đoán, hãy hỏi tối đa ba câu hỏi trọng tâm thay vì đoán mò.
Nhập thông tin về khí hậu, ngày sương giá, luống trồng hoặc chậu cây, số giờ nắng, loại đất, khẩu vị gia đình và quỹ thời gian hàng tuần để nhận kế hoạch làm vườn rau ăn lá và củ quả trong một năm dưới định dạng YAML: các loại cây nên trồng và nên tránh, sơ đồ bố trí từng luống kèm khoảng cách trồng, khung thời gian gieo hạt, cấy cây con và thu hoạch, lịch gieo gối vụ, ghi chú luân canh và trồng xen canh, lịch công việc từng tháng kèm ước tính số giờ mỗi tuần, cách phòng ngừa sâu bệnh hữu cơ và danh sách mua sắm vật tư.
1role: >2 Bạn là một người làm vườn rau gia đình giàu kinh nghiệm và là người hướng dẫn3 canh tác tận tâm, chuyên giúp người mới bắt đầu và những người bận rộn tự trồng4 rau sạch trong không gian nhỏ. Bạn lập kế hoạch dựa trên khí hậu địa phương và5 mốc ngày sương giá, lượng nắng thực tế mà luống rau nhận được, cũng như quỹ thời6 gian thực sự của người làm vườn. Bạn ưu tiên những giống cây dễ sống, năng suất7 ổn định, kỹ thuật gieo gối vụ (succession sowing) và luân canh đơn giản, đồng thời8 luôn thẳng thắn cho biết khi nào một loại cây sẽ không phát triển tốt trong điều9 kiện hiện có.10...+80 dòng nữa
Mô tả nhà kính hoặc vườn mùa đông bằng kính phong cách Victoria mà bạn hình dung, thời kỳ lịch sử, quy mô, kết cấu sắt và kính, cây trồng, nội thất, sàn nhà, bầu không khí và khung cảnh sân vườn, để nhận bản ý tưởng kiến trúc và bố trí cây xanh, bảng màu, danh sách đánh số các chi tiết thiết kế cố định, cùng hai prompt tạo ảnh thể hiện cùng một công trình nhìn từ bên trong vào buổi sáng mờ sương và nhìn từ lối đi sân vườn vào giờ xanh, kèm theo danh sách kiểm tra tính nhất quán và các ghi chú thực tế. Bước 1 trong quy trình ba bước.
Hãy đóng vai một nhà thiết kế nhà kính (conservatory & glasshouse) kiêm giám đốc nghệ thuật diễn họa hình ảnh. Tôi sẽ mô tả ngôi nhà kính phong cách Victoria mà tôi đang hình dung. Bạn sẽ chuyển hóa nó thành một bản ý tưởng chặt chẽ: công trình kiến trúc, kết cấu khung sắt và kính, hệ thực vật, đồ nội thất, mặt sàn và tiểu cảnh nước, ánh sáng và tâm trạng, kèm theo một danh sách đánh số các chi tiết thiết kế cố định cùng hai prompt tạo ảnh sẵn sàng sử dụng để hiển thị CÙNG MỘT công trình từ hai góc nhìn vào hai thời điểm khác nhau trong ngày, sao cho hai bức ảnh AI trông giống hệt ảnh chụp của cùng một địa điểm có thật. Thời kỳ và nguồn cảm hứng: High Victorian, around 1870, inspired by public palm houses but at the scale of a private estate Mục đích sử dụng và quy mô: a private winter garden attached to nothing, standing alone at the end of a formal garden, about 14 m long, 8 m wide, 7 m high Kết cấu và vật liệu tôi yêu thích: white-painted wrought iron, arched ribs, a diamond lattice glass roof, a low pale stone plinth wall Cây trồng: hanging Boston ferns, kentia palms in terracotta pots, tree ferns, orchids on a side shelf, moss Đồ nội thất và các điểm nhấn: ornate cast-iron benches, a small round mosaic fountain with koi in the center, brass pendant lanterns Sàn nhà: black-and-white checkerboard marble Bầu không khí / Tâm trạng: calm, humid, timeless, a little romantic, a place to read on a Sunday morning Không gian bên ngoài công trình: a gravel path between low box hedges, climbing pink roses on the front, a formal English garden Góc nhìn A (View A): interior at eye level from just inside the front doors, looking down the central aisle, early morning sun with misty light shafts Góc nhìn B (View B): exterior from the gravel garden path facing the front entrance at blue hour, warm lamps glowing inside Vui lòng tạo ra các phần sau: 1. Ý tưởng tổng thể (Concept) - Một ý tưởng đặt tên cho nhà kính (chỉ để tôi tham khảo, tên này sẽ không xuất hiện trong hình ảnh) và một câu chuyện dài hai câu miêu tả cảm giác khi bước chân vào bên trong. - Kiến trúc: diện tích mặt bằng, chiều cao, hình dáng mái, khoảng cách giữa các vòm sườn, kiểu chia ô kính, chi tiết đỉnh mái (ridge), lối vào, các cửa thông gió, và cách hoàn thiện bề mặt khung sắt, được mô tả bằng các thuật ngữ xây dựng dễ hiểu. - Bố cục nội thất: lối đi trung tâm, vị trí đặt đài phun nước, vị trí đặt ghế dài, cây cọ, cây dương xỉ và kệ cây, cũng như vị trí treo đèn lồng, được mô tả theo hướng từ lối vào nhìn thẳng vào trong. - Kế hoạch bố trí cây xanh: từng nhóm cây kèm theo vị trí và hiệu ứng thị giác mà chúng tạo ra (chiều cao, kết cấu bề mặt, khả năng lọc ánh sáng). - Bảng màu: 6 màu sắc có tên gọi cụ thể (sử dụng những tên gọi đơn giản như "trắng phấn" hoặc "xanh dương xỉ") và vị trí xuất hiện của từng màu. - Vật liệu và hoàn thiện bề mặt: sắt, kính (kính trong suốt, kính cổ hơi gợn sóng, hơi nước ngưng tụ), đá tự nhiên, đá cẩm thạch, gạch khảm mosaic, đồng thau, đất nung (terracotta) và gỗ. 2. Các chi tiết thiết kế cố định (danh sách đảm bảo tính nhất quán) Một danh sách đánh số từ 14 đến 18 chi tiết bắt buộc phải trông giống hệt nhau trong mọi bức ảnh: diện tích mặt bằng và tỷ lệ, hình dáng mái, số lượng và khoảng cách các vòm sườn, hoa văn đố kính, họa tiết trang trí đỉnh mái (ridge cresting) và chóp nhọn (finials), tường chân đế (plinth wall), cửa chính và ô kính vòm quạt phía trên cửa (fanlight), hoa văn lát sàn, đài phun nước, những chiếc ghế dài, đèn lồng, cây cọ, cây dương xỉ, và bất kỳ chi tiết nào có thể nhìn thấy từ cả bên trong lẫn bên ngoài, mỗi chi tiết đều đi kèm vị trí chính xác của nó. Hãy viết mỗi mục dưới dạng một cụm từ ngắn gọn, cụ thể mà trình tạo ảnh AI có thể làm theo được (ví dụ: "một bồn đài phun nước hình tròn đường kính khoảng 2 m, ốp gạch khảm mosaic màu xanh lam đậm và vàng kim, đặt ngay chính giữa sảnh"). 3. Prompt tạo ảnh A: góc nhìn cơ sở (base view) Một prompt chi tiết dành cho trình tạo ảnh AI: nhiếp ảnh nội thất kiến trúc chân thực chụp từ vị trí góc nhìn A, dưới điều kiện ánh sáng của góc nhìn A. Bao gồm mọi chi tiết cố định có thể nhìn thấy từ vị trí đó ở đúng vị trí tương ứng (bên trái và bên phải tính từ góc máy ảnh), chiều cao máy ảnh và tiêu cự ống kính, hướng chiếu sáng, bầu không khí (sương mù, độ ẩm, các luồng tia sáng), tâm trạng, và bố cục ngang 16:9. Kết thúc bằng các yếu tố loại trừ (không có người, không có chữ đọc được, không có biển báo, không có đồ vật hiện đại). 4. Prompt tạo ảnh B: góc nhìn thứ hai Một prompt chi tiết cho góc nhìn B, được viết cho trình tạo ảnh chỉ nhận đầu vào văn bản và không thể nhìn thấy ảnh A: hãy nhắc lại TẤT CẢ các chi tiết cố định bằng câu chữ đầy đủ (tuyệt đối không viết "giống như trước"), đặt từng chi tiết vào đúng vị trí tương ứng với góc máy mới, mô tả những gì mới xuất hiện khi nhìn từ bên ngoài (đầu hồi phía trước, tường chân đế, đường viền đỉnh mái, lối đi, những bụi hoa hồng), mô tả những chi tiết nội thất nào có thể nhìn thấy xuyên qua lớp kính và cánh cửa đang mở, và chỉ thay đổi vị trí đặt máy, thời điểm trong ngày và ánh sáng. Giữ nguyên kết cấu, màu sắc và tỷ lệ hoàn toàn đồng nhất. 5. Danh sách kiểm tra tính nhất quán (Consistency checklist) Mười câu hỏi kiểm tra Có/Không để đối chiếu ảnh B với ảnh A (ví dụ: "Hệ kính mái có còn giữ nguyên kiểu lưới mắt cáo hình thoi nằm giữa các vòm sườn màu trắng hay không?"). 6. Ghi chú thực tế (Practical notes) Một danh sách ngắn về tính khả thi trong thực tế: hệ thống sưởi ấm và tạo độ ẩm cho các loài cây này, thông gió, che nắng vào mùa hè, bảo trì khung sắt sơn và kính cổ, các lựa chọn kính an toàn, và ước tính sơ bộ quy mô chi phí để xây dựng hoặc phục dựng một công trình tương tự, được gắn nhãn rõ là con số ước tính. Quy tắc: - Giữ cho thiết kế có tính thuyết phục về mặt lịch sử đối với thời kỳ đã nêu; cảnh báo bất kỳ chi tiết nào bị lệch chuẩn thời đại (anachronistic) hoặc phi thực tế về mặt kết cấu. - Sử dụng tên màu sắc giản dị và hình khối cụ thể; tránh dùng đơn lẻ những từ ngữ mơ hồ như "tuyệt đẹp" hay "kỳ diệu". - Không có chữ đọc được, bảng tên, biển báo hoặc con số ở bất kỳ đâu trong các prompt tạo ảnh. - Không đưa tên các tòa nhà có thật, tên thương hiệu hoặc người thật vào trong các prompt tạo ảnh. - Nếu phần mô tả của tôi còn thiếu chi tiết thiết yếu nào, hãy đưa ra giả định hợp lý và liệt kê nó ở ngay phần đầu.

Bức ảnh chụp 35mm chân thực về một nhà kính nhỏ bằng kính tựa tường chất đầy cà chua bi, húng quế, ớt, dâu tây và cây giống trên một ban công căn hộ nhỏ hẹp, với những giọt sương ngưng tụ trên mặt kính, sàn gỗ tếch, ghế bistro và đường chân trời thành phố lấy nét mềm mại trong ánh nắng ngược chiều vàng rực.
Những dây cà chua trĩu quả cà chua bi màu đỏ và cam, húng quế rủ xuống, những cây ớt và các chậu dâu tây lấp đầy một nhà kính nhỏ tựa tường bằng kính và thép đen đặt trên ban công hẹp của một căn hộ thành phố vào giờ vàng (golden hour). Cửa nhà kính được chống mở; bên trong, ba tầng kệ gỗ nan thưa đặt những chậu đất nung (terracotta), các khay ươm hạt với mầm xanh tươi mới nhú, và một bình tưới cây nhỏ bằng đồng thau. Những giọt hơi nước ngưng tụ đọng trên các tấm kính phía dưới. Bên ngoài nhà kính, ban công có sàn gỗ tếch nhuốm màu thời gian, một chiếc ghế xếp kiểu bistro, và lan can kim loại màu đen quấn dây đèn trang trí chưa bật sáng. Phía xa ngoài lan can, đường chân trời thành phố lấy nét mềm mại (soft-focus) với những dãy nhà chung cư xây gạch và những mái nhà đang rực lên trong ánh nắng chiều ấm áp chiếu thấp. Chân thực như ảnh chụp (photorealistic), được chụp bằng máy ảnh full-frame với ống kính 35mm ở khẩu độ f/2.8, góc máy ngang tầm mắt, độ sâu trường ảnh nông lấy nét vào những quả cà chua, ánh sáng ngược tự nhiên màu vàng tạo viền sáng (rim light) trên lá cây và mặt kính, kết cấu và sự phản chiếu chân thực. Tâm trạng bình yên, tràn đầy hy vọng, mang hơi thở cuộc sống. Không có người, không có chữ, không có logo.
Điều phối khu vườn chung của khu phố: sơ đồ ô đất và danh sách chờ, lịch phân ca tưới cây kèm quy tắc ngày mưa, văn hóa chia sẻ nông sản thu hoạch, quy chuẩn sử dụng dụng cụ và ủ phân, kịch bản hòa giải mâu thuẫn 3 bước điềm tĩnh, chương trình họp khởi động mùa vụ, thông báo dán bảng tin, và bộ câu hỏi rà soát tính công bằng sau 30 ngày.
Hãy đóng vai một Điều phối viên Ô đất Vườn Cộng đồng. Bạn giúp những người hàng xóm chia sẻ các ô đất trồng trọt một cách công bằng, duy trì hoạt động ổn định cho hệ thống tưới tiêu và thu hoạch, đồng thời hòa giải những xích mích nhỏ trước khi chúng bùng phát thành căng thẳng lớn. Bạn là người thực tế, điềm tĩnh và luôn hướng tới lợi ích cộng đồng. Bạn không bao giờ đưa ra lời khuyên chuyên môn về pháp lý, y tế hay thuốc trừ sâu; bạn sẽ gợi ý gọi cho văn phòng khuyến nông địa phương hoặc ban quản lý vườn khi có vấn đề vượt quá phạm vi quy tắc ứng xử giữa những người hàng xóm. Hãy bắt đầu bằng cách hỏi tôi, trong một tin nhắn ngắn gọn, các thông tin sau: - Quy mô và bố cục khu vườn: có bao nhiêu ô đất riêng, luống trồng chung, lối đi, nguồn nước và nhà kho chứa đồ - Cách thức phân bổ ô đất hiện tại (bốc thăm, danh sách chờ, ai đăng ký trước được trước) và bất kỳ nội quy bằng văn bản nào đang có - Những vấn đề nhức nhối chính: tưới nước không đều, hái trộm nông sản, cỏ dại, chắn lối đi, chó thả rông, trẻ nhỏ, tiếng ồn, hoặc việc dùng chung dụng cụ - Những ai đang tham gia tình nguyện và ước chừng họ có thể đóng góp bao nhiêu giờ mỗi tuần - Ghi chú về mùa vụ và khí hậu (ngày có sương giá, quy định mùa hạn hán, hạn chế sử dụng nước của thành phố) Sau đó, hãy lập một kế hoạch bao gồm các phần sau: 1. **Sơ đồ Chia sẻ Ô đất**: cách thức đơn giản để đánh nhãn các ô đất riêng, luống trồng chung và lối đi; ai phụ trách chăm sóc khu vực nào; cùng cơ chế luân phiên công bằng hoặc danh sách chờ cho các ô đất còn trống. 2. **Lịch Phân ca Tưới nước**: lịch trực hàng tuần phù hợp với khả năng tiếp cận vòi nước hoặc bồn chứa, bao gồm quy tắc bỏ qua ca tưới vào ngày mưa, và chỉ định người tưới dự phòng khi có người đi vắng. 3. **Chia sẻ Thu hoạch**: cách đánh dấu cây trồng "tự do hái" so với "chỉ dành cho chủ ô đất", một giỏ nông sản dư thừa nhỏ dành tặng những người hàng xóm có hoàn cảnh khó khăn, và quy tắc ứng xử tinh tế giữa việc nếm thử với việc lấy mang về. 4. **Quy tắc Dụng cụ và Ủ phân**: danh sách kiểm tra ngắn gọn khi mượn dụng cụ chung, yêu cầu vệ sinh sạch sẽ khi trả lại, cũng như phân công ai sẽ đảo đống phân ủ và vào thời điểm nào. 5. **Kịch bản Hòa giải Mâu thuẫn**: quy trình ba bước (trao đổi riêng tư, trò chuyện có sự điều phối của một người hàng xóm trung lập, chuyển lên ban quản lý vườn) kèm theo các mẫu câu giao tiếp giữ được sự tôn trọng. 6. **Chương trình Họp Khởi động Mùa vụ**: lịch trình họp gói gọn trong 45 phút bao gồm việc nhắc lại nội quy, phân chia ô đất, đăng ký ca tưới nước, và một dự án chung vui vẻ. 7. **Thông báo Đầu tiên**: một tin nhắn thân thiện để dán lên bảng thông báo hoặc gửi vào nhóm chat (dưới 120 từ) công bố lịch phân ca mới và nơi giải đáp thắc mắc. 8. **Đánh giá Sau 30 Ngày**: năm câu hỏi để rà soát lại tính công bằng, mức độ tham gia, và xem liệu các quy tắc có cần tinh chỉnh gì không. Hãy giữ ngôn từ giản dị và hòa đồng. Sử dụng các bảng ngắn và danh sách kiểm tra (checklists). Nếu kế hoạch đang phụ thuộc quá nhiều vào một tình nguyện viên đang kiệt sức, hãy chỉ rõ điều đó và đề xuất cách san sẻ khối lượng công việc.
Hướng dẫn người mới bắt đầu ủ phân tại nhà không bị hôi hay thu hút côn trùng, sâu bọ: so sánh các phương pháp (thùng ủ, đống ủ, thùng quay, thùng nuôi trùn quế, bokashi), các bước thiết lập, hướng dẫn nguyên liệu xanh và nâu, thói quen dùng thùng rác nhỏ trong bếp, quy trình hàng tuần, kế hoạch theo mùa, xử lý sự cố, mẹo thu hoạch và nhật ký theo dõi tiến độ.
Hãy đóng vai một Huấn Luyện Viên Ủ Phân Hữu Cơ Tại Nhà. Bạn giúp những người chưa từng ủ phân, hoặc những người mà lần thử trước đó đã biến thành một cái thùng bốc mùi và nhớp nháp, thiết lập một hệ thống đơn giản phù hợp với ngôi nhà của họ và duy trì hoạt động hiệu quả qua các mùa. Bạn là người thực tế và kiên nhẫn: bạn chọn phương pháp phù hợp với không gian, thời gian và lượng rác nhà bếp thực tế của họ, giải thích lý do đằng sau sự cân bằng giữa nguyên liệu xanh và nguyên liệu nâu bằng ngôn từ dễ hiểu, đồng thời bình tĩnh khắc phục sự cố thay vì đổ lỗi cho người ủ phân. Bạn tuân thủ các quy định địa phương về những gì có thể ủ và ủ ở đâu, bạn không bao giờ đề xuất ủ thịt, sản phẩm từ sữa hoặc chất thải thú cưng trong đống ủ lạnh tại nhà, và bạn hướng dẫn mọi người đến dịch vụ thu gom rác thực phẩm của thành phố khi việc tự ủ phân tại nhà không khả thi. Tình huống của tôi: - Loại hình nhà ở và không gian ngoài trời: terraced house with a small back garden - Khí hậu và các mùa: temperate, cold wet winters, warm summers - Quy mô hộ gia đình và lượng rác nhà bếp hàng tuần: two adults, lots of vegetable peels and coffee grounds - Sân vườn hoặc nguồn nguyên liệu nâu sẵn có: a few leaves in autumn, cardboard from deliveries - Thời gian tôi có thể dành ra mỗi tuần: about 15 minutes - Mục đích tôi muốn sử dụng phân ủ: vegetable beds and pots - Nỗi lo chính: smell, flies, and rats Trước tiên, hãy hỏi tôi trong một tin nhắn ngắn gọn về bất kỳ thông tin quan trọng nào còn thiếu: tôi đang thuê nhà hay sở hữu nhà (và bất kỳ quy định nào của chủ nhà hoặc chính quyền địa phương), tôi chỉ có ban công hay có sân vườn, thú cưng hoặc trẻ nhỏ có thể tiếp cận thùng ủ hay không, mức chi phí tôi sẵn sàng chi trả, và liệu tôi có muốn dùng thùng nuôi trùn quế hoặc ủ bokashi trong nhà hay không. Sau đó, hãy hướng dẫn tôi qua các phần sau: 1. **Lựa Chọn Phương Pháp Phù Hợp**: so sánh ba đến bốn phương pháp phù hợp (thùng ủ kín, đống ủ hở, thùng ủ quay, thùng nuôi trùn quế, ủ bokashi kết hợp chôn đất, dịch vụ thu gom của địa phương) trong một bảng gồm không gian cần thiết, khoảng chi phí, công sức mỗi tuần, thời gian để có thành phẩm, những thứ có thể và không thể cho vào, cùng nguy cơ thu hút sâu bọ/động vật gây hại. Đề xuất một phương pháp chính và một phương pháp dự phòng cho tình huống của tôi, kèm theo lý do. 2. **Các Bước Thiết Lập**: vị trí đặt thùng ủ (ánh nắng, thoát nước, khoảng cách tới nhà và hàng rào, lối tiếp cận vào mùa đông), những gì cần lót ở lớp đáy, và quy trình trong tuần đầu tiên bằng các bước đánh số ngắn gọn. 3. **Hướng Dẫn Nguyên Liệu Xanh và Nâu**: danh sách hai cột gồm các nguyên liệu xanh (giàu đạm) và nguyên liệu nâu (giàu carbon) phổ biến trong gia đình, quy tắc tỷ lệ đơn giản (tính theo thể tích, không tính theo trọng lượng), danh sách "tuyệt đối không cho vào" kèm lý do, và danh sách "có thể cho vào nhưng cần lưu ý" (họ cam quýt, hành tây, bánh mì, bao bì có thể phân hủy sinh học, cỏ dại có hạt). 4. **Thói Quen Thu Gom Trong Bếp**: kích thước thùng đựng rác hữu cơ nhỏ trong bếp (caddy), cách lót thùng, tần suất đổ rác, và cách ngăn chặn ruồi giấm cũng như mùi hôi trong nhà. 5. **Quy Trình Hàng Tuần**: danh sách kiểm tra từ 10 đến 15 phút: thêm rác hữu cơ, phủ lớp nguyên liệu nâu, kiểm tra độ ẩm bằng bài kiểm tra nắm tay, đảo trộn hoặc làm thoáng khí, và ghi chú những gì tôi đã thêm vào. 6. **Kế Hoạch Theo Mùa**: những thay đổi trong nắng nóng mùa hè, mùa lá rụng vào mùa thu (cách tích trữ đống lá khô để dùng dần), sự chậm lại vào mùa đông, và khởi động lại vào mùa xuân, bao gồm cả cách giữ ấm cách nhiệt cho thùng ủ khi có sương giá. 7. **Bảng Xử Lý Sự Cố**: triệu chứng, nguyên nhân có thể xảy ra, cách khắc phục cho ít nhất tám vấn đề: mùi hôi khó chịu, nhớp nháp và ướt sũng, khô khốc và không phân hủy, ruồi nhặng, kiến, chuột lớn hoặc chuột nhắt, hạt nảy mầm, nấm mốc trắng, trùn bò ra ngoài (đối với thùng nuôi trùn quế). 8. **Thu Hoạch và Sử Dụng**: cách nhận biết phân ủ đã chín hoàn toàn (hình thức, mùi, cảm giác khi chạm vào, nhiệt độ), cách sàng lọc và ủ ổn định (cure), cách sử dụng cho luống cây và chậu trồng, cũng như tỷ lệ pha trộn với đất trồng chậu. 9. **Nhật Ký Tiến Độ**: một mẫu biểu đơn giản để theo dõi ngày tháng, nguyên liệu đã cho vào, độ ẩm, mùi, việc đảo trộn, nhiệt độ (nếu có đo) và ghi chú. Quy tắc: sử dụng ngôn ngữ bình dân dễ hiểu, đoạn văn và danh sách ngắn gọn, dùng hệ đo lường mét trừ khi tôi có yêu cầu khác, và ưu tiên các lựa chọn chi phí thấp hoặc miễn phí trước (tái sử dụng vật chứa, thu gom nguyên liệu nâu miễn phí). Kết thúc bằng một câu khích lệ và bước đầu tiên duy nhất mà tôi nên thực hiện ngay trong tuần này.

Ảnh chụp macro khung vuông chân thực về một bình terrarium thủy tinh tròn đặt trên bàn gỗ: một ngôi nhà gỗ nhỏ lợp ván có ống khói và khung cửa sổ sáng đèn ấm áp, lối đi lát đá bước chân uốn lượn qua lớp rêu đệm, một dòng thác mỏng đổ qua những tảng đá xám xuống hồ nước nhỏ, dương xỉ và cây cỏ nhỏ, cùng những giọt sương ngưng tụ trên mặt kính, phía sau là khung cửa sổ mờ ảo dịu nhẹ.
Một bức ảnh chụp macro chân thực về một bình tiểu cảnh (terrarium) bằng thủy tinh hình cầu hở miệng đặt trên mặt bàn gỗ, bên trong chứa một phong cảnh rêu thu nhỏ cùng ngôi nhà gỗ tí hon và dòng thác nước, trong khung hình vuông tỷ lệ 1:1. Chiếc bình thủy tinh trong suốt, hở miệng chiếm phần lớn khung hình và được bao phủ bởi những giọt nước ngưng tụ nhỏ li ti ở mặt trong. Ở phía bên trái, một ngôi nhà gỗ nhỏ nhuốm màu thời gian với mái dốc lợp ván gỗ và một ống khói gạch nhỏ nằm trên một gò đất phủ rêu; một ô cửa sổ duy nhất tỏa ánh sáng màu hổ phách ấm áp như thể có ngọn đèn đang thắp sáng bên trong. Từ cửa nhà, một lối đi uốn lượn gồm những phiến đá bước chân phẳng màu xám cong xuống xuyên qua thảm rêu hướng về phía mặt trước của chiếc bình. Ở phía bên phải, một dòng thác mỏng ánh bạc đổ xuống giữa những tảng đá xám lởm chởm vào một hồ nước nhỏ tĩnh lặng gần chính giữa phía dưới. Xung quanh mọi thứ là những cụm rêu đệm màu xanh lục tươi tốt căng tròn, những nhánh dương xỉ mảnh mai và các loài cây lá nhỏ, với lớp đất tối màu và những viên sỏi lộ rõ qua lớp kính cong ở phần đáy bình. Chiếc bình đặt trên mặt bàn gỗ màu nâu ấm với những đường vân gỗ hiện rõ; hậu cảnh là một khung cửa sổ được xóa phông mềm mại với tán lá xanh và ánh sáng ban ngày. Ánh sáng tự nhiên dịu nhẹ chiếu xiên từ bên cạnh, độ sâu trường ảnh nông, chi tiết sắc nét trên từng giọt nước và thảm rêu, mang lại cảm giác ấm cúng và kỳ diệu của một thế giới thu nhỏ. Không có người, không có chữ viết, không có logo.
Giữ cho cây bonsai đầu tiên của bạn sống khỏe và bắt đầu tạo dáng: bản chất thực sự của bonsai là gì, loài cây của bạn thuộc nhóm trồng trong nhà hay ngoài trời, bảng thuật ngữ cho người mới, tưới nước theo cảm nhận độ ẩm thay vì theo lịch cố định, bảng ánh sáng và các mùa kèm cách bảo vệ mùa đông, kiến thức cơ bản về đất, chậu và thay chậu, bón phân, bảng chẩn đoán triệu chứng, cắt tỉa lần đầu an toàn, lịch chăm sóc và kế hoạch 4 tuần đầu tiên.
Hãy đóng vai một Huấn luyện viên Chăm sóc Bonsai cho Người mới bắt đầu. Bạn giúp những người mới hoàn toàn giữ cho cây bonsai đầu tiên của họ sống sót và khỏe mạnh, hiểu được vì sao cây có hình dáng như hiện tại và từ từ bắt đầu tạo dáng cho cây, dựa trên chính loài cây, điều kiện ánh sáng, khí hậu và lịch trình thực tế mà họ có. Bạn suy nghĩ như một người thầy kiên nhẫn tại câu lạc bộ bonsai, người đã chứng kiến rất nhiều cây đầu tay chết vì cùng một vài sai lầm quen thuộc: bạn giải thích những gì cây cần bằng ngôn ngữ giản dị, gắn mọi hướng dẫn với đúng loài cây của tôi, cửa sổ hay ban công nhà tôi, mùa hiện tại và thói quen sinh hoạt của tôi, đồng thời thẳng thắn chia sẻ rằng hầu hết cây của người mới gặp vấn đề là do cách tưới nước, thiếu sáng hoặc đem cây ngoài trời vào trồng trong nhà. Bạn không bao giờ hứa hẹn rằng cây chắc chắn sẽ hồi phục hay đạt được một dáng thế nhất định vào một ngày cụ thể; thay vào đó, bạn dạy tôi cách quan sát và đọc hiểu tình trạng của cây. Tình huống của tôi: - Cây của tôi: a small juniper I bought at a garden center, about 25 cm tall, label says "bonsai" - Chậu và đất trồng: a shallow ceramic pot with one drainage hole, the soil looks dark and compact - Vị trí đặt cây hiện tại: on my desk by a north-facing window in my apartment - Không gian ngoài trời tôi có: a small east-facing balcony - Khí hậu và mùa hiện tại: temperate, cold winters with frost, it is autumn now - Cách tôi đang tưới nước: a small glass of water every Sunday - Những biểu hiện tôi nhận thấy: some needles turning brown and dry at the tips - Dụng cụ tôi có: regular household scissors, a watering can - Thời gian tôi có thể dành cho cây: a few minutes each morning, more on weekends - Điều tôi mong muốn: keep it alive first, later learn basic pruning and wiring Trước tiên, trong một tin nhắn ngắn gọn, hãy hỏi tôi bất kỳ thông tin quan trọng nào còn thiếu: tên loài cây chính xác nếu tôi biết (hoặc mô tả về lá, vỏ cây và thân cây để bạn giúp nhận diện), tôi đã nuôi cây được bao lâu, chậu có thoát nước tốt không, đất có bị ướt sũng suốt nhiều ngày không, mỗi vị trí nhận được bao nhiêu giờ nắng trực tiếp, nhiệt độ thấp nhất vào mùa đông tại nơi tôi sống là bao nhiêu, và trong nhà có thú cưng hay trẻ nhỏ có thể cắn phải lá cây hay không. Sau đó, hãy hướng dẫn tôi qua các phần sau: 1. **Bản chất thực sự của Bonsai là gì (What a Bonsai Really Is)**: lời giải thích ngắn gọn, thân thiện rằng bonsai vốn là một cây gỗ hoặc cây bụi bình thường được giữ cho nhỏ gọn trong chậu nhờ kỹ thuật cắt tỉa và chăm sóc, chứ không phải một giống cây lùn đột biến đặc biệt, và vì sao điều đó có nghĩa là cây vẫn cần ánh sáng, nước, sự thông thoáng và chu kỳ các mùa giống hệt như những cây cùng loài mọc tự nhiên ngoài đời. 2. **Xác định trồng Trong nhà hay Ngoài trời trước tiên (Indoor or Outdoor First)**: dựa trên loài cây của tôi, hãy nói rõ đó là cây ngoài trời (ví dụ: tùng bách/juniper, thông, phong, du) hay là cây có thể chịu được môi trường trong nhà (ví dụ: sanh/si/ficus, ngọc bích/jade, một số loài cây nhiệt đới), giải thích vì sao cây ngoài trời sẽ suy yếu dần khi bị nhốt trong nhà, và chỉ cho tôi vị trí tốt nhất mà tôi thực sự có, kèm theo số giờ chiếu sáng mà cây cần. 3. **Các thuật ngữ Bonsai bạn sẽ gặp (Bonsai Words You Will Meet)**: một bảng thuật ngữ ngắn gọn gồm tên thuật ngữ và giải nghĩa dễ hiểu: nebari (bệ rễ), apex (ngọn cây), branch structure (cấu trúc cành), pinching (ngắt đọt), defoliation (vặt lá), wiring (uốn dây), repotting (thay chậu), root pruning (cắt tỉa rễ), bonsai soil (đất trồng bonsai), akadama, pumice (đá bọt), lava rock (đá nham thạch), dormancy (ngủ đông), jin và shari (lũa cành và lũa thân), và "pre-bonsai" (phôi bonsai). 4. **Tưới nước theo cảm nhận độ ẩm, không tưới theo lịch cố định (Watering by Feel, Not by Calendar)**: cách kiểm tra độ ẩm đất bằng ngón tay hoặc que đũa gỗ, ý nghĩa thực sự của việc "tưới đẫm cho đến khi nước chảy ra khỏi lỗ thoát nước dưới đáy chậu", vì sao việc tưới nhấp môi từng chút một mỗi tuần lại nguy hiểm, lượng nước tưới thay đổi thế nào theo nắng, gió, nhiệt độ và mùa, cùng một thói quen kiểm tra hàng ngày đơn giản phù hợp với buổi sáng của tôi. 5. **Ánh sáng, Độ thông thoáng và Các mùa (Light, Air, and Seasons)**: một bảng gồm các cột: mùa, vị trí nên đặt cây, lượng nắng cần thiết, quy luật tưới nước, hoạt động sinh trưởng của cây trong mùa đó và những dấu hiệu cần lưu ý. Bao gồm cách bảo vệ mùa đông cho các loài cây ngoài trời (che chắn khỏi sương giá khắc nghiệt, gió lùa và tình trạng khô kiệt) cũng như lý do vì sao hầu hết các loài cây ôn đới đều cần một giai đoạn ngủ đông lạnh giá. 6. **Đất trồng, Chậu và Thoát nước (Soil, Pot, and Drainage)**: vì sao đất thịt đóng bao thông thường ở tiệm cây cảnh dễ bị giữ nước lâu ngày và gây thối rễ, giá thể bonsai thoát nước tốt trông như thế nào, khi nào thực sự cần thay chậu (và khi nào chưa cần), cùng mùa thay chậu an toàn cho loài cây của tôi. Đừng khuyên tôi thay chậu ngay lập tức trừ khi có dấu hiệu nguy cấp rõ ràng như rễ đang thối hoặc nước hoàn toàn không thể thoát ra ngoài. 7. **Bón phân (Feeding)**: thời điểm và cách thức bón phân trong mùa sinh trưởng, quy trình bón phân nhẹ nhàng cho người mới bắt đầu, lý do cần ngừng hoặc giảm bón phân khi cây ngủ đông, và vì sao tuyệt đối không bón phân cho cây đang ốm yếu hoặc vừa mới thay chậu. 8. **Đọc hiểu tín hiệu của cây (Reading the Tree)**: một bảng xử lý sự cố gồm các cột: dấu hiệu nhìn thấy, nguyên nhân có khả năng xảy ra, những gì cần kiểm tra, cách xử lý. Bao quát các hiện tượng cháy nâu đầu lá, vàng lá, rụng lá, chồi non vươn dài yếu ớt và nhạt màu, lá bị dính nhớp hoặc có côn trùng nhỏ li ti, đốm trắng xù như bông, đất có mùi chua ủng, gốc cây lung lay, và cây không đâm chồi thức giấc vào mùa xuân. Hãy trung thực khi có những tổn thương không thể phục hồi và mục tiêu lúc đó chỉ là giữ cho phần còn lại của cây được khỏe mạnh. 9. **Cắt tỉa và Tạo dáng lần đầu (First Pruning and Shaping)**: những việc tôi có thể làm an toàn trong năm đầu tiên (ngắt đọt hoặc tỉa gọn chồi mới để giữ phom dáng, cắt bỏ cành khô chết), những kỹ thuật nên chờ thêm (cắt tỉa mạnh tay, uốn dây kẽm, xử lý rễ), những dụng cụ nào đáng mua trước tiên (một chiếc kéo tỉa bonsai sắc bén, kìm cạp xéo/concave cutter có thể mua sau), và cách bấm một vết cắt gọn sạch. Nếu tôi muốn thử uốn dây sau này, hãy giải thích nguyên tắc cơ bản và nguy cơ dây ăn lằn vào vỏ cây (wire scarring). 10. **Lịch chăm sóc đơn giản (A Simple Care Calendar)**: danh sách theo từng tháng dành riêng cho loài cây và khí hậu nơi tôi ở, mỗi tháng nêu một hoặc hai công việc trọng tâm. 11. **Kế hoạch 4 tuần đầu tiên (A First 4-Week Plan)**: theo từng tuần: những gì cần thay đổi ngay bây giờ (vị trí đặt cây, phương pháp tưới nước), những gì cần quan sát và ghi chép vào sổ nhật ký cây đơn giản (chụp ảnh, độ ẩm đất, chồi mới), và một kỹ năng nhỏ để thực hành mỗi tuần. Quy tắc: luôn gắn liền lời khuyên với loài cây, điều kiện ánh sáng, khí hậu và mùa của tôi; không bao giờ đưa ra lịch tưới cố định làm quy tắc chính mà phải hướng dẫn cách kiểm tra đất; không khuyến nghị cắt tỉa nặng, cắt rễ hay thay chậu trái mùa hoặc trên cây đang suy yếu; cảnh báo rằng một số loài bonsai phổ biến (ví dụ: ngọc bích/jade, sanh/si/ficus, đỗ quyên/azalea, vạn tuế/sago palm - vốn không phải cây bonsai thực thụ) có thể gây ngộ độc cho thú cưng hoặc gây kích ứng da, và nhắc tôi kiểm tra kỹ loài cây của mình; không dùng thuốc trừ sâu hóa học làm bước đầu tiên mà hãy bắt đầu bằng việc kiểm tra thủ công và các biện pháp sinh học nhẹ nhàng; sử dụng ngôn ngữ bình dân, đoạn văn ngắn và bảng biểu ở những chỗ giúp dễ theo dõi. Kết thúc bằng việc chỉ rõ chính xác những gì tôi nên làm ngay hôm nay cho cây của mình trong ba đến năm bước ngắn gọn.
Xây dựng lịch kiểm tra tưới cây trong nhà từ danh sách các loại cây cùng kích thước và chất liệu chậu, điều kiện ánh sáng, khả năng thoát nước và ngày tưới gần nhất. Điều chỉnh từng khoảng thời gian chờ theo loại chậu, ánh sáng, độ ẩm và mùa (theo bán cầu, giãn cách dài hơn vào mùa đông), sắp xếp lịch kiểm tra vào các ngày cố định trong tuần đã chọn, giải thích rõ thế nào là 'cần tưới nước' và lượng nước cần tưới bao nhiêu, đồng thời cảnh báo các rủi ro như chậu không có lỗ thoát nước. Bao gồm bộ lập lịch bằng Python sử dụng thư viện chuẩn (stdlib) có tính năng xuất tệp .ics và --self-test.
---
name: houseplant-watering-schedule-planner
description: Xây dựng lịch kiểm tra tưới cây trong nhà từ danh sách các loại cây cùng kích thước và chất liệu chậu, điều kiện ánh sáng, khả năng thoát nước và ngày tưới gần nhất. Điều chỉnh từng khoảng thời gian chờ theo loại chậu, ánh sáng, độ ẩm và mùa (theo bán cầu, giãn cách dài hơn vào mùa đông), sắp xếp lịch kiểm tra vào các ngày cố định trong tuần đã chọn, giải thích rõ thế nào là 'cần tưới nước' và lượng nước cần tưới bao nhiêu, đồng thời cảnh báo các rủi ro như chậu không có lỗ thoát nước. Bao gồm bộ lập lịch bằng Python sử dụng thư viện chuẩn (stdlib) có tính năng xuất tệp .ics và --self-test.
---
# Công Cụ Lập Lịch Tưới Cây Trong Nhà
Bạn giúp mọi người giữ cho cây trồng trong nhà luôn tươi tốt mà không chỉ tưới máy móc theo lịch. Kế hoạch sẽ cho họ biết khi nào cần **kiểm tra** từng cây và cần quan sát dấu hiệu gì; họ chỉ tưới nước khi quy tắc riêng của cây đó báo đã đến lúc. Bạn điều chỉnh linh hoạt theo điều kiện thực tế (chậu cây, ánh sáng, hệ thống sưởi, mùa trong năm), giữ cho thói quen thật đơn giản (hai ngày kiểm tra cố định mỗi tuần nếu họ muốn), và chỉ ra những cách bố trí gây chết cây nhiều nhất: chậu không có lỗ thoát nước, cây mọng nước đặt ở góc tối, cây dương xỉ bị khô kiệt trong chậu đất nung (terracotta).
## Các tệp trong kỹ năng này
- `scripts/watering_planner.py` - đọc tệp CSV danh sách cây, gán cho mỗi cây một nhóm nhu cầu nước, tính toán khoảng thời gian giữa các lần kiểm tra theo mùa, tạo lịch trình (có tùy chọn khớp vào các ngày cố định trong tuần), ước tính lượng nước cho mỗi cây, gắn cờ cảnh báo các cách trồng rủi ro, và có thể xuất ra tệp .ics (chỉ dùng thư viện chuẩn của Python 3.8+)
- `references/plant-water-profiles.md` - sáu nhóm nhu cầu tưới nước, các loại cây phổ biến trong từng nhóm, cách kiểm tra "cần tưới nước" cũng như dấu hiệu tưới quá nhiều hoặc quá ít nước
- `references/adjustment-factors.md` - cách kích thước chậu, chất liệu chậu, ánh sáng, độ ẩm, mùa và khả năng thoát nước làm thay đổi khoảng cách giữa các lần kiểm tra, kèm theo các hệ số nhân mà kịch bản sử dụng và cách tinh chỉnh chúng sau vài tuần
- `templates/watering-plan.md` - bản kế hoạch dài một trang để gửi lại cho người dùng (lịch trình hàng tuần, bảng tóm tắt nhanh cho từng cây, các cảnh báo, ngày đánh giá lại)
- `examples/plants.csv` - mười chậu cây trong một căn hộ có bật sưởi vào thời điểm cuối tháng Mười
- `examples/plan-output.md` - kết quả đầu ra thực tế của bộ lập lịch cho danh sách cây đó
## Quy trình thực hiện
### 1. Thu thập danh sách cây trồng
Đối với mỗi cây: tên gọi, loại cây (tên loài hoặc mô tả kiểu "trông giống cây mọng nước"), đường kính chậu tính bằng cm, chất liệu chậu (nhựa, gốm tráng men, đất nung terracotta, vải trồng cây, chậu tự tưới), mức độ ánh sáng tại vị trí đặt cây (thấp = xa cửa sổ, trung bình, sáng = ánh sáng gián tiếp mạnh, trực tiếp = nắng chiếu thẳng lên lá hàng giờ liền), chậu có lỗ thoát nước hay không, và lần tưới nước gần nhất là khi nào. Hãy hỏi thêm về bán cầu nơi họ sống, căn nhà có đang bật sưởi hay không (không khí khô), và những ngày nào trong tuần thuận tiện cho việc kiểm tra nhanh. Nếu không rõ tên cây, hãy yêu cầu mô tả qua ảnh hoặc xếp tạm vào nhóm "top_dry" (khô lớp đất mặt) và nói rõ giả định đó.
### 2. Chạy bộ lập lịch
```
python3 scripts/watering_planner.py examples/plants.csv --start 2026-10-30 --weeks 6 --check-days Mon,Thu --humidity low
python3 scripts/watering_planner.py plants.csv --hemisphere south --weeks 8 --ics plants.ics
python3 scripts/watering_planner.py plants.csv --json
python3 scripts/watering_planner.py --self-test
```
Mã thoát 0 = đã tạo xong kế hoạch, 1 = đã tạo kế hoạch nhưng có cảnh báo mức HIGH cần xử lý ngay (ví dụ: không có lỗ thoát nước), 2 = dữ liệu đầu vào không hợp lệ (chất liệu hoặc mức ánh sáng không xác định, kích thước chậu tính bằng mm, định dạng ngày sai). Nếu không chạy mã, hãy tự tra bảng phân loại và tính theo các hệ số nhân trong tài liệu tham chiếu.
### 3. Kiểm tra kết quả trước khi bàn giao
- Mỗi cây đều có một khoảng cách kiểm tra ở thời điểm hiện tại và, nếu kế hoạch kéo dài sang mùa tiếp theo, khoảng cách mới tương ứng (ví dụ: "7 d (winter: 9 d)").
- Những loại cây ưa ẩm liên tục (dương xỉ, đuôi công calathea, lan ý, húng quế) có thể cần nhiều ngày kiểm tra hơn số ngày cố định trong lịch trình; bộ lập lịch sẽ chỉ rõ điều này. Hãy gợi ý thêm ngày kiểm tra thứ ba, đổi sang chậu nhựa, hoặc dùng chậu tự tưới riêng cho những cây này.
- "Overdue" (Quá hạn) có nghĩa là thời điểm tưới lần cuối cộng với khoảng cách kiểm tra đã trôi qua: hãy kiểm tra cây đó đầu tiên.
- Đọc kỹ các cảnh báo và đưa những cảnh báo mức HIGH thành hành động ưu tiên hàng đầu trong kế hoạch.
### 4. Bàn giao kết quả
Điền vào `templates/watering-plan.md`: lịch trình hàng tuần (kiểm tra cây nào vào ngày nào), bảng hướng dẫn nhanh cho từng cây kèm bài kiểm tra "tưới khi nào" và lượng nước cần tưới, các cảnh báo cùng hướng xử lý, và ngày xem xét lại sau 2-3 tuần để giãn ra hoặc rút ngắn khoảng cách kiểm tra dựa trên tình trạng thực tế họ ghi nhận được ở mỗi lần kiểm tra.
## Ví dụ kết quả
Mười chậu cây, bắt đầu từ Thứ Sáu ngày 2026-10-30, kéo dài sáu tuần, kiểm tra vào các ngày Thứ Hai và Thứ Năm, có bật lò sưởi (độ ẩm thấp). Dương xỉ, đuôi công calathea, lan ý và húng quế được kiểm tra vào mọi ngày kiểm tra trong tuần; trầu bà lá xẻ (monstera) khoảng mỗi tuần một lần (các ngày Thứ Năm); trầu bà (pothos) mỗi tuần một lần (các ngày Thứ Hai); lưỡi hổ mỗi 16 ngày, giãn ra thành 21 ngày vào tháng Mười Hai; cây kim tiền (ZZ plant) mỗi 20 ngày; xương rồng hiện tại mỗi 6 ngày, sang mùa đông là 9 ngày (cây này đang quá hạn, lần tưới cuối là 15 tháng Mười). Cây lan ý đang đặt trong chậu trang trí không có lỗ thoát nước (Cảnh báo HIGH: hãy trồng trong chậu nhựa ươm cây đặt lọt bên trong và đổ hết nước đọng ở chậu bọc ngoài sau khi tưới). Cây dương xỉ trồng trong chậu đất nung và cây húng quế cần được kiểm tra mỗi 1-2 ngày, nên lịch kiểm tra hai lần một tuần không đáp ứng đủ. Xem chi tiết tại `examples/plan-output.md`.
## Quy tắc
- Không bao giờ chỉ định tưới nước cứng nhắc theo lịch cố định mà không kiểm tra trước; luôn gắn mỗi lần kiểm tra với bài thử "tưới khi nào" của từng loại cây.
- Tưới đẫm cho đến khi nước chảy ra ở đáy chậu, sau đó đổ bỏ nước thừa trong đĩa hứng sau 15 phút; tuyệt đối không để đáy chậu ngâm trong nước (với hoa lan: ngâm chậu rồi nhấc ra để ráo nước hoàn toàn).
- Vào mùa đông và ở nơi ánh sáng yếu, cây tiêu thụ ít nước hơn: hãy kéo dài khoảng cách giữa các lần tưới thay vì tưới nhấp nháp từng chút một.
- Khi thấy lá vàng đi kèm đất vẫn còn ướt, hãy xác định nguyên nhân là do tưới quá nhiều nước chứ không phải cây bị khát; phải nêu rõ điều này trước khi đề xuất tưới thêm nước.
- Không tự ý đoán loài cây từ một tên gọi mơ hồ; hãy hỏi lại người dùng hoặc nêu rõ nhóm nhu cầu nước mà bạn đã giả định.
- Chỉ đề cập đến vấn đề độc tính đối với thú cưng khi người dùng hỏi về độ an toàn hoặc có nhắc tới thú cưng/trẻ nhỏ; không thêm thắt thông tin lan man vào kế hoạch.
FILE:references/plant-water-profiles.md
# Các nhóm nhu cầu tưới nước
| Nhóm | Các loại cây điển hình | Tưới khi | Khoảng cách kiểm tra cơ sở* | Độ giãn cách vào mùa đông |
|---|---|---|---|---|
| succulent | xương rồng, nha đam (lô hội), sen đá (echeveria), cây ngọc bích (jade), móng rồng (haworthia), chuỗi ngọc (string of pearls) | đất khô hoàn toàn từ trên xuống đáy: cắm một chiếc đũa gỗ chạm đáy chậu khi rút ra thấy sạch và khô ráo; nhấc chậu thấy nhẹ hẳn | 10 ngày | x2.5 (nhiều loại xương rồng hầu như không cần tưới từ tháng 12 đến tháng 2) |
| dry_tolerant | lưỡi hổ (sansevieria), kim tiền (ZZ plant), cọ đuôi ngựa (ponytail palm), yucca, lan cẩm cù (hoya), peperomia | ít nhất 3/4 độ sâu của đất trong chậu đã khô | 12 ngày | x2.0 |
| top_dry | trầu bà (pothos), trầu bà lá xẻ (monstera), philodendron, đa búp đỏ (rubber plant), bàng Singapore (fiddle leaf fig), thiết mộc lan (dracaena), dây nhện (spider plant), kim ngân (money tree), vạn lộc/ngọc ngân (aglaonema), môn quan âm (alocasia), hồng môn (anthurium), cau tiểu trâm (parlor palm), thu hải đường (begonia), xương rồng Giáng sinh (Christmas cactus) | khô 1/3 lớp đất phía trên (thử bằng ngón tay ngập đến đốt thứ hai đối với chậu 15 cm) | 6 ngày | x1.6 |
| evenly_moist | dương xỉ Boston và dương xỉ tóc thần vệ nữ (maidenhair fern), đuôi công (calathea), maranta (prayer plant), lan ý (peace lily), lá may mắn (fittonia) | lớp đất mặt 1-2 cm vừa chớm khô; không bao giờ để đất khô hoàn toàn | 3 ngày | x1.3 |
| orchid | lan hồ điệp (phalaenopsis) trồng trong giá thể vỏ thông | rễ chuyển màu xám bạc (màu xanh lá = vẫn còn ướt) và vỏ thông đã khô; ngâm nước 10 phút, sau đó để ráo hoàn toàn | 7 ngày | x1.4 |
| herb | húng quế, bạc hà, mùi tây (parsley) đặt trên bệ cửa sổ | lớp đất mặt 1-2 cm đã khô | 2 ngày | x1.2 |
*Mức cơ sở = mùa xuân, chậu nhựa 15 cm có lỗ thoát nước, ánh sáng trung bình, độ ẩm bình thường. Mùa thu nằm ở mức giữa mùa xuân và mùa đông; mùa hè nhân với hệ số x0.85. Xem `adjustment-factors.md`.
## Cách kiểm tra độ ẩm (30 giây cho mỗi cây)
1. **Thử bằng ngón tay:** ấn ngón tay vào đất đến độ sâu theo quy tắc của nhóm cây. Đất khô và tơi rời = khô; mát và dính vào tay = còn ẩm.
2. **Ước lượng độ nặng:** hãy nhấc thử các chậu nhỏ ngay sau khi vừa tưới đẫm một lần để cảm nhận sự khác biệt giữa lúc chậu "no nước" và lúc "cạn nước".
3. **Dùng đũa gỗ/que tre:** đối với các chậu sâu lòng và cây mọng nước, hãy cắm một que xiên gỗ xuống tận đáy chậu trong một phút; nếu rút ra thấy que sẫm màu và ẩm nghĩa là chưa cần tưới.
4. **Bút đo độ ẩm đất** chỉ mang tính tham khảo tương đối; thiết bị này đo độ dẫn điện của muối khoáng lẫn nước nên thường báo sai khi cắm vào giá thể vỏ thông hoặc đất trộn nhiều cát.
## Các dấu hiệu nhận biết
| Tưới quá nhiều nước (phổ biến hơn) | Tưới thiếu nước |
|---|---|
| lá tầng dưới ngả vàng trong khi đất vẫn ướt, gốc thân mềm nhũn hoặc chuyển màu đen, rễ bị thối nhũn, xuất hiện ruồi nấm (fungus gnats), đất có mùi chua ủng | mép lá khô giòn chuyển màu nâu, lá rũ xuống nhưng tươi tỉnh lại chỉ sau vài giờ được tưới nước, đất co lại tách rời khỏi thành chậu, nhấc chậu thấy rất nhẹ |
| Cách khắc phục: ngừng tưới ngay, kiểm tra bộ rễ, thay sang giá thể đất khô mới nếu rễ đã bị thối, kéo dài khoảng cách giữa các lần kiểm tra | Cách khắc phục: tưới đẫm hoàn toàn (ngâm đáy chậu trong nước 20-30 phút nếu đất bị trơ không ngấm nước), rút ngắn khoảng cách kiểm tra lại một chút |
Cây bị rũ lá trong khi đất vẫn **ướt** có nghĩa là bộ rễ đã bị tổn thương: tuyệt đối không tưới thêm nước.
## Kỹ thuật tưới nước
- Tưới từ từ khắp bề mặt đất cho đến khi nước chảy ra ở lỗ đáy chậu; chờ một lát, sau đó đổ bỏ nước đọng trong đĩa hứng sau khoảng 15 phút.
- Dùng nước ở nhiệt độ phòng. Cây đuôi công (calathea) và một số loài dương xỉ dễ bị cháy nâu đầu lá nếu tưới bằng nước cứng hoặc nước đã làm mềm bằng muối; dùng nước mưa hoặc nước lọc sẽ tốt hơn.
- Tưới thẩm thấu ngược từ đáy (ngâm đáy chậu trong khay nước khoảng 20-30 phút) rất hiệu quả với các chậu nhỏ và đất bị khô co rút lại; thỉnh thoảng hãy tưới từ trên xuống để rửa trôi muối khoáng tích tụ.
- Chậu tự tưới: châm thêm nước vào bình chứa khi đã cạn và thỉnh thoảng cứ để bình chứa cạn khô trong một hoặc hai ngày để rễ cây được hô hấp; không dùng loại chậu này cho cây mọng nước.
FILE:references/adjustment-factors.md
# Các hệ số điều chỉnh
Khoảng cách kiểm tra = số ngày cơ sở (theo nhóm cây) x kích thước chậu x chất liệu chậu x ánh sáng x độ ẩm x mùa, được làm tròn và giới hạn trong khoảng 1..45 ngày. Dưới đây là các hệ số nhân được sử dụng trong `scripts/watering_planner.py`.
| Yếu tố | Giá trị | Hệ số nhân | Lý do |
|---|---|---|---|
| Đường kính chậu | dưới 10 cm | 0.6 | ít đất, khô chỉ sau vài ngày |
| | 10-13 cm | 0.8 | |
| | 14-19 cm | 1.0 | mức tham chiếu chuẩn |
| | 20-27 cm | 1.3 | nhiều đất hơn nên giữ nước lâu hơn |
| | từ 28 cm trở lên | 1.6 | chậu lớn vẫn còn ướt ở đáy rất lâu sau khi bề mặt đã khô: cần kiểm tra sâu xuống dưới |
| Chất liệu | nhựa, tráng men, gốm sứ, kim loại | 1.0 | thành chậu không thoát hơi nước |
| | đất nung (terracotta) / đất sét không tráng men | 0.75 | thành chậu thấm hút và làm bay hơi nước |
| | túi vải trồng cây (fabric grow bag) | 0.7 | khô nhanh từ mọi phía |
| | chậu tự tưới | 1.5 | bình chứa cấp ẩm dần cho đất; hãy kiểm tra bình chứa nước thay vì mặt đất |
| Ánh sáng | thấp (cách cửa sổ trên 2 m, phòng hướng Bắc) | 1.4 | cây ít phát triển, tiêu thụ ít nước |
| | trung bình | 1.0 | |
| | ánh sáng gián tiếp mạnh | 0.85 | |
| | nắng chiếu trực tiếp lên lá | 0.7 | |
| Độ ẩm | thấp (đang bật sưởi, dưới ~35 %) | 0.85 | đất và lá mất nước nhanh hơn |
| | bình thường | 1.0 | |
| | cao (phòng tắm, có máy tạo ẩm) | 1.15 | |
| Mùa | mùa xuân | 1.0 | |
| | mùa hè | 0.85 | |
| | mùa thu | mức giữa của mùa xuân và mùa đông | đà tăng trưởng chậm lại khi ngày ngắn đi |
| | mùa đông | hệ số giãn cách mùa đông theo từng nhóm cây (từ x1.2 đến x2.5) | |
Phân chia mùa: ở Bắc bán cầu, tháng 12-tháng 2 là mùa đông, tháng 3-tháng 5 là mùa xuân, tháng 6-tháng 8 là mùa hè, tháng 9-tháng 11 là mùa thu; ở Nam bán cầu lệch đi sáu tháng. Nếu đặt cây ngay cạnh lò sưởi hoặc trong phòng kính có sưởi ấm, hãy chọn mức độ ẩm "low" (thấp) ngay cả vào mùa đông.
## Khả năng thoát nước
Chậu không có lỗ thoát nước là nguyên nhân đơn lẻ lớn nhất gây thối rễ. Cách tốt nhất: giữ nguyên cây trong chậu nhựa ươm cây đặt lọt bên trong chậu trang trí và đổ hết nước đọng ở chậu ngoài sau khi tưới 15 phút. Nếu bắt buộc phải trồng trực tiếp trong chậu không có lỗ, chỉ tưới khoảng một nửa lượng nước thông thường và nghiêng nhẹ chậu để kiểm tra xem có nước đọng dưới đáy không. Bộ lập lịch sẽ gắn cờ trường hợp này ở mức cảnh báo HIGH.
## Lượng nước tưới
Khoảng 15-25 % thể tích chậu, tưới cho đến khi thấy nước thoát ra ở lỗ đáy. Bộ lập lịch ước tính thể tích chậu từ đường kính (giả định chậu thành đứng có chiều cao bằng khoảng 0.9 lần chiều rộng), vì vậy chậu 15 cm cần khoảng 450 ml nước, chậu 24 cm cần khoảng 1.75 lít. Cây mọng nước và cây chịu hạn cũng cần được tưới đẫm mỗi lần như vậy, chỉ là tần suất thưa hơn.
## Tinh chỉnh sau hai hoặc ba tuần
- Đất vẫn còn ẩm ở hầu hết các lần kiểm tra: hãy kéo dài khoảng cách kiểm tra của cây đó thêm 25-50 % (hoặc chuyển thông số ánh sáng sang "low" nếu cây đặt xa cửa sổ).
- Đất khô cong ở mọi lần kiểm tra và lá cây bị rũ xuống: rút ngắn khoảng cách kiểm tra đi 25 %.
- Hãy cập nhật trực tiếp các thay đổi này vào tệp CSV (ví dụ: đổi nhóm cây hoặc mức ánh sáng) rồi chạy lại công cụ, thay vì cố ghi nhớ các trường hợp ngoại lệ trong đầu.
- Chạy lại kế hoạch khi bắt đầu bật hoặc tắt hệ thống sưởi, khi bạn thay chậu mới (chậu lớn hơn = khoảng cách dài hơn), hoặc khi đổi vị trí đặt cây.
## Các trường hợp nằm ngoài quy tắc tính khoảng cách
- Cây mới thay chậu: tưới đẫm một lần ngay sau khi thay chậu, sau đó chờ đến khi đất đạt đúng điều kiện trong quy tắc mới tưới tiếp.
- Các loại củ ngủ đông và xương rồng trong giai đoạn nghỉ đông lạnh giá (5-12 C): hầu như không cần tưới nước; chỉ cần kiểm tra mỗi tháng một lần là đủ.
- Bón phân: chỉ thực hiện vào mùa xuân và mùa hè, pha loãng bằng một nửa liều lượng khuyến cáo, bón vào đúng ngày tưới nước.
FILE:templates/watering-plan.md
# Kế hoạch chăm sóc cây: <nhà / phòng>
**Giai đoạn:** <2026-10-30 đến 2026-12-10> **Ngày kiểm tra:** <Thứ Hai và Thứ Năm, 5-10 phút>
**Điều kiện:** <Bắc bán cầu, đang bật sưởi (không khí khô)> **Đánh giá lại vào:** <2026-11-16>
## Việc cần làm ngay
- <Lan ý (Peace lily): không có lỗ thoát nước - hãy chuyển cây sang chậu nhựa ươm đặt lọt bên trong chậu bọc ngoài; đổ bỏ nước đọng ở chậu bọc ngoài sau khi tưới 15 phút>
- <Spike (xương rồng): đã quá hạn - cần kiểm tra ngay vào Thứ Hai>
## Lịch trình hàng tuần
| Ngày | Kiểm tra các cây sau |
|---|---|
| <Thứ Hai> | <dương xỉ, đuôi công calathea, lan ý, húng quế, hoa lan, trầu bà pothos, xương rồng (mỗi Thứ Hai cách tuần trong tháng Mười Hai)> |
| <Thứ Năm> | <dương xỉ, đuôi công calathea, lan ý, húng quế, hoa lan, trầu bà lá xẻ monstera; lưỡi hổ mỗi 2-3 tuần> |
## Bảng hướng dẫn nhanh
| Cây | Tưới khi | Lượng nước ước tính | Ghi chú |
|---|---|---|---|
| <Monty (monstera)> | <khô 1/3 lớp đất mặt> | <~1.75 l cho đến khi thoát nước> | <cửa sổ hướng Đông nhiều sáng> |
| <Sansa (snake plant)> | <khô 3/4 độ sâu đất> | <~450 ml> | <Tháng Mười Hai: mỗi 3 tuần> |
## Cách kiểm tra
- Ấn ngón tay vào đất đến độ sâu ghi trong cột "Tưới khi"; chỉ tưới nếu đất đã khô đến độ sâu đó.
- Tưới cho đến khi nước chảy ra ở đáy chậu, đổ hết nước trong đĩa hứng sau 15 phút.
- Đất ướt + lá vàng = thừa nước: bỏ qua lượt tưới và báo lại cho tôi.
## Cảnh báo
- <Fernando (dương xỉ Boston) trồng trong chậu đất nung bị khô chỉ sau 2 ngày khi bật sưởi: hãy thêm một buổi kiểm tra vào Thứ Bảy hoặc chuyển sang chậu nhựa>
- <Húng quế cần được kiểm tra hàng ngày trên bệ cửa sổ đầy nắng; hãy tưới ngâm đáy chậu mỗi khi bạn đi ngang qua>
## Khi đánh giá lại
Đối với mỗi cây, hãy ghi chú xem đất thường vẫn còn ẩm (cần giãn cách dài hơn) hay đã khô kiệt (cần rút ngắn lại) vào các buổi kiểm tra; tôi sẽ cập nhật lại kế hoạch.
FILE:examples/plants.csv
name,plant,pot_cm,pot_material,light,drainage,last_watered,notes
Monty,monstera,24,plastic,bright,yes,2026-10-28,living room by the east window
Pothos shelf,pothos,14,glazed,medium,yes,2026-10-27,trailing from the bookshelf
Sansa,snake plant,17,terracotta,low,yes,2026-10-20,hallway corner
Zed,zz plant,20,plastic,medium,yes,,new from the shop
Fernando,boston fern,20,terracotta,bright,yes,2026-10-29,bathroom shelf
Cal,calathea,15,plastic,medium,yes,2026-10-28,bedroom
Spike,cactus,10,terracotta,direct,yes,2026-10-15,south windowsill
Peace lily,peace lily,18,glazed,low,no,2026-10-26,decorative pot with no hole
Orchid,phalaenopsis,12,plastic,bright,yes,2026-10-25,kitchen window
Basil,basil,13,terracotta,direct,yes,2026-10-29,kitchen windowsill
FILE:examples/plan-output.md
# Kế hoạch tưới cây trong nhà: 2026-10-30 đến 2026-12-10
Bán cầu: Bắc Mùa lúc bắt đầu: mùa thu Độ ẩm: thấp Ngày kiểm tra: Thứ Hai, Thứ Năm Số lượng cây: 10
Kiểm tra không đồng nghĩa với tưới nước: hãy chạm tay cảm nhận độ ẩm của đất và chỉ tưới khi quy tắc của cây báo đã đến lúc.
## Danh sách cây
| Cây | Nhóm | Chậu | Ánh sáng | Kiểm tra mỗi | Tưới khi | Lượng nước ước tính | Số lần kiểm tra |
|---|---|---|---|---|---|---|---|
| Monty (monstera) | top_dry | nhựa 24 cm | sáng | 7 d (winter: 9 d) | khô 1/3 lớp đất phía trên (khoảng 3-5 cm đối với chậu 15 cm) | ~1750 ml (cho đến khi thoát nước) | 6 |
| Pothos shelf (pothos) | top_dry | tráng men 14 cm | trung bình | 7 d (winter: 8 d) | khô 1/3 lớp đất phía trên (khoảng 3-5 cm đối với chậu 15 cm) | ~350 ml (cho đến khi thoát nước) | 6 |
| Sansa (snake plant) | dry_tolerant | đất nung 17 cm | thấp | 16 d (winter: 21 d) | đất khô ít nhất 3/4 độ sâu từ trên xuống | ~450 ml (cho đến khi thoát nước) | 3 |
| Zed (zz plant) | dry_tolerant | nhựa 20 cm | trung bình | 20 d | đất khô ít nhất 3/4 độ sâu từ trên xuống | ~750 ml (cho đến khi thoát nước) | 2 |
| Fernando (boston fern) | evenly_moist | đất nung 20 cm | sáng | 2 d (winter: 3 d) | lớp đất mặt 1-2 cm vừa chớm khô; không bao giờ để khô hoàn toàn | ~1000 ml (cho đến khi thoát nước) | 12 |
| Cal (calathea) | evenly_moist | nhựa 15 cm | trung bình | 3 d (winter: 3 d) | lớp đất mặt 1-2 cm vừa chớm khô; không bao giờ để khô hoàn toàn | ~450 ml (cho đến khi thoát nước) | 12 |
| Spike (cactus) (quá hạn: kiểm tra ngay ngày đầu tiên) | succulent | đất nung 10 cm | trực tiếp | 6 d (winter: 9 d) | đất khô hoàn toàn đến tận đáy (rút đũa gỗ ra thấy sạch và khô) | ~100 ml (cho đến khi thoát nước) | 6 |
| Peace lily (peace lily) | evenly_moist | tráng men 18 cm, KHÔNG lỗ | thấp | 4 d (winter: 5 d) | lớp đất mặt 1-2 cm vừa chớm khô; không bao giờ để khô hoàn toàn | ~375 ml, không tưới nhiều hơn | 12 |
| Orchid (phalaenopsis) | orchid | nhựa 12 cm | sáng | 5 d (winter: 6 d) | rễ màu xám bạc và vỏ thông khô; ngâm 10 phút, để ráo hoàn toàn | ngâm 10 phút | 11 |
| Basil (basil) | herb | đất nung 13 cm | trực tiếp | 1 d (winter: 1 d) | lớp đất mặt 1-2 cm đã khô | ~350 ml (cho đến khi thoát nước) | 12 |
## Lịch kiểm tra
| Ngày | Thứ | Mùa | Cây cần kiểm tra |
|---|---|---|---|
| 2026-11-02 | Mon | autumn | Basil, Cal, Fernando, Orchid, Peace lily, Pothos shelf, Spike, Zed |
| 2026-11-05 | Thu | autumn | Basil, Cal, Fernando, Monty, Orchid, Peace lily, Sansa |
| 2026-11-09 | Mon | autumn | Basil, Cal, Fernando, Orchid, Peace lily, Pothos shelf, Spike |
| 2026-11-12 | Thu | autumn | Basil, Cal, Fernando, Monty, Orchid, Peace lily |
| 2026-11-16 | Mon | autumn | Basil, Cal, Fernando, Orchid, Peace lily, Pothos shelf, Spike |
| 2026-11-19 | Thu | autumn | Basil, Cal, Fernando, Monty, Orchid, Peace lily, Sansa |
| 2026-11-23 | Mon | autumn | Basil, Cal, Fernando, Orchid, Peace lily, Pothos shelf, Spike, Zed |
| 2026-11-26 | Thu | autumn | Basil, Cal, Fernando, Monty, Orchid, Peace lily |
| 2026-11-30 | Mon | autumn | Basil, Cal, Fernando, Orchid, Peace lily, Pothos shelf, Spike |
| 2026-12-03 | Thu | winter | Basil, Cal, Fernando, Monty, Orchid, Peace lily, Sansa |
| 2026-12-07 | Mon | winter | Basil, Cal, Fernando, Peace lily, Pothos shelf, Spike |
| 2026-12-10 | Thu | winter | Basil, Cal, Fernando, Monty, Orchid, Peace lily |
## Cảnh báo
| Mức độ | Cây | Lưu ý |
|---|---|---|
| HIGH | Peace lily | chậu không có lỗ thoát nước: nước đọng ở đáy làm thối rễ. Hãy thay chậu có lỗ, hoặc trồng cây trong chậu nhựa ươm đặt lọt bên trong chậu bọc ngoài và đổ hết nước đọng sau khi tưới 15 phút |
| LOW | Fernando | chậu đất nung làm cây này khô rất nhanh; đổi sang chậu nhựa hoặc chậu gốm tráng men sẽ giúp giữ ẩm đều hơn |
| LOW | Fernando | các ngày kiểm tra cố định khiến một số lượt kiểm tra bị trễ hơn một ngày (ví dụ: đến hạn 2026-11-07, lịch xếp vào 2026-11-09); hãy thêm một ngày kiểm tra trong tuần hoặc sờ thử đất xen kẽ giữa các buổi |
| LOW | Basil | các ngày kiểm tra cố định khiến một số lượt kiểm tra bị trễ hơn một ngày (ví dụ: đến hạn 2026-11-03, lịch xếp vào 2026-11-05); hãy thêm một ngày kiểm tra trong tuần hoặc sờ thử đất xen kẽ giữa các buổi |
Các khoảng thời gian trên giả định rằng cây đã bén rễ ổn định trong giá thể thoát nước tốt. Sau 2-3 tuần, hãy kéo dài khoảng cách kiểm tra nếu thấy đất vẫn còn ẩm ở hầu hết các lần kiểm tra, hoặc rút ngắn lại nếu lúc nào kiểm tra đất cũng đã khô kiệt.
FILE:scripts/watering_planner.py
#!/usr/bin/env python3
"""Houseplant watering schedule planner (Python 3.8+ standard library only).
Reads a CSV of plants (species or watering type, pot diameter, pot material, light,
drainage, optional last watering date) and builds a check calendar: how often to
check each plant in the current season, what "needs water" means for it, roughly how
much to give, and which plants to check on which date. Intervals stretch
automatically as the plan crosses into autumn and winter (or shrink into summer), by
hemisphere. Checks can be snapped to fixed weekdays (e.g. Mon,Thu) so the plan fits a
routine. Optional .ics export for a calendar app.
A check is not a watering: on each check, feel the soil and water only if the plant's
rule says so. The intervals are starting points; adjust them after two or three weeks
of real checks (see references/adjustment-factors.md).
Usage:
python3 watering_planner.py plants.csv [--start 2026-10-30] [--weeks 4]
[--hemisphere north|south] [--humidity low|normal|high]
[--check-days Mon,Thu] [--ics plan.ics] [--json]
python3 watering_planner.py --self-test
plants.csv columns: name, plant (species or type), pot_cm, pot_material
(plastic|glazed|ceramic|terracotta|fabric|self-watering), light (low|medium|bright|direct),
drainage (yes|no), last_watered (YYYY-MM-DD, optional), notes (optional).
Types: succulent, dry_tolerant, top_dry, evenly_moist, orchid, herb.
Exit codes: 0 = plan written, 1 = plan written with HIGH warnings (e.g. no drainage), 2 = bad input.
"""
import argparse, csv, datetime as dt, io, json, math, sys
PROFILES = {
# base days (spring, 15 cm plastic, medium light), winter factor, rule, share of pot volume per watering
"succulent": (10, 2.5, "soil dry all the way down (chopstick comes out clean and dry)", 0.15),
"dry_tolerant": (12, 2.0, "soil dry at least 3/4 of the way down", 0.15),
"top_dry": (6, 1.6, "top third of the soil dry (about 3-5 cm in a 15 cm pot)", 0.20),
"evenly_moist": (3, 1.3, "top 1-2 cm just dry; never let it dry out fully", 0.20),
"orchid": (7, 1.4, "roots silvery-grey and bark dry; soak 10 min, drain fully", 0.0),
"herb": (2, 1.2, "top 1-2 cm dry", 0.25),
}
SPECIES = {
"cactus": "succulent", "aloe": "succulent", "aloe vera": "succulent", "echeveria": "succulent",
"jade": "succulent", "jade plant": "succulent", "haworthia": "succulent", "string of pearls": "succulent",
"christmas cactus": "top_dry", "snake plant": "dry_tolerant", "sansevieria": "dry_tolerant",
"zz plant": "dry_tolerant", "zamioculcas": "dry_tolerant", "ponytail palm": "dry_tolerant",
"hoya": "dry_tolerant", "pothos": "top_dry", "monstera": "top_dry", "philodendron": "top_dry",
"rubber plant": "top_dry", "ficus elastica": "top_dry", "fiddle leaf fig": "top_dry",
"dracaena": "top_dry", "spider plant": "top_dry", "money tree": "top_dry", "pachira": "top_dry",
"chinese evergreen": "top_dry", "aglaonema": "top_dry", "dieffenbachia": "top_dry",
"yucca": "dry_tolerant", "bird of paradise": "top_dry", "alocasia": "top_dry", "anthurium": "top_dry",
"parlor palm": "top_dry", "peperomia": "dry_tolerant", "begonia": "top_dry",
"fern": "evenly_moist", "boston fern": "evenly_moist", "maidenhair fern": "evenly_moist",
"calathea": "evenly_moist", "prayer plant": "evenly_moist", "maranta": "evenly_moist",
"peace lily": "evenly_moist", "spathiphyllum": "evenly_moist", "fittonia": "evenly_moist",
"orchid": "orchid", "phalaenopsis": "orchid", "basil": "herb", "mint": "herb", "parsley": "herb",
}
MATERIAL = {"plastic": 1.0, "glazed": 1.0, "ceramic": 1.0, "metal": 1.0, "terracotta": 0.75,
"clay": 0.75, "unglazed": 0.75, "fabric": 0.7, "self-watering": 1.5}
LIGHT = {"low": 1.4, "medium": 1.0, "bright": 0.85, "direct": 0.7}
HUMIDITY = {"low": 0.85, "normal": 1.0, "high": 1.15}
SEASON_FACTOR = {"spring": 1.0, "summer": 0.85}
DAY_NAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
class InputError(Exception):
pass
def season_of(d, hemisphere):
m = d.month if hemisphere == "north" else (d.month + 5) % 12 + 1
return {12: "winter", 1: "winter", 2: "winter", 3: "spring", 4: "spring", 5: "spring",
6: "summer", 7: "summer", 8: "summer"}.get(m, "autumn")
def pot_factor(cm):
if cm < 10:
return 0.6
if cm < 14:
return 0.8
if cm < 20:
return 1.0
if cm < 28:
return 1.3
return 1.6
def pot_litres(cm):
# straight-sided pot about 0.9x as tall as wide, minus ~10 % for the rim gap
r = cm / 2.0
return math.pi * r * r * (0.9 * cm) * 0.9 / 1000.0
def interval_days(p, season, humidity):
base, winter, _, _ = PROFILES[p["type"]]
# autumn sits halfway between spring and the plant's winter slow-down
sf = {"winter": winter, "autumn": (1 + winter) / 2}.get(season) or SEASON_FACTOR[season]
days = base * pot_factor(p["pot_cm"]) * MATERIAL[p["material"]] * LIGHT[p["light"]] * HUMIDITY[humidity] * sf
return max(1, min(45, int(round(days))))
def parse_date(s, what):
try:
return dt.date.fromisoformat(s.strip())
except ValueError:
raise InputError(f"bad date '{s}' for {what} (use YYYY-MM-DD)")
def load_plants(text):
rows = list(csv.DictReader(io.StringIO(text)))
if not rows:
raise InputError("plants CSV has no rows")
cols = {c.strip().lower(): c for c in rows[0] if c}
if "name" not in cols:
raise InputError("plants CSV needs at least a 'name' column (plus plant, pot_cm, pot_material, light, drainage)")
plants, warnings = [], []
for i, r in enumerate(rows, 2):
g = lambda k, d="": ((r.get(cols[k]) or "").strip() if k in cols else "") or d
name = g("name")
if not name:
raise InputError(f"row {i}: empty name")
kind = g("plant", g("type", "")).lower()
if kind in PROFILES:
ptype = kind
elif kind in SPECIES:
ptype = SPECIES[kind]
else:
ptype = next((v for k, v in SPECIES.items() if k in kind), None) if kind else None
if ptype is None:
ptype = "top_dry"
warnings.append(("MEDIUM", name, f"unknown plant '{kind or '?'}': using type top_dry; set the plant column to one of {', '.join(PROFILES)}"))
try:
pot = float(g("pot_cm", "0") or 0)
except ValueError:
raise InputError(f"row {i} ({name}): pot_cm must be a number of centimetres")
if pot <= 0:
pot = 15.0
warnings.append(("LOW", name, "no pot size given: assumed 15 cm"))
if pot > 80:
raise InputError(f"row {i} ({name}): pot_cm {pot} looks wrong (centimetres, not millimetres?)")
mat = g("pot_material", "plastic").lower()
if mat not in MATERIAL:
raise InputError(f"row {i} ({name}): pot_material '{mat}' (use {', '.join(MATERIAL)})")
light = g("light", "medium").lower().replace("bright indirect", "bright").replace("full sun", "direct")
if light not in LIGHT:
raise InputError(f"row {i} ({name}): light '{light}' (use low, medium, bright, direct)")
drainage = g("drainage", "yes").lower() not in ("no", "n", "false", "0")
last = parse_date(g("last_watered"), f"{name} last_watered") if g("last_watered") else None
p = {"name": name, "plant": kind or ptype, "type": ptype, "pot_cm": pot, "material": mat,
"light": light, "drainage": drainage, "last_watered": last, "notes": g("notes")}
plants.append(p)
if not drainage:
warnings.append(("HIGH", name, "pot has no drainage hole: water pools at the bottom and roots rot. Repot, or keep the plant in a nursery pot inside the cover pot and empty the cover pot 15 min after watering"))
if ptype == "succulent" and light == "low":
warnings.append(("MEDIUM", name, "succulent in low light: it will stretch and rot easily; move it to the brightest window and water even less"))
if ptype == "evenly_moist" and light == "direct":
warnings.append(("MEDIUM", name, "moisture-loving plant in direct sun: leaves scorch and soil dries within a day; move it out of direct sun"))
if ptype == "evenly_moist" and mat in ("terracotta", "clay", "unglazed", "fabric"):
warnings.append(("LOW", name, f"{mat} pot dries this plant very fast; a plastic or glazed pot keeps it evenly moist"))
if ptype == "orchid" and mat not in ("plastic",):
warnings.append(("LOW", name, "orchids are easiest in a clear plastic pot with drainage, so you can see the roots"))
if mat == "self-watering" and ptype in ("succulent", "dry_tolerant", "orchid"):
warnings.append(("MEDIUM", name, "self-watering pots keep the soil wet; not suited to plants that need to dry out"))
return plants, warnings
def amount_text(p):
_, _, _, share = PROFILES[p["type"]]
if p["type"] == "orchid":
return "soak 10 min"
if p["material"] == "self-watering":
return "refill reservoir"
ml = pot_litres(p["pot_cm"]) * 1000 * share
ml = int(round(ml / 50.0) * 50) or 50
return f"~{ml} ml (until it drains)" if p["drainage"] else f"~{ml // 2} ml, no more"
def snap(due, prev, allowed):
"""Allowed weekday nearest to the due date (ties go earlier), always after prev."""
if not allowed:
return due
best = None
for off in (0, -1, 1, -2, 2, -3, 3):
d = due + dt.timedelta(days=off)
if d > prev and d.weekday() in allowed:
best = d
break
if best is None:
best = max(due, prev + dt.timedelta(days=1))
while best.weekday() not in allowed:
best += dt.timedelta(days=1)
return best
def plan(plants, start, weeks, hemisphere="north", humidity="normal", check_days=None):
end = start + dt.timedelta(days=7 * weeks - 1)
allowed = {DAY_NAMES.index(x) for x in check_days} if check_days else set()
cal, per_plant, notes = {}, [], []
for p in plants:
s0 = season_of(start, hemisphere)
iv = interval_days(p, s0, humidity)
if p["last_watered"]:
due = p["last_watered"] + dt.timedelta(days=iv)
overdue = due < start
first = max(due, start)
else:
overdue, first = False, start
d = snap(first, start - dt.timedelta(days=1), allowed) if allowed else first
dates, prev = [], None
while d <= end:
dates.append(d)
cal.setdefault(d, []).append(p["name"])
step = interval_days(p, season_of(d, hemisphere), humidity)
due = d + dt.timedelta(days=step)
nd = snap(due, d, allowed)
if allowed and (nd - due).days > max(1, step // 5):
notes.append((p["name"], due, nd))
prev, d = d, nd
later = {season_of(x, hemisphere) for x in dates} - {s0}
per_plant.append({**p, "interval_now": iv, "season_now": s0,
"intervals_later": {s: interval_days(p, s, humidity) for s in sorted(later)},
"rule": PROFILES[p["type"]][2], "amount": amount_text(p),
"checks": [x.isoformat() for x in dates], "overdue": overdue})
return {"start": start, "end": end, "hemisphere": hemisphere, "humidity": humidity,
"check_days": check_days or [], "plants": per_plant,
"calendar": [(d, sorted(cal[d], key=str.lower)) for d in sorted(cal)], "late_snaps": notes}
def render(res, warnings):
st, en = res["start"], res["end"]
out = [f"# Houseplant watering plan: {st.isoformat()} to {en.isoformat()}", "",
f"Hemisphere: {res['hemisphere']} Season at start: {season_of(st, res['hemisphere'])} "
f"Humidity: {res['humidity']} Check days: {', '.join(res['check_days']) or 'any day'} Plants: {len(res['plants'])}", "",
"A check is not a watering: feel the soil and water only when the rule says so.", "",
"## Plants", "",
"| Plant | Type | Pot | Light | Check every | Water when | About | Checks |",
"|---|---|---|---|---|---|---|---|"]
for p in res["plants"]:
iv = f"{p['interval_now']} d"
if p["intervals_later"]:
iv += " (" + ", ".join(f"{s}: {v} d" for s, v in p["intervals_later"].items()) + ")"
pot = f"{p['pot_cm']:g} cm {p['material']}" + ("" if p["drainage"] else ", NO hole")
flag = " (overdue: check first day)" if p["overdue"] else ""
out.append(f"| {p['name']} ({p['plant']}){flag} | {p['type']} | {pot} | {p['light']} | {iv} | {p['rule']} | {p['amount']} | {len(p['checks'])} |")
out += ["", "## Calendar", "", "| Date | Day | Season | Check |", "|---|---|---|---|"]
for d, names in res["calendar"]:
out.append(f"| {d.isoformat()} | {DAY_NAMES[d.weekday()]} | {season_of(d, res['hemisphere'])} | {', '.join(names)} |")
if warnings or res["late_snaps"]:
out += ["", "## Warnings", "", "| Sev | Plant | Note |", "|---|---|---|"]
order = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
for sev, name, msg in sorted(warnings, key=lambda w: (order[w[0]], w[1].lower())):
out.append(f"| {sev} | {name} | {msg} |")
seen = set()
for name, due, nd in res["late_snaps"]:
if name in seen:
continue
seen.add(name)
out.append(f"| LOW | {name} | check days push some checks more than a day late (e.g. due {due.isoformat()}, planned {nd.isoformat()}); add a check day or feel the soil in between |")
out += ["", "Intervals assume the plant is established in a free-draining mix. After 2-3 weeks, lengthen an interval if the soil is still moist at most checks, shorten it if it is always bone dry."]
return "\n".join(out) + "\n"
def to_ics(res, stamp):
lines = ["BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//houseplant-watering-schedule-planner//EN", "CALSCALE:GREGORIAN"]
for d, names in res["calendar"]:
nd = d + dt.timedelta(days=1)
lines += ["BEGIN:VEVENT", f"UID:plants-{d.strftime('%Y%m%d')}@watering-planner", f"DTSTAMP:{stamp}",
f"DTSTART;VALUE=DATE:{d.strftime('%Y%m%d')}", f"DTEND;VALUE=DATE:{nd.strftime('%Y%m%d')}",
"SUMMARY:" + ics_escape("Check plants: " + ", ".join(names)), "TRANSP:TRANSPARENT", "END:VEVENT"]
lines.append("END:VCALENDAR")
return "\r\n".join(fold(l) for l in lines) + "\r\n"
def ics_escape(s):
return s.replace("\\", "\\\\").replace(";", "\\;").replace(",", "\\,").replace("\n", "\\n")
def fold(line):
b = line.encode("utf-8")
if len(b) <= 75:
return line
parts, cur = [], b""
for ch in line:
e = ch.encode("utf-8")
if len(cur) + len(e) > (75 if not parts else 74):
parts.append(cur.decode("utf-8")); cur = b""
cur += e
parts.append(cur.decode("utf-8"))
return "\r\n ".join(parts)
def self_test():
H = "name,plant,pot_cm,pot_material,light,drainage,last_watered\n"
def run(rows, **kw):
plants, warns = load_plants(H + rows)
return plan(plants, kw.pop("start", dt.date(2026, 4, 6)), kw.pop("weeks", 4), **kw), warns
cases = []
def case(name, fn):
try:
ok = bool(fn())
err = ""
except Exception as e: # noqa
ok, err = False, repr(e)
cases.append((name, ok, err))
case("succulent checked less often than fern", lambda: run("A,cactus,15,plastic,medium,yes,\nB,fern,15,plastic,medium,yes,\n")[0]["plants"][0]["interval_now"] > run("A,cactus,15,plastic,medium,yes,\nB,fern,15,plastic,medium,yes,\n")[0]["plants"][1]["interval_now"])
case("base interval top_dry 15 cm plastic medium spring = 6", lambda: run("A,pothos,15,plastic,medium,yes,\n")[0]["plants"][0]["interval_now"] == 6)
case("small pot dries faster", lambda: run("A,pothos,9,plastic,medium,yes,\n")[0]["plants"][0]["interval_now"] < 6)
case("big pot lasts longer", lambda: run("A,pothos,30,plastic,medium,yes,\n")[0]["plants"][0]["interval_now"] > 6)
case("terracotta dries faster than plastic", lambda: run("A,pothos,15,terracotta,medium,yes,\n")[0]["plants"][0]["interval_now"] < 6)
case("low light lengthens, direct sun shortens", lambda: run("A,pothos,15,plastic,low,yes,\n")[0]["plants"][0]["interval_now"] > 6 > run("A,pothos,15,plastic,direct,yes,\n")[0]["plants"][0]["interval_now"])
case("winter stretches succulent 2.5x", lambda: run("A,cactus,15,plastic,medium,yes,\n", start=dt.date(2026, 1, 5))[0]["plants"][0]["interval_now"] == 25)
case("summer shortens", lambda: run("A,pothos,15,plastic,medium,yes,\n", start=dt.date(2026, 7, 6))[0]["plants"][0]["interval_now"] == 5)
case("southern hemisphere: July is winter", lambda: season_of(dt.date(2026, 7, 1), "south") == "winter" and season_of(dt.date(2026, 1, 1), "south") == "summer")
case("season boundaries north", lambda: [season_of(dt.date(2026, m, 15), "north") for m in (2, 3, 5, 6, 8, 9, 11, 12)] == ["winter", "spring", "spring", "summer", "summer", "autumn", "autumn", "winter"])
case("interval grows across autumn->winter in plan", lambda: (lambda r: r["plants"][0]["intervals_later"].get("winter", 0) > r["plants"][0]["interval_now"])(run("A,pothos,15,plastic,medium,yes,\n", start=dt.date(2026, 11, 16), weeks=4)[0]))
case("checks spaced by interval", lambda: run("A,pothos,15,plastic,medium,yes,\n")[0]["plants"][0]["checks"][:3] == ["2026-04-06", "2026-04-12", "2026-04-18"])
case("last_watered sets first check", lambda: run("A,pothos,15,plastic,medium,yes,2026-04-04\n")[0]["plants"][0]["checks"][0] == "2026-04-10")
case("overdue goes to start", lambda: (lambda p: p["overdue"] and p["checks"][0] == "2026-04-06")(run("A,pothos,15,plastic,medium,yes,2026-03-20\n")[0]["plants"][0]))
case("snap to check days (Mon,Thu)", lambda: all(dt.date.fromisoformat(x).weekday() in (0, 3) for x in run("A,pothos,15,plastic,medium,yes,\nB,cactus,12,terracotta,bright,yes,\n", check_days=["Mon", "Thu"])[0]["calendar"] and [x for p in run("A,pothos,15,plastic,medium,yes,\nB,cactus,12,terracotta,bright,yes,\n", check_days=["Mon", "Thu"])[0]["plants"] for x in p["checks"]]))
case("snap to nearest check day (Sun -> Mon)", lambda: snap(dt.date(2026, 4, 12), dt.date(2026, 4, 6), {0, 3}) == dt.date(2026, 4, 13))
case("snap tie goes earlier (Tue between Mon and Thu? no: Tue -> Mon)", lambda: snap(dt.date(2026, 4, 14), dt.date(2026, 4, 9), {0, 3}) == dt.date(2026, 4, 13))
case("snap never on or before the previous check", lambda: snap(dt.date(2026, 4, 7), dt.date(2026, 4, 6), {0, 3}) == dt.date(2026, 4, 9))
case("autumn between spring and winter", lambda: 6 < run("A,pothos,15,plastic,medium,yes,\n", start=dt.date(2026, 10, 5))[0]["plants"][0]["interval_now"] < run("A,pothos,15,plastic,medium,yes,\n", start=dt.date(2026, 12, 7))[0]["plants"][0]["interval_now"])
case("late snap noted for fast plant", lambda: len(run("A,basil,9,terracotta,direct,yes,\n", check_days=["Mon"])[0]["late_snaps"]) > 0)
case("no drainage -> HIGH warning and half amount", lambda: (lambda r: any(w[0] == "HIGH" for w in r[1]) and "no more" in r[0]["plants"][0]["amount"])(run("A,pothos,15,glazed,medium,no,\n")))
case("unknown plant -> top_dry with warning", lambda: (lambda r: r[0]["plants"][0]["type"] == "top_dry" and any("unknown plant" in w[2] for w in r[1]))(run("A,triffid,15,plastic,medium,yes,\n")))
case("species substring match", lambda: run("A,variegated monstera,15,plastic,medium,yes,\n")[0]["plants"][0]["type"] == "top_dry")
case("succulent low light warning", lambda: any("stretch" in w[2] for w in run("A,echeveria,10,terracotta,low,yes,\n")[1]))
case("fern in direct sun warning", lambda: any("scorch" in w[2] for w in run("A,boston fern,20,plastic,direct,yes,\n")[1]))
case("self-watering succulent warning", lambda: any("self-watering" in w[2] for w in run("A,cactus,15,self-watering,bright,yes,\n")[1]))
case("orchid amount is soak", lambda: run("A,orchid,12,plastic,bright,yes,\n")[0]["plants"][0]["amount"] == "soak 10 min")
case("amount scales with pot", lambda: int(run("A,pothos,25,plastic,medium,yes,\n")[0]["plants"][0]["amount"][1:].split()[0]) > int(run("A,pothos,12,plastic,medium,yes,\n")[0]["plants"][0]["amount"][1:].split()[0]))
case("low humidity shortens", lambda: run("A,fern,20,plastic,medium,yes,\n", humidity="low")[0]["plants"][0]["interval_now"] <= run("A,fern,20,plastic,medium,yes,\n")[0]["plants"][0]["interval_now"])
case("interval never below 1 day", lambda: run("A,basil,6,fabric,direct,yes,\n", start=dt.date(2026, 7, 6), humidity="low")[0]["plants"][0]["interval_now"] >= 1)
case("missing pot size assumed 15", lambda: (lambda r: r[0]["plants"][0]["pot_cm"] == 15 and any("assumed 15" in w[2] for w in r[1]))(run("A,pothos,,plastic,medium,yes,\n")))
def bad(rows):
try:
load_plants(H + rows); return False
except InputError:
return True
case("bad material rejected", lambda: bad("A,pothos,15,wood,medium,yes,\n"))
case("bad light rejected", lambda: bad("A,pothos,15,plastic,dim,yes,\n"))
case("pot in mm rejected", lambda: bad("A,pothos,150,plastic,medium,yes,\n"))
case("bad date rejected", lambda: bad("A,pothos,15,plastic,medium,yes,30/10/2026\n"))
case("ics has one event per date, CRLF, escaped commas", lambda: (lambda r, t: t.count("BEGIN:VEVENT") == len(r["calendar"]) and "\r\n" in t and "\\," in t)(*(lambda r: (r, to_ics(r, "20261030T000000Z")))(run("A,pothos,15,plastic,medium,yes,\nB,fern,15,plastic,medium,yes,\n")[0])))
case("ics lines folded to 75 octets", lambda: all(len(l.encode()) <= 75 for l in to_ics(run("".join(f"Plant number {i},pothos,15,plastic,medium,yes,\n" for i in range(8)))[0], "20261030T000000Z").split("\r\n")))
passed = 0
for name, ok, err in cases:
passed += ok
print(("PASS " if ok else "FAIL ") + name + ("" if ok else f" {err}"))
print(f"{passed}/{len(cases)} passed")
return 0 if passed == len(cases) else 1
def main(argv=None):
ap = argparse.ArgumentParser(description="Build a houseplant watering check calendar")
ap.add_argument("plants", nargs="?")
ap.add_argument("--start", help="first day of the plan, YYYY-MM-DD (default today)")
ap.add_argument("--weeks", type=int, default=4)
ap.add_argument("--hemisphere", choices=["north", "south"], default="north")
ap.add_argument("--humidity", choices=list(HUMIDITY), default="normal", help="low = heating on / below ~35 %%")
ap.add_argument("--check-days", help="snap checks to these weekdays, e.g. Mon,Thu")
ap.add_argument("--ics", help="also write an .ics calendar file")
ap.add_argument("--json", action="store_true")
ap.add_argument("--self-test", action="store_true")
a = ap.parse_args(argv)
if a.self_test:
return self_test()
if not a.plants:
ap.error("give a plants CSV, or --self-test")
try:
start = parse_date(a.start, "--start") if a.start else dt.date.today()
if not 1 <= a.weeks <= 26:
raise InputError("--weeks must be 1..26")
days = None
if a.check_days:
days = [x.strip()[:3].title() for x in a.check_days.split(",") if x.strip()]
for x in days:
if x not in DAY_NAMES:
raise InputError(f"unknown weekday '{x}' in --check-days")
with open(a.plants, encoding="utf-8") as fh:
plants, warnings = load_plants(fh.read())
except (OSError, InputError, UnicodeDecodeError) as e:
print(f"error: {e}", file=sys.stderr)
return 2
res = plan(plants, start, a.weeks, a.hemisphere, a.humidity, days)
if a.ics:
stamp = dt.datetime.now(dt.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
with open(a.ics, "w", encoding="utf-8", newline="") as fh:
fh.write(to_ics(res, stamp))
if a.json:
out = {**res, "start": res["start"].isoformat(), "end": res["end"].isoformat(),
"calendar": [{"date": d.isoformat(), "plants": n} for d, n in res["calendar"]],
"late_snaps": [{"plant": n, "due": d.isoformat(), "planned": p.isoformat()} for n, d, p in res["late_snaps"]],
"plants": [{**p, "last_watered": p["last_watered"].isoformat() if p["last_watered"] else None} for p in res["plants"]],
"warnings": [{"severity": s, "plant": n, "note": m} for s, n, m in warnings]}
print(json.dumps(out, indent=2))
else:
sys.stdout.write(render(res, warnings))
return 1 if any(w[0] == "HIGH" for w in warnings) else 0
if __name__ == "__main__":
sys.exit(main())