Есть под рукой Raspberry Pi c подключенной к нему вот такой штукой:


Ещё есть кнопочка. Вот и появилось желание по нажатию кнопочки выводить на светодиодную матрицу что-то полезное, а не баловство. А еще подучить питон — ООП, потоки, парсинг и прочее. Можно сказать, что это мой первый полезный проект на питоне. Так что данная статья будет одновременно полезна для тех, кто хочет сделать домашний информер, и, кроме того, надеюсь, поучительная.
Для корректной работы матрицы с питоном нам потребуется вот такая штука. А информацию для вывода будем грузить с
Эти сервисы взяты для примера, полностью бесплатны. Можно использовать что угодно другое. При желании можно вывести и баллы пробок по Яндексу, но их не так-то просто получить.
Для уменьшения количества обращений к API можно кешировать результаты допустим раз в пол часа и по нажатии кнопки читать закешированное значение.
Теперь приступим к самому интересному. Для того, чтобы подключенные к распи кнопки начали что-то делать, необходимо написать скрипт-демон, который бы реагировал на изменения состояния GPIO. Рассмотрим пример такого скрипта, написанного на Python, который будет обрабатывать длинные и короткие нажатия каждой кнопки и их комбинаций.
Пусть имеем четыре кнопки. Я писал обработку кнопок последовательно, без цикла. Так проще и я не думаю, что у кого-то будет так много кнопок, что придется писать цикл.
Логика проста. Мы переводим указанный пин GPIO в режим считывания высокого напряжения. Далее мы входим в бесконечный цикл с небольшой паузой, в котором запоминаем нынешние значения пинов и сравниваем с предыдущими. Если значение отличается — статус кнопки изменился. А добавив еще и таймер, мы можем сделать триггер длинн��го нажатия кнопки по такой логике: если кнопка была нажата, а сейчас не нажата, и со времени нажатия прошло более 2 секунд, то реагируем на длинные нажатия кнопки.
Точно так же можно обрабатывать комбинации кнопок, добавив условие для двух (или более) кнопок одновременно. Итак, следующий скрипт обрабатывает длинные и короткие нажатия на четыре кнопки и одновременное нажатие на первую и вторую.
При нажатии определенной кнопки или комбинации будет вызываться соответствующий баш-скрипт из папки /leds+buttons. Создадим файлы-пустышки с соответствующим именем как в скрипте. Пример такого файла (button1long):
Теперь из нашего питоновского скрипта сделаем демон. Создадим файлик в папке /etc/init.d под названием buttondaemon
Теперь нам осталось вывести что-нибудь на LED-матрицу. Создадим питон-скрипт, который будет отрабатывать по нажатию кнопки. По непонятной причине urlget отрабатывает минимум секунды за две, при том что та же ссылка открывается браузером моментально. Для того, чтоб видеть начало работы скрипта, а не втыкать 2 секунды в пустую матрицу, скрипт будет показывать анимацию пока грузятся данные.
Сначала покажем текущую температуру и осадки. Чтоб понять, что на экране температура, в правом верхнем углу покажем точку, символизирующую знак градуса.
Чтоб показать двухзначные числа на экране компактненько, нарисуем циферки в размере 3х6:
Про осадки отдельно. Хотелось показать их на одном экране с температурой. Поэтому они отображаются в виде точек количеством от нуля до трех в левом верхнем углу.
Все запросы траффика и курса валют выполнимв это время на фоне в параллельных потоках. Смена данных на матрице анимируется сдвигом. Если загрузить какие-то данные не удалось, вместо них будет показан грустный смайлик.
Протестировав, что всё работает, повесим вызов информера на кнопку:
Итогом всего этого должно получится что-то такое — 7 градусов, ясно, пробки 2 балла, курс евро к гривне 32.02:
Спасибо за внимание!

Ещё есть кнопочка. Вот и появилось желание по нажатию кнопочки выводить на светодиодную матрицу что-то полезное, а не баловство. А еще подучить питон — ООП, потоки, парсинг и прочее. Можно сказать, что это мой первый полезный проект на питоне. Так что данная статья будет одновременно полезна для тех, кто хочет сделать домашний информер, и, кроме того, надеюсь, поучительная.
Для корректной работы матрицы с питоном нам потребуется вот такая штука. А информацию для вывода будем грузить с
- bank-ua.com
- worldweatheronline.com
Эти сервисы взяты для примера, полностью бесплатны. Можно использовать что угодно другое. При желании можно вывести и баллы пробок по Яндексу, но их не так-то просто получить.
Получение баллов Яндекс.Пробок
Нам понадобится:
веб-сервер з PHP – к примеру, www.penguintutor.com/linux/light-webserver;
xvfb – sudo apt-get install xvfb;
CutyCapt – cutycapt.sourceforge.net;
Результат: картинка с заторами и текстовый файлик со значением баллов заторов.
save.php
probki.html
Теперь, если открыть этот файлик в браузере, мы увидим карту с пробками, виджет погоды и пробок, а самое главное — в папке "@" появится файлик probki.txt со значением пробок и их картинка. После этого можем заставить наш сервер открывать эту страницу автоматически по заданному расписанию. Итак, добавим в cron следующее:
веб-сервер з PHP – к примеру, www.penguintutor.com/linux/light-webserver;
xvfb – sudo apt-get install xvfb;
CutyCapt – cutycapt.sourceforge.net;
Результат: картинка с заторами и текстовый файлик со значением баллов заторов.
save.php
<?php $f = "@/probki.txt"; $fileHandle = fopen($f, 'w') or die("Unable to open the ".$f); fwrite($fileHandle, $_GET["val"]); fclose($fileHandle); echo file_get_contents($f); ?>
probki.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Пробки</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="//api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script> <style> html, body, #map { width: 100%; height: 100%; padding: 0; margin: 0; } </style> <script type="text/javascript"> ymaps.ready(init); function init () { var myMap = new ymaps.Map("map", { //Это Киев. Поставьте здесь значение которое Вам нужно. center: [50.47,30.54], zoom: 12, controls: [] }); // Создадим провайдер пробок "Сейчас" с включенным слоем инфоточек. var actualProvider = new ymaps.traffic.provider.Actual({}, { infoLayerShown: true }); // И потом добавим его на карту. actualProvider.setMap(myMap); actualProvider.state.events.add("change", function () { var jamlevel = actualProvider.state.get("level"); if (jamlevel!== null) { //Здесь основная фишка - если вставить вместо пути картинки PHP файлик, то браузер обратится к нему, пытаясь отобразить картинку. document.getElementById("val").src="save.php?val="+jamlevel; } }); } </script> </head> <body bgcolor="#555555"> <!-- тут выведем погоду --> <div style="position: absolute;left: 30px; top: 0px; z-index: 2;"> <a href="http://clck.yandex.ru/redir/dtype=stred/pid=7/cid=1228/*http://pogoda.yandex.ru/kyiv"><img src="http://info.weather.yandex.net/kyiv/2_white.uk.png" border="0" alt="$ <img width="1" height="1" src="http://clck.yandex.ru/click/dtype=stred/pid=7/cid=1227/*http://img.yandex.ru/i/pix.gif" alt="" border="0"/></a> </div> <!-- а тут виведем красивую картинку про заторы --> <div style="position: absolute; right: 30px; top: 0px; z-index: 3;"> <img src="http://info.maps.yandex.net/traffic/kiev/tends_200.png" alt="Пробки на Яндекс.Картах" border="0"/> </div> <div id="map"> </div><!-- тут наша невидимая PHP картинка --> <img id="val" src="" style="display:none" /> </body> </html>
Теперь, если открыть этот файлик в браузере, мы увидим карту с пробками, виджет погоды и пробок, а самое главное — в папке "@" появится файлик probki.txt со значением пробок и их картинка. После этого можем заставить наш сервер открывать эту страницу автоматически по заданному расписанию. Итак, добавим в cron следующее:
/usr/bin/xvfb-run -a -s "-screen 0 1600x1200x16" /usr/bin/CutyCapt --url=http://mywebsite/probki.html --out=/var/www/mywebsite/@/probki.jpg --javascript=on --delay=5000 --min-width=1600 --min-height=1200
Для уменьшения количества обращений к API можно кешировать результаты допустим раз в пол часа и по нажатии кнопки читать закешированное значение.
Кэширование погоды, курса валют и пробок
#!/bin/bash ########################################################### echo $(date +%F/%T%Z) "UpdateInfo started" > /var/log/updateinfo rm -f /var/www/mywebsite/@/currrate.xml /usr/bin/wget http://bank-ua.com/export/currrate.xml -P /var/www/mywebsite/@/ -q -N echo $(date +%F/%T%Z) "UpdateInfo currate" >> /var/log/updateinfo rm -f /var/www/mywebsite/@/weather.json /usr/bin/wget "http://api.worldweatheronline.com/free/v1/weather.ashx?q=Kyyiv&format=json&extra=localObsTime&num_of_days=5&includelocation=yes&lang=uk&key=13a4e16719a757403c5db6f4a8f3067e4534b4d8" -O /var/www/mywebsite/@/weather.json -q -N echo $(date +%F/%T%Z) "UpdateInfo weather" >> /var/log/updateinfo rm -f /var/www/mywebsite/@/probki.jpg rm -f /var/www/mywebsite/@/probki.txt /usr/bin/xvfb-run -a -s "-screen 0 1600x1200x16" /usr/bin/CutyCapt --url=http://mywebsite/probki.php --out=/var/www/mywebsite/@/probki.jpg --javascript=on --delay=5000 --min-width=1600 --min-height=1200 echo $(date +%F/%T%Z) "UpdateInfo Traffic" >> /var/log/updateinfo
Теперь приступим к самому интересному. Для того, чтобы подключенные к распи кнопки начали что-то делать, необходимо написать скрипт-демон, который бы реагировал на изменения состояния GPIO. Рассмотрим пример такого скрипта, написанного на Python, который будет обрабатывать длинные и короткие нажатия каждой кнопки и их комбинаций.
Пусть имеем четыре кнопки. Я писал обработку кнопок последовательно, без цикла. Так проще и я не думаю, что у кого-то будет так много кнопок, что придется писать цикл.
Логика проста. Мы переводим указанный пин GPIO в режим считывания высокого напряжения. Далее мы входим в бесконечный цикл с небольшой паузой, в котором запоминаем нынешние значения пинов и сравниваем с предыдущими. Если значение отличается — статус кнопки изменился. А добавив еще и таймер, мы можем сделать триггер длинн��го нажатия кнопки по такой логике: если кнопка была нажата, а сейчас не нажата, и со времени нажатия прошло более 2 секунд, то реагируем на длинные нажатия кнопки.
Точно так же можно обрабатывать комбинации кнопок, добавив условие для двух (или более) кнопок одновременно. Итак, следующий скрипт обрабатывает длинные и короткие нажатия на четыре кнопки и одновременное нажатие на первую и вторую.
buttondaemon.py
# This Python file uses the following encoding: utf-8 import RPi.GPIO as GPIO import time import os import sys import logging logger = logging.getLogger('buttons_daemon') hdlr = logging.FileHandler('/MyLogs/main.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.WARNING) suffix = " > /dev/null&" #adjust for where your switch is connected button1Pin = 18 button2Pin = 13 button3Pin = 16 button4Pin = 15 prev_input1 = 0 prev_input2 = 0 prev_input3 = 0 prev_input4 = 0 btimer12 = 0 btimer1= 0 btimer2= 0 btimer3= 0 btimer4= 0 GPIO.setmode(GPIO.BOARD) GPIO.setup(button1Pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(button2Pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(button3Pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(button4Pin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) while True: #assuming the script to call is long enough we can ignore bouncing input1 = GPIO.input(button1Pin) input2 = GPIO.input(button2Pin) input3 = GPIO.input(button3Pin) input4 = GPIO.input(button4Pin) if (input1): btimer1 += 1 if (input2): btimer2 += 1 if (input3): btimer3 += 1 if (input4): btimer4 += 1 #Some button up if ((not input1) and (not input2) and (not input3) and (not input4) and ( (prev_input1) or (prev_input2) or (prev_input3) or (prev_input4) ) ): #Button 12 if ((prev_input1) and (prev_input2) and (not prev_input3) and (not prev_input4) ): if ((btimer1>20) and (btimer2>20)): logger.warning("Button12 long"); os.system("sudo /leds+buttons/button12long"+suffix) else: logger.warning("Button12"); os.system("sudo /leds+buttons/button12"+suffix) #Button 1 if ((prev_input1) and (not prev_input2) and (not prev_input3) and (not prev_input4) ): if (btimer1>20): logger.warning("Button1 long"); os.system("sudo /leds+buttons/button1long"+suffix) else: logger.warning("Button1"); os.system("sudo /leds+buttons/button1"+suffix) #Button 2 if ((prev_input2) and (not prev_input1) and (not prev_input3) and (not prev_input4) ): if (btimer2>20): logger.warning("Button2 long"); os.system("sudo /leds+buttons/button2long"+suffix) else: logger.warning("Button2"); os.system("sudo /leds+buttons/button2"+suffix) #Button 3 if ((prev_input3) and (not prev_input2) and (not prev_input1) and (not prev_input4) ): if (btimer3>20): logger.warning("Button3 long"); os.system("sudo /leds+buttons/button3long"+suffix) else: logger.warning("Button3"); os.system("sudo /leds+buttons/button3"+suffix) #Button 4 if ((prev_input4) and (not prev_input2) and (not prev_input3) and (not prev_input1) ): if (btimer4>20): logger.warning("Button4 long"); os.system("sudo /leds+buttons/button4long"+suffix) else: logger.warning("Button4"); os.system("sudo /leds+buttons/button4"+suffix) btimer1=0 btimer2=0 btimer3=0 btimer4=0 prev_input1 = input1 prev_input2 = input2 prev_input3 = input3 prev_input4 = input4 time.sleep(0.2)
При нажатии определенной кнопки или комбинации будет вызываться соответствующий баш-скрипт из папки /leds+buttons. Создадим файлы-пустышки с соответствующим именем как в скрипте. Пример такого файла (button1long):
#!/bin/bash echo Button 1 pressed | wall #Do something exit
Теперь из нашего питоновского скрипта сделаем демон. Создадим файлик в папке /etc/init.d под названием buttondaemon
buttondaemon
Команда start запускает наш питоновский скрипт, а команда stop его останавливает. Раздадим всем скриптам нужные права. Теперь можем испытать, набрав в консоли:
и пожмакаем кнопки, смотря что будет отображаться на экране. Вуаля!
#! /bin/sh # /etc/init.d/buttondaemon ### BEGIN INIT INFO # Provides: buttondaemon # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Daemon to control button events # Description: Daemon which starts python script to control GPIO button events. ### END INIT INFO # If you want a command to always run, put it here # Carry out specific functions when asked to by the system case "$1" in start) echo "Starting button daemon" # run application you want to start sudo python /leds+buttons/buttondaemon.py& ;; stop) echo "Stopping button daemon" # kill application you want to stop kill -9 $(ps -ef | grep -v "grep" | grep buttondaemon.py | awk '{ print $2 }') &> /dev/null ;; *) echo "Usage: /etc/init.d/buttondaemon {start|stop}" exit 1 ;; esac exit 0
Команда start запускает наш питоновский скрипт, а команда stop его останавливает. Раздадим всем скриптам нужные права. Теперь можем испытать, набрав в консоли:
sudo /etc/init.d/buttondaemon start
и пожмакаем кнопки, смотря что будет отображаться на экране. Вуаля!
Теперь нам осталось вывести что-нибудь на LED-матрицу. Создадим питон-скрипт, который будет отрабатывать по нажатию кнопки. По непонятной причине urlget отрабатывает минимум секунды за две, при том что та же ссылка открывается браузером моментально. Для того, чтоб видеть начало работы скрипта, а не втыкать 2 секунды в пустую матрицу, скрипт будет показывать анимацию пока грузятся данные.
Сначала покажем текущую температуру и осадки. Чтоб понять, что на экране температура, в правом верхнем углу покажем точку, символизирующую знак градуса.
Чтоб показать двухзначные числа на экране компактненько, нарисуем циферки в размере 3х6:
digits.py
#!/usr/bin/env python # -*- coding: utf-8 -*- rows = 6 columns = 3 symbol = [[[0 for x in range(columns)] for x in range(rows)] for x in range(10)] symbol[1] = [ [0,0,1], [0,1,1], [0,0,1], [0,0,1], [0,0,1], [0,0,1], ] symbol[2] = [ [1,1,1], [0,0,1], [1,1,1], [1,0,0], [1,0,0], [1,1,1], ] symbol[3] = [ [1,1,1], [0,0,1], [0,1,1], [0,0,1], [0,0,1], [1,1,1], ] symbol[4] = [ [1,0,0], [1,0,0], [1,0,1], [1,1,1], [0,0,1], [0,0,1], ] symbol[5] = [ [1,1,1], [1,0,0], [1,1,1], [0,0,1], [0,0,1], [1,1,1], ] symbol[6] = [ [1,1,1], [1,0,0], [1,1,1], [1,0,1], [1,0,1], [1,1,1], ] symbol[7] = [ [1,1,1], [0,0,1], [0,1,0], [0,1,0], [0,1,0], [0,1,0], ] symbol[8] = [ [1,1,1], [1,0,1], [0,1,0], [1,0,1], [1,0,1], [1,1,1], ] symbol[9] = [ [1,1,1], [1,0,1], [1,0,1], [1,1,1], [0,0,1], [1,1,1], ] symbol[0] = [ [1,1,1], [1,0,1], [1,0,1], [1,0,1], [1,0,1], [1,1,1], ]
Про осадки отдельно. Хотелось показать их на одном экране с температурой. Поэтому они отображаются в виде точек количеством от нуля до трех в левом верхнем углу.
Все запросы траффика и курса валют выполнимв это время на фоне в параллельных потоках. Смена данных на матрице анимируется сдвигом. Если загрузить какие-то данные не удалось, вместо них будет показан грустный смайлик.
informer.py
#!/usr/bin/env python # -*- coding: utf-8 -*- import max7219.led as led import max7219.font as font import threading, sys, time import digits import urllib2 import json import xml.etree.ElementTree as ET debug=0 def log(message): if debug==1: print(message) device = led.matrix(cascaded=1) device.brightness(0) hourglass = [ [0,1,1,1,1,1,1,0], [0,1,0,0,0,0,1,0], [0,0,1,0,0,1,0,0], [0,0,0,1,1,0,0,0], [0,0,0,1,1,0,0,0], [0,0,1,0,0,1,0,0], [0,1,0,0,0,0,1,0], [0,1,1,1,1,1,1,0], ] jopa = [ [0,0,1,1,1,1,1,0], [0,1,1,1,1,1,1,1], [0,1,0,0,1,0,0,1], [0,1,1,1,1,1,1,1], [0,0,1,1,0,1,1,0], [0,0,1,1,1,1,1,0], [0,0,1,1,1,1,1,0], [0,0,1,0,1,0,1,0], ] sad = [ [0,0,1,1,1,1,0,0], [0,1,0,0,0,0,1,0], [1,0,1,0,0,1,0,1], [1,0,0,0,0,0,0,1], [1,0,0,1,1,0,0,1], [1,0,1,0,0,1,0,1], [0,1,0,0,0,0,1,0], [0,0,1,1,1,1,0,0], ] #Thread with wait animation class TAnimationThread (threading.Thread): def __init__(self, threadID): threading.Thread.__init__(self) self.threadID = threadID self.Continue=True def run(self): log("Starting animation") counter=0 while (self.Continue): DrawAnimation(counter) counter+=1 if counter==7: counter=0 time.sleep(0.8) def stop(self): self.Continue = False log("Stopping animation") def DrawAnimation(counter): #draw log("Drawing animation"+str(counter)) if counter==0: for j in range(8): for i in range(8): if hourglass[j][i] == 1: device.pixel(i, 7-j, 1, redraw=False) elif counter>0 and counter<5: device.pixel(1+counter, 1, 1, redraw=False) elif counter==5 or counter==6: device.pixel(counter-2, 2, 1, redraw=False) else: device.clear() device.flush() def fetch_traffic(url): global TrafficData try: response = urllib2.urlopen(url) TrafficData = int(response.read()) log("Traffic fetched") except BaseException: TrafficData=-100 log(TrafficData) def fetch_currrate(url): global CurrencyData try: response = urllib2.urlopen(url) root = ET.fromstring(response.read()) CurrencyData=float(root[16][5].text)/100 log("Currency fetched") except BaseException: CurrencyData=-100 log(CurrencyData) #Let's begin log("Starting animation thread") AnimationThread = TAnimationThread(1) AnimationThread.start() log("Starting traffic thread") TrafficThread = threading.Thread(target=fetch_traffic, args=("http://tarasius.name/@/probki.txt",)) TrafficThread.start() CurrencyThread = threading.Thread(target=fetch_currrate, args=("http://tarasius.name/@/currrate.xml",)) CurrencyThread.start() # Get and show temperature log("Starting weather fetch") try: response = urllib2.urlopen("http://tarasius.name/@/weather.json") data = json.loads(response.read()) response.close() temp = int(data["data"]["current_condition"][0]["temp_C"]) precip = float(data["data"]["current_condition"][0]["precipMM"]) temp1 = abs(temp)/10 temp2 = abs(temp)%10 except BaseException: temp=-100 precip=-100 temp1=-100 temp2=-100 log("Stopping animation thread") AnimationThread.stop() device.clear() device.flush() m = [[0 for x in range(8)] for x in range(64)] if precip==-100: #cloudcover was unavailable for j in range(8): for i in range(8): if sad[i][j] == 1: m[j][7-i]=1 #draw cloudcover elif precip>1.5: m[0][7] = 1 m[2][7] = 1 m[4][7] = 1 elif precip<=1.5 and precip>0.5: m[1][7] = 1 m[3][7] = 1 elif precip<=0.5 and precip>0.1: m[2][7] = 1 if temp>-100: if temp<0: #Draw minus m[0][3] = 1 if temp1==0: m[1][3]=1 m[2][3]=1 m[3][3]=1 if temp1<>0: #Draw first digit for j in range(digits.rows): for i in range(digits.columns): if digits.symbol[temp1][j][i] == 1: m[i+1][5-j] = 1 #draw second digit for j in range(digits.rows): for i in range(digits.columns): if digits.symbol[temp2][j][i] == 1: m[i+5][5-j] = 1 #draw celsium sign m[7][7] = 1 log("Drawing temperature") for i in range(8): for j in range(8): if m[j][i]==1: device.pixel(j, i, 1, redraw=False) device.flush() time.sleep(5) #Show traffic #Draw first digit TrafficThread.join() if TrafficData==10: for j in range(8): for i in range(8): if jopa[j][i] == 1: m[10+i][j]=1 elif TrafficData==-100: for j in range(8): for i in range(8): if sad[j][i] == 1: m[10+i][7-j]=1 else: #draw car m[10][6]=1 m[10][3]=1 m[11][7]=1 m[11][6]=1 m[11][5]=1 m[11][4]=1 m[11][3]=1 m[11][2]=1 m[12][5]=1 m[12][4]=1 TrafficData = TrafficData%10 #draw second digit for j in range(digits.rows): for i in range(digits.columns): if digits.symbol[TrafficData][j][i] == 1: m[i+15][5-j]=1 log("Drawing traffic") for step in range(9): device.clear() for i in range(8): for j in range(8): if m[i+step+2][j]==1: device.pixel(i, j, 1, redraw=False) device.flush() time.sleep(0.2) time.sleep(5) #Show currency CurrencyThread.join() if CurrencyData==-100: for j in range(8): for i in range(8): if sad[j][i] == 1: m[22+i][7-j]=1 else: cur=str(CurrencyData) for d in range(5): if cur[d]==".": digit=-1 else: digit=int(cur[d]) if digit==-1: m[22+d*5][0]=1 else: for j in range(digits.rows): for i in range(digits.columns): if digits.symbol[digit][j][i] == 1: m[i+21+d*5][5-j]=1 log("Drawing currency") for step in range(36): device.clear() for i in range(8): for j in range(8): if m[i+step+11][j]==1: device.pixel(i, j, 1, redraw=False) device.flush() time.sleep(0.2) device.clear() device.flush() sys.exit()
Протестировав, что всё работает, повесим вызов информера на кнопку:
#!/bin/bash echo "Button 1 pressed" | wall python /leds+buttons/informer.py > /dev/null& exit
Итогом всего этого должно получится что-то такое — 7 градусов, ясно, пробки 2 балла, курс евро к гривне 32.02:
Спасибо за внимание!
