# Project export: HydroSense

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Did you know the average American household uses 30,000 gallons of water a year? 20% of that comes from showering. We created a smart IOT showerhead that can fix this issue.
- Devpost: https://devpost.com/software/hydrosense-xbnphl
- GitHub: https://github.com/shibcreate/HydroSense
- Result: winner (Sustainability Hacks)
- Team: 1 GitHub contributor(s) — Shinika Balasundar (6 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

# HydroSense Smart Showerhead

HydroSense is a revolutionary smart showerhead designed to address the significant water wastage associated with traditional showering. With an innovative blend of cutting-edge technology and user-friendly features, HydroSense aims to transform your showering experience while contributing to water conservation efforts.

## Elevator Pitch

Did you know that the average American uses enough water to fill over eight Olympic-sized swimming pools every year while showering? HydroSense is here to change that. Our super-smart showerhead leverages advanced technology to optimize water usage without compromising on the showering experience. Say goodbye to unnecessary water wastage and hello to a greener, more sustainable lifestyle.

## Team

- Shinika Balasundar
- Jordan Nguyen
- Brian Chiang
- Novel Alam

## Features

- **Smart Water Usage**: HydroSense intelligently monitors and adjusts water flow based on real-time conditions, ensuring you get the perfect shower while minimizing water consumption.

- **IoT Integration**: Connect HydroSense to your smart home ecosystem. Control and monitor your shower remotely using your preferred IoT platform.

- **Weather-Informed Showers**: Thanks to integration with Weather-API, HydroSense adapts to weather conditions, optimizing water usage accordingly.

- **User-Friendly Interface**: Our intuitive Streamlit-based interface allows users to easily customize shower preferences and track water usage patterns.

- **Energy-Efficient Heating**: HydroSense works seamlessly with your water heater to monitor energy-efficient heating, contributing to both water and energy conservation.

## Technologies Used

- Microcontroller
- IoT (Internet of Things)
- Streamlit
- XAMPP
- MySQL
- Python
- C
- Arduino IDE
- GPT-API
- Weather-API
- PHP
- Apache

## Installation

1. Clone the HydroSense repository.
   ```bash
   git clone https://github.com/hydrosense/smart-showerhead.git


## Detected evidence (automated analysis)

Indexed codebase: 7 recognized source files, 20 KB.
- PHP (language) — detected in the code
- Python (language) — detected in the code
- C (language) — claimed on Devpost, not found in the code
- Streamlit (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (11 of 11)

```
cache/cache_db_0.9.db
Homepage.py
pages/AskAI.py
pages/Drought.py
pages/Finance_Data.py
pages/Individual_Data.py
pandasai.log
README.md
requirements.txt
Smart_Shower_Head_Draft.ino
test_data.php
```

### Dependencies

- requirements.txt: mysql-connector-python@=8.3.0

### Recent commits (newest first)

- Add files via upload
- Update Smart_Shower_Head_Draft.ino
- Update Homepage.py
- Add files via upload
- Update README.md
- Update README.md
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
mysql-connector-python=8.3.0
```

### test_data.php

```php
<?php

$hostname = "localhost";
$username = "root";
$password = "";
$database = "hydrosense";

$conn = mysqli_connect($hostname, $username, $password, $database);

if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}

echo "Database connection is OK ";

// Check if any of the required parameters are present
if (isset($_REQUEST["Time"]) && isset($_REQUEST["Liters"]) && isset($_REQUEST["PersonType"]) && isset($_REQUEST["Temperature"])) {

    $T = $_REQUEST["Time"];
    $L = $_REQUEST["Liters"];
    $P = $_REQUEST["PersonType"];
    $t = $_REQUEST["Temperature"];

    $sql = "INSERT INTO data (Time, Liters, PersonType, Temperature) VALUES ('$T', '$L', '$P', '$t')";

    if (mysqli_query($conn, $sql)) {
        echo "New record created successfully";
    } else {
        echo "Error: " . $sql . "<br>" . mysqli_error($conn);
    }
} else {
    echo "One or more parameters are missing.";
}

?>

```

### Homepage.py

```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd 
import mysql.connector
import random
import json
import requests
import streamlit as st
from streamlit_lottie import st_lottie

@st.cache_resource
def init_connection():
    return mysql.connector.connect(**st.secrets["mysql"])

conn = init_connection()

@st.cache_data(ttl=600)
def run_query(query):
    with conn.cursor() as cur:
        cur.execute(query)
        return cur.fetchall()
    
def load_lottieurl(url: str):
    r = requests.get(url)
    if r.status_code != 200:
        return None
    return r.json()

person_type_names = {1: "Novel", 2: "Brian", 3: "Shinika", 4: "Jordan"}

person_types_query = "SELECT DISTINCT PersonType FROM data;"
person_types = [type[0] for type in run_query(person_types_query)]

st.title("HydroSense Data Analytics")
lottie_hello = load_lottieurl("https://lottie.host/543507b2-f845-4573-b93f-cef085bdf2bf/paxE6qfziA.json")

st_lottie(lottie_hello, loop=True, width=700, height=300)

query_all = "SELECT Liters, Time, Temperature, PersonType FROM data;"
data_all = run_query(query_all)
df_all = pd.DataFrame(data_all, columns=['Liters', 'Time', 'Temperature', 'PersonType'])

fig_liters_all = px.scatter(df_all, x='Time', y='Liters', color='PersonType', trendline="ols", title='Liters vs Time for All Individuals in Household', labels={'Liters': 'Liters (L)', 'Time': 'Time'})

fig_liters_all.add_shape(
    go.layout.Shape(
        type="line",
        x0=df_all['Time'].min(),
        x1=df_all['Time'].max(),
        y0=75,
        y1=75,
        line=dict(color="red", width=2),
    )
)

fig_liters_all.update_traces(marker=dict(color=[f'#{random.randint(0, 0xFFFFFF):06x}' for _ in range(len(df_all))]), showlegend=False)
st.plotly_chart(fig_liters_all)

fig_temperature_all = px.scatter(df_all, x='Temperature', y='Liters', color='PersonType', trendline="ols", title='Temperature vs Liters for All Individuals in Household', labels={'Temperature': 'Temperature (°C)', 'Liters': 'Liters (L)'})

# Add a red line at 75 liters
fig_temperature_all.add_shape(
    go.layout.Shape(
        type="line",
        x0=df_all['Temperature'].min(),
        x1=df_all['Temperature'].max(),
        y0=75,
        y1=75,
        line=dict(color="red", width=2),
    )
)

fig_temperature_all.update_traces(marker=dict(color=[f'#{random.randint(0, 0xFFFFFF):06x}' for _ in range(len(df_all))]), showlegend=False)
st.plotly_chart(fig_temperature_all)

st.header("Individual Milestones")

st.subheader("Usage Analytics:")
shortest_bath_person = df_all.loc[df_all['Time'].idxmin()]
coldest_bath_person = df_all.loc[df_all['Temperature'].idxmin()]
least_liters_person = df_all.loc[df_all['Liters'].idxmin()]

shortest_bath_person_name = person_type_names.get(shortest_bath_person['PersonType'], f"Person {shortest_bath_person['PersonType']}")
coldest_bath_person_name = person_type_names.get(coldest_bath_person['PersonType'], f"Person {coldest_bath_person['PersonType']}")
least_liters_person_name = person_type_names.get(least_liters_person['PersonType'], f"Person {least_liters_person['PersonType']}")

st.write(f"Shortest shower individual:")
st.write(f"- Person: {shortest_bath_person_name}")
st.write(f"- Time: {shortest_bath_person['Time']} minutes")

st.write(f"Least heat shower individual:")
st.write(f"- Person: {coldest_bath_person_name}")
st.write(f"- Temperature: {coldest_bath_person['Temperature']} °C")

st.write(f"Water-saving shower individual:")
st.write(f"- Person: {least_liters_person_name}")
st.write(f"- Liters: {least_liters_person['Liters']} Liters")

# Average Values section
st.header("Average Values")

# Calculate and display average total time, liters, and temperature
st.subheader("Average Total Time: (in minutes)")
st.write(df_all['Time'].mean())

st.subheader("Average Total Temperature: (in celcius)")
st.write(df_all['Temperature'].mean())

st.subheader("Average Total Liters:")
st.write(df_all['Liters'].mean())

lottie_hello1 = load_lottieurl("https://lottie.host/6a36fd81-4f6a-4d2e-b31f-86ca3f542a83/gabbKRET4U.json")

st_lottie(lottie_hello1, loop=True, width=700, height=300)

```

### pages/AskAI.py

```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd 
import mysql.connector
import random
import json
import requests
import streamlit as st
from streamlit_lottie import st_lottie
from pandasai import SmartDataframe
from pandasai.llm import OpenAI
import os

@st.cache_resource
def init_connection():
    return mysql.connector.connect(**st.secrets["mysql"])

# Connect to the database
conn = init_connection()
os.environ["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"] = "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"

@st.cache_data(ttl=600)
def run_query(query):
    with conn.cursor() as cur:
        cur.execute(query)
        return cur.fetchall()
    
st.title("AI Data Analytics")
    
# Query to fetch data for all people
query_all = "SELECT Liters, Time, Temperature, PersonType FROM data;"
data_all = run_query(query_all)
df_all = pd.DataFrame(data_all, columns=['Liters', 'Time', 'Temperature', 'PersonType'])

with st.expander("Dataframe Preview"):
    st.write(df_all)


ask = st.text_area("Chat with the AI")
st.write(ask)

if ask:
    llm = OpenAI(api_token=os.environ["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"])
    query_engine = SmartDataframe(df_all, config={"llm": llm})
    answer = query_engine.chat(ask)
    st.write(answer)
```

### pages/Individual_Data.py

```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd 
import mysql.connector
import random
import json
import requests
import streamlit as st
from streamlit_lottie import st_lottie
st.markdown("# Individual Data Statistics")

# Lottie animation
st_lottie_url = "https://lottie.host/64f9e01d-7fcb-4e84-9c4b-7ccda90ef287/qDWRcquCX1.json"
st_lottie(st_lottie_url, width=700, height=300, speed=1, key="individual_stats_lottie")

import plotly.express as px
import pandas as pd 
import mysql.connector
import random

# Function to initialize connection to the database
@st.cache_resource
def init_connection():
    return mysql.connector.connect(**st.secrets["mysql"])

# Connect to the database
conn = init_connection()

# Function to run query and fetch data
@st.cache_data(ttl=600)
def run_query(query):
    with conn.cursor() as cur:
        cur.execute(query)
        return cur.fetchall()

# Mapping numeric values to names
person_type_mapping = {1: 'Novel', 2: 'Brian', 3: 'Shinika', 4: 'Jordan'}

person_types_query = "SELECT DISTINCT PersonType FROM data;"
person_types = [person_type_mapping[type[0]] for type in run_query(person_types_query)]

# Dropdown menu for selecting person type
selected_person = st.selectbox("Select Person Type:", person_types)

selected_person_numeric = next(key for key, value in person_type_mapping.items() if value == selected_person)

query = f"SELECT Liters, Time, Temperature, PersonType FROM data WHERE PersonType = {selected_person_numeric};"
data = run_query(query)
df = pd.DataFrame(data, columns=['Liters', 'Time', 'Temperature', 'PersonType'])

fig_liters = px.scatter(df, x='Time', y='Liters', title=f'Liters vs Time for {selected_person}', labels={'Liters': 'Liters (L)', 'Time': 'Time'})
st.plotly_chart(fig_liters)

fig_temperature = px.scatter(df, x='Temperature', y='Liters', title=f'Temperature vs Liters for {selected_person}', labels={'Temperature': 'Temperature (°C)', 'Liters': 'Liters (L)'})
st.plotly_chart(fig_temperature)

st.header("Average Values")

average_dropdown = st.selectbox("Select Average Value:", ["Average Time", "Average Temperature", "Average Liters"])

# Calculate and display average values based on the selected dropdown
if average_dropdown == "Average Time":
    st.subheader("Average Time:")
    st.write(df['Time'].mean())

elif average_dropdown == "Average Temperature":
    st.subheader("Average Temperature:")
    st.write(df['Temperature'].mean())

elif average_dropdown == "Average Liters":
    st.subheader("Average Liters:")
    st.write(df['Liters'].mean())

```

### pages/Finance_Data.py

```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd 
import mysql.connector
import random
import json
import requests
import streamlit as st
from streamlit_lottie import st_lottie

@st.cache_resource
def init_connection():
    return mysql.connector.connect(**st.secrets["mysql"])

conn = init_connection()

@st.cache_data(ttl=600)
def run_query(query):
    with conn.cursor() as cur:
        cur.execute(query)
        return cur.fetchall()
    
def load_lottieurl(url: str):
    r = requests.get(url)
    if r.status_code != 200:
        return None
    return r.json()
    
st.title("Finance and Energy Data Analytics")
lottie_hello = load_lottieurl("https://lottie.host/95f4da18-1a11-4e32-9218-c3760a5f1ba1/EWkjGnYuKp.json")

st_lottie(lottie_hello, loop=True, width=700, height=300)

person_type_names = {1: "Novel", 2: "Brian", 3: "Shinika", 4: "Jordan"}

# Get unique person types from the database
person_types_query = "SELECT DISTINCT PersonType FROM data;"
person_types = [type[0] for type in run_query(person_types_query)]

cost_per_liter = st.number_input("Enter Cost Per Liter (in dollars):", min_value=0.0, value=0.0, step=0.01)

cost_per_liter_dict = {}

person_type_count = {}

# Loop through each person type
for person_type in person_types:
    query_selected = f"SELECT Liters, Time, Temperature, PersonType FROM data WHERE PersonType = '{person_type}';"
    data_selected = run_query(query_selected)
    df_selected = pd.DataFrame(data_selected, columns=['Liters', 'Time', 'Temperature', 'PersonType'])

    df_selected['Cost'] = cost_per_liter * df_selected['Liters']

    person_name = person_type_names.get(person_type, f"Person {person_type}")
    st.subheader(f"Cost per Liter for {person_name}:")
    st.write(df_selected[['PersonType', 'Cost']])

    cost_per_liter_dict[person_type] = df_selected['Cost'].iloc[0]

    person_type_count[person_type] = len(df_selected)

# Display total cost for all people
total_cost_dollars = sum(cost_per_liter_dict.values())
st.subheader("Total Cost for All People:")
st.write(f"${total_cost_dollars:.2f}")

st.subheader("Breakdown of Costs for Each Person:")
for person_type, cost in cost_per_liter_dict.items():
    person_name = person_type_names.get(person_type, f"Person {person_type}")
    st.write(f"{person_name}: ${cost:.2f} (Count: {person_type_count[person_type]})")

st.subheader("Total Showers:")
for person_type, total_showers in person_type_count.items():
    person_name = person_type_names.get(person_type, f"Person {person_type}")
    st.write(f"{person_name}: Showers Total: {total_showers}")

st.header("Energy Usage")

# Query data for energy usage
energy_query = "SELECT PersonType, SUM((4.2 * Liters * 20) / 3600) as TotalEnergy FROM data GROUP BY PersonType;"
energy_data = run_query(energy_query)
df_energy = pd.DataFrame(energy_data, columns=['PersonType', 'TotalEnergy'])

# Create a bar chart using Plotly Express with different colors for each person type
color_sequence = px.colors.qualitative.Set1  # You can choose a different color sequence
fig_energy = px.bar(df_energy, x='PersonType', y='TotalEnergy', color='PersonType', color_discrete_sequence=color_sequence, labels={'TotalEnergy': 'Total Energy Usage'})
fig_energy.update_layout(title='Total Energy Usage by Person Type', xaxis_title='Person Type', yaxis_title='Total Energy (KWH)')

# Display the bar chart in the Streamlit app
st.plotly_chart(fig_energy)

```

### pages/Drought.py

```python
import json
import streamlit as st
import mysql.connector
from urllib import parse, request

st.markdown("<h1 style='text-align: center; color: white;'>Drought Estimation and Usage</h1>", unsafe_allow_html=True)

# Function to initialize database connection
def init_connection():
    secrets = st.secrets["mysql"]
    return mysql.connector.connect(
        host=secrets["host"],
        port=secrets["port"],
        user=secrets["user"],
        password=secrets["password"],
        database=secrets["database"]
    )

# Function to make API request for weather forecast
def fetch_weather_forecast(city_state):
    url = f'https://api.aerisapi.com/forecasts/{parse.quote(city_state)}?format=json&filter=day&limit=7&fields=periods.dateTimeISO,loc,periods.maxTempF,periods.pop,periods.precipIN,periods.maxHumidity,periods.maxDewpointF,periods.weather&client_id=uTlj2O8JRDeX8LTrI6DC4&client_secret=0YxyOTlJCS96SuJdV03yWOjQS1safDOVWoWngW2V'
    
    try:
        req = request.urlopen(url)
        response = req.read()
        weather_data = json.loads(response)

        if weather_data['success']:
            return weather_data
        else:
            st.error(f"An error occurred: {weather_data['error']['description']}")
    except Exception as e:
        st.error(f"An error occurred: {str(e)}")
    finally:
        req.close()

# Function to estimate drought conditions
def estimate_drought(day_data):
    precipitation_threshold = 0.1 
    temperature_threshold = 90 
    humidity_threshold = 30  

    # Extract relevant information
    precipitation = day_data.get('precipIN', 0)
    temperature = day_data.get('maxTempF', 0)
    humidity = day_data.get('maxHumidity', 0)

    # Basic drought estimation criteria
    is_drought_day = precipitation < precipitation_threshold or temperature > temperature_threshold or humidity < humidity_threshold

    return is_drought_day

# Function to fetch most recent shower data from MySQL database based on PersonType
def fetch_mysql_data(person_type):
    conn = init_connection()

    query = f"SELECT Time, Liters, Temperature FROM data WHERE PersonType = {person_type} ORDER BY Time ASC LIMIT 1;"
    cursor = conn.cursor(dictionary=True)

    try:
        cursor.execute(query)
        data = cursor.fetchone()
        return data
    except Exception as e:
        st.error(f"An error occurred while fetching data from MySQL: {str(e)}")
    finally:
        cursor.close()
        conn.close()

def main():
    city_state = st.text_input("Enter City and State (e.g., san jose,ca):", "san jose,ca")
    
    person_type_names = {1: "Novel", 2: "Brian", 3: "Shinika", 4: "Jordan"}
    
    person_types = list(person_type_names.values())
    selected_person_type_name = st.selectbox("Select Person Type:", person_types)

    # Reverse mapping to get the corresponding number for the selected name
    selected_person_type = {v: k for k, v in person_type_names.items()}[selected_person_type_name]

    # Fetch weather forecast from API
    weather_data = fetch_weather_forecast(city_state)

    if weather_data and weather_data['success']:
        try:
            # Extract relevant information
            location = weather_data['response'][0]['loc']['name']
        except KeyError:
            location = "N/A"
        
        forecasts = weather_data['response'][0]['periods']

        # Display information for the first set only
        st.header(f"Weather Forecast for {location}")
        first_period = forecasts[0] if forecasts else {}
        st.write(f"Date: {first_period.get('dateTimeISO', 'N/A')}")
        st.write(f"Max Temperature: {first_period.get('maxTempF', 'N/A')} °F")
        st.write(f"Probability of Precipitation: {first_period.get('pop', 'N/A')}%")
        st.write(f"Precipitation: {first_period.get('precipIN', 'N/A')} inches")
        st.write(f"Max Humidity: {first_period.get('maxHumidity', 'N/A')}%")
        st.write(f"Max Dewpoint: {first_period.get('maxDewpointF', 'N/A')} °F")
        st.write(f"Weather: {first_period.get('weather', 'N/A')}")

        # Estimate drought conditions
        is_drought_day = estimate_drought(first_period)

        if is_drought_day:
            st.warning("Drought conditions are estimated for this day.")
            water_recommendation = "Use water conservatively. Consider reducing water usage today."
        else:
            st.info("No significant drought conditions are estimated this day.")
            water_recommendation = "Use water according to normal consumption guidelines."

        st.write("Water Consumption Recommendation:")
        st.write(water_recommendation)

        st.write("-" * 30)

        # Fetch most recent shower data from MySQL database based on selected PersonType
        mysql_data = fetch_mysql_data(selected_person_type)

        if mysql_data:
            st.header("Most Recent Shower:")
            st.write(f"Time: {mysql_data['Time']}")
            st.write(f"Liters: {mysql_data['Liters']} Liters")
            st.write(f"Person Type: {selected_person_type_name}")
            st.write(f"Temperature: {mysql_data['Temperature']} °C")

            # Check if Liters crossed the 10L threshold when drought is present
            if is_drought_day and mysql_data['Liters'] > 10:
                st.error("Your recent shower crossed the 10L threshold during drought conditions.")
        else:
            st.warning("No data available from the MySQL database.")
    else:
        st.warning("No weather data available.")

if __name__ == "__main__":
    main()

```