
ESP-Jumpstart: быстрое создание приложений на ESP32. Часть 3
Завершающая статья из цикла ESP-Jumpstart расскажет как добавить в прошивку облачные функции, OTA обновления и индивидуальные ключи и идентификаторы для устройства. В результате вы получите готовую реализацию работающего в облаке IoT устройства с функционалом умной розетки.
Истинный потенциал "умных" устройств может быть раскрыт, когда подключение к сети используется для удаленного управления. В этой статье мы подключим интеллектуальную розетку к облачной платформе и включим дистанционное управление и мониторинг устройства.
Как правило, это достигается с помощью одного из сценариев, показанных на рисунке.
Рис.1. Облачные подключения
В большинстве случаев, когда устройство подключено к облаку, платформа предоставляет возможность управления и мониторинга через RESTful web API. Клиенты, прошедшие авторизацию, например приложения для смартфонов, могут использовать эти API для удаленного доступа к устройству.
Кроме того, интеграция с различными облачными сервисами также может увеличить ценность решения для пользователей. Например, умный термостат может быть связан с системой, предоставляющей информацию о погоде или с облачными интерфейсами голосового помощника (например, Alexa или Google Voice Assistant) для голосового управления.
Безопасность прежде всего
Прежде чем мы углубимся в детали работы с облачными сервисами, несколько слов о безопасности.
Соединение с любой удаленной облачной инфраструктурой всегда должно осуществляться с использованием TLS (Transport Layer Security). Это стандарт, и он позволяет сделать связь безопасной. Это протокол транспортного уровня. Любые высокоуровневые протоколы, такие как HTTP или MQTT, могут использовать TLS в качестве основного транспорта. Все известные поставщики облачных услуг предоставляют сервис подключения устройств по протоколу TLS.
Сертификаты CA
Одним из аспектов TLS является проверка сервера с использованием сертификатов CA. TLS использует сертификат CA для проверки того, что вы действительно общаетесь с сервером, с которым должны общаться. Чтобы эта проверка прошла, на ваше устройство должен быть предварительно загружен один или несколькими действительных и доверенных сертификатов CA. TLS будет использовать их в качестве доверенных сертификатов, а затем проверять сервер на основе этих доверенных сертификатов. В следующей главе будет рассказано, как сделать сертификат CA частью вашей прошивки.
Встраивание файлов в прошивку
Время от времени прошивка должна использовать определенные файлы напрямую. Например, сертификаты CA должны быть встроены в прошивку для проверки сервера.
Вопрос в том, как сделать все содержимое этих файлов частью образа прошивки и как получить к ним доступ в своей прошивке?
ESP-IDF предоставляет отличный механизм для этого. Component.mk файл может быть использован для информирования системы сборки, что содержимое некоторых файлов должно быть встроено в образ микропрограммы. Это можно сделать, добавив следующую строку в файл component.mk вашего приложения.
COMPONENT_EMBED_TXTFILES := cloud_cfg/server.cert
В приведенном выше примере система сборки сделает файл cloud_cfg/server.cert частью прошивки. Содержимое этого файла находится в адресном пространстве встроенного программного обеспечения и может быть напрямую использовано следующим образом:
extern const uint8_t certificate_pem_crt_start[] asm("_binary_server_cert_start");
extern const uint8_t certificate_pem_crt_end[] asm("_binary_server_cert_end");
Доступ к файлу можно получить, используя приведенные выше указатели на начало и конец области памяти.
AWS IoT
В этой главе мы рассмотрим подключение устройства к AWS IoT.
Быстрая настройка
Если у вас уже есть зарегистрированный аккаунт на облачной платформе, этот раздел можно пропустить.
Для упрощения регистрации мы создали веб-страницу, которая позволяет быстро подключить устройство к облачной платформе AWS IoT. На этой странице будет создан набор учетных данных для вашего устройства, которые могут использоваться для аутентификации в облаке. Учетные данные будут действовать в течение 14 дней, что даст вам достаточно времени для экспериментов с функцией дистанционного управления и обновлениями OTA. По истечении этого срока вы можете самостоятельно создать учетную запись AWS и использовать облако в своей работе.
Как создать учетные данные для своего устройства:
- Зайдите на адрес: https://espressif.github.io/esp-jumpstart/
- Введите адрес электронной почты, на который должны быть отправлены учетные данные устройства.
- Вы получите письмо, содержащее учетные данные устройства, которые нужно занести в прошивку.
Демо
Чтобы начать работать с облаком, у вас должны быть подготовлены несколько файлов:
- Закрытый ключ устройства;
- Сертификат устройства;
- Идентификатор устройства;
- Сертификат CA для доменного имени службы AWS-IoT;
- Адрес точки доступа.
Прежде чем углубляться в код, давайте просто проверим, как работает устройство с подключением к облаку. Воспользуемся кодом из папки 5_cloud/ проекта esp-jumpstart.
Чтобы настроить работу с AWS IoT, сделайте следующее:
- Перейдите в каталог 5_cloud/
- Скопируйте файлы (перезаписав имеющиеся), как указано ниже: (Обратите внимание, что некоторые почтовые клиенты могут переименовывать файлы и добавлять к ним расширение .txt. Убедитесь, что загруженные файлы имеют правильные наименования):
- Сертификат AWS CA в 5_cloud/main/cloud_cfg/server.cert
- Закрытый ключ устройства в 5_cloud/main/cloud_cfg/device.key
- Сертификат устройства в 5_cloud/main/cloud_cfg/device.cert
- Идентификатор устройства в 5_cloud/main/cloud_cfg/deviceid.txt
- Адрес точки доступа в 5_cloud/main/cloud_cfg/endpoint.txt
- Соберите прошивку и загрузите ее в контроллер.
Теперь устройство должно подключиться к облачной платформе AWS IoT и передавать в облако любые изменения состояния. Контроллер также будет получать изменения состояния из облака.
Дистанционное управление
Для удаленного управления AWS IoT предоставляет RESTful веб-API для всех подключенных к нему устройств. Приложения (в том числе и на телефоне) могут взаимодействовать с этим API для управления и мониторинга устройства. Для симуляции приложения воспользуемся утилитой cURL.
С помощью следующей команды curl, мы можем прочитать текущее состояние устройства:
curl --tlsv1.2 --cert cloud_cfg/device.cert \
--key cloud_cfg/device.key \
https://a3orti3lw2padm-ats.iot.us-east-1.amazonaws.com:8443/things/<contents-of-deviceid.txt-file>/shadow \
| python -mjson.tool
В приведенной выше команде нужно заменить <contents-of-deviceid.txt-file> на идентификатор устройства из присланного файла.
Примечание. Для доступа к состоянию устройства в AWS нужно предоставить корректные ключи из файлов device.cert и device.key. Убедитесь, что команда ссылается на те же файлы, что были настроены в прошивке. Это гарантирует прохождение авторизации для доступа к состоянию устройства. В продакшен версии необходимо создать отдельные ключи аутентификации в облаке для клиентов, таких как curl или приложения, для доступа/изменения состояния устройства.
Состояние устройства может быть изменено с помощью следующей команды:
curl -d '{"state":{"desired":{"output":false}}}' \
--tlsv1.2 --cert cloud_cfg/device.cert \
--key cloud_cfg/device.key \
https://a3orti3lw2padm-ats.iot.us-east-1.amazonaws.com:8443/things/<contents-of-deviceid.txt-file>/shadow \
| python -mjson.tool
Она сформирует HTTP POST запрос с данными JSON в теле запроса. Эти данные переведут состояние устройства в false.
Вы можете наблюдать соответствующее изменение состояния устройства всякий раз при передаче нового состояния с помощью команды cURL.
Дистанционное управление работает. Давайте теперь посмотрим на код.
Код
Весь код для работы с облаком расположен в файле cloud_aws.c. Структура в этом файле соответствует AWS IoT SDK.
Код использует API драйвера из предыдущих статей, app_driver_get_state () и app_driver_toggle_state () для получения и изменения состояния выхода контроллера.
Для работы с AWS IoT в прошивку нужно встроить 3 файла:
- Сертификат AWS CA 5_cloud/main/cloud_cfg/server.cert
- Закрытый ключ устройства 5_cloud/main/cloud_cfg/device.key
- Сертификат устройства 5_cloud/main/cloud_cfg/device.cert
Для этого используется описанный ранее механизм встраивания.
В качестве следующего шага давайте рассмотрим одно из самых распространенных требований к подключенному устройству - OTA обновление прошивки.
ОТА обновление прошивки
Прежде чем мы обсудим обновление прошивки, рассмотрим из каких разделов состоит флэш-память.
Разделы Flash памяти
ESP-IDF разделяет флэш-память на несколько логических разделов для хранения различных компонентов. Типичный способ деления показан на рис. 2.
Рис.2. Структура разделов Flash
Как видно, структура является статической до адреса флэш-памяти 0x9000. Первая часть флэш-памяти содержит загрузчик, за которым сразу же следует таблица разделов. В таблице разделов хранится информация о том, как следует интерпретировать остальную часть флэш-памяти. Обычно в памяти будет как минимум 1 раздел NVS и 1 раздел прошивки.
Механизм ОТА
Для обновления прошивки используется активно-пассивная схема разделов. Два раздела флэш-памяти зарезервированы для компонента «прошивка», как показано на рис. 3. Раздел OTA Data запоминает, какой из них является активным разделом.
Рис.3. Flash разделы для реализации OTA
Процесс обновления прошивки происходит следующим образом:
- Шаг 0: OTA 0 - активная прошивка. Раздел данных OTA data хранит эту информацию.
- Шаг 1: Процесс обновления прошивки начинается. Пассивный раздел OTA 1 идентифицирован, очищен и в него записывается новая прошивка.
- Шаг 2: Обновленная прошивка полностью записана, и выполняется ее проверка.
- Шаг 3. Обновление прошивки считается успешным, в раздел OTA data заносится информация о том, что OTA 1 теперь является активным разделом. При следующей загрузке будет использована прошивка из этого раздела.
Рис. 4. Процесс обновления прошивки
Обновление разделов Flash
Итак, как именно дать указание IDF создать таблицу разделов, в которой есть разделы OTA-Data и 2 раздела для хранения прошивки?
Это может быть достигнуто путем создания специального файла разделов. Это простой CSV файл, который инструктирует IDF, какие разделы нужны, каков их размер и как их размещать.
Файл разделов, который используется для этого примера, показан ниже:
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset
# make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, , 0x6000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1600K,
ota_1, app, ota_1, , 1600K,
Приведенный выше файл разделов заставит IDF создать разделы: NVS, OTA-Data, OTA 0 и OTA 1 определенных размеров.
После того как мы создадим этот файл раздела, мы должны дать команду IDF использовать этот файл, а не стандартное разделение памяти. Это можно сделать, обновив конфигурацию SDK. Для тестирования воспользуемся папкой 6_ota/, в файле конфигурации которой 6_ota/sdkconfig.defaults уже внесены необходимые изменения.
Но если вы хотите использовать другой файл разделов или изменить смещение основной прошивки, вам следует изменить файл. Это можно сделать, выполнив команду make menuconfig , а затем настроив правильные параметры в menuconfig -> Таблица разделов.
Для пользователей ESP8266
Если ваша плата ESP8266 имеет 2 МБ флэш-памяти, используйте следующую таблицу разделов.
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x4000,
otadata, data, ota, 0xd000, 0x2000,
phy_init, data, phy, 0xf000, 0x1000,
ota_0, app, ota_0, 0x10000, 0xC5000,
ota_1, app, ota_1, 0x110000, 0xC5000,
Код
Теперь давайте посмотрим на код для фактического выполнения обновления прошивки.
esp_http_client_config_t config = {
.url = url,
.cert_pem = (char *)upgrade_server_cert_pem_start,
};
esp_err_t ret = esp_https_ota(&config);
- Структура esp_http_client_config_t используется для определения источника обновления OTA. Она включает в себя URL-адрес, с которого следует выполнить обновление, а также сертификат CA для проверки сервера обновления.
- Затем выполняется запрос API esp_https_ota (), который инициирует обновление прошивки. Если процесс обновления прошивки успешен (или обновление не выполнено), этот API возвращает соответствующий код ошибки.
- По умолчанию в примере к прошивке подключен CA сертификат GitHub для обновления прошивки. Разместите образ новой прошивки на GitHub и попробуйте выполнить обновление. В идеале вы должны установить сертификат CA соответствующего сервера, с которого и будете загружать обновления.
Получение URL обновления прошивки
Открытый вопрос - как устройство получает URL-адрес для обновления прошивки? Команда обновления прошивки обычно отличается от команд удаленного управления, которые обсуждались в предыдущей главе. Это связано с тем, что обновление прошивки обычно запускается производителем устройства для партии или группы устройств на основе определенных критериев.
Для простоты мы будем использовать ту же инфраструктуру удаленного управления, чтобы передавать на устройство команду с адресом обновления прошивки. Но обратите внимание, что в реальном сценарии вам нужно будет использовать другой механизм, управляемый через облако.
Для быстрой проверки работы механизма обновления прошивки у нас есть пример образа (из приложения 1_hello_world), загруженный на GitHub. Мы можем попытаться обновить образ этой прошивки следующей командой:
>curl -d '{"state":{"desired":{"ota_url":"https://raw.githubusercontent.com/wiki/espressif/esp-jumpstart/images/hello-world.bin"}}}' \
--tlsv1.2 --cert cloud_cfg/device.cert \
--key cloud_cfg/device.key \
https://a3orti3lw2padm-ats.iot.us-east-1.amazonaws.com:8443/things/<contents-of-deviceid.txt-file>/shadow | python -mjson.tool/p>
После успешного обновления устройство выполнит прошивку Hello World.
Мы изучили процесс обновления прошивки по беспроводной сети, но для реальных производственных задач каждое устройство в серии должно содержать набор уникальных данных. Как подготовить эти данные и загрузить в устройство, мы обсудим в следующей главе.
Производство
При создании IoT устройств часто бывает необходимо хранить некоторую уникальную информацию на каждом устройстве.
Например, в предыдущей главе, для обеспечения аутентификации устройства в облаке, мы встроили сертификат устройства в саму прошивку. Это легко, когда мы делаем одно устройство, но что делать, когда нам нужно создавать сотни тысяч таких устройств? В этой главе мы рассмотрим, как это реализовать.
Помните, мы использовали разделы NVS для постоянного хранения пар ключ-значение во флэш-памяти? Поскольку этот раздел хранится во флэш-памяти контроллера, он доступен даже после перезагрузки устройства. А стереть его можно по аналогии с функционалом Reset to Factory, реализованном ранее.
Мы можем использовать подобный раздел NVS для хранения уникальных пар ключ-значение для каждого устройства во время производства. Но нужно предусмотреть, чтобы эта информация не стиралась при сбросе к заводским настройкам. Этого можно добиться, создав еще один раздел NVS, который будет использоваться для хранения уникальной запрограммированной на заводе информации. Поскольку этот раздел программируется только при производстве, мы будем использовать его только для чтения, обращаясь к нему только для получения уникальных значений, которые были настроены для конкретного контроллера.
Несколько разделов NVS
В предыдущей главе мы рассматривали, как задавать разделы флэш памяти. В этом примере в прошивку мы добавим дополнительный раздел NVS, в котором будут храниться уникальные заводские настройки, и назовем его fctry. Посмотрите, как это реализовано в файле 7_mfg/partitions.csv.
Код
Теперь, когда раздел NVS создан, мы можем получить к нему доступ, используя стандартные API-интерфейсы NVS. Единственное, что вам нужно - это указать NVS, чтобы он использовал нужный раздел NVS при выполнении операций чтения. Это можно сделать, инициализировав дескриптор NVS следующим образом:
#define MFG_PARTITION_NAME "fctry"
/* Error checks removed for brevity */
nvs_handle fctry_handle;
nvs_flash_init_partition(MFG_PARTITION_NAME);
nvs_open_from_partition(MFG_PARTITION_NAME, "mfg_ns",
NVS_READWRITE, &fctry_handle);
Теперь операции чтения NVS, которые выполняются с помощью дескриптора fctry_handle, приведут к получению данных из нужного раздела. Например,
nvs_get_str(fctry_handle, "serial_no", buf, &buflen);
Итак, теперь мы можем убрать код, который встраивает сертификаты в прошивку, и вместо этого читать их с уникального заводского раздела, который прошит для конкретного устройства.
Генерация заводских данных
Мы знаем теперь как читать и где хранить фабричные данные. Но как их сформировать и подготовить для записи в раздел fctry?
Рис. 5. Создание фабричного раздела
Специальная утилита /nvs_flash/nvs_partition_generator/nvs_partition_gen.py позволяет создать образ NVS на компьютере разработчика. Этот образ затем может быть записан во флэш-память в расположение раздела fctry .
Эта утилита принимает файл CSV и генерирует из него образ раздела NVS. В CSV-файле хранится информация о парах ключ-значение, которые будут частью созданного раздела NVS. При производстве будут сгенерированы сотни тысяч таких образов разделов NVS, по одному на каждое производимое устройство, а затем они будут записаны в соответствующие устройства.
Пример CSV-файла с именем mfg_config.csv доступен в приложении. Каждая из его строк содержит значения переменных, которые являются уникальными при производстве. Обновите этот файл в соответствии с вашими уникальными настройками.
Раздел NVS может быть сформирован следующей командой:
$ python $IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py --input mfg_config.csv --output my_mfg.bin --size 0x6000
Файл my_mfg.bin - это данные раздела NVS, которые теперь можно прошить в устройство, например, следующей командой::
$ $IDF_PATH/components/esptool_py/esptool/esptool.py --port $ESPPORT write_flash 0x340000 my_mfg.bin
Для пользователей ESP8266
Если у вашей платы ESP8266 меньше 2 МБ флэш-памяти, используйте следующую команду для прошивки my_mfg.bin.
$ $IDF_PATH/components/esptool_py/esptool/esptool.py --port $ESPPORT write_flash 0x1D5000 my_mfg.bin
Теперь, если вы загрузите свою прошивку, она будет работать точно так же, как прошивка из предыдущей главы. Но в этом случае сам образ прошивки не зависит от уникальных настроек для каждого устройства.
Это позволяет создавать столько уникальных образов, сколько вы хотите, а затем прошивать их в соответствующие платы.
Итак, теперь у нас есть полнофункциональная, готовая к работе прошивка устройства, готовая к загрузке!
Предыдущие главы:
- ESP-Jumpstart: быстрое создание приложений на ESP32. Часть 1
- ESP-Jumpstart: быстрое создание приложений на ESP32. Часть 2
Полезные ссылки:
- Безопасная загрузка
- Шифрование Flash памяти
- Шифрование NVS
- ESP32: TLS (безопасность транспортного уровня) и устройства IoT
- Функции безопасности контроллера ESP32
Источник: https://docs.espressif.com
Производители: ESPRES
Разделы: Приемо-передатчики
Опубликовано: 17.02.2020