Smart Weather and Environmental Alarm for Temperature and Outfit Recommendations (SWEATER)
Kod finns på:
https://github.com/frankuman/SWEATER-IoT/
Innehållsförteckning
- Författare
- Projektöversikt
- Funktioner
- Systemarkitektur
- Syfte
- Material
- Pico Material och Beskrivning
- Pi Material och Beskrivning
- Installation
- Datorinstallation
- Pi Programvaruinstallation
- Mosquitto (MQTT Broker) Installation
- Starta HUB
- Pico Programvara
- Pi Hårdvara
- Pico Hårdvara
- Komma igång
- Plattform
- Kärnfunktioner
- Datatransmission
- Datlagring
- Andra frågor
- Slutföra designen
- Bilder
- Videopresentation
- Licens
Författare
Namn: Oliver Bölin
Referenser: ob222qw
Projektöversikt
SWEATER-IoT är utformad för att ge smarta rekommendationer för dagliga kläder baserat på aktuella väderförhållanden och inomhustemperaturer. Systemet fungerar även som en väckarklocka, som visar aktuell tid, temperaturer och klädrekommendationer, och låter användare ställa in alarm och uppgifter via en Python Flask-instrumentpanel.
SWEATER använder två olika API:er för att förutsäga vilka kläder som ska bäras.
Funktioner
- Display
- Visar tid, väderdata och alarmtid.
- Sensorer
- Mäter inomhustemperaturer.
- openAI api
- Används för att förutsäga vilka kläder som ska bäras baserat på bilder, väderdata och inomhustemperatur.
- Du behöver ett openAI API-konto och finansiera det. Varje förutsägelse kostar 0,01$. Små summor som 5$ räcker därför i 500 dagar om en förutsägelse görs varje morgon.
- Registrera dig här OpenAI Signup
- weatherapi
- Hämtar väderdata utomhus.
- Du behöver ett weatherapi-konto. Detta är gratis för 1 miljon samtal per månad. SWEATER gör cirka 8000 per månad.
- Registrera dig här weatherAPI Signup
- Hub
- Använder trådning för att kontrollera MQTT-kommunikation, flask-servern och API-anrop.
- Skicka anpassade kommandon.
- Använder Bootstrap och Plotly för att visa snygga GUI och diagram.
- Ställ in alarm på distans.
Beräknad tid för att slutföra installationen: Ungefär 4 timmar
Syfte
Jag valde att göra något unikt, som ännu inte har gjorts (så vitt jag vet). Med en Raspberry Pi och en USB-kamera bestämde jag mig för att göra en smart väckarklocka som heter SWEATER. Problemet för många människor är att antingen klä sig för varmt eller för kallt för vädret. Att bara kolla temperaturen på telefonen är inte alltid tillräckligt, och när man tittar ut genom fönstret vet man inte vad vädret egentligen är. Lösningen med SWEATER är att ställa ett alarm för nästa dag, och när man vaknar hälsas man med inomhus- och utomhustemperaturen och vad man ska ha på sig för dagen.
Material
Pico Material och Beskrivning
Artikel | Bild | Pris & Länk | Specifikationer |
---|---|---|---|
Raspberry Pi Pico W | 71,2 SEK – Electrokit | Samlar in temperatur- och fuktighetsdata och visar information på skärmarna. | |
DHT11 Temperatur- och Fuktighetssensor | 39,2 SEK – Electrokit | Mäter temperatur och fuktighet. | |
MCP9700-E/TO TO-92 Temperatursensor | 9,6 SEK – Electrokit | Mäter temperatur. | |
Gröna, Röda och Gula Lysdioder (3 varje) | 74 SEK – Amazon | Lyser enligt temperatur. | |
I2C LCD 2004 Modul 20×4 Display | 121 SEK – Amazon | Visar inomhus- och utomhustemperatur, aktuell tid, datum och dag. | |
1,3″ OLED 128 x 64 pixlar I2C | 99 SEK – Amazon | Visar nästa alarmtid och vad man ska ha på sig när det utlöses. | |
Jumperkablar och Kopplingsdäck | 134 SEK – Amazon | Ansluter komponenter och tillhandahåller en plattform för att bygga kretsen. | |
Micro-USB-kabel | Tidigare inköpt | Ansluter Raspberry Pi Pico till Raspberry Pi. |
Pi Material och Beskrivning
Artikel | Bild | Pris & Länk | Specifikationer |
---|---|---|---|
Raspberry Pi 4 B | 583,2 SEK – Electrokit | Agerar som nav genom att vara värd för Flask-webbapplikationen. | |
SD-kort (för Raspberry Pi) | 103,2 SEK – Electrokit | Lagring för Raspberry Pi-operativsystemet och data. | |
Strömförsörjning för Raspberry Pi | 79,2 SEK – Electrokit | Ger ström till Raspberry Pi. | |
USB Webbkamera (Aukey PC-LM1E) | Pris varierar | Används för att ta bilder för förutsägelser. | |
1 TB Extern HDD | Ej nödvändig | Valfri lagring för ytterligare data. |
Installation
Följ dessa steg-för-steg-instruktioner för att framgångsrikt installera en SWEATER.
Datorinstallation
Vald IDE
- IDE: VS Code
Grundläggande installation
- Installera VS Code:
- Ladda ner och installera VS Code från den officiella webbplatsen.
- Installera Python >= 3.11:
- Se till att Python är installerat på ditt system. Installera det från den officiella webbplatsen om det behövs.
- Flasha Firmware:
- Flasha MicroPython-firmware på Raspberry Pi Pico genom att ladda ner firmware och dra det till Pico när den är ansluten via USB.
- Starta Pi:
- Starta Pi och följ den initiala installationen. Om du inte har ett förinstallerat SD-kort med ett OS på det, kan du ladda ner Raspberry Pi Imager.
Pi Programvaruinstallation
1. Uppdatera Paketlista
Först, uppdatera din paketlista för att säkerställa att du får den senaste versionen tillgänglig:
sudo apt update
Mosquitto (MQTT Broker) Installation
För att installera och ställa in Mosquitto MQTT broker på Raspberry Pi 4 B, följ dessa steg:
1. Installera Mosquitto
Installera Mosquitto broker och Mosquitto-klienter:
sudo apt install mosquitto mosquitto-clients
2. Följ guiden för att ställa in Mosquitto
Säkerställ att ställa in Mosquitto-lyssnaren på port 1883
Starta HUB
1. Ladda ner Hub till Pi
sudo git clone https://github.com/frankuman/SWEATER-IoT/hub
2. Skapa en virtuell miljö
Eftersom openAI python-modulen inte fungerar så enkelt som avsett, måste vi ställa in en virtuell miljö. Men oroa dig inte, det är lättare än förväntat.
1. Installera virtualenv
sudo pip install virtualenv
2. gå in i den nedladdade katalogen
cd hub
3. skapa miljön
python3 -m venv myenv
4. aktivera miljön
source myenv/bin/activate
3. Installera Nödvändiga Paket
pip install -r requirements.txt
eller
pip3 install -r requirements.txt
4. Ändra config.ini-filen
[MQTT]
broker = localhost
topic_pub = home/control
topic_sub = home/temperature
topic_time_req = home/time/request
topic_time_resp = home/time/response
[Paths]
temperature_data_file = Change to desired location
current_temperature_data = Change to desired location
image_directory = static/images
[API]
weather_url = http://api.weatherapi.com/v1/forecast.json
weather_key = Change to your API key (https://weatherapi.com)
location = Karlskrona (Change to your location)
[OpenAI]
api_key = Change to your openai API key (https://openai.com/api/)
5. Starta hub
Medan huben kanske inte kommunicerar för tillfället, kan den startas med följande kommando
python sweaterhub.py
Åtkomsträttsproblem
Om huben har åtkomsträttsproblem, kan du behöva ge den åtkomsträtt
sudo chmod -r 777 hub
sudo chmod -r 777 hub/static
sudo chmod -r 777 hub/static/images
sudo chmod -r 777 path/to/json_storage
Pico Programvara
1. Ladda ner SWEATER Pico-programvaran
git clone https://github.com/frankuman/SWEATER-IoT/sweater
2. Ändra config.py-filen
import ubinascii
import machine
SSID = 'ssid' #change this
PASSWORD = 'password' #change this
MQTT_BROKER = '192.168.0.101' #change this
MQTT_CLIENT_ID = ubinascii.hexlify(machine.unique_id())
MQTT_TOPIC = 'home/temperature'
MQTT_TOPIC_SUB = 'home/control'
MQTT_TOPIC_TIME_REQ = 'home/time/request'
MQTT_TOPIC_TIME_RESP = 'home/time/response'
Pi Hårdvara
1. Anslut USB-kameran till Pi
Pico Hårdvara
1. Anslut allt enligt kretsdiagrammet
Kretsdiagram
I2C LCD Display:
- VCC: Ansluten till VSYS.
- GND: Ansluten till jord.
- SDA: Ansluten till GP14.
- SCL: Ansluten till GP15.
OLED Display:
- VDD: Ansluten till strömskenan (3,3V).
- GND: Ansluten till jordskenan.
- SCK: Ansluten till GP21.
- SDA: Ansluten till GP20.
DHT11 Sensor:
- VCC: Ansluten till strömskenan (3,3V).
- GND: Ansluten till jordskenan.
- Data: Ansluten till GP26.
MCP9700 Temperatursensor:
- VCC: Ansluten till strömskenan (3,3V).
- GND: Ansluten till jordskenan.
- Vout: Ansluten till GP27.
Lysdioder:
- Röda lysdioder (Anod): Ansluten till GP6, GP7 och GP8.
- Gula lysdioder (Anod): Ansluten till GP3, GP4 och GP5.
- Gröna lysdioder (Anod): Ansluten till GP0, GP1 och GP2.
Elektriska Beräkningar
Effekt = Spänning x Ström
- OLED: 3,3V x 40mA = 132mW
- LCD: 5V x 120mA = 600mW
- Lysdioder: 3V, 20mA vardera för 9 lysdioder, totalt = 180mA x 3v = 540mW
- DHT11: 3V x 0,5mA = 1,5mW
- MCP9700A: 3V x 6µA = 0,018mW
- Pico: 3,3V x 45mA = 148,5mW
- Total effektförbrukning = 1422mW = 1,422W
Om vi använder ett 12V 2Ah batteri kan vi räkna ut hur länge det kommer att hålla
(12 * 2)/(1,422) = 16,8 timmar
Komma igång
Besök localhost på din raspberry pi när allt är igång.
http://192.168.0.X:5000/
Plattform
För detta projekt använder SweaterHub python Flask frontend-gränssnitt tillsammans med Plotly och Bootstrap.
Varför?
Bootstrap skapar ett snyggt GUI som är interaktivt och responsivt eftersom GUI:et måste vara användbart för telefoner.
För lagring används två JSON-filer, vilket skapar enkelhet och lätt installation för användarna. Jag valde att skapa min egen plattform eftersom jag redan behövde skapa ett gränssnitt för
larmet. Jag har tidigare erfarenhet av
flask-programmering så det var det bästa valet. Och eftersom det redan fanns ett behov av navet var det enkelt att integrera diagrammen med navet.
Instrumentpanel
Instrumentpanelen har olika funktioner som ses på bilden. Nedan finns två bilder, en som användes för den senaste förutsägelsen, och en som användes när sidan besöktes för kameratestsyften.
Det finns möjlighet att skicka anpassade kommandon. Följande kommandon är
Blinka LED-lamporna
flash
Gör samma som om ett alarm skulle ha ställts men omedelbart
alarm
Visar texten på LCD
text to display on LCD
Visar texten efter OLED: på OLED
OLED:text to display on OLED
Visar alla olika kläder som är möjliga för förutsägelse
OLED:showall
Historik
Historiksidan visar olika diagram med all insamlad data.
Kärnfunktioner
Mycket av koden är väldigt okommenterad och stressad och hårdkodad. Jag förväntar mig inte att den ska vara särskilt läsbar.
Om du vill förstå kärnfunktionerna presenteras lite kod och ett flödesschema nedan.
flowchart TD
subgraph PICO_Loop_Subgraph["Forever Loop"]
direction TB
Sensor_Data["Get sensor data"]
Set_Lights["Set lights"]
Display_Screens["Display on screens"]
Check_Messages["Check for any MQTT messages\nand send temperature to PI"]
Do_Stuff["Do stuff depending on message"]
PICO_Loop["Forever loop"]
end
subgraph PICO["PICO (Sweater)"]
direction TB
PICO_Start["main.py\nSTART"]
PICO_Util["get time, connect wifi,\nother util stuff"]
PICO_Loop_Subgraph
end
subgraph Alarm_Process["Alarm Process"]
direction TB
Check_Alarm["Check if alarm is set\non frontend"]
Get_Weather["Every 300 seconds\nget weather API data"]
Capture_Images["Capture images"]
Predict["Predict"]
Send_to_PICO["Send to PICO"]
end
subgraph PI["PI (SweaterHub)"]
direction TB
PI_Start["sweaterhub.py\nSTART"]
Start_Frontend["Start frontend"]
Start_MQTT["Start MQTT thread"]
Log_Temperatures["Log temperatures"]
Start_Alarm["Start alarm thread"]
Display_Data["Display_Data"]
Alarm_Process
end
PICO_Start --> PICO_Util
PICO_Util --> PICO_Loop
PICO_Loop --> Sensor_Data
Sensor_Data --> Set_Lights
Set_Lights --> Display_Screens
Display_Screens --> Check_Messages
Check_Messages --> Do_Stuff & Log_Temperatures
Do_Stuff --> PICO_Loop
PI_Start --> Start_Frontend & Start_MQTT & Start_Alarm
Start_Frontend --> Display_Data
Start_MQTT --> Log_Temperatures
Start_Alarm --> Get_Weather & Alarm_Process
Check_Alarm -- If alarm is set and current time == alarm time --> Capture_Images
Capture_Images --> Predict
Predict --> Send_to_PICO
Send_to_PICO --> Check_Messages
style PICO_Loop_Subgraph stroke:#757575
style Alarm_Process stroke:#424242
communication.py
Denna funktion är grunden för att ta emot meddelanden. I frontend finns möjlighet att mata in anpassade meddelanden för testning.
def control_callback(topic, msg):
topic_str = topic.decode()
message = msg.decode()
print(f"Received message on {topic_str}: {message}")
if message == 'flash':
flash_lights(1)
print("Received flash command!")
elif len(message) > 1 and message[0] == "2":
global outside_temp
outside_temp = message[2:]
print(outside_temp)
elif len(message) > 3 and message[0:2] == "at":
alarmtime = message[3:]
print("Displaying alarm")
alarmtime = str(alarmtime)
display_alarm(alarmtime)
elif len(message) > 4 and message[0:4] == "pred":
prediction = message[5:]
print("Displaying prediction")
display_prediction(prediction)
elif len(message) > 4 and message[0:4] == "OLED":
message = message[5:]
print("Displaying OLED")
display_on_oled(str(message))
else:
...
display.py
Dessa två funktioner är för att visa alarmtiden på OLED-displayen. Genom att använda bitmappsbokstäver skriver vi dem i
en stor och snygg font istället. De andra funktionerna för att visa förutsägelsen på OLED delar upp strängen i en lista så att
den kan visas på de enskilda raderna på OLED.
def draw_large_digit(digit, x, y):
for row_index, row in enumerate(digit):
for col_index in range(16):
if row & (1 << (15 - col_index)):
display.pixel(x + col_index, y + row_index, 1)
def display_alarm(alarmtime):
display.poweron()
display.fill(0)
alarmtime = str(alarmtime)
x_offset = 16
for char in alarmtime:
if char.isdigit():
draw_large_digit(digits[int(char)], x_offset, 20)
x_offset += 20
elif char == ':':
draw_large_digit(colon, x_offset, 20)
x_offset += 20
display.text(" Alarm Time", 0, 0)
display.show()
main.py
Detta är huvudloopen i main.py. För att få tid för klockan använder den NTP innan den går in i loopen. Sedan visas var 3:e sekund
vind (kph), fuktighet, prognos (C) och chans för regn för dagen. Varannan 3:e sekund visas
datum, veckodag, inomhus- och utomhustemperatur. Den visar alltid den aktuella timmen, minuten och sekunden.
def main_loop():
counter = 0
temp_str = "Temp: --.-C"
while True:
current_time = adjusted_time()
date_str = format_date(current_time)
day_str = format_day_of_week(current_time)
time_str = format_time(current_time)
if counter % 30 == 0:
tmpsensor1 = temp()
outside_temp_str = get_outside_temp()
outside_temp_str = f"Outside Temp: {outside_temp_str}C"
print("Sensor 1: ", tmpsensor1)
try:
temperature, humidity = measure_temp_humidity()
print("Sensor 2: tmp ", temperature, " humidity: ", humidity)
set_lights((tmpsensor1 + temperature) / 2)
message = f"{(tmpsensor1 + temperature) / 2}"
temp_str = "Inside Temp: {:.1f}C".format((tmpsensor1 + temperature) / 2)
except Exception as error:
print("Sensor 2: Exception occurred", error)
set
_lights(tmpsensor1)
message = f"{tmpsensor1}"
temp_str = "Inside Temp: {:.1f}C".format(tmpsensor1)
try:
mqtt_publish(client, MQTT_TOPIC, message)
except Exception as error:
print("/--/ Could not send via MQTT")
set_lights((tmpsensor1 + temperature) / 2)
print(date_str, day_str, time_str, temp_str)
date_str = f"{date_str}:{day_str}"
if counter % 6 == 0 eller counter % 6 == 1 eller counter % 6 == 2:
wind_speed, outside_humidity, forecast_avg_temp, chance_of_rain = get_weather_data()
toptext = f" w:{wind_speed} h:{outside_humidity}"
bottomtext = f"fcast:{forecast_avg_temp} rain%:{chance_of_rain}"
display_message(toptext, outside_temp_str, time_str, bottomtext)
else:
display_message(date_str, outside_temp_str, time_str, temp_str)
try:
client.check_msg()
except Exception as error:
print(error)
print("/--/ Could not check the messages via MQTT")
counter += 1
time.sleep(1)
time.sleep(1)
main_loop()
sweaterhub.py
Denna trådiga funktion kontrollerar den globala variabeln alarm_time. Om den är inställd via flask-gränssnittet och sedan utlöses, hämtar den väderdata och sedan
kallar på trigger-funktionen. Trigger-funktionen tar sedan 5 bilder för att få kameran använd till ljuset, och skickar sedan all data till
gpt-4o API.
def check_alarm_time():
global alarm_time
global last_prediction_time
counter = 0
print("Starting check_alarm_time thread")
while True:
current_time = datetime.now()
if alarm_time:
if current_time.strftime("%H:%M") == alarm_time:
weather_data = store_api_temp()
try:
alarm_trigger(weather_data)
except Exception as e: #use latest data if api call didnt work
with open(temperature_data_file, 'r') as file:
lines = file.readlines()
if lines:
weather_data = json.loads(lines[-1])
alarm_trigger(weather_data)
alarm_time = None
if counter % 300 == 0: # every 5 minutes right now, can be updates
weather_data = store_api_temp()
if weather_data:
current_temp = weather_data['current_temp']
send_api_temp(f"2:{current_temp}")
if alarm_time == None:
wind_speed = weather_data['wind_speed']
humidity = weather_data['humidity']
forecast_avg_temp = weather_data['forecast_avg_temp']
chance_of_rain = weather_data['chance_of_rain']
LCD_TEXT = f"wd:Wind:{wind_speed}|Humidity:{humidity}|forecast:{forecast_avg_temp}|rain%:{chance_of_rain}"
client.publish(MQTT_TOPIC_PUB, LCD_TEXT)
else: #if api call failed send latest temp with X indicating error
with open(temperature_data_file, 'r') as file:
lines = file.readlines()
if lines:
weather_data = json.loads(lines[-1])
current_temp = weather_data['current_temp']
send_api_temp(f"2:{current_temp}X")
counter += 1
time.sleep(1)
alarm_thread = threading.Thread(target=check_alarm_time)
alarm_thread.start()
app.alarm_thread_started = True
Datatransmission
För att skicka data från huben till Pico och från Pico till huben används MQTT-protokollet. Detta protokoll är lättviktigt och enkelt att implementera.
Inga särskilda säkerhetsfunktioner har införts i denna version, men jag kan anta att SSL enkelt kan implementeras i framtiden.
- Pico till Pi Pico skickar data till Pico var 30:e sekund
- Pi till Pico Pico skickar data till Pico var 300:e sekund eller när ett alarm utlöses
Varför?
Detta var det bästa alternativet eftersom Pi redan använder wifi. Det finns inget behov av långdistansanslutning (som LoRa) eftersom allt ändå ska vara nära.
Flask-servern är endast tillgänglig på det lokala nätverket, och Pi har kapaciteten att vara en mqtt-broker. Det är perfekt! 🙂
Datlagring
Eftersom minnet kan vara ett problem för framtida användare (32 GB kan vara taket för många användare), sparas endast två bilder åt gången. När en ny tas skrivs den över.
För att lagra data används endast två (2!) JSON-filer. JSON är enkelt att skapa, lättviktigt och tar inte mycket lagringsutrymme. Användaren kan också enkelt ta bort dem om de vill rensa dem
och programvaran skapar nya tomma. Data lagras för alltid. Men diagrammen visar endast 24 timmar data. Det finns ingen automation eller trigger beroende på data i SWEATER.
Andra frågor
SWEATER tar inte emot data från SweaterHUB.
Om SWEATER inte tar emot någon data från huben, håll huben igång och koppla ur SWEATER och koppla in den igen. Den bör ta emot data igen.
Slutföra designen
3D-printbart fodral
Det finns ett 3D-printbart fodral om någon användare skulle försöka skriva ut ett. Det har hål för skärmarna och ett hål för LED-lamporna. Hålet för LED-lamporna har också en
insättare för ett frostigt diffusor-akrylark. Detta fodral behöver dock lite arbete.
Det har 3 hål på sidan, om någon försöker implementera knappar
Det behöver något för att hålla skärmarna och ett hål för USB-kabeln.
Slutliga tankar
Detta projekt var verkligen roligt att lära sig IoT-programmering, MQTT-meddelanden och programmering för skärmar. Jag tror att SWEATER är lite unikt och ett coolt koncept.
Framtida arbete
För framtida arbete finns det lite arbete som skulle vara intressant att se.
- Implementera kameran på Pico istället
- Fixa det 3D-printbara fodralet
- Använd OLED mer, eftersom det inte visar något interaktivt för tillfället.
Bilder
Videopresentation
Kommer snart B)
Licens
Detta projekt är licensierat under MIT-licensen. Se LICENSE-filen för detaljer.