Chaos IoT
Liiketunnistimella toimiva kamera.
1 Johdanto
Tarkoituksena on tehdä IoT -laite, jonka avulla voidaan valvoa etänä tilaa. Laitteistoina käytetään Raspberry Pi 3 (model B) -tietokonetta, liiketunnistinta sekä kameraa. Raspberry Pi:n käyttöjärjestelmänä Raspbian Stretch, ohjelmointikielinä Python, PHP, HTML, CSS ja JavaScript.
2 Termit
Raspi = Raspberry Pi 3
PIR Sensori = Liiketunnistin
Skripti = Algoritmi
3 Vaatimukset
3.1 Tarvittavat Osat
Raspberry Pi 3, virtalähde, muistikortti (microSD), kortinlukija, PIR-sensori, Raspberry Pi kameramoduuli, kytkentäjohto, hiiri, näppäimistö, näyttö.
3.2 Tietotaidot
Tietokoneen perusymmärrys ja perustaidot.
4 Sovelluksen Toteutus
4.1 Yleinen Arkkitehtuuri
4.1.1 Käyttöjärjestelmän Asennus
Käyttöjärjestelmä (Raspbian Stretch with desktop) ladataan Raspberryn virallisilta sivuilta: https://www.raspberrypi.org/downloads/raspbian/ Kansiosta löytyvä näköistiedosto kirjoitetaan sd -kortille Etcher -ohjelmistolla, joka ladataan ja asennetaan https://etcher.io/ sivulta. Muistikortti asennetaan kortinlukijaan/koneeseen, avataan Etcher -ohjelmisto, painetaan “Select image” ja valitaan äsken ladattu käyttöjärjestelmäkansio. Tämän jälkeen klikataan “Select drive” ja valitaan muistikortti. Lopuksi “Flash!”. Kun Etcher on lopettanut kirjoittamisen, muistikortti asennetaan Raspberryyn ja seurataan alkuasennusohjeita.
4.1.2 Kieli-, näppäimistö- ja kamera-asetukset
Kun käyttöjärjestelmä on asennettu, säädetään asetuksia: Käynnistysvalikko -> Asetukset -> Raspberry Pi -> Configuration -> Localisation -> Set locate -> Kieliksi Suomi ja Keyboard->Suomi Interfaces->Camera: enable ja GPIO: enable
4.1.3 Videokameran suoratoistoserverin asennus
Suoratoistoa varten tietokoneelle asennetaan UV4L kamera-ajuri, sekä suoratoistoserveri ohjelmisto. Yksityiskohtaiset asennusohjeet löytyvät osoitteesta: http://www.linux-projects.org/uv4l/installation/ Asennus suoritetaan Raspbian Wretch käyttöjärjestelmän terminaalissa, käyttäen alla listattuja komentoja.
curl http://www.linux-projects.org/listing/uv4l_repo/lpkey.asc | sudo apt-key add -
Tämän jälkeen /etc/apt/sources.list tiedostoon lisätään seuraava rivi:
deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/stretch
stretch main
Tiedostoa /etc/apt/sources.list päästään muokkaamaan komennolla
sudo nano /etc/apt/sources.list
Tiedoston muokkauksen jälkeen suoritetaan järjestelmän päivityskomento
sudo apt-get update
Päivitys komennon jälkeen asennetaan UV4L ajuri ja ohjelmisto käyttäen komentoa
sudo apt-get install uv4l uv4l-raspicam
Ajurin ja ohjelmiston lisäksi asennetaan valinnainen lisäosa, joka mahdollistaa palvelun käynnistämisen käyttöjärjestelmän käynnistymisen yhteydessä. Lisäosa asennetaan komennolla
sudo apt-get install uv4l-raspicam-extras
UV4L ajuri ja ohjelmisto on nyt asennettu ja valmis käytettäväksi. Ohjelmiston graafiseen käyttöliittymään päästään syöttämällä verkkoselaimen osoitekenttään osoite http://localhost:8080/
Suoratoisto on nähtävissä ainoastaan sisäverkosta. Mikäli suoratoistoa haluttaisiin päästä katsomaan myös sisäverkon ulkopuolelta, tulisi reitittimestä avata portti 8080.
4.1.4 PIR-sensorin asennus
PIR-sensori kytketään Raspberry Pi:n GPIO pinneihin. Sensorin VCC kytketään Rasperry Pi:n pinniin numero 2, joka antaa sensorille 5V käyttöjännitteen. PIR-sensorin GND eli maa kytketään Raspberry Pi:n pinniin numero 6, joka on niin ikään GND eli maa. PIR-sensorin OUT kytketään Rasperry Pi:n datapinniin GPIO18 eli pinniin numero 12.
Liite 9.9 Raspberry Pi pin layout
Liite: 9.10 Raspberry Pi ja PIR-sensori
4.1.5 Kameran Asennus
Raspberry Pi kameramoduuli asennetaan Raspberry Pi:n CSI liittimeen, joka sijaitsee ethernet-liittimen ja HDMI-liittimen välissä. Kameran kaapeli asetetaan liittimeen siten, että kaapelin sininen puoli jää ethernet-liittimen puolelle.
Liite: 9.11 Raspberry Pi kameramoduuli
5 Käyttöliittymän Kuvaus
Hallintapaneeliin pääsee sähköpostiin tulevan liikkeestä ilmoittavan viestin “Hallitse ilmoituksia” -linkin kautta. Avautuvalla sivulla on kolme välilehteä:
Ilmoitukset -välilehdellä näkyvät raspin ottamat kuvat ja niiden ajankohdat.
Käyttäjät -välilehdellä käyttäjien tiedot. Mahdollisuus lisätä tunnuksia jotka saavat sähköpostin kun liikettä on havaittu ja tarvittaessa myös poistaa vanhoja tunnuksia.
Asetukset -välilehdellä Raspberryn hallintatyökalut.
App Key: Ohjelmiston käyttäjälle luoma yksilöllinen tunniste, jonka avulla palvelin kohdistaa vastaanottamansa tiedot tietylle käyttäjälle.
1.kuvake: Sammuttaa ilmoitusten lähetyksen
2.kuvake: Käynnistää raspin uudelleen
3.kuvake: Tilastot (mahdollisuus rajata päivämäärillä)
4.kuvake: Käynnistää etäterminaalin (tästä voi lähettää komentoja raspille jotka se toteuttaa/suorittaa kuten esimerkiksi: sudo reboot (käynnistää raspin uudelleen) tai sudo apt-get update (päivittää) jne..)
6 Funktioiden Kuvaukset
Kaikki koodit ja funktiot löytyvät meidän julkisesta GitHub profiililta:
https://github.com/OGkaaos/Chaos-IoT
Ensiksi pitää tarkistaa että palvelimella PHP versio on >5.4 ja tietokanta >5.5.51-38.1 ja jos on uudempi versio niin katso kohta 6.3 jossa näytetään miten koodi voidaan muokata toimivaksi jos on uudempi php/tietokanta.
kansiolle uploads/ pitää antaa 777 käyttöoikeudet jotta raspi pääsisi lataa kuvia sinne ja myös että FTP tunnuksella pitää olla root kansiona -> uploads/ kansio!
Liite 9.2 on kaavio joka näyttää mitä mikäkin algoritmi/koodi tekee. Ja koodien sisälle on lisätty kommentit jotka kertovat mitä mikäkin funktio tekee. Syy siihen et miksi laitettiin GitHub:iin on se että koodit ovat liiän pitkiä laittaakseen tähän.
Raspberry Pi:ihin tulisi asentaa seuraavat kirjastot (ei pakollisia):
1 Python Pillow (ei pakollinen):
https://pillow.readthedocs.io/en/latest/installation.html tämä pitää asentaa jos halua asentaa seuraavan kirjaston ”resizeimage” jolla pystyy muokkaamaan kuvan kokoa.
Asennusohjeet (Python Pillow):
Kirjoita terminaliin:
pip install pillow
2 Resizeimage (ei pakollinen):
https://pypi.python.org/pypi/python-resize-image tällä voidaan vaihtaa kuvan kokoa.
Asennusohjeet (Resizeimage):
Kirjoita terminaliin:
pip install python-resize-image
Jotta koodi toimisi. Jos niitä asenna niin raspin koodista (motion_detector.py) pitää poistaa seuraavat koodit:
from PIL import Image # Jotta voidaan vaihtaa kuvan kokoa
from resizeimage import resizeimage # Jotta voidaan vaihtaa kuvan kokoa
# tässä muutetaan kuvan kokoa jotta dashboard toimisi mahdollisimman nopeasti
fd_img = open('/home/pi/Desktop/havainnot/' + date + '.png', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_cover(img, [480, 360]) # Kuvan koko 480x360 img.save('/home/pi/Desktop/havainnot/' + date + '.png', img.format)
fd_img.close() # Suljetaan fd_img (resizeimage)
6.1 Algoritmien Järjestys
Seuraa 9.2 kaaviota aloittamalla ylhäältä ja siitä siirtymällä alaspäin. Aloita näistä:
- db.php
- Tähän tiedostoon tulisi lisätä oman MySQL tietokannan tiedot (host, username, password, table) ja tämä tiedosto lisätään jokaiseen php scriptiin.
- signup.php
- signin.php
- manage.php
6.2 Tietokanta
Tulisi luoda tietokanta (MySQL) jonka saa luotua webbihotelli tarjoajan sivulta (omasta dashboardista). ><(9.8) löytyy kuvia tietokannasta mutta taulukkoja: image_logs, livestream ei tarvitse luoda. Luo tietokantaan seuraavat taulukot:
- “commander” 9.8.1 ja siihen seuraavat 6 riviä:
- “command_id”, type: int(11), not null, extra: auto_increment
- “command_appkey”, type: varchar(255), not null
- “command_do”, type: varchar(255), null
- “command_response”, type: longtext, null
- “command_read”, type: varchar(255), null
- “command_ip” type: varchar(255), null
- “mailer” 9.8.2 ja siihen seuraavat 4 riviä:
- “mailer_id”, type: int(11), not null, extra: auto_increment
- “mailer_appkey”, type: varchar(255), not null
- “mailer_mail”, type: varchar(255), not null
- “mailer_created”, type: datetime, null tai not null
- “notifications” 9.8.3 ja siihen seuraavat 4 riviä:
- “notification_id”, type: int(11), not null, extra: auto_increment
- “notification_appkey”, type: varchar(255), not null
- “notification_img”, type: varchar(255), null
- “notification_time”, type: datetime, null tai not null
- “settings” 9.8.4 ja siihen seuraavat 12 riviä:
- “setting_id”, type: int(11), not null, extra: auto_increment
- “setting_appkey”, type: varchar(255), not null
- “setting_amount”, type: varchar(255), null
- “setting_time”, type: varchar(255), null
- “setting_stream”, type: varchar(255), null
- “setting_other”, type: varchar(255), null
- “setting_mode”, type: varchar(255), null
- “setting_status”, type: datetime, null
- “setting_cpu”, type: varchar(255), null
- “setting_ram”, type: varchar(255), null
- “setting_disk”, type: varchar(255), null
- “setting_ip”, type: varchar(255), null
- “users” 9.8.5 ja siihen seuraavat 6 riviä:
- “user_id”, type: int(11), not null
- “firstname”, type: varchar(255), not null
- “lastname”, type: varchar(255), not null
- “password”, type: varchar(60), not null
- “app_key”, type: varchar(10), not null
- “email”, type: varchar(60), not null
6.3 Ongelmat / Parannukset
Jotta ohjelmasta saataisiin turvallinen siihen pitäisi tehdä seuraavat muokkaukset:
- Salasanat pitäisi muuttaa hash:eiksi eli salatuiksi.
- MySQL pitäisi päivittää MySQLi jotta toimisi uusimpien PHP versioiden kanssa ja se onnistuu seuraavasti:
mysql_connect("TIETOKANTA OSOITE/IP", "KÄYTTÄJÄNIMI", "SALASANA") or die(mysql_error()); mysql_select_db("TAULUKKO") or die(mysql_error());
Korvaamalla tällä:$conn = mysqli_connect("TIETOKANTA OSOITE/IP", "KÄYTTÄJÄNIMI", "SALASANA") or die(mysqli_error());
mysqli_select_db("TAULUKKO") or die(mysqli_error());
Kaikistä php tiedostoista jossa on mysql yhteys/query pätkät seuraavasti:
mysql_query("SELECT * FROM users WHERE email='$email'");
Korvaamalla tällä:$mysql = "SELECT * FROM users WHERE email='$email'"; $mysql_1 = mysqli_query($conn, $mysql);
/* $conn meinaa tietokanta tiedostossa tietokanta yhteyttä ja $mysql meinaa ylemmän rivin query:iä */
Kaikki jossa ilmentyy mysql ! mutta query pysyy samana eli
$mysql = ”SELECT * FROM taulukon_nimi WHERE rivi = ’$joku’ ”;
$mysqli_query($conn, $mysql);
6.4 MySQL Injection ja sen estäminen
Sivustolla voi estää MySQL Injectionin vaihtamalla scripteistä (script/): $_POST / $_GET kohdat:
Esimerkki (activate.php):
$activate = $_GET[”status”];
Korvaa tällä:$activate_html = htmlspecialchars(isset($_GET[”status”]) ? $_GET[“status”] : “”);
$activate = str_replace(“”, “'”, $activate_html);
Tämä estää käyttäjien lisäämään turhia “scriptejä” teksi kenttiin.
6.5 Python Koodi ja sen Testailu
Python koodi löytyy myös https://github.com/OGkaaos/Chaos-IoT/blob/master/Raspberry%20Koodi/motion_detector.py github:istä.
Voit testailla raspberry koodia aluksi rekisteröitymällä tälle sivulle tästä jonka jälkeen voit käyttää Python Generator:ia luodaakseen valmis python koodi omalla APP Avaimella jonka saat dashboardista asetukset välilehdeltä. Kun koodi on valmis voit lisätä sen raspiin ja käynnistää sen koodin. Ohjeet koodin availuun/käynnistykseen löytyvät kohdan 6.5.1 yläpuolelta (jos havainnot saapuu dashboardiin (ilmoitukset) välilehteen ilman virheitä ja kaikki toimii moitteettomasti niin voit jatkaa lataamalla oma kopio softasta tästä)
Python Generator (Ilman koodin muokkailua): Python Generator tai sitten manuaalisesti:
import os # Käyttöjärjestelmä
import RPi.GPIO as GPIO # Raspberry GPIO
import time # Ajanhallinta
import requests # Nettisivun selailua varten
import picamera # Raspberry kamera (PiCamera())
import ftplib # FTP Latausta varten
import datetime # Päivämäärän luontia varten
import subprocess # Remote-Terminal varten
import threading # Timer:iä varten
from PIL import Image # Jotta voidaan vaihtaa kuvan kokoa
from resizeimage import resizeimage # Jotta voidaan vaihtaa kuvan kokoa
camera = picamera.PiCamera() # PiCamera
pin = 18 # Liiketunnistimen PIN -> 18
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.IN)
print "Paina Ctrl+C lopetakseen."
time.sleep(2)
print "Valmis..";
# Remote Terminal Koodi
def updates():
threading.Timer(3.0, updates).start() # timer :: toistuu aina 3 sek välein
# hakee/etsii tulevia komentoja
link = 'https://marcosraudkett.com/mvrclabs/code/scripts/admin/script/pi-terminal/APPKEY/'
f = requests.get(link) # lukee sivulla olevan tekstin
#print f.text
# toteutetaan komento raspberrillä
shell = subprocess.Popen(f.text, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout
response = shell.read() # luetaan shell
#print response
# skripti joka palauttaa viestin äskeiselle komennolla joka toteutettiin
link_response = 'https://marcosraudkett.com/mvrclabs/code/scripts/admin/script/pi-terminal-response/APPKEY/&response='+response
f2 = requests.get(link_response) # lukee sivulla olevan tekstin
updates()
# Liikettä Havaittu
try:
while True:
if (GPIO.input(pin)==1):
print "Liiketta Havaittu"
# luodaan päivämäärä + kellonaika NYT
date = datetime.datetime.now().strftime("%m-%d-%Y_%H%M%S")
# ottaa kuvan
camera.capture('/home/pi/Desktop/havainnot/' + date + '.png')
# tässä muutetaan kuvan kokoa jotta dashboard toimisi mahdollisimman nopeasti
fd_img = open('/home/pi/Desktop/havainnot/' + date + '.png', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_cover(img, [480, 360])
img.save('/home/pi/Desktop/havainnot/' + date + '.png', img.format)
fd_img.close()
camera.vflip = True
# FTP Lataus
session = ftplib.FTP('website.com','FTP KÄYTTÄJÄNIMI','FTP SALASANA') # FTP Tiedot
file = open('/home/pi/Desktop/havainnot/' + date + '.png', 'rb')
session.storbinary('STOR ' + date + '.png', file)
file.close()
session.quit()
# skripti joka tallentaa tietokantaan ja myös ilmoittaa käyttäjille jolla on kyseinen appkey ja &img=KUVAN PVM.png
requests.get('https://marcosraudkett.com/mvrclabs/code/scripts/admin/script/service.php?app_key=APPKEY&img=' + date + '.png').content
os.remove('/home/pi/Desktop/havainnot/' + date + '.png')
# odottaa 4 sek ennenkuin voi havaita uudelleen.
time.sleep(4)
except KeyboardInterrupt:
print "Dead"
GPIO.cleanup()
Python koodia voi avaa seuraavalla komennolla:
python /home/pi/Desktop/motion_detector.py
python /kansio/kansio/kansio/tiedoston_nimi.py
6.5.1 Python on Startup
Mikäli haluaa että python koodi avautuu heti kun raspi käynnistyy niin ohjeet siihen löytyy seuraavasta linkistä: http://www.instructables.com/id/Raspberry-Pi-Launch-Python-script-on-startup/7 Yhteenveto
Mikäli haluaa nähdä livestreamin muualta kuin sisäverkosta, on avattava reitittimestä portti 8080 tai muulla tavoin avattava yhteys Raspberrystä internetiin. Tämä tekisi sovelluksesta hieman käyttökelpoisemman
Aluksi piti käyttää IoT alustana Cayenne IoT:tä, mutta huomasimme, että se asettaa projektille rajoitteita. Tästä syystä päätimme toteuttaa projektin ilman Cayenneä.
Lähteet
https://www.raspberrypi.org/
https://www.linux-projects.org/uv4l/installation/
https://www.raspberrypi.org/documentation/installation/installing-images/README.md