EE 629 �Internet of Things �Lesson 4: Django and Flask
Kevin W. Lu
2023-07-02
Lesson 4: Django and Flask
2
* Contribution by Yuan Liu, 2019 Fall
Lab 4A — Django
3
Lab 4B — Django REST
4
View App — Landscape
5
View App — Portrait
6
Lab 4C — Flask
7
Lab 4D — LAMP
8
Milestones of Internet Layers
9
CERN and WWW
10
Web 3.0
11
| Year | World Wide Web Evolution |
1.0 | 1989—1990 | First web browser by Tim Berners-Lee |
1999—2004 | User-generated content (UGC), usability, and interoperability | |
3.0 | 2001—2006 | Semantic Web with common data formats and exchange protocols on the web, most fundamentally the Resource Description Framework (RDF) |
Clearnet and Surface Web
12
Splinternet
13
Framework
14
Request-Response by REST(ful) API
15
Client
Server
Request (GET, PUT, POST, DELETE) with payload (JSON or XML)
Request (GET, PUT, POST, DELETE) with payload (JSON or XML)
Response (JSON or XML)
Response (JSON or XML)
Django Web Framework
16
Django Architecture
17
Client
Side
Server
Side
Database
Django
Framework
Django Template
App
Logic
Model
View
Logic
Django Software Foundation (DSF)
18
SQLite
19
Django REST Framework
20
Django Reinhardt 1910—1953
21
Romani People and Flamenco
22
Berkeley Software Distribution
23
Install Django and REST Framework
pi@piot4:~ $ pip3 -V
pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7)
pi@piot4:~ $ sudo pip3 install -U setuptools
pi@piot4:~ $ sudo pip3 install -U django
pi@piot4:~ $ sudo pip3 install -U djangorestframework
pi@piot4:~ $ sudo pip3 install -U django-filter
pi@piot4:~ $ sudo pip3 install -U markdown
pi@piot4:~ $ sudo pip3 install -U requests
pi@piot4:~ $ python3
>>> import django
>>> django.VERSION
(4, 0, 2, 'final', 0)
>>> exit()
pi@piot4:~ $ cd iot
pi@piot4:~/iot $ git pull
pi@piot4:~/iot $ cd
pi@piot4:~ $
24
Install MariaDB Server and Client
pi@piot4:~ $ sudo apt update
pi@piot4:~ $ sudo apt install mariadb-server mariadb-client
pi@piot4:~ $ sudo apt install python3-mysqldb
pi@piot4:~ $ sudo pip3 install -U mysqlclient
pi@piot4:~ $ sudo mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
25
MariaDB and MySQL were named after Michael Widenius' daughters
Set Root Password and
Remove Anonymous Users
Set root password? [Y/n]
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n]
... Success!
26
Disallow Root Login Remotely and
Remove Test Database and Access
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n]
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n]
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
27
Reload Privilege Tables
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n]
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
pi@piot4:~ $
28
Connect to MariaDB Server
pi@piot4:~ $ sudo mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 55
Server version: 10.3.17-MariaDB-0+deb10u1 Raspbian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [mysql]>
29
Create or Drop User 0/1
MariaDB [mysql]> select user, host from mysql.user;
+------+-----------+
| User | Host |
+------+-----------+
| root | localhost |
+------+-----------+
1 row in set (0.001 sec)
MariaDB [mysql]> create user pi@localhost identified by 'raspberry';
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> select user, host from mysql.user;
+------+-----------+
| user | host |
+------+-----------+
| pi | localhost |
| root | localhost |
+------+-----------+
2 rows in set (0.001 sec)
MariaDB [mysql]>
30
Create or Drop User 1/1
MariaDB [mysql]> select user, host from mysql.user;
+------+-----------+
| user | host |
+------+-----------+
| pi | localhost |
| root | localhost |
+------+-----------+
2 rows in set (0.001 sec)
MariaDB [mysql]> drop user pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> select user, host from mysql.user;
+------+-----------+
| User | Host |
+------+-----------+
| root | localhost |
+------+-----------+
1 row in set (0.001 sec)
MariaDB [mysql]>
31
Create or Drop Database
MariaDB [mysql]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.001 sec)
MariaDB [mysql]> create database test;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.001 sec)
MariaDB [mysql]> drop database test;
Query OK, 0 rows affected (0.00 sec)
MariaDB [mysql]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.001 sec)
MariaDB [mysql]>
32
Create All Databases in Exercise 4
MariaDB [mysql]> create database stevens;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> create database weather;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> create database wordpress;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> create database parking;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> create database sensing;
Query OK, 1 row affected (0.001 sec)
MariaDB [mysql]> create database myraspi;
Query OK, 1 row affected (0.001 sec)
33
Grant Privileges to Users
MariaDB [mysql]> grant all privileges on stevens.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> grant all privileges on weather.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> grant all privileges on wordpress.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> grant all privileges on parking.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> grant all privileges on sensing.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> grant all privileges on myraspi.* to pi@localhost;
Query OK, 0 rows affected (0.001 sec)
34
Four Ways to Quit MariaDB
MariaDB [mysql]> quit
Bye
pi@piot4:~ $
MariaDB [mysql]> exit
Bye
pi@piot4:~ $
MariaDB [mysql]> Bye
pi@piot4:~ $
MariaDB [(none)]> Ctrl-C -- exit!
Aborted
pi@piot4:~ $
35
Django Project Files and Databases
36
SQL: Structured Query Language, URL: Uniform Resource Locator, WSGI: Web Server Gateway Interface
HTTP Response Status Code
In response to a client's request, the server issues the HTTP response status code in five categories defined by the standard
37
Stevens Project
Django Framework
Start Django Project and App
First create MySQL database stevens and grant all privileges to pi@localhost
pi@piot4:~ $ django-admin startproject stevens
pi@piot4:~ $ cd stevens
pi@piot4:~/stevens $ ls
manage.py stevens
pi@piot4:~/stevens $ python3 manage.py startapp myapp
pi@piot4:~/stevens $ ls
manage.py myapp stevens
pi@piot4:~/stevens $ cd stevens
pi@piot4:~/stevens/stevens $ ls
__init__.py __pycache__ settings.py urls.py wsgi.py
pi@piot4:~/stevens/stevens $ nano settings.py
pi@piot4:~/stevens/stevens $ cp ~/iot/lesson4/stevens/urls.py .
pi@piot4:~/stevens/stevens $ cd ../myapp
pi@piot4:~/stevens/myapp $ ls
admin.py apps.py __init__.py migrations models.py tests.py views.py
pi@piot4:~/stevens/myapp $ cp ~/iot/lesson4/stevens/admin.py .
pi@piot4:~/stevens/myapp $ cp ~/iot/lesson4/stevens/models.py .
pi@piot4:~/stevens/myapp $ cp ~/iot/lesson4/stevens/views.py .
39
Copy Templates and Static Files
pi@piot4:~/stevens/myapp $ mkdir static templates
pi@piot4:~/stevens/myapp $ cd templates
pi@piot4:~/stevens/myapp/templates $ mkdir myapp
pi@piot4:~/stevens/myapp/templates $ cd myapp
pi@piot4:~/stevens/myapp/templates/myapp $ cp ~/iot/*4/stevens/index.html .
pi@piot4:~/stevens/myapp/templates/myapp $ ls
index.html
pi@piot4:~/stevens/myapp/templates/myapp $ cd ~/stevens/myapp/static
pi@piot4:~/stevens/myapp/static $ cp ~/iot/*4/static/favicon.ico .
pi@piot4:~/stevens/myapp/static $ mkdir myapp
pi@piot4:~/stevens/myapp/static $ cd myapp
pi@piot4:~/stevens/myapp/static/myapp $ cp ~/iot/*4/static/*css .
pi@piot4:~/stevens/myapp/static/myapp $ cp ~/iot/*4/static/*js .
pi@piot4:~/stevens/myapp/static/myapp $ ls
bootstrap.min.css bootstrap.min.js jquery.min.js script.js
pi@piot4:~/stevens/myapp/static/myapp $ cd ~/stevens
40
Django Project Directory
41
/stevens | manage.py | |||
/stevens | __init__.py settings.py urls.py wsgi.py | |||
/myapp | admin.py apps.py __init__.py models.py tests.py views.py | |||
/migrations | __init__.py | |||
/static | favicon.ico | |||
/myapp | *.css *.js | |||
/templates | /myapp | index.html |
Print Directory Tree
pi@piot4:~/stevens $ tree -d
.
├── myapp
│ ├── migrations
│ ├── static
│ │ └── myapp
│ └── templates
│ └── myapp
└── stevens
└── __pycache__
10 directories
pi@piot4:~/stevens $ cd stevens
pi@piot4:~/stevens/stevens $ tree
.
├── asgi.py
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── settings.cpython-37.pyc
├── settings.py
├── urls.py
└── wsgi.py
1 directory, 7 files
pi@piot4:~/stevens/stevens $ cd ..
pi@piot4:~/stevens $ tree -I *pyc
.
├── manage.py
├── myapp
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ ├── models.py
│ ├── __pycache__
│ ├── static
│ │ ├── favicon.ico
│ │ └── myapp
│ │ ├── bootstrap.min.css
│ │ ├── bootstrap.min.js
│ │ ├── jquery.min.js
│ │ └── script.js
│ ├── templates
│ │ └── myapp
│ │ └── index.html
│ ├── tests.py
│ └── views.py
└── stevens
├── asgi.py
├── __init__.py
├── __pycache__
├── settings.py
├── urls.py
└── wsgi.py
8 directories, 19 files
42
Contribution by Dler Hasan, 2017 Spring
settings.py 0/1
Since settings.py generated from the command "django-admin startproject" contains SECRET_KEY and other important settings, only copy the code highlighted in bold from ~/iot/lesson4/stevens/settings.txt and keep all other in settings.py intact:
...
ALLOWED_HOSTS = ['*']
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
...
43
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
settings.py 1/1
...
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.mysql',
'NAME': 'stevens',
'USER': 'pi',
'PASSWORD': 'raspberry',
'HOST': '',
'PORT': '',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
...
TIME_ZONE = 'America/New_York'
...
44
urls.py
...
from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from myapp import views
admin.autodiscover()
urlpatterns = [
path('favicon.ico', RedirectView.as_view(
url=staticfiles_storage.url('favicon.ico'),
permanent=False), name="favicon"),
path('', views.home, name='home'),
path('admin/doc/', include('django.contrib.admindocs.urls')),
path('admin/', admin.site.urls),
]
45
admin.py
from django.contrib import admin
from myapp.models import TemperatureData
# Register your models here.
admin.site.register(TemperatureData)
46
models.py
from django.db import models
# Create your models here.
class TemperatureData(models.Model):
date_time = models.CharField(max_length=30)
temperature = models.CharField(max_length=5)
latitude = models.CharField(max_length=20)
longitude = models.CharField(max_length=20)
def __str__(self):
return self.date_time
47
views.py
from django.shortcuts import render
from myapp.models import TemperatureData
from django.template import RequestContext
# Create your views here.
def home(request):
tempData = TemperatureData.objects.order_by('-id')[0]
date_time = tempData.date_time
temperature = tempData.temperature
lat = tempData.latitude
lon = tempData.longitude
return render(request, 'myapp/index.html', {'date_time': date_time,
'temperature': temperature, 'lat': lat, 'lon': lon})
48
index.html 0/2
<!DOCTYPE html>
<html lang="en">
<head>
<title>Weather Station</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/myapp/bootstrap.min.css">
<script src="/static/myapp/jquery.min.js"></script>
<script src="/static/myapp/bootstrap.min.js"></script>
<style>
#map-canvas {
width: 400px;
height: 300px;
}
</style>
49
index.html 1/2
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapCanvas = document.getElementById('map-canvas');
var mapOptions = {
center: new google.maps.LatLng({{lat}}, {{lon}}),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(mapCanvas, mapOptions)
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
50
Contribution by Piyush Rao, 2017 Fall
myCenter = new google.maps.LatLng({{lat}}, {{lon}})
var marker = new google.maps.Marker({position: myCenter,
animation: google.maps.Animation.BOUNCE});
marker.setMap(map)
var infowindow = new google.maps.InfoWindow({content: "Location"});
infowindow.open(map,marker);
?key=YOUR_API_KEY
index.html 2/2
<body>
<div class="container-fluid">
<center><h1>Weather Station</h1></center>
<center><h3>Stevens Institute of Technology</h3></center>
<center><h4>{{date_time}}</h4></center>
<div class="row">
<div class="col-sm-3"><h4>Temperature</h4></div>
<div class="col-sm-3"><h4>{{temperature}}°F</h4></div>
<div class="col-sm-6" style="height:300px">
<div id="map-canvas"></div></div>
</div>
</div>
</body>
</html>
51
Static Files
https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css
https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js
https://code.jquery.com/jquery-3.7.0.min.js
https://github.com/ded/script.js/blob/master/src/script.js
52
Make and Run Migrations
Make and run migrations once and only after any changes to the Django files
pi@piot4:~/stevens $ python3 manage.py makemigrations myapp
Migrations for 'myapp':
myapp/migrations/0001_initial.py
- Create model TemperatureData
pi@piot4:~/stevens $ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying myapp.0001_initial... OK
Applying sessions.0001_initial... OK
53
Set Django Server Administration
Set Django administration username and password
pi@piot4:~/stevens $ python3 manage.py createsuperuser
Username (leave blank to use 'pi'):
Email address: EMAIL_ADDRESS
Password: ADMIN_PASSWORD
Password (again): ADMIN_PASSWORD
Superuser created successfully.
pi@piot4:~/stevens $
54
Run Django Server and View App
pi@piot4:~/stevens $ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
September 29, 2019 - 10:35:06
Django version 2.2.5, using settings 'stevens.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
55
Run Django Server and View App
pi@piot4:~/stevens $ python3 manage.py runserver 0.0.0.0:8000
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
September 29, 2019 - 10:35:06
Django version 2.2.5, using settings 'stevens.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
56
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
Django Administration Log In
57
Click Temperature Data
58
Add Temperature Data
59
Save Data
60
Django Administration Log Out
61
Django Administration Log Out
62
View App — Landscape
63
View App — Portrait
64
Darkened Watermarked Maps
65
Maps API Key
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"
></script>
66
Weather Project
Django REST Framework
Start Django REST Project and App
First create MySQL database weather and grant all privileges to pi@localhost
pi@piot4:~ $ django-admin startproject weather
pi@piot4:~ $ cd weather
pi@piot4:~/weather $ python3 manage.py startapp myapp
pi@piot4:~/weather $ cd weather
pi@piot4:~/weather/weather $ nano settings.py
pi@piot4:~/weather/weather $ cp ~/iot/lesson4/weather/urls.py .
pi@piot4:~/weather/weather $ cd ../myapp
pi@piot4:~/weather/myapp $ cp ~/iot/lesson4/weather/admin.py .
pi@piot4:~/weather/myapp $ cp ~/iot/lesson4/weather/models.py .
pi@piot4:~/weather/myapp $ cp ~/iot/lesson4/weather/views.py .
pi@piot4:~/weather/myapp $ nano views.py
68
Copy Templates and Static Files
pi@piot4:~/weather/myapp $ cp ~/iot/*4/weather/serializers.py .
pi@piot4:~/weather/myapp $ mkdir static templates
pi@piot4:~/weather/myapp $ cd static
pi@piot4:~/weather/myapp/static $ cp ~/iot/*4/static/favicon.ico .
pi@piot4:~/weather/myapp/static $ mkdir myapp
pi@piot4:~/weather/myapp/static $ cd myapp
pi@piot4:~/weather/myapp/static/myapp $ cp ~/iot/*4/static/*css .
pi@piot4:~/weather/myapp/static/myapp $ cp ~/iot/*4/static/*js .
pi@piot4:~/weather/myapp/static/myapp $ cd ~/weather/myapp/templates
pi@piot4:~/weather/myapp/templates $ mkdir myapp
pi@piot4:~/weather/myapp/templates $ cd myapp
pi@piot4:~/weather/myapp/templates/myapp $ cp ~/iot/*4/weather/index.html .
pi@piot4:~/weather/myapp/templates/myapp $ cd ~/weather
pi@piot4:~/weather $ cp ~/iot/*4/weather/controller.py .
pi@piot4:~/weather $ nano controller.py
pi@piot4:~/weather $
69
Django REST Project Directory
70
/weather | controller.py manage.py | |||
/weather | __init__.py settings.py urls.py wsgi.py | |||
/myapp | admin.py __init__.py models.py serializers.py tests.py views.py | |||
/migrations | __init__.py | |||
/static | favicon.ico | |||
/myapp | *.css *.js | |||
/templates | /myapp | index.html |
settings.py 0/1
Since settings.py generated from the command "django-admin startproject" contains SECRET_KEY and other important settings, only copy the code highlighted in bold from ~/iot/lesson4/weather/settings.txt and keep all other in settings.py intact:
...
ALLOWED_HOSTS = ['*']
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework',
]
...
71
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
settings.py 1/1
...
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.mysql',
'NAME': 'weather',
'USER': 'pi',
'PASSWORD': 'raspberry',
'HOST': '',
'PORT': '',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
...
TIME_ZONE = 'America/New_York'
...
72
urls.py
...
from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from rest_framework import routers
from myapp import views
admin.autodiscover()
router = routers.DefaultRouter()
router.register('dt', views.DtViewSet)
router.register('tmp', views.TmpViewSet)
router.register('hmd', views.HmdViewSet)
urlpatterns = [
path('favicon.ico', RedirectView.as_view(
url=staticfiles_storage.url('favicon.ico'),
permanent=False), name="favicon"),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
path('admin/', admin.site.urls),
path('home/', views.home),
]
73
admin.py
from django.contrib import admin
from myapp.models import LocationData
# Register your models here.
admin.site.register(LocationData)
74
models.py
from django.db import models
# Create your models here.
class LocationData(models.Model):
location = models.CharField(max_length=30)
latitude = models.CharField(max_length=20)
longitude = models.CharField(max_length=20)
def __str__(self):
return self.location
class Dt(models.Model):
name = models.CharField(max_length=30)
class Tmp(models.Model):
name = models.CharField(max_length=50)
class Hmd(models.Model):
name = models.CharField(max_length=50)
75
views.py 0/1
from django.shortcuts import render
from myapp.models import LocationData, Dt, Tmp, Hmd
from rest_framework import viewsets
from django.template import RequestContext
from myapp.serializers import DtSerializer, TmpSerializer, HmdSerializer
import requests
import json
# Create your views here.
class DtViewSet(viewsets.ModelViewSet):
queryset = Dt.objects.all()
serializer_class = DtSerializer
class TmpViewSet(viewsets.ModelViewSet):
queryset = Tmp.objects.all()
serializer_class = TmpSerializer
class HmdViewSet(viewsets.ModelViewSet):
queryset = Hmd.objects.all()
serializer_class = HmdSerializer
76
views.py 1/1
def home(request):
locData = LocationData.objects.order_by('-id')[0]
lat = locData.latitude
lon = locData.longitude
dtstate = '2017-02-11T17:45:00-05:00'
r = requests.get('http://127.0.0.1:8000/dt/1/', auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
dtstate = output['name']
tmpstate = '20'
r = requests.get('http://127.0.0.1:8000/tmp/1/', auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
tmpstate = output['name']
hmdstate = '50'
r = requests.get('http://127.0.0.1:8000/hmd/1/', auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
hmdstate = output['name']
return render(request, 'myapp/index.html',
{'lat': lat, 'lon': lon, 'dtstate':dtstate, 'tmpstate':tmpstate, 'hmdstate':hmdstate})
77
Change Django administration password in three instances
serializers.py
from myapp.models import Dt, Tmp, Hmd
from rest_framework import serializers
class DtSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Dt
fields = ('url', 'name')
class TmpSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Tmp
fields = ('url', 'name')
class HmdSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Hmd
fields = ('url', 'name')
78
index.html 0/2
<!DOCTYPE html>
<html lang="en">
<head>
<title>Weather Station</title>
<meta charset="utf-8">
<meta http-equiv="refresh" content="10">
<meta name="viewport" content="width=device width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/myapp/bootstrap.min.css">
<script src="/static/myapp/jquery.min.js"></script>
<script src="/static/myapp/bootstrap.min.js"></script>
<style>
#map-canvas {
width: 400px;
height: 300px;
}
</style>
79
index.html 1/2
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapCanvas = document.getElementById('map-canvas');
var mapOptions = {
center: new google.maps.LatLng({{lat}}, {{lon}}),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(mapCanvas, mapOptions)
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
80
Contribution by Piyush Rao, 2017 Fall
myCenter = new google.maps.LatLng({{lat}}, {{lon}})
var marker = new google.maps.Marker({position: myCenter,
animation: google.maps.Animation.BOUNCE});
marker.setMap(map)
var infowindow = new google.maps.InfoWindow({content: "Location"});
infowindow.open(map,marker);
?key=YOUR_API_KEY
index.html 2/2
<body>
<div class="container-fluid">
<center><h1>Weather Station</h1></center>
<center><h3>Stevens Institute of Technology</h3></center>
<center><h4>{{dtstate}}</h4></center>
<div class="row">
<div class="col-sm-3"><h4>Temperature</h4>
<h4>{{tmpstate|floatformat:1}}°C</h4></div>
<div class="col-sm-3"><h4>Humidity</h4>
<h4>{{hmdstate|floatformat:1}}%</h4></div>
<div class="col-sm-6" style="height:300px">
<div id="map-canvas"></div></div>
</div>
</div>
</body>
</html>
81
Ladyada and Adafruit
82
CircuitPython-DHT Library
$ pip3 install adafruit-blinka
$ cd ~/iot/lesson4
$ python3 blinkatest.py
Hello blinka!
Digital IO ok!
I2C ok!
SPI ok!
done!
$ pip3 install adafruit-circuitpython-dht
$ sudo apt install libgpiod2
$ python3 dht_simpletest.py
Temp: 75.7 F / 24.3 C Humidity: 50.2%
Temp: 75.9 F / 24.4 C Humidity: 50.2%
Temp: 75.9 F / 24.4 C Humidity: 50.2%
Temp: 75.9 F / 24.4 C Humidity: 50.3%
Temp: 75.9 F / 24.4 C Humidity: 50.4%
Temp: 75.9 F / 24.4 C Humidity: 50.4%
Temp: 75.9 F / 24.4 C Humidity: 50.4%
83
controller.py 0/1
import time
import datetime
import board
import adafruit_dht
import sys
import requests
dhtDevice = adafruit_dht.DHT22(board.D24)
def runController():
now = datetime.datetime.now()
dt = now.replace(microsecond=0)
print(dt)
print('Temperature: {0:0.1f} C'.format(tmp))
print('Humidity: {0:0.1f} %'.format(hmd))
setDtState(dt)
setTmpState(tmp)
setHmdState(hmd)
84
controller.py 1/1
def setDtState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/dt/1/', data=values, auth=('pi', 'raspberry'))
def setTmpState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/tmp/1/', data=values, auth=('pi', 'raspberry'))
def setHmdState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/hmd/1/', data=values, auth=('pi', 'raspberry'))
while True:
try:
hmd = dhtDevice.humidity
tmp = dhtDevice.temperature
if hmd is None or tmp is None:
time.sleep(2)
continue
runController()
time.sleep(10)
except KeyboardInterrupt:
exit()
85
Change Django administration password in three instances
Make and Run Migrations
pi@piot4:~/weather $ python3 manage.py makemigrations myapp
Migrations for 'myapp':
myapp/migrations/0001_initial.py
- Create model Dt
- Create model Hmd
- Create model LocationData
- Create model Tmp
pi@piot4:~/weather $ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying myapp.0001_initial... OK
Applying sessions.0001_initial... OK
86
Set Django Server Administration
Set Django administration username and password
pi@piot4:~/weather $ python3 manage.py createsuperuser
Username (leave blank to use 'pi'):
Email address: EMAIL_ADDRESS
Password: PASSWORD
Password (again): PASSWORD
Superuser created successfully.
pi@piot4:~/weather $
87
Run Server and Controller
Run Django server
pi@piot4:~/weather $ python3 manage.py runserver
At the first time, open a browser and go to http://127.0.0.1:8000/admin to add location data with Location Stevens, Latitude 40.7451, and Longitude -74.0255, click SAVE
Post the following in HTML form:
2020 to the Dt List at http://127.0.0.1:8000/dt
25 to the Tmp List at http://127.0.0.1:8000/tmp
50 to the Hmd List at http://127.0.0.1:8000/hmd
Run native controller service on a separate terminal window
pi@piot4:~/weather $ python3 controller.py
View app with a browser at http://127.0.0.1:8000/home
88
Django Administration Log In
89
Click Location Data
90
Add Location Data
91
Save Location Data
92
Location Data Saved
93
Post Date and Time
94
Date and Time Posted
95
Post Temperature Data
96
Temperature Data Posted
97
Post Humidity Data
98
Humidity Data Posted—Log Out
99
View App — Landscape
100
View App — Portrait
101
Run Controller.py
102
Lighting Project
Django REST Framework
Lighting Project and App 0/1
This Django project for lighting uses the default SQLite3 database
pi@piot4:~ $ django-admin startproject lighting
pi@piot4:~ $ cd lighting
pi@piot4:~/lighting $ ls
lighting manage.py
pi@piot4:~/lighting $ python3 manage.py startapp myapp
pi@piot4:~/lighting $ ls
lighting manage.py myapp
pi@piot4:~/lighting $ cd lighting
pi@piot4:~/lighting/lighting $ ls
__init__.py __pycache__ settings.py urls.py wsgi.py
pi@piot4:~/lighting/lighting $ nano settings.py
pi@piot4:~/lighting/lighting $ cp ~/iot/lesson4/lighting/urls.py .
pi@piot4:~/lighting/lighting $ cd ../myapp
pi@piot4:~/lighting/myapp $ ls
admin.py apps.py __init__.py migrations models.py tests.py views.py
pi@piot4:~/lighting/myapp $ cp ~/iot/lesson4/lighting/models.py .
pi@piot4:~/lighting/myapp $ cp ~/iot/lesson4/lighting/views.py .
pi@piot4:~/lighting/myapp $ nano views.py
104
Lighting Project and App 1/1
pi@piot4:~/lighting/myapp $ cp ~/iot/*4/lighting/serializers.py .
pi@piot4:~/lighting/myapp $ mkdir static templates
pi@piot4:~/lighting/myapp $ cd static
pi@piot4:~/lighting/myapp/static $ cp ~/iot/*4/static/favicon.ico .
pi@piot4:~/lighting/myapp/static $ cd ../templates
pi@piot4:~/lighting/myapp/templates $ mkdir myapp
pi@piot4:~/lighting/myapp/templates $ cd myapp
pi@piot4:~/lighting/myapp/templates/myapp $ cp ~/iot/*4/light*/index.html .
pi@piot4:~/lighting/myapp/templates/myapp $ cd ~/lighting
pi@piot4:~/lighting $ cp ~/iot/*4/lighting/controller.py .
pi@piot4:~/lighting $
105
Django REST Project Directory
106
/lighting | controller.py db.sqlite3 manage.py | |||
/lighting | __init__.py settings.py urls.py wsgi.py | |||
/myapp | admin.py apps.py __init__.py models.py serializers.py tests.py views.py | |||
/migrations | __init__.py | |||
/static | favicon.ico | |||
/templates | /myapp | index.html |
settings.py 0/1
Since settings.py generated from the command "django-admin startproject" contains SECRET_KEY and other important settings, only insert the code highlighted in bold and keep all other in settings.py intact:
...
ALLOWED_HOSTS = ['*']
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework',
]
...
107
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
settings.py 1/1
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
...
TIME_ZONE = 'America/New_York'
...
108
urls.py
...
from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from rest_framework import routers
from myapp import views
admin.autodiscover()
router = routers.DefaultRouter()
router.register('mode', views.ModeViewSet)
router.register('state', views.StateViewSet)
urlpatterns = [
path('favicon.ico', RedirectView.as_view(
url=staticfiles_storage.url('favicon.ico'),
permanent=False), name="favicon"),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
path('admin/', admin.site.urls),
path('home/', views.home),
]
109
models.py
from django.db import models
# Create your models here.
class Mode(models.Model):
name = models.CharField(max_length=50)
class State(models.Model):
name = models.CharField(max_length=50)
110
views.py 0/3
from django.shortcuts import render
from myapp.models import Mode, State
from rest_framework import viewsets
from django.template import RequestContext
from myapp.serializers import ModeSerializer, StateSerializer
import requests
import json
# Create your views here.
class ModeViewSet(viewsets.ModelViewSet):
queryset = Mode.objects.all()
serializer_class = ModeSerializer
class StateViewSet(viewsets.ModelViewSet):
queryset = State.objects.all()
serializer_class = StateSerializer
111
views.py 1/3
def home(request):
out = ''
currentmode = 'auto'
currentstate = 'off'
if 'on' in request.POST:
values = {"name": "on"}
r = requests.put('http://127.0.0.1:8000/state/1/',
data=values, auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
out = output['name']
if 'off' in request.POST:
values = {"name": "off"}
r = requests.put('http://127.0.0.1:8000/state/1/',
data=values, auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
out = output['name']
112
Change Django administration password in six instances
views.py 2/3
if 'auto' in request.POST:
values = {"name": "auto"}
r = requests.put('http://127.0.0.1:8000/mode/1/',
data=values, auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
out = output['name']
if 'manual' in request.POST:
values = {"name": "manual"}
r = requests.put('http://127.0.0.1:8000/mode/1/',
data=values, auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
out = output['name']
113
views.py 3/3
r = requests.get('http://127.0.0.1:8000/mode/1/',
auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
currentmode = output['name']
r = requests.get('http://127.0.0.1:8000/state/1/',
auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
currentstate = output['name']
return render(request, 'myapp/index.html', {'name':out,
'currentmode':currentmode, 'currentstate':currentstate})
114
serializers.py
from myapp.models import Mode, State
from rest_framework import serializers
class ModeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Mode
fields = ('url', 'name')
class StateSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = State
fields = ('url', 'name')
115
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
</head>
<body>
<p>{{r}}</p>
<h3>State</h3>
<form action="" method="post">{% csrf_token %}
<input type="submit" name="on" value="on" />
<input type="submit" name="off" value="off" />
</form>
<br>
<h3>Mode</h3>
<form action="" method="post">{% csrf_token %}
<input type="submit" name="auto" value="auto" />
<input type="submit" name="manual" value="manual" />
</form>
</body>
</html>
116
csrf_token is to prevent cross-site request forgeries (CSRF)
controller.py 0/7
import time
import datetime
import sqlite3
import spidev
import RPi.GPIO as GPIO
# Initialize SQLite
con = sqlite3.connect('db.sqlite3')
cur = con.cursor()
# LDR channel on MCP3008
LIGHT_CHANNEL = 0
# GPIO Setup
GPIO.setmode(GPIO.BCM)
LIGHT_PIN = 25 # 1k-ohm resistor between + and GPIO-25 (P6)
117
controller.py 1/7
# Open SPI bus
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 976000
# Light Level Threshold
threshold = 100
# Function to read LDR connected to MCP3008
def readLDR():
light_level = ReadChannel(LIGHT_CHANNEL)
if light_level == 0:
lux = 0
else:
lux = ConvertLux(light_level, 2)
return lux
# Function to convert LDR reading to Lux
def ConvertLux(data, places):
R=10 #10k-ohm resistor between LDR and 3V3
volts = (data * 3.3) / 1023
volts = round(volts, places)
lux = 500 * (3.3 - volts) / (R * volts)
return lux
118
RLDR
R=10KΩ
VIN=3.3V
GND
VLDR
VLDR=VINRLDR/(R+RLDR)
controller.py 2/7
# Function to read SPI data from MCP3008 chip
def ReadChannel(channel):
# Send three bytes 00000001 10000000 00000000 over SPI MOSI to MCP3008
adc = spi.xfer2([1, (8 + channel) << 4, 0])
# Extract the rightmost 10 bits from the three bytes returned
data = ((adc[1]&3) << 8) + adc[2]
return data
119
controller.py 3/7
# Get current mode from DB
def getCurrentMode():
cur.execute('SELECT * FROM myapp_mode')
data = cur.fetchone() # (1, u'auto')
return data[1]
# Get current state from DB
def getCurrentState():
cur.execute('SELECT * FROM myapp_state')
data = cur.fetchone() # (1, u'on')
return data[1]
# Store current state in DB
def setCurrentState(val):
query = 'UPDATE myapp_state set name = "'+val+'"'
cur.execute(query)
120
controller.py 4/7
def switchOnLight(PIN):
GPIO.setup(PIN, GPIO.OUT)
GPIO.output(PIN, True)
def switchOffLight(PIN):
GPIO.setup(PIN, GPIO.OUT)
GPIO.output(PIN, False)
121
controller.py 5/7
def runManualMode():
# Get current state from DB
currentState = getCurrentState()
if currentState == 'on':
print('Manual - On')
switchOnLight(LIGHT_PIN)
elif currentState == 'off':
print('Manual - Off')
switchOffLight(LIGHT_PIN)
122
controller.py 6/7
def runAutoMode():
# Read LDR
lightlevel = readLDR()
if lightlevel < threshold:
print('Auto - On (lux=%d)' % lightlevel)
switchOnLight(LIGHT_PIN)
else:
print('Auto - Off (lux=%d)' % lightlevel)
switchOffLight(LIGHT_PIN)
123
controller.py 7/7
# Controller main function
def runController():
currentMode = getCurrentMode()
if currentMode == 'auto':
runAutoMode()
elif currentMode == 'manual':
runManualMode()
return True
while True:
try:
runController()
time.sleep(5)
except KeyboardInterrupt:
GPIO.cleanup()
exit()
124
LDR, ADC, and LED Setup
125
Run Web and Native Services
After the first time, skip these three steps if no changes
pi@piot4:~/lighting $ python3 manage.py makemigrations myapp
pi@piot4:~/lighting $ python3 manage.py migrate
pi@piot4:~/lighting $ python3 manage.py createsuperuser
pi@piot4:~/lighting $ ls
controller.py db.sqlite3 lighting manage.py myapp
Run Django server
pi@piot4:~/lighting $ python3 manage.py runserver
At the first time, post the following in HTML form:
auto to the mode list at http://127.0.0.1:8000/mode
off to the state list at http://127.0.0.1:8000/state
Run native controller service on a separate terminal window
pi@piot4:~/lighting $ python3 controller.py
View app with a browser at http://127.0.0.1:8000/home
126
Post Mode
127
Post Mode
128
Post State
129
Post State
130
App Views
131
Parking Project
Django REST Framework
Parking Project and App 0/1
First create MySQL database parking and grant all privileges to pi@localhost
pi@piot4:~ $ django-admin startproject parking
pi@piot4:~ $ cd parking
pi@piot4:~/parking $ ls
manage.py parking
pi@piot4:~/parking $ python3 manage.py startapp myapp
pi@piot4:~/parking $ ls
manage.py myapp parking
pi@piot4:~/parking $ cd parking
pi@piot4:~/parking/parking $ ls
__init__.py __pycache__ settings.py urls.py wsgi.py
pi@piot4:~/parking/parking $ nano settings.py
pi@piot4:~/parking/parking $ cp ~/iot/lesson4/parking/urls.py .
pi@piot4:~/parking/parking $ cd ../myapp
pi@piot4:~/parking/myapp $ ls
admin.py apps.py __init__.py migrations models.py tests.py views.py
pi@piot4:~/parking/myapp $ cp ~/iot/lesson4/parking/models.py .
pi@piot4:~/parking/myapp $ cp ~/iot/lesson4/parking/views.py .
pi@piot4:~/parking/myapp $ nano views.py
133
Parking Project and App 1/1
pi@piot4:~/parking/myapp $ cp ~/iot/*4/parking/serializers.py .
pi@piot4:~/parking/myapp $ mkdir static templates
pi@piot4:~/parking/myapp $ cd static
pi@piot4:~/parking/myapp/static $ cp ~/iot/*4/static/favicon.ico .
pi@piot4:~/parking/myapp/static $ mkdir myapp
pi@piot4:~/parking/myapp/static $ cd myapp
pi@piot4:~/parking/myapp/static/myapp $ cp ~/iot/*4/static/*css .
pi@piot4:~/parking/myapp/static/myapp $ cp ~/iot/*4/static/*js .
pi@piot4:~/parking/myapp/static/myapp $ cp ~/iot/*4/static/*png .
pi@piot4:~/parking/myapp/static/myapp $ cd ~/parking/myapp/templates
pi@piot4:~/parking/myapp/templates $ mkdir myapp
pi@piot4:~/parking/myapp/templates $ cd myapp
pi@piot4:~/parking/myapp/templates/myapp $ cp ~/iot/*4/parking/index.html .
pi@piot4:~/parking/myapp/templates/myapp $ cd ~/parking
pi@piot4:~/parking $ cp ~/iot/*4/parking/controller.py .
pi@piot4:~/parking $ nano controller.py
pi@piot4:~/parking $
134
Django REST Project Directory
135
/parking | controller.py manage.py | |||
/parking | __init__.py settings.py urls.py wsgi.py | |||
/myapp | admin.py apps.py __init__.py models.py serializers.py tests.py views.py | |||
/migrations | __init__.py | |||
/static | favicon.ico | |||
/myapp | *.css *.js *.png | |||
/templates | /myapp | index.html |
settings.py 0/1
Since settings.py generated from the command "django-admin startproject" contains SECRET_KEY and other important settings, only insert the code highlighted in bold and keep all other in settings.py intact:
...
ALLOWED_HOSTS = ['*']
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework',
]
...
136
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
settings.py 1/1
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'parking',
'USER': 'pi',
'PASSWORD': 'raspberry',
'HOST': '',
'PORT': '',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
...
TIME_ZONE = 'America/New_York'
...
137
urls.py
...
from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from rest_framework import routers
from myapp import views
admin.autodiscover()
router = routers.DefaultRouter()
router.register('state', views.StateViewSet)
urlpatterns = [
path('favicon.ico', RedirectView.as_view(
url=staticfiles_storage.url('favicon.ico'),
permanent=False), name="favicon"),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
path('admin/', admin.site.urls),
path('home/', views.home),
]
138
models.py
from django.db import models
# Create your models here.
class State(models.Model):
name = models.CharField(max_length=50)
139
views.py 0/1
from django.shortcuts import render
from myapp.models import State
from rest_framework import viewsets
from django.template import RequestContext
from myapp.serializers import StateSerializer
import requests
import json
# Create your views here.
class StateViewSet(viewsets.ModelViewSet):
queryset = State.objects.all()
serializer_class = StateSerializer
140
views.py 1/1
def home(request):
currentstate = 'empty'
r = requests.get('http://127.0.0.1:8000/state/1/',
auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
currentstate = output['name']
if currentstate == 'empty':
occupiedCount = 0
emptyCount = 1
else:
occupiedCount = 1
emptyCount = 0
return render(request, 'myapp/index.html',
{'currentstate': currentstate,
'occupiedCount': occupiedCount,
'emptyCount': emptyCount})
141
Change Django administration password
serializers.py
from myapp.models import State
from rest_framework import serializers
class StateSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = State
fields = ('url', 'name')
142
index.html 0/2
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="3">
<title>Smart Parking App</title>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/myapp/bootstrap.min.css">
<script src="/static/myapp/jquery.min.js"></script>
<script src="/static/myapp/script.js"></script>
</head>
<body>
<div class="app-container">
<header class="app-header clearfix">
<h1 class="app-logo js-app-title icon-home">Smart Parking Dashboard</h1>
<div class="app-state"><span class="app-loading-loader">
</span></div>
<h4>Parking Lot #: 123<br>
Empty: {{emptyCount}}<br>
Occupied: {{occupiedCount}}</h4>
</header>
143
index.html 1/2
<div role="main" class="app-content clearfix">
<div class="app-loading"><span class="app-loading-loader">
</span></div>
<div class="app-content-inner">
<form class="dashboard-control js-form clearfix">
<fieldset>
<div class="field clearfix">
<table width = "90%" border="1">
<tr>
<td width="100%"> 1
<center>
{% if currentstate == 'empty' %}
<img src="/static/myapp/g.png">
{% else %}
<img src="/static/myapp/r.png">
{% endif %}
</center>
<br>
</td>
</tr>
</table>
144
index.html 2/2
</div>
</fieldset>
</form>
</div></div></div>
</body>
</html>
145
Static Files
g.png
http://www.clker.com/cliparts/e/d/U/J/J/e/green-hover-md.png
r.png
http://www.clker.com/cliparts/o/Q/g/b/u/W/r-hover-md.png
146
controller.py 0/2
import RPi.GPIO as GPIO
import time
import sys
import requests
GPIO.setmode(GPIO.BCM)
SENSOR_PIN = 17 # 1k-ohm resistor between Echo and GPIO-17 (P0)
TRIGGER_PIN = 18 # connect Trigger to GPIO-18 (P1)
threshold = 10 # cm
147
controller.py 1/2
def readUltrasonicSensor():
GPIO.setup(TRIGGER_PIN, GPIO.OUT)
GPIO.setup(SENSOR_PIN, GPIO.IN)
GPIO.output(TRIGGER_PIN, GPIO.LOW)
time.sleep(0.3)
GPIO.output(TRIGGER_PIN, True)
time.sleep(0.00001)
GPIO.output(TRIGGER_PIN, False)
while GPIO.input(SENSOR_PIN) == 0:
signaloff = time.time()
while GPIO.input(SENSOR_PIN) == 1:
signalon = time.time()
timepassed = signalon - signaloff
distance = timepassed * 17000 # speed of sound = 34000 cm/s
if distance < threshold:
return 1
else:
return 0
148
controller.py 2/2
def runController():
pinState = readUltrasonicSensor()
if pinState == 1:
print('Occupied')
setCurrentState('occupied')
else:
print('Empty')
setCurrentState('empty')
def setCurrentState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/state/1/', data=values,
auth=('pi', 'raspberry'))
while True:
try:
runController()
time.sleep(1)
except KeyboardInterrupt:
GPIO.cleanup()
exit()
149
Change password (or 127.0.0.1 with host IP address)
Ultrasonic Sensor Setup
150
5V
GND
Echo
Trigger
Run Web and Native Services
After the first time, skip these three steps if no changes
pi@piot4:~/parking $ python3 manage.py makemigrations myapp
pi@piot4:~/parking $ python3 manage.py migrate
pi@piot4:~/parking $ python3 manage.py createsuperuser
Run Django server
pi@piot4:~/parking $ python3 manage.py runserver
At the first time, post the following in HTML form:
empty to the state list at http://127.0.0.1:8000/state
Run native controller service on a separate terminal window
pi@piot4:~/parking $ python3 controller.py
View app with a browser at http://127.0.0.1:8000/home
151
Post State
152
Post State
153
App Views − Empty
154
App Views − Occupied
155
Sensing Project
Django REST Framework
Sensing Project and App 0/1
First create MySQL database sensing and grant all privileges to pi@localhost
pi@piot4:~ $ django-admin startproject sensing
pi@piot4:~ $ cd sensing
pi@piot4:~/sensing $ ls
manage.py sensing
pi@piot4:~/sensing $ python3 manage.py startapp myapp
pi@piot4:~/sensing $ ls
manage.py myapp sensing
pi@piot4:~/sensing $ cd sensing
pi@piot4:~/sensing/sensing $ ls
__init__.py __pycache__ settings.py urls.py wsgi.py
pi@piot4:~/sensing/sensing $ nano settings.py
pi@piot4:~/sensing/sensing $ cp ~/iot/lesson4/sensing/urls.py .
pi@piot4:~/sensing/sensing $ cd ../myapp
pi@piot4:~/sensing/myapp $ ls
admin.py apps.py __init__.py migrations models.py tests.py views.py
pi@piot4:~/sensing/myapp $ cp ~/iot/lesson4/sensing/models.py .
pi@piot4:~/sensing/myapp $ cp ~/iot/lesson4/sensing/views.py .
pi@piot4:~/sensing/myapp $ nano views.py
157
Sensing Project and App 1/1
pi@piot4:~/sensing/myapp $ cp ~/iot/*4/sensing/serializers.py .
pi@piot4:~/sensing/myapp $ mkdir static templates
pi@piot4:~/sensing/myapp $ cd static
pi@piot4:~/sensing/myapp/static $ cp ~/iot/*4/static/favicon.ico .
pi@piot4:~/sensing/myapp/static $ mkdir myapp
pi@piot4:~/sensing/myapp/static $ cd myapp
pi@piot4:~/sensing/myapp/static/myapp $ cp ~/iot/*4/static/*css .
pi@piot4:~/sensing/myapp/static/myapp $ cp ~/iot/*4/static/*js .
pi@piot4:~/sensing/myapp/static/myapp $ cp ~/iot/*4/static/*png .
pi@piot4:~/sensing/myapp/static/myapp $ cd ~/sensing/myapp/templates
pi@piot4:~/sensing/myapp/templates $ mkdir myapp
pi@piot4:~/sensing/myapp/templates $ cd myapp
pi@piot4:~/sensing/myapp/templates/myapp $ cp ~/iot/*4/sensing/index.html .
pi@piot4:~/sensing/myapp/templates/myapp $ cd ~/sensing
pi@piot4:~/sensing $ cp ~/iot/*4/sensing/controller.py .
pi@piot4:~/sensing $ nano controller.py
pi@piot4:~/sensing $
158
Django REST Project Directory
159
/sensing | controller.py manage.py | |||
/sensing | __init__.py settings.py urls.py wsgi.py | |||
/myapp | admin.py __init__.py models.py serializers.py tests.py views.py | |||
/migrations | __init__.py | |||
/static | favicon.ico | |||
/myapp | *.css *.js *.png | |||
/templates | /myapp | index.html |
settings.py 0/1
Since settings.py generated from the command "django-admin startproject" contains SECRET_KEY and other important settings, only insert the code highlighted in bold and keep all other in settings.py intact:
...
ALLOWED_HOSTS = ['*']
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework',
]
...
160
Contributions by Allison Butler, Isaac Hirschfeld, and Brian Voyer, 2017 Spring;
Nicholas Antonov, 2018 Spring; Matthew Bergwall, 2018 Summer
settings.py 1/1
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'sensing',
'USER': 'pi',
'PASSWORD': 'raspberry',
'HOST': '',
'PORT': '',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
...
TIME_ZONE = 'America/New_York'
...
161
urls.py
...
from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from rest_framework import routers
from myapp import views
admin.autodiscover()
router = routers.DefaultRouter()
router.register('room', views.RoomViewSet)
router.register('door', views.DoorViewSet)
urlpatterns = [
path('favicon.ico', RedirectView.as_view(
url=staticfiles_storage.url('favicon.ico'),
permanent=False), name="favicon"),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
path('admin/', admin.site.urls),
path('home/', views.home),
]
162
models.py
from django.db import models
# Create your models here.
class Room(models.Model):
name = models.CharField(max_length=50)
class Door(models.Model):
name = models.CharField(max_length=50)
163
views.py 0/1
from django.shortcuts import render
from myapp.models import Room, Door
from rest_framework import viewsets
from django.template import RequestContext
from myapp.serializers import RoomSerializer, DoorSerializer
import requests
import json
# Create your views here.
class RoomViewSet(viewsets.ModelViewSet):
queryset = Room.objects.all()
serializer_class = RoomSerializer
class DoorViewSet(viewsets.ModelViewSet):
queryset = Door.objects.all()
serializer_class = DoorSerializer
164
views.py 1/1
def home(request):
roomstate = 'no'
r = requests.get('http://127.0.0.1:8000/room/1/', auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
roomstate = output['name']
doorstate = 'closed'
r = requests.get('http://127.0.0.1:8000/door/1/', auth=('pi', 'raspberry'))
result = r.text
output = json.loads(result)
doorstate = output['name']
return render(request, 'myapp/index.html',
{'roomstate':roomstate, 'doorstate':doorstate})
165
Change Django administration password in two instances
serializers.py
from myapp.models import Room, Door
from rest_framework import serializers
class RoomSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Room
fields = ('url', 'name')
class DoorSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Door
fields = ('url', 'name')
166
index.html 0/1
<!DOCTYPE html>
<html lang=en>
<head>
<title>Smart Sensing App</title>
<meta charset="utf-8">
<meta http-equiv="refresh" content="3">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/myapp/bootstrap.min.css">
<script src="/static/myapp/jquery.min.js"></script>
<script src="/static/myapp/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid">
<h1>Room</h1>
<div class="row">
<center>
{% if roomstate == 'no' %}
<img src="/static/myapp/g.png">
{% else %}
<img src="/static/myapp/r.png">
167
index.html 1/1
{% endif %}
</center>
</div>
<br>
<h1>Door</h1>
<div class="row">
<center>
{% if doorstate == 'closed' %}
<img src="/static/myapp/g.png">
{% else %}
<img src="/static/myapp/r.png">
{% endif %}
</center>
</div>
</div>
</body>
</html>
168
controller.py 0/2
import RPi.GPIO as GPIO
import time
import sys
import requests
GPIO.setmode(GPIO.BCM)
ROOM_SENSOR_PIN = 27
DOOR_SENSOR_PIN = 23
GPIO.setup(ROOM_SENSOR_PIN, GPIO.IN)
GPIO.setup(DOOR_SENSOR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def readingRoomSensor():
if GPIO.input(ROOM_SENSOR_PIN):
print('motion detected')
return 1
else:
return 0
169
controller.py 1/2
def readingDoorSensor():
if GPIO.input(DOOR_SENSOR_PIN):
print('door opened')
return 1
else:
return 0
def runController():
roomState = readingRoomSensor()
if roomState == 1:
setRoomState('yes')
else:
setRoomState('no')
doorState = readingDoorSensor()
if doorState == 1:
setDoorState('open')
else:
setDoorState('closed')
170
controller.py 2/2
def setRoomState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/room/1/', data=values, auth=('pi', 'PASSWORD'))
def setDoorState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/door/1/', data=values, auth=('pi', 'PASSWORD'))
while True:
try:
runController()
time.sleep(3)
except KeyboardInterrupt:
GPIO.cleanup()
exit()
171
Change password (or 127.0.0.1 with host IP address) in two instances
Motion and Door Sensors Setup
172
Door Sensor
Motion Sensor
Run Web and Native Services
After the first time, skip these three steps if no changes
pi@piot4:~/sensing $ python3 manage.py makemigrations myapp
pi@piot4:~/sensing $ python3 manage.py migrate
pi@piot4:~/sensing $ python3 manage.py createsuperuser
Run Django server
pi@piot4:~/sensing $ python3 manage.py runserver
At the first time, post the following in HTML form:
no to the room list at http://127.0.0.1:8000/room
closed to the door list at http://127.0.0.1:8000/door
Run native controller service on a separate terminal window
pi@piot4:~/sensing $ python3 controller.py
View app with a browser at http://127.0.0.1:8000/home
173
Post Room
174
Post Room
175
Post Door
176
Post Door
177
App View
178
Motion Detected
179
Door Opened
180
Motion Detected and Door Opened
181
Flask
Alexa Skill
Flask with Jinja2 and Werkzeug
The Pocoo Team led by Georg Brandl (Germany) and Armin Ronacher (Austria) have worked on various Python libraries and applications since 2004
Armin Ronacher (nickname mitsuhiko) has led the following projects under the three-clause BSD license
183
Torii
184
Flask Example 0/1
Raspberry Pi Python has Flask (tutorial, adding a favicon) web development framework based on Jinja2 template engine and Werkzeug WSGI toolkit
pi@piot4:~/iot/lesson4 $ cat hello_world.py
from flask import Flask
from flask import send_from_directory
import os
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico',
mimetype='image/vnd.microsoft.icon')
if __name__ == "__main__":
app.run()
185
Contribution by Meng Cao, 2015 Spring
Flask Example 1/1
pi@piot4:~/iot/lesson4 $ python3 hello_world.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)�127.0.0.1 - - [22/Mar/2018 11:50:29] "GET / HTTP/1.1" 200 -�127.0.0.1 - - [22/Mar/2018 11:50:30] "GET /favicon.ico HTTP/1.1" 200 -
^C
pi@piot4:~/iot/lesson4 $
186
Contribution by Meng Cao, 2015 Spring
Flask-Ask
Flask-Ask is a Flask extension of rapid Alexa skills kit (ASK) development for Amazon Echo devices; quickstart to run memory_game.py with templates.yaml and ngrok tunneling service, then add, configure, and test a new Alexa skill of Memory Game that asks to repeat three numbers backwards
pi@piot4:~ $ sudo pip3 install -U flask-ask
pi@piot4:~ $ sudo pip3 install 'cryptography<2.2'
pi@piot4:~ $ cd iot/lesson4
pi@piot4:~/iot/lesson4 $ cat templates.yaml
welcome: Welcome to memory game. I'm going to say three numbers for you to repeat backwards. Ready?
round: Can you repeat the numbers {{ numbers|join(", ") }} backwards?
win: Good job!
lose: Sorry, that's the wrong answer.
pi@piot4:~/iot/lesson4 $ python3 memory_game.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 409-630-116
187
Contributions by Khalid Alnuaim and Mutni Alshammari, 2018 Spring
Run Ngrok on Another Terminal
Ngrok is secure tunneling service that makes a device available from anywhere online
Grok was coined by Robert A. Heinlein 1907—1988 in Stranger in a Strange Land (1961) and has been included in the Jargon File for computer programmers
pi@piot4:~ $ sudo wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
pi@piot4:~ $ sudo unzip ngrok-stable-linux-arm.zip
pi@piot4:~ $ ./ngrok http 5000
ngrok by @inconshreveable (Ctrl+C to quit)� �Session Status online �Session Expires 7 hours, 59 minutes �Version 2.3.35 �Region United States (us) �Web Interface http://127.0.0.1:4040 �Forwarding http://3058ee9157f9.ngrok.io -> localhost:5000 �Forwarding https://3058ee9157f9.ngrok.io -> localhost:5000 � �Connections ttl opn rt1 rt5 p50 p90 � 0 0 0.00 0.00 0.00 0.00
188
Create Alexa Skill
AMAZON.StopIntent, one of the Standard Built-in Intents, is required*
189
Test Alexa Skill
Click "Test" tab > Enable skill testing from "Off" to "Development"
Type or click and hold the microphone button to speak
Alexa: "Welcome to memory game. I'm going to say three numbers for you to repeat backwards. Ready?"
Alexa: "Can you repeat the numbers 0, 9, 6 backwards?"
Alexa: "Good job!"
190
Alexa Simulator
191
Apache
WordPress
Apache Software Foundation (ASF)
193
Apache
194
Four Color Theorem
195
Apache Web Server 0/2
pi@piot4:~ $ sudo apt update
pi@piot4:~ $ sudo apt install apache2
pi@piot4:~ $ sudo service apache2 restart
196
Apache Web Server 1/2
pi@piot4:~ $ sudo apt install php7.3
pi@piot4:~ $ cd /var/www/html
pi@piot4:/var/www/html $ ls
index.html
pi@piot4:/var/www/html $ sudo mv index.html index.html.bak
pi@piot4:/var/www/html $ sudo cp ~/iot/lesson4/index.php .
pi@piot4:/var/www/html $ cat index.php
<?php
echo "Hello world!";
echo "<br>";
echo date('Y-m-d H:i:s');
echo "<br>";
phpinfo();
?>
pi@piot4:/var/www/html $ cd
pi@piot4:~ $
197
Apache Web Server 2/2
pi@piot4 ~ $ sudo service apache2 restart
pi@piot4 ~ $
198
WordPress — Download
Build a Linux-Apache-MySQL-PHP (LAMP) web server with WordPress
pi@piot4:~ $ sudo apt install php7.3-mysql
pi@piot4:~ $ cd /var/www/html
pi@piot4:/var/www/html $ sudo chown pi: .
pi@piot4:/var/www/html $ mv index.php index.php.bak
pi@piot4:/var/www/html $ wget https://wordpress.org/latest.tar.gz
pi@piot4:/var/www/html $ tar xzf latest.tar.gz
pi@piot4:/var/www/html $ mv wordpress/* .
pi@piot4:/var/www/html $ rm -rf wordpress latest.tar.gz
pi@piot4:/var/www/html $ cd
pi@piot4:~ $ sudo service apache2 restart
pi@piot4:~ $
199
-x: extract
-z: gzipped archive
-f: get from a file, not a tape
Contribution by Xingyuan Guo, 2018 Fall
WordPress — Get Started
200
WordPress — Database
201
pi
WordPress — Copy Configuration
202
WordPress — Paste Configuration
pi@piot4:~ $ cd /var/www/html
pi@piot4:/var/www/html $ ls
index.html.bak wp-admin wp-includes wp-signup.php
index.php wp-blog-header.php wp-links-opml.php wp-trackback.php
index.php.bak wp-comments-post.php wp-load.php xmlrpc.php
license.txt wp-config-sample.php wp-login.php
readme.html wp-content wp-mail.php
wp-activate.php wp-cron.php wp-settings.php
Create the wp-config.php file
pi@piot4:/var/www/html $ nano wp-config.php
Paste the text and save the wp-config.php file
pi@piot4:/var/www/html $ ls
index.html.bak wp-admin wp-cron.php wp-settings.php
index.php wp-blog-header.php wp-includes wp-signup.php
index.php.bak wp-comments-post.php wp-links-opml.php wp-trackback.php
license.txt wp-config.php wp-load.php xmlrpc.php
readme.html wp-config-sample.php wp-login.php
wp-activate.php wp-content wp-mail.php
pi@piot4:/var/www/html $
203
WordPress — Installation
204
WordPress — Success
205
WordPress — Log In
206
WordPress — Dashboard
207
WordPress — Posts
208
WordPress — Themes
209
WordPress — 2020 Default Theme
210
WordPress — Widgets
211
WordPress — Menus
212
WordPress — Visit Site
213
WordPress — Log Out
214
Drupal
215
Wix
216
Mobirise
217
Lesson 4 Summary
218
controller.py 0/1
import time
import datetime
import Adafruit_DHT
import sys
import requests
DHT_TYPE = Adafruit_DHT.DHT22
DHT_PIN = 24
def runController():
now = datetime.datetime.now()
dt = now.replace(microsecond=0)
print(dt)
print('Temperature: {0:0.1f} C'.format(tmp))
print('Humidity: {0:0.1f} %'.format(hmd))
setDtState(dt)
setTmpState(tmp)
setHmdState(hmd)
219
controller.py 1/1
def setDtState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/dt/1/', data=values, auth=('pi', 'raspberry'))
def setTmpState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/tmp/1/', data=values, auth=('pi', 'raspberry'))
def setHmdState(val):
values = {'name': val}
r = requests.put('http://127.0.0.1:8000/hmd/1/', data=values, auth=('pi', 'raspberry'))
while True:
try:
hmd, tmp = Adafruit_DHT.read(DHT_TYPE, DHT_PIN)
if hmd is None or tmp is None:
time.sleep(2)
continue
runController()
time.sleep(10)
except KeyboardInterrupt:
exit()
220
Change Django administration password in three instances
Adafruit Python Libraries
Install Adafruit_Python_DHT library on Raspberry Pi
pi@piot4:~ $ git clone https://github.com/adafruit/Adafruit_Python_DHT.git
pi@piot4:~ $ cd *DHT
pi@piot4:~/Adafruit_Python_DHT $ sudo python3 setup.py install
pi@piot4:~/Adafruit_Python_DHT $ cd
Install Adafruit_Python_BMP library on Raspberry Pi
pi@piot4:~ $ git clone https://github.com/adafruit/Adafruit_Python_BMP.git
pi@piot4:~ $ cd *BMP
pi@piot4:~/Adafruit_Python_BMP $ sudo python3 setup.py install
pi@piot4:~/Adafruit_Python_BMP $ cd
Install Adafruit_Python_ADXL345 library on Raspberry Pi
pi@piot4:~ $ git clone https://github.com/adafruit/Adafruit_Python_ADXL345.git
pi@piot4:~ $ cd *ADXL*
pi@piot4:~/Adafruit_Python_ADXK345 $ sudo python3 setup.py install
pi@piot4:~/Adafruit_Python_ADXL345 $ cd
pi@piot4:~ $
221
DHT Test
Run DHT simple test
pi@piot4:~ $ cd *DHT/ex*
pi@piot4:~/Adafruit_Python_DHT/examples $ ls
AdafruitDHT.py google_spreadsheet.py simpletest.py
pi@piot4:~/Adafruit_Python_DHT/examples $ cd
pi@piot4:~ $ cd demo
pi@piot4:~/demo $ cp ~/*DHT/ex*/simple* .
pi@piot4:~/demo $ nano simpletest.py
Comment out Beaglebone Black pin = 'P8_11'
Uncomment Raspberry Pi pin, and change it to pin = 24
control-x y enter
pi@piot4:~/demo $ python3 simpletest.py
Temp=19.4*C Humidity=41.4%
pi@piot4:~/demo $
222
BMP Test
Run BMP simple test
pi@piot4:~ $ cd *BMP/ex*
pi@piot4:~/Adafruit_Python_BMP/examples $ ls
google_spreadsheet.py simpletest.py
pi@piot4:~/Adafruit_Python_BMP/examples $ python3 simpletest.py
Temp = 19.40 *C
Pressure = 100193.00 Pa
Altitude = 95.18 m
Sealevel Pressure = 100189.00 Pa
pi@piot4:~/Adafruit_Python_BMP/examples $
223
ADXL345 Test
Run ADXL345 simple test
pi@piot4:~ $ cd *ADXL345/ex*
pi@piot4:~/Adafruit_Python_ADXL345/examples $ ls
simpletest.py
pi@piot4:~/Adafruit_Python_ADXL345/examples $ python3 simpletest.py
Printing X, Y, Z axis values, press Ctrl-C to quit...
X=0, Y=0, Z=0
X=-28, Y=127, Z=208
X=-27, Y=126, Z=207
X=-28, Y=127, Z=207
X=-27, Y=127, Z=207
X=-27, Y=126, Z=208
X=-27, Y=127, Z=206
^C
pi@piot4:~/Adafruit_Python_ADXL345/examples $
224