MicroPython:Платы/WiPy/Общая информация о WiPy
Общая информация о WiPy[1]
Нет поддержки чисел с плавающей точкой
Из-за ограниченной памяти в WiPy-порте MicroPython нет поддержки чисел с плавающей точкой и модуля math. Это значит, что в коде для WiPy нельзя использовать числа с плавающей точкой, а все деления нужно выполнять при помощи «//» вместо «/». Пример:
>>> r = 4 // 2 # это будет работать
>>> r = 4 / 2 # это работать НЕ БУДЕТ
Перед подачей питания
Внимание! GPIO-контакты WiPy не устойчивы к 5-вольтовому напряжению. Если подключить их к напряжению выше 3.6 вольт, это нанесет плате непоправимый ущерб. АЦП-контакты, работая в аналоговом режиме, не выдерживают напряжение выше 1.8 вольт. Обязательно учитывайте это, собирая свои проекты с использованием WiPy. |
Поведение WLAN по умолчанию
Если WiPy загрузить с фабричными настройками по умолчанию, она запустится в режиме точки доступа c SSID, который начинается с wipy-wlan, и паролем www.wipy.io. Подключитесь к этой сети, и доступ к WiPy можно будет получить по адресу 192.168.1.1. Чтобы получить доступ к интерактивной оболочке, откройте Telnet-сессию с этим адресом на порте по умолчанию (23). Вас попросят ввести учетные данные: логин будет micro, а пароль – python.
REPL Telnet
Стандартный Linux’овский Telnet работает как часы (также используется в OSX), но и другие инструменты вроде PuTTy тоже работают нормально. Учетные данные по умолчанию: пользователь – micro, пароль – python. О том, как их изменить, читайте в описании класса network.Server (см. ниже). Вот пример использования в оболочке Linux (будучи подключенным к WiPy в режиме точки доступа):
$ telnet 192.168.1.1
Локальная файловая система и FTP-доступ
На WiPy есть маленькая внутренняя файловая система (диск) под названием «/flash», которая находится на внешней flash-памяти с доступом по последовательному интерфейсу. Если к WiPy подключена и смонтирована SD-карта, она тоже будет доступна.
При запуске WiPy загрузка всегда выполняется из файла «boot.py», который находится в «/flash» файловой системы. Кроме того, при запуске текущей директорией становится «/flash».
Эта файловая система доступна через нативный FTP-сервер, запущенный на WiPy. Откройте свой FTP-клиент и подключитесь к:
url: ftp://192.168.1.1, пользователь: micro, пароль: python.
О том, как поменять эти настройки, читайте в описании класса network.Server (см. ниже). Рекомендуемые клиенты: стандартный FTP-клиент Linux (также используется в OSX), Filezilla и FireFTP. Например, в оболочке Linux:
$ ftp 192.168.1.1
FTP-сервер на WiPy не поддерживает активный режим, только пассивный. Поэтому при использовании нативного FTP-клиента Unix сразу после залогинивания сделайте следующее:
ftp> passive
Помимо этого, в FTP-сервере поддерживается только одно одновременное подключение. Более подробно об этом читайте ниже, в разделе о настройках Filezilla.
Настройки Filezilla
Не используйте кнопку быстрого подключения. Вместо этого откройте «Менеджер сайтов» (Site Manager) и создайте новые настройки. На вкладке «Общие» (General) в меню «Шифрование» выберите «Использовать обычный FTP (небезопасно)» (Only use plain FTP (insecure)). На вкладке «Настройки передачи» (Transfer Settings) ограничьте максимальное количество подключений числом 1, т.к. в противном случае Filezilla попытается открыть второе управляющее соединение во время извлечения и сохранения файлов, поэтому в целях простоты и уменьшения размера кода должно быть только одно управляющее соединение и одно соединение для передачи данных. Возможно, другие FTP-клиенты тоже работают похожим образом.
Беспроводное (OTA) обновление прошивки
Беспроводные (OTA) обновления можно выполнять через FTP-сервер. Загрузите файл «mcuimg.bin» в «/flash/sys/mcuimg.bin» (это должно занять примерно 6 секунд). Вы, впрочем, не увидите, что этот файл сохранится в «/flash/sys/», потому что он сохраняется в обход пользовательской файловой системы. Он сохранится во внутренней скрытой файловой системе, но будьте уверены, что он был стопроцентно передан и сохранен и даже подписан при помощи контрольной суммы MD5 в целях защиты целостности. Затем сбросьте WiPy, нажав на переключатель на плате или написав:
>>> import machine
>>> machine.reset()
Программные обновления можно найти тут (Binaries.zip). Рекомендуем обновлять прошивку до самой последней версии, но сначала советуем прочесть описание внесенных в нее изменений.
Примечание! Файл «bootloader.bin» внутри архива «Binaries.zip» нужен только для примера. Для OTA-обновления он не нужен.
Узнать версию прошивки можно следующим образом:
>>> import os
>>> os.uname().release
Если номер версии меньше, чем у последнего релиза здесь, советуем обновить прошивку WiPy!
Режимы загрузки и безопасная загрузка
Если вы загрузились как обычно или нажали на кнопку сброса, WiPy загрузится в стандартном режиме: сначала будет выполнен файл «boot.py», а затем «main.py».
Эту очередность загрузки можно поменять, притянув контакт GP28 к состоянию HIGH (подключите его к 3.3-вольтовому выходному контакту) во время сброса. Эта процедура также позволяет откатиться к более старым версиям прошивки. WiPy может хранить до трех разных версий прошивок: одну фабричную и две пользовательские.
После сброса, если контакт GP28 находится в состоянии HIGH, светодиод сердцебиения начнет медленно мигать, и если спустя 3 секунды GP28 по-прежнему будет в состоянии HIGH, этот светодиод начнет мигать чуть быстрее, после чего WiPy выберет для загрузки предыдущую пользовательскую прошивку. Если эта предыдущая прошивка – это как раз то, что надо, GP28 нужно в течение ближайших 3 секунд переключить обратно на LOW. Если спустя 3 секунды на GP28 по-прежнему будет HIGH, будет выбрана фабричная прошивка, после чего светодиод быстро замигает в течение 1.5 секунды, а потом WiPy начнет загрузку.
Теперь попробуем описать этот механизм более наглядно. Если отключить подачу 3.3-вольтового напряжения от контакта загрузки GP28 в течение...
- ...первого 3-секундного окна, это выполнит безопасную загрузку и выберет последнюю прошивку.
- ...второго 3-секундного окна, это выполнит безопасную загрузку и выберет предыдущую пользовательскую прошивку.
- ...последнего 1.5-секундного окна, это выполнит безопасную загрузку и выберет фабричную прошивку.
Как видите, во всех этих трех сценариях будет выполнена безопасная загрузка, что означает, что выполнение файлов «boot.py» и «main.py» будет пропущено. Это полезно, если плата дала сбой из-за краша, вызванного пользовательским скриптом. Выбор прошивки в безопасном режиме не сохраняется, поэтому при следующем обычном сбросе WiPy вновь запустит последнюю прошивку.
Светодиод сердцебиения
По умолчанию светодиод сердцебиения мигает каждые 4 секунды, чтобы сообщить о том, что система «жива». Но его можно выключить при помощи модуля wipy.
>>> import wipy
>>> wipy.heartbeat(False)
В данный момент с помощью светодиода сердцебиения можно заметить два типа ошибок:
- Если он мигает быстро, это означает ошибку в Python-скрипте (например, «main.py»). Для отладки этой неисправности используйте REPL.
- Если он просто горит и не мигает, это означает аппаратный сбой. Программно исправить его не получится, единственный способ – это нажать на кнопку сброса.
Более подробно о режимах сна
- machine.idle() – энергопотребление около 12 мА (в режиме WLAN-станции). Источники пробуждения: любые аппаратные прерывания (включая системный таймер systick с периодичностью 1 мс), никаких специальных настроек не требуется.
- machine.lightsleep() – энергопотребление 950 мкА (в режиме WLAN-станции). Источники пробуждения: Pin, RTC и WLAN.
- machine.deepsleep() – энергопотребление около 350 мкА. Источники пробуждения: Pin и RTC.
Более подробно о классе «machine.Pin»
На плате WiPy контакты определяются их строковыми ID:
from machine import Pin
g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1)
Вы также можете настроить объект Pin на запуск прерываний. Например:
from machine import Pin
def pincb(pin):
print(pin.id())
pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN)
pin_int.irq(trigger=Pin.IRQ_RISING, handler=pincb)
# функцию обратного вызова можно запустить вручную:
pin_int.irq()()
# чтобы отключить функцию обратного вызова:
pin_int.irq().disable()
Теперь функция обратного вызова будет запускаться каждый раз, когда сигнал на GPIO-контакте перейдет в задний фронт. Внимание: механические кнопки страдают так называемым «дребезгом» – их нажатие и отпускание часто генерирует серию импульсов, отскакивающих к границам диапазона напряжения на контакте. Более подробно о дребезге и способах справиться с ним читайте здесь.
Все объекты Pin привязываются к GPIO-контактам при помощи привязывающей функции.
В аргументе drive можно задать следующую силу тока:
- Pin.LOW_POWER – контакт сможет работать с 2 мА.
- Pin.MED_POWER – контакт сможет работать с 4 мА.
- Pin.HIGH_POWER – контакт сможет работать с 6 мА.
Что касается аргумента alt, то здесь вам поможет вот эта таблица, где можно посмотреть, какие альтернативные функции поддерживаются разными контактами WiPy.
Аргумент priority нужен, чтобы задать приоритет прерывания (1-7). А в аргументе wake можно задать следующие значения:
- Если wake_from=machine.Sleep.ACTIVE, плату может пробудить любой контакт.
- Если wake_from=machine.Sleep.SUSPENDED, плату могут пробудить контакты GP2, GP4, GP10, GP11, GP17`` и GP24. Помните, что в этом случае источником пробуждения может быть только один из этих контактов одновременно. То есть в результате источником пробуждения будет тот контакт, которому самым последним задали machine.Sleep.SUSPENDED.
- Если wake_from=machine.Sleep.HIBERNATE, плату могут пробудить контакты GP2, GP4, GP10, GP11, GP17 и GP24. В этом случае источниками пробуждения можно сделать все эти 6 контактов одновременно – нужно лишь задать им machine.Sleep.HIBERNATE.
Дополнительные методы для класса Pin:
- machine.Pin.alt_list() – возвращает список альтернативных функций, поддерживаемых контактом. Это будет кортеж формата ('ALT_FUN_NAME', ALT_FUN_INDEX).
Более подробно о классе «machine.I2C»
На плате WiPy только один аппаратный I2C-блок (имеет идентификатор «0»). По умолчанию именно этот I2C-блок используется для конструирования экземпляра класса I2C. По умолчанию для SCL-линии будет использоваться контакт GP23, а для SDA-линии – контакт GP13. Объект I2C, использующий единственный аппаратный I2C-блок WiPy, конструируется очень просто:
i2c = machine.I2C()
Контакты и частоту можно задать следующим образом:
i2c = machine.I2C(freq=400000, scl='GP23', sda='GP13')
Для линий SDA/SCL можно использовать не все контакты WiPy. Более подробно смотрите в распиновке платы.
Известные проблемы
Несовместимость в создании SSL-сокетов
До обертки с помощью ssl.wrap_socket() SSL-сокеты нужно создавать следующим образом:
import socket
import ssl
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
ss = ssl.wrap_socket(s)
Сертификаты, используемые для проверки другой стороны подключения, а также для аутентификации, которую выполняет другая сторона в адрес нашей стороны, нужно использовать по порядку. Эти сертификаты нужно хранить в виде файлов при помощи FTP-сервера, в специальных местах и под специальными названиями.
- Сертификат для проверки другой стороны: «/flash/cert/ca.pem».
- Сертификат для аутентификации нашей стороны: «/flash/cert/cert.pem».
- Ключ для нашего собственного сертификата: «/flash/cert/private.key».
Примечание: Эти файлы сохраняются во внутреннюю скрытую файловую систему (как и обновления прошивки), что делает их невидимыми.
Например, чтобы при помощи сертификатов подключиться к серверам Blynk, возьмите файл «ca.pem», находящийся в папке с примерами для Blynk, и поместите его в «/flash/cert/».
Затем сделайте следующее:
import socket
import ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
Несовместимости в модуле «uhashlib»
Из-за аппаратных особенностей WiPy данные перед хэшированием должны быть буферизированы, что делает невозможным расчет хэша больших блоков данных – тех, что не влезают в RAM-память. Но есть и решение: поскольку в этом случае общий размер данных обычно известен заранее, этот размер можно передать конструктору, благодаря чему аппаратный хэш-движок WiPy можно инициализировать без использования буферизации. Если вы задали размер блока (block_size), нужно также указать первую порцию данных data. Используя это расширение, обязательно убедитесь, что размер всех промежуточных порций (включая первую) кратен 4 байтам. Последняя порция данных может быть любого размера.
Пример:
hash = uhashlib.sha1('abcd1234', 1001) # размер первой порции
# кратен 4 байтам
hash.update('1234') # тоже кратен 4 байтам
...
hash.update('12345') # последняя порция
# может быть любого размера
hash.digest()
Посторонняя функция в модуле «machine»
- main(filename) – задает главный скрипт filname, который будет запущен после выполнения «boot.py». Если не вызвать эту функцию, будет запущен «main.py», используемый по умолчанию.
Эту функцию имеет смысл вызывать только из «boot.py».
Особый способ управления серверами Telnet/FTP (через модуль «network»)
Класс Server управляет поведением и настройками FTP- и Telnet-серверов, запущенных на WiPy. Все изменения, сделанные с помощью методов этого класса, затронут серверы обоих типов.
Пример:
import network
server = network.Server()
server.deinit() # disable the server
# снова включаем сервер с новыми настройками:
server.init(login=('user', 'password'), timeout=600)
Конструктор
- class network.Server(id, ...) – создает экземпляр сервера. Аргументы для инициализации смотрите в описании метода init().
Методы
- server.init(\*, login=('micro', 'python'), timeout=300) – инициализирует (и фактически запускает) сервер. Опционально можно задать аргументы user, password и timeout (в секундах).
- server.deinit() – останавливает работу сервера.
- server.timeout([timeout_in_seconds]) – задает или считывает таймаут сервера.
- server.isrunning() – возвращает True, если сервер запущен, и False, если нет.
Особая поддержка VFS-подобных систем
В WiPy не реализована полная поддержка MicroPython VFS. Вместо этого в модуле uos есть следующие функции:
- mount(block_device, mount_point, \*, readonly=False) – монтирует блочное устройство (вроде объекта SD) в точке монтирования mount_point. Пример:
os.mount(sd, '/sd')
- unmount(path) – выполняет размонтирование ранее смонтированного блочного устройства по пути path.
- mkfs(block_device или path) – форматирует память, находящуюся по указанному пути (должно быть «/flash» или «/sd»). Также можно задать блочное устройство вроде объекта SD перед его монтированием.