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() з тими самими обліковими даними, з очікуванням, обгорнутим у тайм-аут, як і при початковому підключенні. Відступайте між спробами – одна секунда, дві, чотири, подвоюючи до хвилини чи близько того – щоб тривале відключення не навантажувало AP і не витрачало бюджет енергії радіо на spin-цикли:
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 — налаштування мережі.