Набор «Малина»

Электронная версия брошюры из набора «Малина». Здесь собраны все исходные коды экспериментов, подсказки и хаки по прохождению набора.

Видеообзор

Подключение и запуск

Если под рукой нет внешнего монитора, настрой SSH.

Настройка Wi-Fi

Подключись к Raspberry Pi по SSH.

Открой в текстовом редакторе «nano» файл настроек Wi-Fi. Для этого введи команду

~ $ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

и нажми Enter.

Откроется файл, в конце добавь параметры сети.

network={
    ssid="имя твоего wi-fi"
    psk="пароль твоего wi-fi"
}

Закрой файл сочетанием клавиш ctrl+X (cmd+X для Mac OS) на клавиатуре. Редактор спросит, сохранить ли изменения. Нажми клавишу Y (да), а затем Enter. Выполни перезагрузку системы командой sudo reboot

~ $ sudo reboot

После перезагрузки отсоедини кабель Ethernet и работай с Расберри через Wi-Fi.

Ресурсы

Windows OS

Mac OS

Эксперименты

3. Маячок

При первом запуске редактора Thonny Python IDE главное меню скрыто. Чтоб сделать его видимым, нужно нажать на ссылку в верхнем правом углу окна IDE. Подтвердите изменения После перезапуска IDE изменения вступят в силу.

blynk.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
 
i = 0
while (i < 5):
    i = i + 1
    time.sleep(0.5)
    GPIO.output(17, GPIO.HIGH)
    time.sleep(0.5)
    GPIO.output(17, GPIO.LOW)
 
GPIO.cleanup()
blynk.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
 
i = 0
while i < 5:
    i = i + 1
    time.sleep(0.5)
    GPIO.output(17, GPIO.HIGH)
    time.sleep(0.5)
    GPIO.output(17, GPIO.LOW)
GPIO.cleanup()

4. Выключатель

toggle.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(2, GPIO.IN)
 
while (True):
    time.sleep(0.5)
    button = GPIO.input(2)
    print(button)
toggle.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(2, GPIO.IN)
 
while True:
    time.sleep(0.5)
    button = GPIO.input(2)
    print(button)

Передай переменную button в функцию output, чтобы управлять светодиодом.

while (True):
    button = GPIO.input(2)
    GPIO.output(24, button)
while True:
    button = GPIO.input(2)
    GPIO.output(24, button)

Не забудь добавить строку инициализации пина на выход.

GPIO.setup(24, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)

5. Переключатель

switch.py
import RPi.GPIO as GPIO
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(8, GPIO.IN)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(26, GPIO.OUT)
 
while (True):
    button = GPIO.input(8)
    if (button == False):
        GPIO.output(24, GPIO.HIGH)
        GPIO.output(26, GPIO.LOW)
    else:
        GPIO.output(24, GPIO.LOW)
        GPIO.output(26, GPIO.HIGH)
switch.py
import RPi.GPIO as GPIO
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(8, GPIO.IN)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(26, GPIO.OUT)
 
while True:
    button = GPIO.input(8)
    if button == False:
        GPIO.output(24, GPIO.HIGH)
        GPIO.output(26, GPIO.LOW)
    else:
        GPIO.output(24, GPIO.LOW)
        GPIO.output(26, GPIO.HIGH)

6. Управление яркостью

brightnessControl.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
pwm = GPIO.PWM(18, 1000)
dutyCycle = 50
pwm.start(dutyCycle)
 
while (True):
    time.sleep(0.01)
    dutyCycle = dutyCycle + 1
    if (dutyCycle > 100):
        dutyCycle = 0
    pwm.ChangeDutyCycle(dutyCycle)
brightnessControl.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
pwm = GPIO.PWM(18, 1000)
dutyCycle = 50
pwm.start(dutyCycle)
 
while True:
    time.sleep(0.01)
    dutyCycle = dutyCycle + 1
    if dutyCycle > 100:
        dutyCycle = 0
    pwm.ChangeDutyCycle(dutyCycle)

7. Панель управления светом

function.py
import RPi.GPIO as GPIO
 
def isPressed(btn, led):
    if (GPIO.input(btn) == False):
        GPIO.output(led, GPIO.HIGH)
    else:
        GPIO.output(led, GPIO.LOW)
 
button1 = 3
button2 = 4
led1 = 14
led2 = 15
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(button1, GPIO.IN)
GPIO.setup(button2, GPIO.IN)
GPIO.setup(led1, GPIO.OUT)
GPIO.setup(led2, GPIO.OUT)
 
while (True):
    isPressed(button1, led1)
    isPressed(button2, led2)
function.py
import RPi.GPIO as GPIO
 
 
def isPressed(btn, led):
    if GPIO.input(btn) == False:
        GPIO.output(led, GPIO.HIGH)
    else:
        GPIO.output(led, GPIO.LOW)
 
 
button1 = 3
button2 = 4
led1 = 14
led2 = 15
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(button1, GPIO.IN)
GPIO.setup(button2, GPIO.IN)
GPIO.setup(led1, GPIO.OUT)
GPIO.setup(led2, GPIO.OUT)
 
while True:
    isPressed(button1, led1)
    isPressed(button2, led2)

8. Массивная оптимизация

oneMassive.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
leds = [12, 13, 14, 18]
 
for led in leds:
    GPIO.setup(led, GPIO.OUT)
    GPIO.output(led, GPIO.HIGH)
 
time.sleep(3)
 
for led in leds:
    GPIO.output(led, GPIO.LOW)
 
GPIO.cleanup()
oneMassive.py
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
leds = [12, 13, 14, 18]
 
for led in leds:
    GPIO.setup(led, GPIO.OUT)
    GPIO.output(led, GPIO.HIGH)
time.sleep(3)
 
for led in leds:
    GPIO.output(led, GPIO.LOW)
GPIO.cleanup()
twoMassive.py
import RPi.GPIO as GPIO
 
def isPressed(btn, led):
    state = 1-GPIO.input(btn)
    GPIO.output(led, state)
 
leds = [12, 13, 14, 18]
buttons = [2, 3, 4, 8]
 
GPIO.setmode(GPIO.BCM)
for i in range(4):
    GPIO.setup(leds[i], GPIO.OUT)
    GPIO.setup(buttons[i], GPIO.IN)
 
while (True):
    for i in range(4):
        isPressed(buttons[i], leds[i])
twoMassive.py
import RPi.GPIO as GPIO
 
 
def isPressed(btn, led):
    state = 1 - GPIO.input(btn)
    GPIO.output(led, state)
 
 
leds = [12, 13, 14, 18]
buttons = [2, 3, 4, 8]
 
GPIO.setmode(GPIO.BCM)
for i in range(4):
    GPIO.setup(leds[i], GPIO.OUT)
    GPIO.setup(buttons[i], GPIO.IN)
while True:
    for i in range(4):
        isPressed(buttons[i], leds[i])

9. Web-сервер

simpleServer.py
from flask import Flask
app = Flask('simpleServer')
 
@app.route('/')
def index():
    return 'Hello Amperka'
 
app.run(debug=True, port=3000, host='0.0.0.0')
simpleServer.py
from flask import Flask
 
app = Flask('simpleServer')
 
 
@app.route('/')
def index():
    return 'Hello, Amperka'
 
 
app.run(debug=True, port=3000, host='0.0.0.0')

10. Landing page

Ссылка на архив с файлами web-сервера.

http://amperka.github.io/malina_support/web-server.zip
landing.py
from flask import Flask, send_file
 
app = Flask('landingPage')
 
@app.route('/')
def index():
    return send_file('landing.html')
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/'+filename)
 
app.run(debug=True, port=3000, host='0.0.0.0')
landing.py
from flask import Flask, send_file
 
app = Flask('landingPage')
 
 
@app.route('/')
def index():
    return send_file('landing.html')
 
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/' + filename)
 
 
app.run(debug=True, port=3000, host='0.0.0.0')

Если при перезапуске сервера консоль ответит сообщением «socket.error: [Errno 98] Address already in use», набери команду

ps -u

В консоль выведется список запущенных процессов. Найди строку с файлом landing.py. Во второй колонке будет указан номер процесса. Отключи его командой

kill -9 2141

Где 2141 — номер процесса. Команда kill «убивает» процесс, иногда это называют «убить девяткой».

Запусти сервер заново.

11. Интернет свет

light.py
from flask import Flask, send_file
import RPi.GPIO as GPIO
 
GPIO.setmode(GPIO.BCM)
led = 18
GPIO.setup(led, GPIO.OUT)
 
app = Flask('lightControl')
 
@app.route('/')
def index():
    return send_file('light.html')
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/'+filename)
 
@app.route('/turnOn')
def turnOn():
    GPIO.output(led, GPIO.HIGH)
    return 'turnedOn'
 
@app.route('/turnOff')
def turnOff():
    GPIO.output(led, GPIO.LOW)
    return 'turnedOff'
 
app.run(debug=True, port=3000, host='0.0.0.0')
light.py
from flask import Flask, send_file
import RPi.GPIO as GPIO
 
GPIO.setmode(GPIO.BCM)
led = 18
GPIO.setup(led, GPIO.OUT)
 
app = Flask('lightControl')
 
 
@app.route('/')
def index():
    return send_file('light.html')
 
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/' + filename)
 
 
@app.route('/turnOn')
def turnOn():
    GPIO.output(led, GPIO.HIGH)
    return 'turnedOn'
 
 
@app.route('/turnOff')
def turnOff():
    GPIO.output(led, GPIO.LOW)
    return 'turnedOff'
 
 
app.run(debug=True, port=3000, host='0.0.0.0')

12. Обратная связь

sudo pip3 install flask-socketio eventlet
feedback.py
from flask import Flask, send_file
from flask_socketio import SocketIO
import RPi.GPIO as GPIO
 
app = Flask('feedback')
socketio = SocketIO(app)
 
GPIO.setmode(GPIO.BCM)
btn = 2
GPIO.setup(btn, GPIO.IN)
 
 
@app.route('/')
def index():
    return send_file('feedback.html')
 
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/' + filename)
 
 
@socketio.on('isPressed')
def checkButton(receivedData):
    if GPIO.input(btn) == False:
        socketio.emit('button', 'pressed')
    else:
        socketio.emit('button', 'released')
 
 
socketio.run(app, port=3000, host='0.0.0.0', debug=True)
feedback.py
from flask import Flask, send_file
from flask_socketio import SocketIO
import RPi.GPIO as GPIO
 
app = Flask('feedback')
socketio = SocketIO(app)
 
GPIO.setmode(GPIO.BCM)
buttons = [2, 3, 4, 8]
for btn in buttons:
    GPIO.setup(btn, GPIO.IN)
 
 
@app.route('/')
def index():
    return send_file('feedback.html')
 
 
@app.route('/images/<filename>')
def get_image(filename):
    return send_file('images/' + filename)
 
 
@socketio.on('isPressed')
def checkButton(receivedData):
    data = {btn: GPIO.input(btn) for btn in buttons}
    socketio.emit('button', data)
 
 
socketio.run(app, port=3000, host='0.0.0.0', debug=True)

Запусти сервер командой

python3 feedback.py

13. Погодный фиджет

fydget.py
import requests, json
from pprint import pprint
 
url = 'http://api.openweathermap.org/data/2.5/forecast'
 
payload = {
    'lat': '55.7522200',
    'lon': '37.6155600',
    'units': 'metric',
    'appid': 'e699d23b5b50c39d8e96dba883b4b4d5',
}
 
res = requests.get(url, params=payload)
data = json.loads(res.text)
 
 
weather = data['list'][0]
 
 
def pars_weather(weatherType, timeRange, measurementUnits):
    if (weatherType in weather) and (
        timeRange in weather[weatherType].keys()
    ):
        print(
            weatherType,
            ': ',
            weather[weatherType][timeRange],
            measurementUnits,
        )
    else:
        print(weatherType, ': ', 'none')
 
 
pars_weather('clouds', 'all', '%')
pars_weather('rain', '3h', 'mm')
pars_weather('snow', '3h', 'mm')
print('temp:', weather['main']['temp'], 'C')

Наш вариант погодного фиджета:

amperka.github.io/malina_support/weather.py

14. Бот ВКонтакте

vk.py
# -*- coding: utf-8 -*-
import time
import vk_api
 
from socket import gethostbyname
 
vk = vk_api.VkApi(token = 'твой токен')
 
param = {
    'count' : 1,
    'time_offset' : 5,
    'filter' : 'unread'
}
 
def write_msg(user_id, msg, random):
    vk.method('messages.send', {
        'user_id': user_id,
        'message': msg,
        'random_id':random,
    })
while True:
    response = vk.method('messages.getConversations', param)
    if response['items']:
        item = response['items'][0]
        last_mess = item['last_message']
        random = last_mess['random_id']
        my_id = last_mess['peer_id']
        text = last_mess['text']
        write_msg(my_id, text, random)    
    time.sleep(1)

17. Кинотеатр

amperka.github.io/malina_support/omx-web.zip

18. Поставь торрент заранее

deluge_vk.py
# -*- coding: utf-8 -*-
import time
import vk_api
 
from deluge_client import DelugeRPCClient
from pprint import pprint
 
vk = vk_api.VkApi(token = 'твой токен')
 
 
values = {
    'count' : 1,
    'offset' : 0,
    'filter' : 'unread'
}
 
client = DelugeRPCClient(
    '127.0.0.1',
    58846,
    'pi',
    'raspberry'
)
 
client.connect()
 
def write_msg(user_id, msg , random):
    vk.method('messages.send', {
        'user_id': user_id,
        'message': msg,
        'random_id':random,
    })
 
while True:
    response = vk.method('messages.getConversations', values)
    if response['items']:
        item = response['items'][0]
        last_mess = item['last_message']
        random = last_mess['random_id']
        my_id = last_mess['peer_id']
        text = last_mess['text'] 
        client.call('core.add_torrent_url', text, {'move_completed_path' : '/home/pi/Torrents'})
        write_msg(my_id, u'Download is begin!', random)
    time.sleep(1)

Включить все светодиоды на Облаке

import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
leds = [10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 24, 26]
 
for led in leds:
    GPIO.setup(led, GPIO.OUT)
    GPIO.output(led, GPIO.HIGH)
 
time.sleep(3)
 
for led in leds:
    GPIO.output(led, GPIO.LOW)
 
GPIO.cleanup()