diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ae660a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +.myp-workbench/ +.mypy_cache/ +.claude/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..abff4e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,240 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Fyto is a Raspberry Pi Zero 2W-based plant monitoring system that displays animated emotions on a 2-inch IPS LCD screen based on real-time sensor readings. The project uses a socket-based client-server architecture where sensor readings drive emotion display changes. + +## System Architecture + +### Two-Process Communication Model + +The system consists of two Python processes that communicate via TCP sockets on port 1013: + +1. **Display Server** (`Code/main.py`): + - Listens on `0.0.0.0:1013` + - Controls the 2-inch LCD display via SPI + - Receives 5-byte emotion codes from the sensor client + - Plays 180-frame animations by loading PNG files sequentially + - Uses interrupt flag `doInterrupt` to stop current animation when new emotion arrives + - All images are rotated 180° before display + +2. **Sensor Client** (`Code/sensors.py`): + - Connects to the display server on `0.0.0.0:1013` + - Reads from ADS1115 16-bit ADC via I2C + - Sends 5-byte emotion strings: `'happy'`, `'sleep'`, `'thirs'`, `'savor'`, `'hotty'`, `'freez'` + - Uses state flags to prevent redundant emotion transmissions + - Continuously loops reading sensors (no delay between readings) + +### Emotion Trigger Logic + +The sensor client evaluates conditions in this priority order (first match wins): +1. **Light level** → `'sleep'` (<20%) or `'happy'` (>20%) +2. **Moisture level** → `'thirs'` (<10%), `'savor'` (10-90% rising), or `'savor'` (>90%) +3. **Temperature** → `'hotty'` (>30°C) or `'freez'` (<22°C) + +### Hardware Communication + +- **LCD Display**: SPI interface via `spidev` (90MHz frequency) + - Uses GPIO pins: RST=27, DC=25, BL=18 + - Driven by `lib/LCD_2inch.py` (240x320 resolution) + +- **ADS1115 ADC**: I2C interface at address 0x48 + - A0: Unused/Open + - A1: LM35 temperature sensor (analog) + - A2: Capacitive moisture sensor + - A3: LDR light sensor + +### Emotion Animation System + +- Animations stored in `Code/emotion/[emotion_name]/frame[0-179].png` +- Folder names: `happy`, `sleepy`, `hot`, `freeze`, `savory`, `thirsty` +- Note: Code sends shortened names (`'sleep'`, `'thirs'`, etc.) but expects full folder names +- Each animation loops through 180 PNG frames loaded sequentially +- Current animation can be interrupted by setting `doInterrupt=1` flag + +## Development Commands + +### Running the System + +**Terminal 1 (Display Server):** +```bash +cd Code +python3 main.py +``` + +**Terminal 2 (Sensor Client):** +```bash +cd Code +python3 sensors.py +``` + +Note: The display server must start first to establish the socket listener. + +### Sensor Calibration + +Edit `Code/calibration.py` to change which ADC channel to read: +```python +chan = AnalogIn(ads, ADS.P2) # Moisture sensor +chan = AnalogIn(ads, ADS.P3) # Light sensor +chan = AnalogIn(ads, ADS.P1) # Temperature sensor +``` + +Run calibration: +```bash +cd Code +python3 calibration.py +``` + +Record the min/max raw ADC values, then update the `_map()` function calls in `sensors.py`: +```python +LDR_Percent = _map(LDR_Value, 22500, 50, 0, 100) # Dark to bright +Moisture_Percent = _map(Moisture_Value, 31000, 15500, 0, 100) # Dry to wet +``` + +### Documentation Website + +Generate schemdraw-based wiring diagrams: +```bash +uv run docs/generate_schematic.py +``` + +Preview the GitHub Pages website locally: +```bash +cd docs +python3 -m http.server 8000 +# Open http://localhost:8000 +``` + +The website includes: +- Interactive wiring diagrams with tabbed views +- Hover-animated emotion previews (loads every 6th frame via Canvas API) +- Hardware requirements and setup guide +- Bash-highlighted quick start commands + +## Critical Hardware Details + +### ADS1115 Channel Assignments + +The code expects this specific wiring (matches `sensors.py` lines 10-12): +- **A0**: Open/Unused +- **A1**: LM35 Temperature Sensor +- **A2**: Capacitive Moisture Sensor +- **A3**: LDR Light Sensor + +⚠️ **Warning**: The original Instructables tutorial shows different channel assignments. If wiring differs from above, you must modify `sensors.py` channel definitions. + +### Temperature Sensor Requirement + +- **Must use LM35** analog sensor (outputs analog voltage) +- **Do NOT use DS18B20** digital sensor (requires completely different code) + +### I2C Configuration + +Before running, ensure I2C is enabled and Serial is disabled: +```bash +sudo raspi-config +# Interface Options → I2C → Enable +# Interface Options → Serial → Disable +``` + +Verify ADS1115 is detected at address 0x48: +```bash +sudo i2cdetect -y 1 +``` + +### Voltage Protection + +Strongly recommended: Use a 5V-to-3.3V bidirectional logic level converter for all sensor connections. The Raspberry Pi GPIO pins are 3.3V only and can be permanently damaged by 5V signals. + +## Code Modification Patterns + +### Adding New Emotions + +1. Create new folder in `Code/emotion/[new_emotion]/` with 180 frames (frame0.png - frame179.png) +2. Add emotion logic to `sensors.py` (send 5-byte string) +3. Update `main.py` if folder name differs from sent string +4. For documentation website: Copy every 6th frame to `docs/emotions/[new_emotion]/` + +### Adjusting Sensor Thresholds + +Edit the condition checks in `sensors.py`: +- Light thresholds: Lines 50, 57 (currently 20%) +- Moisture thresholds: Lines 65, 74, 83 (currently 10%, 90%) +- Temperature thresholds: Lines 93, 99 (currently 30°C, 22°C) + +### Changing Display Rotation + +Modify line 46 in `main.py`: +```python +image = image.rotate(180) # Change angle or remove +``` + +## Project Structure + +``` +Code/ +├── main.py # Display server (SPI LCD control) +├── sensors.py # Sensor client (I2C ADC reading) +├── calibration.py # Sensor calibration utility +├── emotion/ # 180-frame PNG animations per emotion +│ ├── happy/ +│ ├── sleepy/ +│ ├── hot/ +│ ├── freeze/ +│ ├── savory/ +│ └── thirsty/ +└── lib/ # LCD driver libraries + ├── LCD_2inch.py # Main 2" display driver + ├── lcdconfig.py # GPIO/SPI hardware interface + └── LCD_*.py # Other display drivers (unused) + +docs/ # GitHub Pages website +├── index.html # Main landing page with Canvas animations +├── wiring-diagram.html # Full-screen interactive wiring guide +├── generate_schematic.py # PEP 723 script for schemdraw diagrams +├── diagrams/ # SVG schematics and wiring diagrams +└── emotions/ # Subset of animation frames (every 6th frame) + +3D/ # STL files for 3D-printed enclosure +``` + +## Dependency Management + +### Raspberry Pi Dependencies +```bash +sudo apt-get install python3-pip python3-pil python3-numpy +pip3 install adafruit-circuitpython-ads1x15 spidev +``` + +### Documentation Dependencies +The `generate_schematic.py` script uses PEP 723 inline script metadata for `uv run`: +```python +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "schemdraw>=0.18", +# ] +# /// +``` + +No virtual environment or manual package installation needed—just run `uv run docs/generate_schematic.py`. + +## Common Issues + +### Emotion Folder Name Mismatch +The code sends abbreviated emotion names but looks for full folder names: +- Sent: `'thirs'`, `'savor'`, `'sleep'`, `'hotty'`, `'freez'` +- Expected folders: `thirsty`, `savory`, `sleepy`, `hot`, `freeze` + +The display server handles this mapping, but folder names must match exactly. + +### Socket Connection Refused +- Ensure `main.py` (display server) is running before `sensors.py` (client) +- Check no other process is using port 1013: `lsof -i :1013` + +### Erratic Sensor Readings +- Use ADS1115 modules with pre-soldered headers (breadboard connections create noise) +- Verify I2C is enabled and Serial is disabled in `raspi-config` +- Add logic level converter for cleaner 5V-to-3.3V signal conversion diff --git a/Code/lib/LCD_1inch28.py b/Code/lib/LCD_1inch28.py index 94a199f..b93c544 100644 --- a/Code/lib/LCD_1inch28.py +++ b/Code/lib/LCD_1inch28.py @@ -1,21 +1,69 @@ +""" +LCD_1inch28.py - Driver for 1.28 inch Round LCD Display (240x240) + +This module provides a driver for the GC9A01 based 1.28 inch round LCD display. +The display uses SPI communication and supports 16-bit RGB565 color format. + +Display Specifications: + - Resolution: 240x240 pixels + - Interface: SPI + - Color Format: RGB565 (16-bit) + - Controller: GC9A01 + +Usage: + from lib import LCD_1inch28 + + lcd = LCD_1inch28.LCD_1inch28() + lcd.Init() + lcd.clear() + lcd.ShowImage(image) # PIL Image object +""" import time from . import lcdconfig + class LCD_1inch28(lcdconfig.RaspberryPi): + """ + Driver class for 1.28 inch round LCD display (GC9A01 controller). + + Inherits from lcdconfig.RaspberryPi to access GPIO and SPI functionality. + + Attributes: + width (int): Display width in pixels (240) + height (int): Display height in pixels (240) + """ width = 240 - height = 240 + height = 240 + def command(self, cmd): + """ + Send a command byte to the LCD controller. + + Args: + cmd (int): Command byte to send (0x00-0xFF) + """ self.digital_write(self.DC_PIN, self.GPIO.LOW) self.spi_writebyte([cmd]) def data(self, val): + """ + Send a data byte to the LCD controller. + + Args: + val (int): Data byte to send (0x00-0xFF) + """ self.digital_write(self.DC_PIN, self.GPIO.HIGH) self.spi_writebyte([val]) def reset(self): - """Reset the display""" + """ + Perform a hardware reset of the display. + + Toggles the reset pin HIGH -> LOW -> HIGH with 10ms delays + to reset the LCD controller to its initial state. + """ self.GPIO.output(self.RST_PIN,self.GPIO.HIGH) time.sleep(0.01) self.GPIO.output(self.RST_PIN,self.GPIO.LOW) @@ -24,7 +72,16 @@ def reset(self): time.sleep(0.01) def Init(self): - """Initialize dispaly""" + """ + Initialize the LCD display. + + Performs module initialization, hardware reset, and sends the + complete initialization sequence for the GC9A01 controller. + This configures power settings, gamma correction, display timing, + and enables the display. + + Must be called before any other display operations. + """ self.module_init() self.reset() @@ -264,7 +321,19 @@ def Init(self): time.sleep(0.02) def SetWindows(self, Xstart, Ystart, Xend, Yend): - #set the X coordinates + """ + Set the drawing window area on the display. + + Defines the rectangular region where subsequent pixel data + will be written. Uses CASET (0x2A) and RASET (0x2B) commands. + + Args: + Xstart (int): Starting X coordinate (0-239) + Ystart (int): Starting Y coordinate (0-239) + Xend (int): Ending X coordinate (1-240, exclusive) + Yend (int): Ending Y coordinate (1-240, exclusive) + """ + # Set the X coordinates self.command(0x2A) self.data(0x00) #Set the horizontal starting point to the high octet self.data(Xstart) #Set the horizontal starting point to the low octet @@ -280,9 +349,27 @@ def SetWindows(self, Xstart, Ystart, Xend, Yend): self.command(0x2C) - def ShowImage(self,Image): - """Set buffer to value of Python Imaging Library image.""" - """Write display buffer to physical display""" + def ShowImage(self, Image): + """ + Display a PIL Image on the LCD. + + Converts the image from RGB888 to RGB565 format and writes + the pixel data to the display via SPI in 4096-byte chunks. + + Args: + Image (PIL.Image): A PIL Image object. Must be exactly + 240x240 pixels in RGB mode. + + Raises: + ValueError: If the image dimensions don't match the display + (240x240 pixels). + + Note: + RGB565 conversion: + - Red: 5 bits (bits 15-11) + - Green: 6 bits (bits 10-5) + - Blue: 5 bits (bits 4-0) + """ imwidth, imheight = Image.size if imwidth != self.width or imheight != self.height: raise ValueError('Image must be same dimensions as display \ @@ -298,7 +385,13 @@ def ShowImage(self,Image): self.spi_writebyte(pix[i:i+4096]) def clear(self): - """Clear contents of image buffer""" + """ + Clear the display to white. + + Fills the entire display with white pixels (0xFF) by writing + a buffer of white pixel data to the full display area. + Data is sent in 4096-byte chunks via SPI. + """ _buffer = [0xff]*(self.width * self.height * 2) self.SetWindows ( 0, 0, self.width, self.height) self.digital_write(self.DC_PIN,self.GPIO.HIGH) diff --git a/README.md b/README.md new file mode 100644 index 0000000..167db4b --- /dev/null +++ b/README.md @@ -0,0 +1,314 @@ +# Fyto - Turn Your Plant Into a Pet + +Fyto is an intelligent planter that transforms your houseplant into an interactive companion. It monitors your plant's environment through sensors and displays animated emotions on a color LCD screen, helping you understand your plant's needs at a glance. + +**📱 [View the Project Website](https://yourname.github.io/fyto/)** - Interactive wiring diagrams, full documentation, and build guide. + +## Features + +Fyto expresses **six distinct emotions** based on sensor readings: + +| Emotion | Trigger | Folder | +|---------|---------|--------| +| **Thirsty** | Soil moisture < 10% | `thirsty` | +| **Savory** | Recently watered (moisture rising) | `savory` | +| **Happy** | Optimal conditions | `happy` | +| **Sleepy** | Low light (< 20%) | `sleepy` | +| **Hot** | Temperature > 30°C | `hot` | +| **Freeze** | Temperature < 22°C | `freeze` | + +## Hardware Requirements + +### Core Components +- **Raspberry Pi Zero 2W** - Main controller (1GHz quad-core ARM Cortex-A53) +- **240x320 2-inch IPS LCD Display** - For displaying emotions +- **ADS1115 16-bit ADC** - Analog-to-digital converter (Pi lacks native analog inputs) + +### Sensors +- **Capacitive Soil Moisture Sensor** - Prevents corrosion unlike resistive sensors +- **LM35 Temperature Sensor** - Analog temperature sensor (**Important:** Do NOT use DS18B20 - see Troubleshooting) +- **LDR Light Sensor Module** - Detects ambient light levels + +### Power & Accessories +- 5V 2A Power Adapter +- Micro USB Breadboard Power Supply Module +- 30AWG Silicone Wires (5m recommended) +- Perforated Board (for soldering) +- 2mm Transparent Acrylic Sheet (display cover) + +### Recommended Addition +- **I2C 4-Channel Bi-Directional 5V to 3.3V Logic Level Converter** - Protects GPIO pins from voltage differences. Highly recommended to avoid damaging your Pi. + +## Wiring Diagram + +**Visual diagrams are available in the [docs](docs/) folder:** +- [Interactive Wiring Diagram (HTML)](docs/wiring-diagram.html) - Open in browser for full interactive view +- [SVG Wiring Diagram](docs/diagrams/fyto-wiring.svg) - Printable vector diagram +- [Schemdraw Schematic](docs/diagrams/fyto_schematic.svg) - Generated circuit schematic +- [Pinout Reference](docs/diagrams/fyto_pinout.svg) - GPIO pin reference diagram + +To regenerate the schemdraw diagrams: +```bash +uv run docs/generate_schematic.py +``` + +### LCD to Raspberry Pi Zero 2W + +| LCD Pin | Pi Zero Pin | GPIO | +|---------|-------------|------| +| VCC | Pin 1 | 3.3V | +| GND | Pin 9 | Ground | +| DIN | Pin 21 | GPIO 9 (MOSI) | +| CLK | Pin 23 | GPIO 11 (SCLK) | +| CS | Pin 24 | GPIO 8 (CE0) | +| DC | Pin 37 | GPIO 26 | +| RST | Pin 36 | GPIO 16 | +| BL | Pin 19 | GPIO 10 | + +### ADS1115 ADC Connections + +| ADS1115 Pin | Connection | +|-------------|------------| +| VCC | 3.3V | +| GND | Ground | +| SCL | Pi SCL (Pin 5 / GPIO 3) | +| SDA | Pi SDA (Pin 3 / GPIO 2) | +| A0 | (Open) | +| A1 | LM35 Temperature Sensor | +| A2 | Capacitive Moisture Sensor | +| A3 | LDR Light Sensor | + +> **Important:** The original Instructables wiring diagram shows different channel assignments. The wiring above matches what the code expects. If you wire according to the original diagram, you'll need to modify `sensors.py`. + +## Raspberry Pi Setup + +### 1. Enable I2C + +```bash +sudo raspi-config +``` + +Navigate to: **Interface Options** → **I2C** → **Enable** + +> **Important:** Make sure I2C is enabled and Serial connection is **disabled**. + +### 2. Install Dependencies + +```bash +sudo apt-get update +sudo apt-get install python3-pip python3-pil python3-numpy + +pip3 install adafruit-circuitpython-ads1x15 +pip3 install spidev +``` + +### 3. Clone the Repository + +```bash +git clone https://github.com/CodersCafeTech/Fyto.git +cd Fyto/Code +``` + +## Calibration + +Before running the main program, calibrate your sensors to get accurate readings. + +### 1. Test Individual Sensors + +Edit `calibration.py` to test each sensor channel: + +```python +# For Moisture sensor (A2): +chan = AnalogIn(ads, ADS.P2) + +# For Light sensor (A3): +chan = AnalogIn(ads, ADS.P3) + +# For Temperature sensor (A1): +chan = AnalogIn(ads, ADS.P1) +``` + +Run the calibration script: +```bash +python3 calibration.py +``` + +### 2. Record Min/Max Values + +For each sensor, record the raw ADC values at: +- **Moisture:** Dry soil (max) and wet soil (min) +- **Light:** Dark room (max ~22500) and bright light (min ~50) + +### 3. Update sensors.py + +Update the `_map()` function calls with your calibrated values: + +```python +# Current defaults - adjust based on your calibration +LDR_Percent = _map(LDR_Value, 22500, 50, 0, 100) +Moisture_Percent = _map(Moisture_Value, 31000, 15500, 0, 100) +``` + +## Running Fyto + +Fyto uses two Python scripts that communicate via sockets: + +### Terminal 1 - Start the Display Server +```bash +cd Code +python3 main.py +``` + +### Terminal 2 - Start the Sensor Reader +```bash +cd Code +python3 sensors.py +``` + +### Auto-Start on Boot (Optional) + +Create a systemd service or add to `/etc/rc.local`: + +```bash +cd /path/to/Fyto/Code && python3 main.py & +sleep 5 +cd /path/to/Fyto/Code && python3 sensors.py & +``` + +## 3D Printing + +The enclosure consists of three parts: +- Outer cover +- Base +- Plant container (water-tight) + +### Files +- Original STEP file: `3D/Flower_Latest v16.step` +- Pre-sliced STL files: [Google Drive](https://drive.google.com/drive/folders/1KikgjQQ0zHyn-Ojjpr6-c6RQJZTwspdg?usp=sharing) (community contribution) + +### Print Settings +- Material: PLA +- Infill: 10% +- The vase design is water-tight even at faster print speeds + +## Project Structure + +``` +Fyto/ +├── Code/ +│ ├── main.py # Display server - shows emotions on LCD +│ ├── sensors.py # Reads sensors and sends emotion triggers +│ ├── calibration.py # Sensor calibration utility +│ ├── emotion/ # Animation frames for each emotion +│ │ ├── happy/ # 180 frames (frame0.png - frame179.png) +│ │ ├── thirsty/ +│ │ ├── savory/ +│ │ ├── sleepy/ +│ │ ├── hot/ +│ │ └── freeze/ +│ └── lib/ # LCD driver libraries +│ ├── LCD_2inch.py # 2-inch display driver +│ ├── lcdconfig.py # GPIO/SPI configuration +│ └── ... +└── 3D/ + └── Flower_Latest v16.step +``` + +## Troubleshooting + +### Common Issues + +#### "Folder not found" errors +The emotion folder names in the code use shortened names. Ensure these match: +- Code sends: `thirs`, `savor`, `happy`, `sleep`, `hotty`, `freez` +- Folder names: `thirsty`, `savory`, `happy`, `sleepy`, `hot`, `freeze` + +The current code has been updated to handle this, but if you see errors, check that the folder names match exactly. + +#### Temperature sensor not working +**Use the LM35 analog sensor, NOT the DS18B20.** The DS18B20 is digital and won't work with this code without modifications. The LM35 outputs an analog voltage proportional to temperature. + +#### Erratic sensor readings during calibration +- Use an ADS1115 module with **pre-soldered headers** if possible +- Breadboard connections can create noise +- Consider using a logic level converter for cleaner signals + +#### GPIO pins not responding / damaged +Always use a **5V to 3.3V logic level converter** when connecting 5V sensors to the Pi. The Pi's GPIO pins are 3.3V only and can be permanently damaged by 5V signals. + +#### I2C device not detected +```bash +sudo i2cdetect -y 1 +``` +You should see the ADS1115 at address `0x48`. If not: +- Check wiring +- Ensure I2C is enabled in `raspi-config` +- Ensure Serial is disabled + +#### Adafruit library import errors +If you have a fresh Raspberry Pi OS install (2023+), Adafruit libraries have been updated. Make sure you're using: +```python +import adafruit_ads1x15.ads1115 as ADS +from adafruit_ads1x15.analog_in import AnalogIn +``` + +### Sensor Quality Note +Capacitive moisture sensors can vary in quality. Some arrive damaged or incorrectly manufactured. Consider purchasing from reputable sellers and testing before final assembly. + +## Emotion Thresholds + +Current thresholds in `sensors.py`: + +| Condition | Threshold | Emotion Triggered | +|-----------|-----------|-------------------| +| Low light | < 20% | Sleepy | +| Adequate light | > 20% | Happy | +| Low moisture | < 10% | Thirsty | +| Rising moisture | 10-90% (increasing) | Savory | +| High moisture | > 90% | Savory | +| High temperature | > 30°C | Hot | +| Low temperature | < 22°C | Freeze | + +Adjust these values in `sensors.py` based on your plant's needs and local climate. + +## GitHub Pages Website + +This project includes a complete documentation website that can be hosted on GitHub Pages. + +### Setup GitHub Pages + +1. Go to your GitHub repository settings +2. Navigate to **Pages** (under "Code and automation") +3. Under **Source**, select "Deploy from a branch" +4. Under **Branch**, select `main` and `/docs` folder +5. Click **Save** + +Your site will be available at: `https://[username].github.io/[repository-name]/` + +The website includes: +- Interactive wiring diagrams +- Complete hardware list +- Step-by-step setup guide +- Emotion showcase +- Embedded SVG schematics + +### Local Preview + +To preview the website locally: +```bash +# Using Python's built-in server +cd docs +python3 -m http.server 8000 + +# Open http://localhost:8000 in your browser +``` + +## Credits + +- Original project by [Coders Cafe](https://github.com/CodersCafeTech) +- [Instructables Tutorial](https://www.instructables.com/Fyt%C3%B3-Turn-Your-Plant-Into-Pet/) +- Community contributions and troubleshooting tips + +## License + +See [LICENSE.md](LICENSE.md) for details. diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..fe78eab --- /dev/null +++ b/docs/README.md @@ -0,0 +1,89 @@ +# Fyto Documentation Website + +This directory contains the GitHub Pages website for the Fyto project. + +## Contents + +- `index.html` - Main project website with interactive features + - **Animated emotions on hover** - Cycles through actual emotion frames +- `wiring-diagram.html` - Detailed wiring guide with connection tables +- `diagrams/` - SVG wiring diagrams and schematics +- `emotions/` - Sample emotion animation frames (60 frames per emotion, ~2MB total) +- `generate_schematic.py` - Script to regenerate schemdraw diagrams +- `_config.yml` - GitHub Pages configuration +- `.nojekyll` - Ensures all files are served by GitHub Pages + +### Emotion Animations + +The website includes hover animations for each emotion card. When you hover over an emotion, it plays the actual animation frames from the Fyto display. To keep the repository size manageable, we include every 3rd frame (60 frames per emotion instead of the full 180). + +## Local Preview + +To preview the website locally: + +```bash +# From the docs directory +python3 -m http.server 8000 + +# Then open http://localhost:8000 in your browser +``` + +## Publishing to GitHub Pages + +1. Push this repository to GitHub +2. Go to repository **Settings** → **Pages** +3. Under **Source**, select: + - Branch: `main` (or your default branch) + - Folder: `/docs` +4. Click **Save** + +Your site will be available at: `https://[username].github.io/[repo-name]/` + +## Regenerating Diagrams + +The schemdraw-generated diagrams can be regenerated with: + +```bash +# From the project root +uv run docs/generate_schematic.py + +# Or from the docs directory +uv run generate_schematic.py +``` + +This will regenerate: +- `diagrams/fyto_schematic.svg` - Circuit schematic +- `diagrams/fyto_pinout.svg` - GPIO pinout reference + +The hand-crafted `diagrams/fyto-wiring.svg` is static and should be edited manually if needed. + +## Editing the Website + +### Main Landing Page (`index.html`) +- Modern single-page design +- Tabbed wiring diagram viewer +- Emotion showcase +- Hardware requirements +- Quick start guide + +### Detailed Wiring Page (`wiring-diagram.html`) +- Full-screen wiring diagram +- Color-coded connections +- Interactive hover effects +- Connection reference tables +- Important safety notes + +## Dependencies + +The website is pure HTML/CSS/JavaScript with no build step required. The only dependency is for regenerating diagrams: + +- Python 3.9+ +- schemdraw (installed automatically by `uv run`) + +## Browser Support + +The website works in all modern browsers: +- Chrome/Edge (latest) +- Firefox (latest) +- Safari (latest) +- Mobile browsers (responsive design) diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..58b5dbd --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,20 @@ +# GitHub Pages Configuration for Fyto + +# Theme (using none since we have custom HTML) +theme: null + +# Exclude files from site build +exclude: + - generate_schematic.py + - "*.pyc" + - __pycache__ + +# Include SVG and other assets +include: + - diagrams + +# Site settings +title: "Fyto - Turn Your Plant Into a Pet" +description: "An interactive plant monitor that displays emotions based on environmental sensors" +url: "https://github.com/CodersCafeTech/Fyto" +author: "Coders Cafe" diff --git a/docs/assets/freeze.gif b/docs/assets/freeze.gif new file mode 100644 index 0000000..38f5e7f Binary files /dev/null and b/docs/assets/freeze.gif differ diff --git a/docs/assets/happy.gif b/docs/assets/happy.gif new file mode 100644 index 0000000..79a9bad Binary files /dev/null and b/docs/assets/happy.gif differ diff --git a/docs/assets/hot.gif b/docs/assets/hot.gif new file mode 100644 index 0000000..c535756 Binary files /dev/null and b/docs/assets/hot.gif differ diff --git a/docs/assets/savory.gif b/docs/assets/savory.gif new file mode 100644 index 0000000..f953ec8 Binary files /dev/null and b/docs/assets/savory.gif differ diff --git a/docs/assets/sleepy.gif b/docs/assets/sleepy.gif new file mode 100644 index 0000000..a1bf34c Binary files /dev/null and b/docs/assets/sleepy.gif differ diff --git a/docs/assets/stl-icon.png b/docs/assets/stl-icon.png new file mode 100644 index 0000000..b50b456 Binary files /dev/null and b/docs/assets/stl-icon.png differ diff --git a/docs/assets/thirsty.gif b/docs/assets/thirsty.gif new file mode 100644 index 0000000..7aa7794 Binary files /dev/null and b/docs/assets/thirsty.gif differ diff --git a/docs/diagrams/fyto-wiring.svg b/docs/diagrams/fyto-wiring.svg new file mode 100644 index 0000000..1c4480a --- /dev/null +++ b/docs/diagrams/fyto-wiring.svg @@ -0,0 +1,452 @@ + + + Fyto Plant Monitor - Wiring Diagram + Complete wiring diagram for the Fyto plant monitoring project showing connections between Raspberry Pi Zero 2W, ADS1115 ADC, 2" LCD Display, and sensors. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fyto - Plant Monitor Wiring Diagram + Raspberry Pi Zero 2W • ADS1115 ADC • 2" LCD • Environmental Sensors + + + + 3.3V POWER RAIL + + + GROUND RAIL + + + + + + + Raspberry Pi + Zero 2W + + + + + + + + + + 3V3 + 1 + + + + SDA + 3 + + + + SCL + 5 + + + + 7 + + + + GND + 9 + + + + 11 + + 13 + + 15 + + 17 + + + + BL + 19 + + + + + + 5V + 2 + + + + 4 + + 6 + + 8 + + 10 + + 12 + + 14 + + 16 + + 18 + + 20 + + + + + MOSI + Pin 21 + + + + SCLK + Pin 23 + + + + CE0 + Pin 24 + + + + RST + Pin 36 + + + + DC + Pin 37 + + + + + + + + ADS1115 + 16-bit ADC Converter + + + + + + + + VDD + + + GND + + + SCL + + + SDA + + + + A0 + + + A1 + + + A2 + + + A3 + + + Channel Assignments: + A0 = Open (unused) + A1 = LM35 Temperature + A2 = Moisture Sensor + A3 = LDR Light Sensor + + + + + + + + 2" IPS LCD Display + 240×320 RGB (SPI Interface) + + + + 😊 + + + + VCC + + + GND + + + DIN + + + CLK + + + + CS + + + DC + + + RST + + + BL + + + + + + + + + + LM35 + Temperature Sensor (Analog) + + + + TO-92 + + + + VCC + + + OUT + + + GND + + + + + + Capacitive Moisture + Soil Moisture Sensor + + + + + + + + VCC + + + OUT + + + GND + + + + + + LDR Module + Light Dependent Resistor + + + + + + + + + + VCC + + + OUT + + + GND + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + → A1 + → A2 + → A3 + + + + + + + + Wire Colors + + + + 3.3V Power + + + Ground + + + I2C SDA + + + I2C SCL + + + SPI MOSI + + + SPI SCLK + + + SPI CS + + + LCD DC + + + LCD RST + + + LCD BL + + + Temp Signal + + + Moisture Sig + + + Light Signal + + + + ⚠️ IMPORTANT + Use LM35 (analog) + NOT DS18B20 (digital) + + + + + Fyto Plant Monitor - github.com/CodersCafeTech/Fyto - Wiring matches code configuration + + diff --git a/docs/diagrams/fyto_pinout.svg b/docs/diagrams/fyto_pinout.svg new file mode 100644 index 0000000..fe4689b --- /dev/null +++ b/docs/diagrams/fyto_pinout.svg @@ -0,0 +1 @@ +Fyto - Pin Connection ReferenceRaspberry Pi Zero 2W GPIO Header13V33SDA5SCL79GND1113151719BL21MOSI23SCLK252729313335373925V4681012141618202224CE0262830323436RST3840LCD Display ConnectionsVCC -> Pin 1 (3V3)GND -> Pin 9 (GND)DIN -> Pin 21 (MOSI)CLK -> Pin 23 (SCLK)CS -> Pin 24 (CE0)DC -> Pin 37 (GPIO26)RST -> Pin 36 (GPIO16)BL -> Pin 19 (GPIO10)ADS1115 ADC ConnectionsVDD -> Pin 1 (3V3)GND -> Pin 9 (GND)SCL -> Pin 5 (SCL)SDA -> Pin 3 (SDA)A1 -> LM35 OUTA2 -> Moisture OUTA3 -> LDR OUTSensor ConnectionsAll sensors: VCC -> 3V3, GND -> GNDLM35 Temp: OUT -> ADS1115 A1Moisture: OUT -> ADS1115 A2LDR Light: OUT -> ADS1115 A3 \ No newline at end of file diff --git a/docs/diagrams/fyto_schematic.svg b/docs/diagrams/fyto_schematic.svg new file mode 100644 index 0000000..ad194ad --- /dev/null +++ b/docs/diagrams/fyto_schematic.svg @@ -0,0 +1 @@ +Fyto - Plant Monitor SchematicRaspberry Pi Zero 2W + Sensors13V33SDA5SCL9GND19GPIO1021MOSI23SCLK24CE036RST37DC25VRaspberry PiZero 2WVDDVDDGNDGNDSCLSCLSDASDAA0A0A1A1A2A2A3A3ADS111516-bit ADCVCCVCCGNDGNDDINDINCLKCLKCSCSDCDCRSTRSTBLBL2" IPS LCD240x320+VCC-GNDOUTOUTLM35Temp+VCC-GNDOUTOUTMoistureSensor+VCC-GNDOUTOUTLDRLight3.3VGNDWire Color Legend:3.3V PowerGroundI2C SDAI2C SCLSPI MOSISPI SCLKSPI CS / MoistureLDR Signal \ No newline at end of file diff --git a/docs/generate_schematic.py b/docs/generate_schematic.py new file mode 100644 index 0000000..165a16e --- /dev/null +++ b/docs/generate_schematic.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "schemdraw>=0.18", +# ] +# /// +""" +Fyto Project - Schematic Diagram Generator + +Generates wiring schematics for the Fyto plant monitoring project using schemdraw. +This creates a clean schematic showing all connections between: +- Raspberry Pi Zero 2W +- ADS1115 ADC +- 2-inch LCD Display +- LM35 Temperature Sensor +- Capacitive Moisture Sensor +- LDR Light Sensor + +Usage: + cd docs + uv run generate_schematic.py + + # Or from project root: + uv run docs/generate_schematic.py +""" + +from pathlib import Path + +import schemdraw +import schemdraw.elements as elm +from schemdraw.elements import intcircuits as ic + +# Get the directory where this script is located +SCRIPT_DIR = Path(__file__).parent.resolve() +OUTPUT_DIR = SCRIPT_DIR / "diagrams" + + +def create_fyto_schematic(): + """Generate the main Fyto wiring schematic.""" + + schemdraw.theme('monokai') + with schemdraw.Drawing() as d: + d.config(unit=2, fontsize=10) + + # Title + d += elm.Label().at((0, 12)).label('Fyto - Plant Monitor Schematic', fontsize=14, halign='left') + d += elm.Label().at((0, 11.2)).label('Raspberry Pi Zero 2W + Sensors', fontsize=10, halign='left', color='gray') + + # ============================================ + # Raspberry Pi Zero 2W (as custom IC) + # ============================================ + pi_pins = [ + ic.IcPin(name='3V3', pin='1', side='left'), + ic.IcPin(name='SDA', pin='3', side='left'), + ic.IcPin(name='SCL', pin='5', side='left'), + ic.IcPin(name='GND', pin='9', side='left'), + ic.IcPin(name='GPIO10', pin='19', side='left'), + ic.IcPin(name='MOSI', pin='21', side='left'), + ic.IcPin(name='SCLK', pin='23', side='left'), + ic.IcPin(name='CE0', pin='24', side='right'), + ic.IcPin(name='RST', pin='36', side='right'), + ic.IcPin(name='DC', pin='37', side='right'), + ic.IcPin(name='5V', pin='2', side='right'), + ] + + d += (pi := ic.Ic(pins=pi_pins, size=(4, 6), + label='Raspberry Pi\nZero 2W').at((0, 5))) + + # ============================================ + # ADS1115 ADC (as custom IC) + # ============================================ + ads_pins = [ + ic.IcPin(name='VDD', pin='VDD', side='left'), + ic.IcPin(name='GND', pin='GND', side='left'), + ic.IcPin(name='SCL', pin='SCL', side='left'), + ic.IcPin(name='SDA', pin='SDA', side='left'), + ic.IcPin(name='A0', pin='A0', side='right'), + ic.IcPin(name='A1', pin='A1', side='right'), + ic.IcPin(name='A2', pin='A2', side='right'), + ic.IcPin(name='A3', pin='A3', side='right'), + ] + + d += (ads := ic.Ic(pins=ads_pins, size=(3, 4), + label='ADS1115\n16-bit ADC').at((10, 6))) + + # ============================================ + # LCD Display (as custom IC) + # ============================================ + lcd_pins = [ + ic.IcPin(name='VCC', pin='VCC', side='left'), + ic.IcPin(name='GND', pin='GND', side='left'), + ic.IcPin(name='DIN', pin='DIN', side='left'), + ic.IcPin(name='CLK', pin='CLK', side='left'), + ic.IcPin(name='CS', pin='CS', side='right'), + ic.IcPin(name='DC', pin='DC', side='right'), + ic.IcPin(name='RST', pin='RST', side='right'), + ic.IcPin(name='BL', pin='BL', side='right'), + ] + + d += (lcd := ic.Ic(pins=lcd_pins, size=(3, 4), + label='2" IPS LCD\n240x320').at((10, 0))) + + # ============================================ + # Sensors (simplified representations) + # ============================================ + + # LM35 Temperature Sensor + lm35_pins = [ + ic.IcPin(name='VCC', pin='+', side='left'), + ic.IcPin(name='OUT', pin='OUT', side='right'), + ic.IcPin(name='GND', pin='-', side='left'), + ] + d += (lm35 := ic.Ic(pins=lm35_pins, size=(2, 1.5), + label='LM35\nTemp').at((18, 7))) + + # Moisture Sensor + moist_pins = [ + ic.IcPin(name='VCC', pin='+', side='left'), + ic.IcPin(name='OUT', pin='OUT', side='right'), + ic.IcPin(name='GND', pin='-', side='left'), + ] + d += (moist := ic.Ic(pins=moist_pins, size=(2, 1.5), + label='Moisture\nSensor').at((18, 5))) + + # LDR Light Sensor + ldr_pins = [ + ic.IcPin(name='VCC', pin='+', side='left'), + ic.IcPin(name='OUT', pin='OUT', side='right'), + ic.IcPin(name='GND', pin='-', side='left'), + ] + d += (ldr := ic.Ic(pins=ldr_pins, size=(2, 1.5), + label='LDR\nLight').at((18, 3))) + + # ============================================ + # Power Rails + # ============================================ + + # 3.3V Rail (red) + d += elm.Line().at((-3, 9)).right().length(24).color('red').linewidth(2) + d += elm.Label().at((-3, 9.3)).label('3.3V', fontsize=9, color='red') + + # GND Rail (black) + d += elm.Line().at((-3, -2)).right().length(24).color('black').linewidth(2) + d += elm.Label().at((-3, -1.7)).label('GND', fontsize=9, color='black') + + # ============================================ + # I2C Connections (Pi to ADS1115) + # ============================================ + + # SDA connection (blue) + d += elm.Wire('c', k=0.5).at(pi.SDA).to(ads.SDA).color('blue') + + # SCL connection (orange) + d += elm.Wire('c', k=0.5).at(pi.SCL).to(ads.SCL).color('orange') + + # ============================================ + # SPI Connections (Pi to LCD) + # ============================================ + + # MOSI to DIN (green) + d += elm.Wire('c', k=-0.3).at(pi.MOSI).to(lcd.DIN).color('green') + + # SCLK to CLK (purple) + d += elm.Wire('c', k=-0.4).at(pi.SCLK).to(lcd.CLK).color('purple') + + # CE0 to CS (brown) + d += elm.Wire('c', k=0.3).at(pi.CE0).to(lcd.CS).color('brown') + + # DC connection + d += elm.Wire('c', k=0.4).at(pi.DC).to(lcd.DC).color('gray') + + # RST connection + d += elm.Wire('c', k=0.5).at(pi.RST).to(lcd.RST).color('pink') + + # BL (Backlight) connection + d += elm.Wire('c', k=-0.2).at(pi.GPIO10).to(lcd.BL).color('cyan') + + # ============================================ + # Sensor to ADS1115 Connections + # ============================================ + + # LM35 OUT to A1 + d += elm.Wire('c', k=0.3).at(lm35.OUT).to(ads.A1).color('red') + + # Moisture OUT to A2 + d += elm.Wire('c', k=0.3).at(moist.OUT).to(ads.A2).color('brown') + + # LDR OUT to A3 + d += elm.Wire('c', k=0.3).at(ldr.OUT).to(ads.A3).color('yellow') + + # ============================================ + # Power Connections + # ============================================ + + # Pi 3V3 to power rail + d += elm.Line().at(pi.inL1).up().toy(9).color('red') + + # Pi GND to ground rail + d += elm.Line().at(pi.GND).down().toy(-2).color('black') + + # ADS1115 VDD to power rail + d += elm.Line().at(ads.VDD).up().toy(9).color('red') + + # ADS1115 GND to ground rail + d += elm.Line().at(ads.GND).down().toy(-2).color('black') + + # LCD VCC to power rail + d += elm.Line().at(lcd.VCC).up().toy(9).color('red') + + # LCD GND to ground rail + d += elm.Line().at(lcd.GND).down().toy(-2).color('black') + + # Sensor power connections + d += elm.Line().at(lm35.VCC).up().toy(9).color('red') + d += elm.Line().at(lm35.GND).down().toy(-2).color('black') + + d += elm.Line().at(moist.VCC).up().toy(9).color('red') + d += elm.Line().at(moist.GND).down().toy(-2).color('black') + + d += elm.Line().at(ldr.VCC).up().toy(9).color('red') + d += elm.Line().at(ldr.GND).down().toy(-2).color('black') + + # ============================================ + # Legend + # ============================================ + legend_x = -3 + legend_y = -4 + + d += elm.Label().at((legend_x, legend_y)).label('Wire Color Legend:', fontsize=10, halign='left') + d += elm.Line().at((legend_x, legend_y - 0.5)).right().length(0.5).color('red').linewidth(2) + d += elm.Label().at((legend_x + 0.7, legend_y - 0.5)).label('3.3V Power', fontsize=8, halign='left') + + d += elm.Line().at((legend_x, legend_y - 1)).right().length(0.5).color('black').linewidth(2) + d += elm.Label().at((legend_x + 0.7, legend_y - 1)).label('Ground', fontsize=8, halign='left') + + d += elm.Line().at((legend_x, legend_y - 1.5)).right().length(0.5).color('blue').linewidth(2) + d += elm.Label().at((legend_x + 0.7, legend_y - 1.5)).label('I2C SDA', fontsize=8, halign='left') + + d += elm.Line().at((legend_x, legend_y - 2)).right().length(0.5).color('orange').linewidth(2) + d += elm.Label().at((legend_x + 0.7, legend_y - 2)).label('I2C SCL', fontsize=8, halign='left') + + d += elm.Line().at((legend_x + 5, legend_y - 0.5)).right().length(0.5).color('green').linewidth(2) + d += elm.Label().at((legend_x + 5.7, legend_y - 0.5)).label('SPI MOSI', fontsize=8, halign='left') + + d += elm.Line().at((legend_x + 5, legend_y - 1)).right().length(0.5).color('purple').linewidth(2) + d += elm.Label().at((legend_x + 5.7, legend_y - 1)).label('SPI SCLK', fontsize=8, halign='left') + + d += elm.Line().at((legend_x + 5, legend_y - 1.5)).right().length(0.5).color('brown').linewidth(2) + d += elm.Label().at((legend_x + 5.7, legend_y - 1.5)).label('SPI CS / Moisture', fontsize=8, halign='left') + + d += elm.Line().at((legend_x + 5, legend_y - 2)).right().length(0.5).color('yellow').linewidth(2) + d += elm.Label().at((legend_x + 5.7, legend_y - 2)).label('LDR Signal', fontsize=8, halign='left') + + # Save the schematic (SVG only - use browser/Inkscape to convert to PNG) + svg_path = OUTPUT_DIR / 'fyto_schematic.svg' + d.save(str(svg_path)) + print(f"Schematic saved to {svg_path}") + + +def create_connection_table(): + """Generate a simple connection reference diagram.""" + + with schemdraw.Drawing() as d: + d.config(unit=1.5, fontsize=9) + + # Title + d += elm.Label().at((0, 16)).label('Fyto - Pin Connection Reference', fontsize=14, halign='left') + + # Pi Zero header representation + d += elm.Label().at((0, 14)).label('Raspberry Pi Zero 2W GPIO Header', fontsize=11, halign='left') + + # Create a simplified 40-pin header visualization + header_x = 1 + header_y = 12 + + # Draw pin header outline + d += elm.Line().at((header_x - 0.3, header_y + 0.3)).right().length(5) + d += elm.Line().at((header_x - 0.3, header_y + 0.3)).down().length(10.6) + d += elm.Line().at((header_x - 0.3, header_y - 10.3)).right().length(5) + d += elm.Line().at((header_x + 4.7, header_y + 0.3)).down().length(10.6) + + # Pin definitions (physical pin number: function) + left_pins = { + 1: ('3V3', 'red'), + 3: ('SDA', 'blue'), + 5: ('SCL', 'orange'), + 9: ('GND', 'black'), + 19: ('BL', 'cyan'), + 21: ('MOSI', 'green'), + 23: ('SCLK', 'purple'), + } + + right_pins = { + 2: ('5V', 'red'), + 24: ('CE0', 'brown'), + 36: ('RST', 'pink'), + 37: ('DC', 'gray'), + } + + # Draw left side pins (odd numbers) + for pin_num in range(1, 40, 2): + y_pos = header_y - ((pin_num - 1) / 2) * 0.5 + d += elm.Dot(radius=0.08).at((header_x, y_pos)) + d += elm.Label().at((header_x - 0.2, y_pos)).label(str(pin_num), fontsize=7, halign='right') + + if pin_num in left_pins: + name, color = left_pins[pin_num] + d += elm.Line().at((header_x, y_pos)).left().length(1).color(color).linewidth(2) + d += elm.Label().at((header_x - 1.2, y_pos)).label(name, fontsize=8, halign='right', color=color) + + # Draw right side pins (even numbers) + for pin_num in range(2, 41, 2): + y_pos = header_y - ((pin_num - 2) / 2) * 0.5 + d += elm.Dot(radius=0.08).at((header_x + 0.5, y_pos)) + d += elm.Label().at((header_x + 0.7, y_pos)).label(str(pin_num), fontsize=7, halign='left') + + if pin_num in right_pins: + name, color = right_pins[pin_num] + d += elm.Line().at((header_x + 0.5, y_pos)).right().length(1).color(color).linewidth(2) + d += elm.Label().at((header_x + 1.7, y_pos)).label(name, fontsize=8, halign='left', color=color) + + # Connection tables + table_x = 8 + + # LCD Connections + d += elm.Label().at((table_x, 14)).label('LCD Display Connections', fontsize=11, halign='left') + lcd_connections = [ + ('VCC', '->', 'Pin 1 (3V3)'), + ('GND', '->', 'Pin 9 (GND)'), + ('DIN', '->', 'Pin 21 (MOSI)'), + ('CLK', '->', 'Pin 23 (SCLK)'), + ('CS', '->', 'Pin 24 (CE0)'), + ('DC', '->', 'Pin 37 (GPIO26)'), + ('RST', '->', 'Pin 36 (GPIO16)'), + ('BL', '->', 'Pin 19 (GPIO10)'), + ] + for i, (src, arrow, dst) in enumerate(lcd_connections): + d += elm.Label().at((table_x, 13 - i * 0.5)).label(f'{src} {arrow} {dst}', fontsize=8, halign='left') + + # ADS1115 Connections + d += elm.Label().at((table_x, 8)).label('ADS1115 ADC Connections', fontsize=11, halign='left') + ads_connections = [ + ('VDD', '->', 'Pin 1 (3V3)'), + ('GND', '->', 'Pin 9 (GND)'), + ('SCL', '->', 'Pin 5 (SCL)'), + ('SDA', '->', 'Pin 3 (SDA)'), + ('A1', '->', 'LM35 OUT'), + ('A2', '->', 'Moisture OUT'), + ('A3', '->', 'LDR OUT'), + ] + for i, (src, arrow, dst) in enumerate(ads_connections): + d += elm.Label().at((table_x, 7 - i * 0.5)).label(f'{src} {arrow} {dst}', fontsize=8, halign='left') + + # Sensor Connections + d += elm.Label().at((table_x, 3)).label('Sensor Connections', fontsize=11, halign='left') + sensor_info = [ + 'All sensors: VCC -> 3V3, GND -> GND', + 'LM35 Temp: OUT -> ADS1115 A1', + 'Moisture: OUT -> ADS1115 A2', + 'LDR Light: OUT -> ADS1115 A3', + ] + for i, info in enumerate(sensor_info): + d += elm.Label().at((table_x, 2.3 - i * 0.5)).label(info, fontsize=8, halign='left') + + svg_path = OUTPUT_DIR / 'fyto_pinout.svg' + d.save(str(svg_path)) + print(f"Pinout reference saved to {svg_path}") + + +if __name__ == '__main__': + # Ensure output directory exists + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + + print("Generating Fyto schematics...") + print(f"Output directory: {OUTPUT_DIR}") + print() + + create_fyto_schematic() + create_connection_table() + + print() + print("Done! Generated files:") + for f in OUTPUT_DIR.iterdir(): + print(f" - {f.name}") diff --git a/docs/generated_animated_emotions.py b/docs/generated_animated_emotions.py new file mode 100644 index 0000000..1c034b4 --- /dev/null +++ b/docs/generated_animated_emotions.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "pillow>=12.0.0", +# ] +# /// +import os +from PIL import Image + +def natural_sort_key(s: str): + import re + return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)] + +def load_pngs(input_dir: str): + files = [f for f in os.listdir(input_dir) if f.lower().endswith(".png")] + files.sort(key=natural_sort_key) + if not files: + raise FileNotFoundError("No PNG files found in the input directory.") + paths = [os.path.join(input_dir, f) for f in files] + images = [Image.open(p).convert("RGBA") for p in paths] + return images + +def make_gif(input_dir: str, output_path: str, fps: float = 12.0, loop: int = 0, optimize: bool = True, scale: float = 1.0): + frames = load_pngs(input_dir) + # Optional scaling + if scale != 1.0: + scaled = [] + for im in frames: + w, h = im.size + new_size = (max(1, int(w * scale)), max(1, int(h * scale))) + scaled.append(im.resize(new_size, resample=Image.Resampling.LANCZOS)) + frames = scaled + + # Duration per frame in milliseconds + duration_ms = int(round(1000.0 / fps)) + + # GIF requires palette; Pillow will convert while saving + first, rest = frames[0], frames[1:] + first.save( + output_path, + save_all=True, + append_images=rest, + duration=duration_ms, + loop=loop, + optimize=optimize, + disposal=2 # restore to background (helps with transparency artifacts) + ) + print(f"Saved GIF to {output_path} with {len(frames)} frames at {fps} FPS.") + +if __name__ == "__main__": + # Iterate over folders in "emotions" path and create GIFs + for emotion in os.listdir("../Code/emotion"): + emotion_dir = os.path.join("../Code/emotion", emotion) + if os.path.isdir(emotion_dir): + output_gif_path = f"./assets/{emotion}.gif" + make_gif(input_dir=emotion_dir, output_path=output_gif_path, fps=12, loop=0, optimize=True, scale=0.5) diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..2aff92f --- /dev/null +++ b/docs/index.html @@ -0,0 +1,730 @@ + + + + + + + Fyto - Turn Your Plant Into a Pet + + + + +
+
🌱
+

Fyto

+

Transform your houseplant into an interactive pet with emotions that respond to environmental conditions

+
+ + 📦 View on GitHub + + + 🔌 See Wiring Diagrams + + + 📖 Full Tutorial + +
+
+ +
+ +
+

See Fyto in Action

+

Watch how Fyto brings your plant to life

+
+ +
+
+ + +
+

Six Expressive Emotions

+

Fyto displays different emotions based on real-time sensor data
+ 💡 Hover over each emotion to see the animated display!

+ +
+
+
+ Happy emotion animation +
+
Happy
+
Optimal conditions - perfect environment!
+
+
+
+ Sleepy emotion animation +
+
Sleepy
+
Low light detected (< 20%)
+
+
+
+ Hot emotion animation +
+
Hot
+
Temperature above 30°C
+
+
+
+ Freeze emotion animation +
+
Freeze
+
Temperature below 22°C
+
+
+
+ Savory emotion animation +
+
Savory
+
Recently watered - moisture rising
+
+
+
+ Thirsty emotion animation +
+
Thirsty
+
Soil moisture < 10% - needs water!
+
+
+
+ + +
+

Wiring Diagrams

+

Complete visual guides for assembling your Fyto

+ +
+ + + + +
+ + +
+
+ +
+
+ + +
+
+ + Fyto Wiring Diagram + +
+
+ + +
+
+ + Fyto Circuit Schematic + +
+
+ + +
+
+ + Fyto Pinout Reference + +
+
+
+ + +
+
+
+ ⚠️ Important Setup Notes +
+
    +
  • Use LM35, NOT DS18B20: The code requires an analog temperature sensor. DS18B20 is digital and won't work without modifications.
  • +
  • Logic Level Converter Recommended: Use a 5V to 3.3V bi-directional converter to protect your Pi's GPIO pins.
  • +
  • Enable I2C: Run sudo raspi-config → Interface Options → I2C → Enable. Also disable Serial.
  • +
  • Channel Assignment: The original tutorial has different ADC channel assignments. Our wiring matches the actual code: A1=Temperature, A2=Moisture, A3=Light.
  • +
  • Calibrate Sensors: Use calibration.py to test each sensor individually before final assembly.
  • +
+
+
+ + +
+

Hardware Requirements

+

Everything you need to build Fyto

+ +
+

Core Components

+
    +
  • Raspberry Pi Zero 2W - Main controller (1GHz quad-core)
  • +
  • 2" IPS LCD Display (240×320) - For emotion animations
  • +
  • ADS1115 16-bit ADC - Analog-to-digital converter
  • +
  • LM35 Temperature Sensor - Analog temp sensor (TO-92 package)
  • +
  • Capacitive Soil Moisture Sensor - Corrosion-resistant
  • +
  • LDR Light Sensor Module - Ambient light detection
  • +
  • 5V 2A Power Adapter - Power supply
  • +
  • Micro USB Power Module - Breadboard power distribution
  • +
  • 30AWG Silicone Wires (5m) - Flexible wiring
  • +
  • Logic Level Converter (5V ↔ 3.3V) - GPIO protection (highly recommended)
  • +
+
+
+ + +
+

Key Features

+ +
+
+
🎨
+

Animated Emotions

+

180 frames per emotion create smooth, engaging animations on the vibrant IPS LCD display

+
+
+
📊
+

Real-Time Monitoring

+

Continuous sensor readings for temperature, moisture, and light levels

+
+
+
🔌
+

I2C & SPI

+

Uses both I2C (sensors) and SPI (display) for efficient communication

+
+
+
🐍
+

Python Powered

+

Easy-to-modify Python code using Adafruit libraries

+
+
+
🌡️
+

Multi-Sensor

+

Temperature, moisture, and light sensors work together to assess plant health

+
+
+
🖨️
+

3D Printable Case

+

Custom-designed planter case with STL files included

+
+
+
+ + +
+

Quick Start

+ +
+
# Clone the repository
+git clone https://github.com/CodersCafeTech/Fyto.git
+cd Fyto
+
+# Install dependencies
+sudo apt-get update
+sudo apt-get install python3-pip python3-pil python3-numpy
+pip3 install adafruit-circuitpython-ads1x15 spidev
+
+# Enable I2C
+sudo raspi-config
+# Navigate to: Interface Options → I2C → Enable
+
+# Calibrate sensors
+cd Code
+python3 calibration.py
+
+# Run Fyto (two terminals)
+# Terminal 1:
+python3 main.py
+
+# Terminal 2:
+python3 sensors.py
+
+
+ + +
+

Resources & Links

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + diff --git a/docs/stl/Flower_BASE v1.stl b/docs/stl/Flower_BASE v1.stl new file mode 100644 index 0000000..1fc4646 Binary files /dev/null and b/docs/stl/Flower_BASE v1.stl differ diff --git a/docs/stl/Flower_MAIN v1.stl b/docs/stl/Flower_MAIN v1.stl new file mode 100644 index 0000000..b8dd7ad Binary files /dev/null and b/docs/stl/Flower_MAIN v1.stl differ diff --git a/docs/stl/Flower_Vase v1.stl b/docs/stl/Flower_Vase v1.stl new file mode 100644 index 0000000..76e676f Binary files /dev/null and b/docs/stl/Flower_Vase v1.stl differ diff --git a/docs/stl/fyto-stl-files.zip b/docs/stl/fyto-stl-files.zip new file mode 100644 index 0000000..85d5f53 Binary files /dev/null and b/docs/stl/fyto-stl-files.zip differ diff --git a/docs/wiring-diagram.html b/docs/wiring-diagram.html new file mode 100644 index 0000000..365f021 --- /dev/null +++ b/docs/wiring-diagram.html @@ -0,0 +1,1046 @@ + + + + + + Fyto - Wiring Diagram + + + + + +
+

🌱 Fyto Wiring Diagram

+

Turn Your Plant Into a Pet - Complete Wiring Guide

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + 3.3V POWER RAIL + + + GROUND RAIL + + + + + Raspberry Pi + Zero 2W + + + + + + + + + 3V3 + 1 + + + + SDA + 3 + + + + SCL + 5 + + + + GND + 9 + + + + BL + 19 + + + + MOSI + 21 + + + + SCLK + 23 + + + + + 5V + 2 + + + + CE0 + 24 + + + + RST + 36 + + + + DC + 37 + + + + + + + ADS1115 + 16-bit ADC + + + + + + + VDD + + + GND + + + SCL + + + SDA + + + + A0 + (open) + + + A1 + + + A2 + + + A3 + + + A1=Temp | A2=Moisture | A3=Light + + + + + + 2" IPS LCD + 240×320 Display + + + + 😊 + + + + + VCC + + + GND + + + DIN + + + CLK + + + CS + + + DC + + + RST + + + BL + + + + + + + + 🌡️ LM35 + Temperature Sensor + + + + + + + VCC + + + OUT + + + GND + + + + + + + 💧 Capacitive + Moisture Sensor + + + + + + + + VCC + + + OUT + + + GND + + + + + + + ☀️ LDR Module + Light Sensor + + + + + + + + VCC + + + OUT + + + GND + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ← A1 (Temp) + ← A2 (Moisture) + ← A3 (Light) + + + +
+ + +
+
+

📺 LCD Display → Raspberry Pi

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LCD PinWirePi PinGPIO
VCCRedPin 13.3V
GNDBlackPin 9Ground
DINGreenPin 21GPIO 9 (MOSI)
CLKPurplePin 23GPIO 11 (SCLK)
CSBrownPin 24GPIO 8 (CE0)
DCGrayPin 37GPIO 26
RSTPinkPin 36GPIO 16
BLCyanPin 19GPIO 10
+
+ +
+

📊 ADS1115 ADC → Raspberry Pi

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ADS PinWirePi PinGPIO
VDDRedPin 13.3V
GNDBlackPin 9Ground
SCLOrangePin 5GPIO 3 (SCL)
SDABluePin 3GPIO 2 (SDA)
+
+ +
+

🌡️💧☀️ Sensors → ADS1115

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SensorSensor PinConnects To
LM35 (Temp)VCC3.3V Rail
OUTADS1115 A1
GNDGround Rail
MoistureVCC3.3V Rail
OUTADS1115 A2
GNDGround Rail
LDR (Light)VCC3.3V Rail
OUTADS1115 A3
GNDGround Rail
+
+
+ + +
+

🎨 Wire Color Reference

+
+
+
+ Red - 3.3V Power +
+
+
+ Black - Ground +
+
+
+ Blue - I2C SDA +
+
+
+ Orange - I2C SCL +
+
+
+ Green - SPI MOSI +
+
+
+ Purple - SPI SCLK +
+
+
+ Brown - SPI CS (CE0) +
+
+
+ Gray - LCD DC +
+
+
+ Pink - LCD Reset +
+
+
+ Cyan - LCD Backlight +
+
+
+ Yellow - LDR Signal +
+
+
+ + +
+

⚡ Important Wiring Notes

+ +
+ + +
+ + + +