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 @@ + + 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 @@ + \ 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 @@ + \ 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 @@ + + +
+ + + +Transform your houseplant into an interactive pet with emotions that respond to environmental conditions
+ +Watch how Fyto brings your plant to life
+Fyto displays different emotions based on real-time sensor data
+ 💡 Hover over each emotion to see the animated display!
Complete visual guides for assembling your Fyto
+ +sudo raspi-config → Interface Options → I2C → Enable. Also disable Serial.calibration.py to test each sensor individually before final assembly.Everything you need to build Fyto
+ +180 frames per emotion create smooth, engaging animations on the vibrant IPS LCD display
+Continuous sensor readings for temperature, moisture, and light levels
+Uses both I2C (sensors) and SPI (display) for efficient communication
+Easy-to-modify Python code using Adafruit libraries
+Temperature, moisture, and light sensors work together to assess plant health
+Custom-designed planter case with STL files included
+# 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+
Complete source code, 3D files, and emotion animations
+Original step-by-step build guide with photos
+Official Facebook Group
+Full-page wiring diagram with connection tables
+Courtesy of theoldelement.
+Turn Your Plant Into a Pet - Complete Wiring Guide
+ + +| LCD Pin | +Wire | +Pi Pin | +GPIO | +
|---|---|---|---|
| VCC | +Red | +Pin 1 | +3.3V | +
| GND | +Black | +Pin 9 | +Ground | +
| DIN | +Green | +Pin 21 | +GPIO 9 (MOSI) | +
| CLK | +Purple | +Pin 23 | +GPIO 11 (SCLK) | +
| CS | +Brown | +Pin 24 | +GPIO 8 (CE0) | +
| DC | +Gray | +Pin 37 | +GPIO 26 | +
| RST | +Pink | +Pin 36 | +GPIO 16 | +
| BL | +Cyan | +Pin 19 | +GPIO 10 | +
| ADS Pin | +Wire | +Pi Pin | +GPIO | +
|---|---|---|---|
| VDD | +Red | +Pin 1 | +3.3V | +
| GND | +Black | +Pin 9 | +Ground | +
| SCL | +Orange | +Pin 5 | +GPIO 3 (SCL) | +
| SDA | +Blue | +Pin 3 | +GPIO 2 (SDA) | +
| Sensor | +Sensor Pin | +Connects To | +
|---|---|---|
| LM35 (Temp) | +VCC | +3.3V Rail | +
| OUT | +ADS1115 A1 | +|
| GND | +Ground Rail | +|
| Moisture | +VCC | +3.3V Rail | +
| OUT | +ADS1115 A2 | +|
| GND | +Ground Rail | +|
| LDR (Light) | +VCC | +3.3V Rail | +
| OUT | +ADS1115 A3 | +|
| GND | +Ground Rail | +
sudo raspi-config → Interface Options → I2C → Enable. Also disable Serial.calibration.py to verify each sensor works before final assembly.