9.4. Поднятие канала связи#
Канальный уровень, рассмотренный на предыдущей странице, в основном работает автоматически, но есть одно место, где скрипту на Python приходится вмешаться: указать камере, к какой сети подключиться. Пока этот шаг не выполнится успешно, ни одна из сетевых возможностей, рассматриваемых в остальной части этого раздела, работать не будет.
9.4.1. Модуль network#
Модуль network предоставляет Python доступ к сетевому оборудованию камеры. Точный набор интерфейсов зависит от платы: у многих камер есть беспроводной чип, и они предоставляют класс WLAN (названный в честь Wireless Local Area Network); некоторые платы также имеют встроенный порт Ethernet и предоставляют класс LAN (названный в честь Local Area Network, то есть проводной версии). Шаблон использования одинаков для обоих, с одним важным отличием: беспроводному интерфейсу нужно указать, к какой сети подключиться, тогда как Ethernet подхватывает то, что находится на кабеле.
9.4.2. Процедура подключения к Wi-Fi#
Подключение к сети Wi-Fi состоит из трёх шагов: создать интерфейс, поднять его, попросить его подключиться к именованной сети с паролем. Интерфейс ведёт переговоры с точкой доступа в фоновом режиме; вызов isconnected() сообщает, когда канал связи окончательно поднялся:
import network
import time
wlan = network.WLAN(network.WLAN.IF_STA)
wlan.active(True)
wlan.connect("my-network", "my-password")
while not wlan.isconnected():
time.sleep_ms(100)
print("link up")
Аргумент IF_STA выбирает режим станции – камера присоединяется к сети, которую размещает кто-то другой. Противоположный режим, IF_AP, заставляет камеру разместить собственную небольшую сеть, к которой могут подключаться другие устройства; это полезно для интерфейсов настройки и развёртывания на месте, но не является обычным случаем.
Как только isconnected() возвращает True, камера находится в сети. Всё остальное, что требовалось более высоким уровням для собственной настройки, произошло автоматически, пока канал связи поднимался; на следующих страницах эти части расписываются по одной.
9.4.3. Что может пойти не так#
На этом шаге проявляется несколько практических режимов отказа.
Неверное имя сети или пароль. Попытка подключения молча повторяется, пока приложение не сдастся. Оберните ожидание тайм-аутом, чтобы приведённый выше цикл не блокировался навсегда:
start = time.ticks_ms() while not wlan.isconnected(): if time.ticks_diff(time.ticks_ms(), start) > 10000: raise OSError("Wi-Fi did not come up in 10 s") time.sleep_ms(100)
Вне зоны действия. Камера и точка доступа должны находиться достаточно близко, чтобы сигнал был достаточно сильным для удержания канала связи.
status()возвращает код, указывающий, почему канал связи не поднят;scan()возвращает список сетей, которые видит радиомодуль, – это диагностика, которую стоит запустить, когдаconnectне удаётся.Точка доступа требует больше, чем пароль. Открытые сети (без пароля) и распространённые сети, защищённые паролем, охватываются
connect, как показано выше. В более крупных сетях на рабочих местах и в учебных заведениях иногда используется другая схема, в которой камере приходится аутентифицироваться на отдельном сервере входа; для них нужны дополнительные аргументы дляconnect. Полный набор возможностей см. в класс WLAN – управление встроенными интерфейсами WiFi.
9.4.4. Поддержание соединения#
Поднять канал связи – это половина задачи. Поддержание соединения – другая половина: точки доступа перезагружаются, камера выходит из зоны действия, аренды DHCP истекают, прошивка радиомодуля иногда зависает. Камера, которая будет жить в сети месяцами, должна замечать это и восстанавливаться самостоятельно.
Шаблон обнаружения состоит в том, чтобы вызывать isconnected() один раз за итерацию основного цикла и реагировать, когда он возвращает False. isconnected() может ненадолго солгать, когда соединение разорвалось, а радиомодуль ещё не заметил этого – отправка через сокет, которая завершается неудачей, когда канал связи «должен» быть поднят, служит для приложения дополнительным свидетельством разрыва. status() – более авторитетный источник, когда эти два показателя расходятся.
Шаблон переподключения – это disconnect(), за которым следует connect() с теми же учётными данными, причём ожидание обёрнуто тайм-аутом, как при первоначальном подключении. Делайте задержки между попытками – одна секунда, две, четыре, удваивая примерно до минуты – чтобы длительный сбой не нагружал точку доступа и не расходовал энергетический бюджет радиомодуля на циклы ожидания:
import network
import time
_BACKOFF_S = (1, 2, 4, 8, 16, 32, 60)
def reconnect(wlan, ssid, password):
for delay in _BACKOFF_S:
wlan.disconnect()
wlan.connect(ssid, password)
deadline = time.ticks_add(time.ticks_ms(), 10_000)
while not wlan.isconnected():
if time.ticks_diff(deadline, time.ticks_ms()) < 0:
break
time.sleep_ms(100)
if wlan.isconnected():
return True
time.sleep(delay)
return False
Когда этот вспомогательный код продолжает возвращать False, может зависнуть сама прошивка радиомодуля. Последнее средство – перезапуск питания радиомодуля: active(False), короткая пауза, active(True), переподключение с нуля. Это возвращает прошивку радиомодуля в известное состояние ценой нескольких дополнительных секунд простоя:
def radio_power_cycle(wlan, ssid, password):
wlan.active(False)
time.sleep(1)
wlan.active(True)
return reconnect(wlan, ssid, password)
Камера, которая была вне сети несколько минут, – это реальный сбой, который приложение должно увидеть. Код восстановления должен отражать это состояние – помечать сеть как неработоспособную во флаге, который проверяет основной цикл, и позволять приложению пропускать сетевые отправки, которые оно сделало бы, пока флаг не сброшен, – чтобы длительный сбой не подвешивал приложение в ожидании сокетов, в которые никогда не удастся записать.
9.4.5. Ethernet, когда он есть#
Платы со встроенным Ethernet предоставляют тот же шаблон без шага connect. Интерфейс LAN поднимается с помощью active(), и как только кабель подключён, интерфейс готов к использованию:
import network
lan = network.LAN()
lan.active(True)
print("link up")
С этого момента остальные страницы этого раздела применяются одинаково, независимо от того, какой интерфейс вывел камеру в сеть. Более высоким уровням всё равно, является ли канал связи под ними Wi-Fi или Ethernet – «подключено» значит «подключено».
Полный справочник по WLAN и LAN, включая параметры конфигурации, которые сюда не поместились, см. в network — настройка сети.