Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Infineon Team
Published © MIT

Smart Plant Pot with PSOC6, MicroPython & Home Assistant

Sensor-driven plant care with LED emotions, powered by MicroPython and integrated with Home Assistant.

IntermediateFull instructions provided6 hours1,595
Smart Plant Pot with PSOC6, MicroPython & Home Assistant

Things used in this project

Hardware components

CY8CPROTO-062-4343W
Infineon CY8CPROTO-062-4343W
×1
Adafruit STEMMA Soil Sensor - I2C Capacitive Moisture Sensor
×1
Photo resistor
Photo resistor
×2
LED Panel WS2812B 16x16 256 LEDs Flexibel
×1
Adafruit SHT30
×1
Infineon PAS CO2 5V Miniboard
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Infineon EZ-PD™ Barrel Connector Replacement (BCR) evaluation kit CY4533
×1

Software apps and online services

MicroPython
MicroPython
MQTT
MQTT
Home Assistant
Home Assistant

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

lower_part.stl

Lower part of the plant pot.

Sketchfab still processing.

upper_part.stl

Upper part of the plant pot.

Sketchfab still processing.

Schematics

Schematic

Code

plant.py

MicroPython
Module for tracking the plant status as described in the article - Upload to your MicroPython board.
import machine
import time

import sht30
import pasco2
import stemma_soil_sensor
import seesaw

import face

PIN_SCL = 'P6_0'
PIN_SDA = 'P6_1'
PIN_LUX1 = 'P10_0'
PIN_LUX2 = 'P10_3'

def fuzzy_operator(value, minValue, maxValue, relevance=2):
        '''
        Returns a value larger than 0 if the value is outside the range.
        The higher the value, the further away from the optimal range.
        '''
        if not value: return 0
        if value > maxValue: x = value - maxValue
        elif value < minValue: x = minValue - value
        else: return 0
        return relevance * x / (maxValue - minValue)

class Plant:
    condition = None
    temperature = None
    humidity = None
    moisture = None
    light = None
    co2 = None
    update_timer = 0
    def __init__(self, minTemp=16, maxTemp=23, minHum=45, maxHum=60, minMoisture=600, maxMoisture=1400, minLight=30000, maxLight=33000, minCO2=600, maxCO2=1600):
        self.minTemp = minTemp
        self.maxTemp = maxTemp
        self.minHum = minHum
        self.maxHum = maxHum
        self.minMoisture = minMoisture
        self.maxMoisture = maxMoisture
        self.minLight = minLight
        self.maxLight = maxLight
        self.minCO2 = minCO2
        self.maxCO2 = maxCO2

    def __str__(self):
        return f"Temperature: {self.temperature}, Humidity: {self.humidity}, Moisture: {self.moisture}, Light: {self.light}, CO2: {self.co2}, Condition: {self.condition}"
    
    def check_condition(self):
        '''
        Check if the plant is in good condition.
        Will set the condition to a score between 3 (best) and 0 (worst).
        '''
        condition = 3
        condition -= fuzzy_operator(self.temperature, self.minTemp, self.maxTemp)
        condition -= fuzzy_operator(self.humidity, self.minHum, self.maxHum)
        condition -= fuzzy_operator(self.moisture, self.minMoisture, self.maxMoisture)
        condition -= fuzzy_operator(self.light, self.minLight, self.maxLight)
        condition -= fuzzy_operator(self.co2, self.minCO2, self.maxCO2)
        self.condition = int(max(0, round(condition,0)))

    def init_sensors(self):
        # I2C interface for PAS CO2, SHT30, DPS368
        i2c = machine.I2C(scl='P6_0', sda='P6_1', freq=400000)
        # I2C sensors
        self.sensor_sht = sht30.SHT30(i2c, i2c_address=sht30.ALTERNATE_I2C_ADDRESS)
        self.sensor_co2 = pasco2.PASCO2(i2c, measInterval=60)
        self.sensor_co2.initialize()
        self.sensor_soil = stemma_soil_sensor.StemmaSoilSensor(i2c)
        self.sensor_lux1 = machine.ADC(PIN_LUX1)
        self.sensor_lux2 = machine.ADC(PIN_LUX2)
    
    def read_sensors(self):
        self.temperature, self.humidity = self.sensor_sht.measure()
        self.moisture = self.sensor_soil.get_moisture()
        self.light = (self.sensor_lux1.read_u16() + self.sensor_lux2.read_u16()) / 2
        if time.time() - self.update_timer > 60:
            co2ppm = self.sensor_co2.get_co2_value()
            if co2ppm > 0:
                self.co2 = co2ppm # Take CO2 value only if ready.
                self.update_timer = time.time()
    
    def update_face(self):
        if self.condition == 3:
            face.show_face(face.get_happy_pattern())
        elif self.condition == 2:
            face.show_face(face.get_neutral_pattern())
        elif self.condition == 1:
            face.show_face(face.get_sad_pattern())
        else:
            face.show_face(face.get_dead_pattern())
        
    def loop(self):
        self.read_sensors()
        self.check_condition()
        self.update_face()

face.py

MicroPython
Module for showing "faces" on the 16x16 WS2812B LED matrix - Upload to your MicroPython board.
from machine import Pin, bitstream
from time import sleep

# Define the timing for the bitstream based on the LED's datasheet
timing = [500, 1125, 800, 750]
PIN_LEDS = Pin('P9_6', Pin.OUT, value=0)

num_leds = 256  # 16x16 matrix has 256 LEDs
led_data = bytearray(num_leds * 3)  # Each LED requires 3 bytes for RGB

def create_color(red, green, blue, brightness=0.2):
    red = int(red * brightness)
    green = int(green * brightness)
    blue = int(blue * brightness)
    return bytearray([green, red, blue])

def clear_leds():
    global led_data
    for i in range(num_leds * 3):
        led_data[i] = 0

def set_led(x, y, color):
    if 0 <= x < 16 and 0 <= y < 16:
        if x % 2 == 0:
            index = (x * 16) + y  # Normal order for even columns
        else:
            index = (x * 16) + (15 - y)  # Reverse order for odd columns
        led_data[index * 3: (index + 1) * 3] = color

def get_dead_pattern():
    '''
    Define the eyes, mouth, and details of the sad face
    '''
    eyes = [(4, 4), (3, 5), (5, 5), (5, 3),
            (11, 4), (12, 3), (12, 5),
            (3, 3), (10, 3), (10, 5)]  # Coordinates for the eyes

    mouth = [(6, 10), (7, 10), (8, 10), (11, 11), (10, 10), (5, 10),
                    (4, 11), (9, 10)]

    # Define colors
    color = create_color(255, 0, 0)
    
    return eyes, mouth, color

def get_sad_pattern():
    '''
    Define the eyes, mouth, and details of the sad face
    '''
    eyes = [(4, 4), (3, 5), (5, 4), (4, 3), (3, 4), (4, 5), (5, 5), (5, 3),
            (11, 5), (11, 4), (11, 3), (12, 4), (12, 3), (12, 5), (10, 4),
            (3, 3), (10, 3), (10, 5)]  # Coordinates for the eyes

    mouth = [(6, 10), (7, 10), (8, 10), (11, 11), (10, 10), (5, 10),
                 (4, 11), (7, 9), (8, 9), (9, 9), (6, 9), (9, 10)]

    # Define colors
    color = create_color(255, 0, 0)
    
    return eyes, mouth, color

def get_neutral_pattern():
    '''
    Define the eyes, mouth, and details of the neutral face
    '''
    eyes = [(4, 4), (3, 5), (5, 4), (4, 3), (3, 4), (4, 5), (5, 5), (5, 3),
            (11, 5), (11, 4), (11, 3), (12, 4), (12, 3), (12, 5), (10, 4),
            (3, 3), (10, 3), (10, 5)]  # Coordinates for the eyes
    
    mouth = [(6, 10), (7, 10), (8, 10), (11, 10), (10, 10), (5, 10),
                    (4, 10), (7, 9), (8, 9), (9, 9), (6, 9), (9, 10)]

    # Define colors
    color = create_color(255, 255, 0)
    
    return eyes, mouth, color

def get_happy_pattern():
    '''
    Define the eyes, mouth, and details of the smiley face
    '''
    eyes = [(4, 4), (3, 5), (5, 4), (4, 3), (3, 4), (4, 5), (5, 5), (5, 3), (11, 5), (11, 4), (11, 3), (12, 4), (12, 5), (10, 4), (10, 3), (10, 5)]  # Coordinates for the eyes
    mouth = [(6, 11), (7, 11), (8, 11), (9, 11), (10, 10), (5, 10), (11, 9), (4, 9), (7, 10), (8, 10), (9, 10), (6, 10)]  # A curved smile

    # Define colors
    color = create_color(255, 255, 255)
    
    return eyes, mouth, color

def show_face(pattern):
    # Clear the LED matrix
    clear_leds()
    
    eyes, mouth, color = pattern
    
    # Set eyes
    for (x, y) in eyes:
        set_led(x, y, color)
    
    # Set mouth
    for (x, y) in mouth:
        set_led(x, y, color)
    
    # Light the whole matrix
    bitstream(PIN_LEDS, 0, timing, led_data)

mqtt_secrets.py

MicroPython
Credentials for MQTT Broker - Modify according to your needs.
broker = ''
user = ''
password = ''

main.py

MicroPython
import time

import network
import wifi_secrets, mqtt_secrets

sta = network.WLAN(network.STA_IF)
sta.connect(wifi_secrets.ssid, wifi_secrets.psk)

# mip module ("mip installs packages")
import mip

# Adafruit SHT30
mip.install('github:ederjc/micropython-sht30/sht30.py')

# Infineon PAS CO2
mip.install("https://raw.githubusercontent.com/jaenrig-ifx/micropython-lib/mpy-lib/pasco2-sensor-module/micropython/drivers/sensor/pasco2/pasco2.py")

# Adafruit Seesaw Soil Sensor
mip.install('github:mihai-dinculescu/micropython-adafruit-drivers/seesaw/stemma_soil_sensor.py')
mip.install('github:mihai-dinculescu/micropython-adafruit-drivers/seesaw/seesaw.py')

# umqtt
mip.install('umqtt.simple')
import umqtt.simple

# uhome
mip.install('github:ederjc/uhome/uhome/uhome.py')
import uhome

from plant import Plant

### Plant Setup ###
plant = Plant()
plant.init_sensors()

### Home Assistant Integration ###
device = uhome.Device('Smart Plant', mf='Infineon', mdl='PSOC 6')
mqttc = umqtt.simple.MQTTClient(device.id, mqtt_secrets.broker, user=mqtt_secrets.user, password=mqtt_secrets.password, keepalive=60)
device.connect(mqttc)

temperature = uhome.Sensor(device, 'Temperature', device_class="temperature", unit_of_measurement='°C')
humidity = uhome.Sensor(device, 'Air Humidity', device_class="humidity", unit_of_measurement='%')
co2 = uhome.Sensor(device, 'CO2', device_class="carbon_dioxide", unit_of_measurement='ppm')
brightness = uhome.Sensor(device, 'Brightness', device_class="illuminance", unit_of_measurement='lx')
moisture = uhome.Sensor(device, 'Soil Moisture', device_class="moisture", unit_of_measurement='%')
condition = uhome.Sensor(device, 'Condition', device_class="enum", icon="mdi:flower")

def update_ha_sensors():
    temperature.publish(plant.temperature)
    humidity.publish(plant.humidity)
    co2.publish(plant.co2)
    brightness.publish(plant.light)
    moisture.publish(plant.moisture/20)
    condition.publish(plant.condition)

device.discover_all()

while 1:
    plant.loop()
    print(plant)
    update_ha_sensors()
    time.sleep(5)

wifi_secrets.py

MicroPython
Credentials for WiFi network - Modify according to your needs.
ssid = ''
psk = ''

Credits

Infineon Team
106 projects • 171 followers
Contact
Thanks to bwduncan and rsc1975.

Comments

Please log in or sign up to comment.