FirmwareOverTheAir. A po naszemu coś dla tych, którzy chcą mieć aktualny firmware na swoich modułach bez kabelkologii i rozbierania łączników, puszek itp., aby dostać się do TX i RX, nie licząc oczywiście pierwszego flashowania.
Jak wygląda dobrodziejstwo FOTA?
Wchodzimy w tryb konfiguracji modułu, przestawiamy Firmware Update = YES. Zapisujemy i wychodzimy. Jeśli jest nowsza wersja firmware dla definicji modułu to się pobierze i zaktualizuje (sami musimy ją stworzyć i umieścić tam gdzie trzeba).
Dla kogo jest ten FAQ?
Dla tych co sobie sami kompilują soft. Trzeba deko ogarniać linuxa i minimalnie znać c, bash, sql, php.
Co zawiera ten FAQ w skrócie?
Kilka słów o niezbędnikach,
Trochę teorii,
Instalacja narzędzi,
Jak kompilować i flashować,
Zabiegi na bazie danych,
Jak kompilować pod www,
Zabiegi po stronie www.
Co trzeba mieć/umieć na tym etapie?
1. Umieć kompilować firmware
2. Posiadać konwerter USB ↔ UART i umieć flashować esptool-em
3. Mieć własną instancję SUPLA (ja mam na Dokerze)
4. Własny serwer www, może być lokalnie (u mnie akurat www jest w świecie)
5. Wirtualną maszynę lub jakąś dystrybuję linuxa (u mnie jest to Ubuntu).
6. Pobrać wszystkie niezbędne źródła na linuxa i dla porządku umieścić w jednym katalogu jak poniżej
Kod: Zaznacz cały
cd /home/$USER
mkdir SUPLA
cd SUPLA
git clone https://github.com/SUPLA/supla-espressif-esp
git clone https://github.com/SUPLA/supla-esp-signtool
mkdir Firmware
Jeśli mamy już pobrane oprogramowanie, to co teraz?
Musimy wygenerować klucze publiczny i prywatny.
Po co jest klucz publiczny i prywatny?
Klucz publiczny służy do zweryfikowania poprawności pobranego wsadu w procesie aktualizacji. Klucz prywatny do podpisania skrótu wsadu, zasada jak na schemacie
Skąd wziąć klucze?
Trzeba wygenerować własną parę kluczy, za pomocą pobranych narzędzi supla-esp-signtool
Jak zainstalować supla-esp-signtool?
Najpierw uaktualniamy zainstalowane pakiety i instalujemy libgmp-dev
Kod: Zaznacz cały
sudo apt update
sudo apt upgrade
sudo apt install libgmp-dev
Pobieramy wersje nettle-3.3, na niej mi wszystko zadziałało. Chętni mogą sprawdzić inne wersje.
https://www.lysator.liu.se/~nisse/nettle/
Rozpakowujemy i będąc wewnątrz katalogu nettle-3.3 wykonujemy
Kod: Zaznacz cały
./configure
make
make check
sudo make install
Następnie przechodzimy do lokalizacji supla-esp-signtool do katalogu Release i kompilujemy
Kod: Zaznacz cały
cd /home/$USER/SUPLA/supla-esp-signtool-master/Release/
make
Kod: Zaznacz cały
Finished building: ../src/sigtool.c
Building target: supla-esp-sigtool
Invoking: Cross GCC Linker
gcc -o "supla-esp-sigtool" ./src/sigtool.o -lhogweed -lnettle
/usr/bin/ld: ./src/sigtool.o: undefined reference to symbol '__gmpz_init'
//usr/lib/x86_64-linux-gnu/libgmp.so.10: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
makefile:30: polecenia dla obiektu 'supla-esp-sigtool' nie powiodły się
make: *** [supla-esp-sigtool] Błąd 1
Kod: Zaznacz cały
nano objects.mk
Kod: Zaznacz cały
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
USER_OBJS :=
LIBS := -lhogweed -lnettle -lgmp
Kod: Zaznacz cały
make clean
make
Jak wygenerować parę kluczy?
Przechodzimy do katalogu z singtool i wykonujemy polecenie
Kod: Zaznacz cały
cd /home/$USER/SUPLA/supla-esp-signtool-master/Release/
./supla-esp-sigtool -k klucz -g
Co robić dalej z kluczami?
Klucz prywatny strzeżemy jak oka w głowie. Jeżeli nadpiszemy sobie klucz prywatny, to czekać nas będzie ponownie kabelkologia modułów, które wykorzystują klucz publiczny z tej pary.
Klucz publiczny wykorzystamy później. Na tę chwilę klucz publiczny konwertujemy do tablicy poleceniem
Kod: Zaznacz cały
./supla-esp-sigtool -k klucz.pub -c public_key_in_c_code
Kod: Zaznacz cały
ln -s /home/$USER/SUPLA/supla-esp-signtool-master/Release/public_key_in_c_code /home/$USER/SUPLA/supla-espressif-esp/src/include/board/public_key_in_c_code
Jeśli mam już parę kluczy to co teraz?
Tworzymy własną definicję płytki, może być zbudowana na bazie przykładów z pobranych źródeł .
Zapisujemy nasze wypociny np. jako moja.c i moja.h. Umieszczamy w definicji płytki klucz publiczny w postaci tablicy
Kod: Zaznacz cały
const uint8_t rsa_public_key_bytes[512] = {
Kod: Zaznacz cały
#include ”public_key_in_c_code”
Co dalej?
Kompilujemy ./build.sh wybierając naszą płytkę z parametrem FOTA=1
Nie mam w build.sh swojej płytki, jak ją dodać?
Analogicznie do pozostałych. Odnajdujemy case z opcjami
Kod: Zaznacz cały
case $1 in
"moja")
FLASH_SIZE="2048"
FOTA=1
;;
"wifisocket")
;;
Kod: Zaznacz cały
#elif defined(__BOARD_moja)
#include "board/moja.c"
Kod: Zaznacz cały
cd /home/$USER/SUPLA/supla-espressif-esp/src/
./build.sh moja
Gdzie wgrywamy skompilowany firmware?
Na adresy które wyświetlił nam kompilator. Pamiętajmy jednak, że kompilujemy i wgrywamy za pomocą kabli tylko user1 (mam tu na myśli, że nie musimy wgrywać user2)
Kod: Zaznacz cały
boot.bin------------>0x00000
user1.2048.new.5.bin--->0x01000
Jak flashować?
Ja to robię na esptoolu, możemy się w tym miejscu przesiąść na Flash Download Tools lub coś innego, tylko po co
Czyścimy i flashujemy, wybierając odpowiednią mapę, tę dla której kompilowaliśmy, czyli w tym przypadku 2MB-c1. Ja na esptoolu mam tak
Kod: Zaznacz cały
esptool.py -p /dev/ttyUSB0 -b 115200 erase_flash
esptool.py -p /dev/ttyUSB0 -b 115200 write_flash -fm dio -ff 40m -fs 2MB-c1 \
0x00000 /home/$USER/SUPLA/Firmware/boot_v1.5.bin \
0x01000 /home/$USER/SUPLA/Firmware/moja_user1.2048.new.5.bin \
0x1fc000 /opt/Espressif/ESP8266_NONOS_SDK154/bin/esp_init_data_default.bin
Dlaczego wgrywamy na 2MB a nie 4MB skoro mam w module dostępne 4MB?
Mapa jest dowolna, ważne żeby kompilację i flashowanie dokonać na tych samych ustawieniach i żeby zmieściło się do modułu. Równie dobrze mogłem skompilować z parametrem 4MB lub 4MB-c1.
Jeśli wgramy na innej mapie, moduł też wstanie i będzie działać, ale aktualizacja już nie będzie działać o czym sam się przekonałem, podczas próby przebrnięcia przez wszystkie etapy. Parametr mapy jest przesyłany do sprawdzenia nowych wersji, dlatego musimy zachować spójność. Kompiluje 4MB-c1 to wgrywam z taką mapą. Jak kompiluję 4MB, to wgrywam z taką samą. Nie zapominajcie także o pliku inicjującym chip esp_init_data_default.bin, którego adres zależy od wybranej mapy.
Mam starą wersję esptoola i nie mam takich parametrów, co teraz?
Poszukaj w helpie parametrów dla swojej wersji lub zaktualizuj do najnowszej. Kiedyś pisałem jak to zrobiłem tutaj
viewtopic.php?p=19434#p19434
Co do zrobienia po stronie bazy danych?
Trzeba wskazać gdzie moja kompilacja ma szukać nowych wersji softu, wskazać mapę z jaką jest skompilowany .bin i jeszcze parę innych drobiazgów.
Jeśli macie tabelę esp_update, esp_update_log i niezbędne procedury to fajnie, będzie mniej roboty. Ja nie miałem, moja baza przechodziła konwersje z 2.0 -> 2.1 -> 2.2 i jakoś jej tych tabel zabrakło.
Jak sprawdzić czy mam tabele w bazie?
Dla instalacji dockerowej składnia jest następująca
Kod: Zaznacz cały
source supla-docker/.env && docker exec supla-db mysql -u supla --password=$DB_PASSWORD supla -e "show tables like 'esp_update' "
Kod: Zaznacz cały
Tables_in_supla (esp_update)
esp_update
esp_update
esp_update_log
https://github.com/SUPLA/supla-cloud/bl ... 234138.php
i procedura supla_get_device_firmware_url
https://github.com/SUPLA/supla-cloud/bl ... 222022.php
Czy na bazie robimy coś jeszcze?
Gdyby nie było, ja już miałem
Kod: Zaznacz cały
DELIMITER $$
--
-- Procedures
--
DROP PROCEDURE IF EXISTS `supla_get_device_firmware_url`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `supla_get_device_firmware_url` (IN `device_id` INT, IN `platform` TINYINT, IN `fparam1` INT, IN `fparam2` INT, IN `fparam3` INT, IN `fparam4` INT, OUT `protocols` TINYINT, OUT `host` VARCHAR(100), OUT `port` INT, OUT `path` VARCHAR(100)) NO SQL
BEGIN
SET @protocols = 0;
SET @host = '';
SET @port = 0;
SET @path = '';
SET @fparam1 = fparam1;
SET @fparam2 = fparam2;
SET @platform = platform;
SET @device_id = device_id;
INSERT INTO `esp_update_log`(`date`, `device_id`, `platform`, `fparam1`, `fparam2`, `fparam3`, `fparam4`) VALUES (NOW(),device_id,platform,fparam1,fparam2,fparam3,fparam4);
SELECT u.`protocols`, u.`host`, u.`port`, u.`path` INTO @protocols, @host, @port, @path FROM supla_iodevice AS d, esp_update AS u WHERE d.id = @device_id AND u.`platform` = @platform AND u.`fparam1` = @fparam1 AND u.`fparam2` = @fparam2 AND u.`device_name` = d.name AND u.`latest_software_version` != d.`software_version` AND
(
version_to_int(d.`software_version`) = 0 OR
version_to_int(u.`latest_software_version`) = 0 OR
version_to_int(u.`latest_software_version`) > version_to_int(d.`software_version`)
)
AND
( u.`device_id` = 0 OR u.`device_id` = device_id ) LIMIT 1;
SET protocols = @protocols;
SET host = @host;
SET port = @port;
SET path = @path;
END$$
DROP FUNCTION IF EXISTS `version_to_int`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `version_to_int` (`version` VARCHAR(10)) RETURNS INT(11) NO SQL
BEGIN
DECLARE result INT DEFAULT 0;
DECLARE n INT DEFAULT 0;
DECLARE m INT DEFAULT 0;
DECLARE dot_count INT DEFAULT 0;
DECLARE last_dot_pos INT DEFAULT 0;
DECLARE c VARCHAR(1);
WHILE n < LENGTH(version) DO
SET n = n+1;
SET c = SUBSTRING(version, n, 1);
IF c <> '.' AND ( ASCII(c) < 48 OR ASCII(c) > 57 )
THEN
SET result = 0;
RETURN 0;
END IF;
IF c = '.' THEN
SET dot_count = dot_count+1;
IF dot_count > 2 THEN
SET result = 0;
RETURN 0;
END IF;
END IF;
IF c = '.' OR n = LENGTH(version) THEN
SET m = n-last_dot_pos-1;
IF c <> '.' THEN
SET m = n-last_dot_pos;
SET dot_count = dot_count+1;
END IF;
SET result = result + POWER(10, 9-dot_count*3) * SUBSTRING(version, last_dot_pos+1, m);
SET last_dot_pos = n;
END IF;
END WHILE;
RETURN result;
END$$
DELIMITER ;
Co wpisać do tabeli esp_update?
Taki insert robimy, oczywiście nazwę domeny zmieniamy na swoją, nazwę kompilacji, wersję softu i nazwę pliku, oraz fparam1 jeśli kompilujemy z inną mapą.
Kod: Zaznacz cały
source supla-docker/.env && docker exec supla-db mysql -u supla --password=$DB_PASSWORD supla -e " \
INSERT INTO esp_update (id, device_id, device_name, platform, latest_software_version, fparam1, fparam2, protocols, host, port, path) VALUES \
(1, 0, 'moja', 1, '2.7.2', 5, 0, 1, 'www.mojadomena.pl', 80, 'get_file.php?file=moja_user2.2048.new.5.bin'), \
(2, 0, 'moja', 1, '2.7.2', 5, 1, 1, 'www.mojadomena.pl', 80, 'get_file.php?file=moja_user1.2048.new.5.bin');"
Tak samo jak standardowo, ale trzeba skompilować user 1 i user2 a później je podpisać kluczem prywatnym
Kod: Zaznacz cały
./build.sh moja
./build.sh moja user2
Jak podpisać pliki kluczem prywatnym?
Przechodzimy do katalogu z signtool i wskazujemy odpowiedni plik z kluczem i plik do podpisu
Kod: Zaznacz cały
cd /home/$USER/SUPLA/supla-esp-signtool-master/Release
./supla-esp-sigtool -k klucz -s /home/$USER/SUPLA/Firmware/moja_user1.2048.new.5.bin
./supla-esp-sigtool -k klucz -s /home/$USER/SUPLA/Firmware/moja_user2.2048.new.5.bin
Kod: Zaznacz cały
./supla-esp-sigtool -k klucz -v /home/$USER/SUPLA/Firmware/moja_user1.2048.new.5.bin
./supla-esp-sigtool -k klucz -v /home/$USER/SUPLA/Firmware/moja_user2.2048.new.5.bin
Teoretycznie nic, bo pliki *.bin nie są rozpoznawane przez przeglądarkę jako coś do otwarcia i są od razu pobierane, ale dobrze jest sobie wstawić taki prosty skrypt znaleziony w sieci, zapisujemy pod jakąś nazwą np. get_file.php i wrzucamy na serwer www. Tworzymy jeszcze w tym samym miejscu co get_file.php katalog „update” do którego będziemy w wrzucać nasze pliki bin
Kod: Zaznacz cały
<?php
if(!empty($_GET['file'])) {
$file = str_replace('..','',$_GET['file']);
$cat_with_file = 'update';
$local_file = $cat_with_file.'/'.$file;
if(file_exists($local_file) && is_file($local_file))
{
//Otwarcie pliku
$fp = fopen($local_file, 'rb');
//Wysyłanie informacji o pliku do przeglądarki
header('Content-Type: application/octet-stream'); //Typ
header('Content-Length: ' .filesize($local_file)); //Rozmiar
header('Content-Disposition: filename='.$file); //Nazwa
//Zrzucanie pliku i zatrzymanie skryptu
fpassthru($fp);
exit;
}
else die("ERROR: Plik ".$file." nie istnieje!");
}
else header('HTTP/1.0 404 Not Found', true, 404);
?>
Czy to już?
Wystarczy wysłać podpisane pliki na serwer www do katalogu "update" i gotowe. Możemy korzystać z dobrodziejstwa jakie daje nam FOTA
P.S. Uff. Taka dygresja mnie naszła, choć nic nowego nie stworzyłem.
Wiecie co jest najbardziej czasochłonne podczas tworzenia oprogramowania
Tworzenie dokumentacji