===== Инструкция набора «Малина» с платой Rasberry Pi 3 Model B ===== Электронная версия книги из набора [[amp>product/malina?utm_source=announce&utm_campaign=malina&utm_medium=wiki|«Малина»]]. Здесь собраны все исходные коды экспериментов, подсказки и хаки по прохождению набора. {{ :malina:titile.png?nolink |}} ===== Видеообзор ===== {{youtube>CNW2KdwlanE?large}} ===== Подключение и запуск ==== Если под рукой нет внешнего монитора, [[rpi:installation:ssh|настрой 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. ===== Ресурсы ===== * [[https://www.putty.org/|Putty]] — клиент для удалённого доступа к устройствам по протоколам SSH, Telnet и UART. * [[https://filezilla-project.org/download.php?show_all=1|FileZilla]] — FTP-клиент. * [[https://www.realvnc.com/en/connect/download/viewer/|RealVNC]] — клиент для удаленного доступа к рабочему столу устройства. * [[https://angryip.org/download|Angry IP Scanner]] — утилита для сканирования IP-адресов в подключенной сети. ===== Эксперименты ===== ==== 3. Маячок ==== При первом запуске редактора Thonny Python IDE главное меню скрыто. Чтоб сделать его видимым, нужно нажать на ссылку в верхнем правом углу окна IDE. {{ :malina:1.png?nolink |}} Подтвердите изменения {{ :malina:2.png?nolink |}} После перезапуска IDE изменения вступят в силу. {{ :malina:3.png?nolink |}} 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. Выключатель ==== 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) Не забудь добавить строку инициализации пина на выход. GPIO.setup(24, GPIO.OUT) ==== 5. Переключатель ==== 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. Управление яркостью ==== 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. Панель управления светом ==== 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. Массивная оптимизация ==== 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() 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-сервер ==== from flask import Flask app = Flask('simpleServer') @app.route('/') def index(): return 'Hello, Amperka!' app.run(port=3000, host='0.0.0.0') ==== 10. Landing page ==== Ссылка на архив с файлами web-сервера. http://amperka.github.io/malina_support/web-server.zip from flask import Flask, send_file app = Flask('landingPage') @app.route('/') def index(): return send_file('landing.html') @app.route('/images/') 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 В консоль выведется список запущенных процессов. {{ :malina:ps.png?nolink |}} Найди строку с файлом landing.py. Во второй колонке будет указан номер процесса. Отключи его командой kill -9 2141 Где 2141 — номер процесса. {{ :malina:kill.png?nolink |}} Команда kill «убивает» процесс, иногда это называют «убить девяткой». Запусти сервер заново. ==== 11. Интернет свет ==== 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/') 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 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/') 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) Запусти сервер командой python3 feedback.py ==== 13. Погодный фиджет ==== import requests, json url = "http://api.openweathermap.org/data/2.5/forecast" payload = { "lat": "широта_твоего_города", "lon": "долгота_твоего_города", "units": "metric", "appid": "твой_ключ", } 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") ==== 14. Бот ВКонтакте ==== import time import vk_api 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) ==== 18. Кинотеатр ==== amperka.github.io/malina_support/omx-web.zip ==== 19. Поставь торрент заранее ==== import time import vk_api from deluge_client import DelugeRPCClient vk = vk_api.VkApi(token = 'твой_ключ') values = { 'count' : 1, 'time_offset' : 5, '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, { 'download_location': '/home/pi/Torrents' }) write_msg(my_id, 'Download started!', 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()