Фреймворк LCE на чипе ESP8266

Как настроить устройство?

ЯЗЫК

Железо чипа ESP8266
Язык команд СИФАК
Основы языка
Арифметика
Планирование времени, цикла, запуск задач
Работа с переменными в языке
Операторы условия
Операции текстовых строк
Служебные переменные
Системная часть — edge
Логи в консоли

ВОЗМОЖНОСТИ

GPIO
Аналоговый вход A0
Прерывания от GPIO
Файловая система
Внутренние специфические функции ESP
Звуки, мелодии, сэмплы
Авторизация

ПРОТОКОЛЫ СВЯЗИ

WIFI
UDP
NTP (синхронизация времени)
MDNS
MQTT
MODBUS/TCP
SERIAL

ВНЕШНИЕ УСТРОЙСТВА

Датчик DS18B20
Сервоприводы
Бесконтактные карты NFC RFID-RC522
Бесконтактные карты WIEGAND


2


Как настроить устройство?

Если у вас есть устройство этой системы, необходимо сделать следующее:

1. Включить девайс и услышать звуковые сигналы.
2. Найти WiFi сетку вида ESP-cf8e5e, которую устройство создает само от безысходности и отсутствия доступа к интернету.
3. Необходимо залогиниться в эту сеть и открыть любой сайт не https, а лучше не париться (не на всей мобильниках почему-то работает dns), а сразу открывать титул чипа по адресу http://192.168.4.1
4. Чтобы стать админом, надо увидеть в верхнем правом углу экрана желтый кружок, ткнуть туда и набрать пароль. Если вы не меняли пароль (в config.txt), то по умолчанию он «gluki»
5. Далее следует кнопкой WiFIscan найти нужную сеть и залогиниться в нее. Связь при этом пропадет, но чип перезагрузится и войдет в сеть, о чем сообщит, высвистывая последние цифры IP. Если по какой-то причине (бывает из-за устаревшей версии) не получается это сделать кнопкой, откройте файл-менеджер чипа Files и там впишите логин и на следующей строчке пароль в файл /wifi_last.txt (втрой перенос строки не делайте).
6. После входа в сеть чип пойдет обновлять файлы и прошивку. Это займет какое-то время, может минут 5, не выключайте устройство! Выключение во время обновления прошивки может его убить и спасет только программатор.
7. Далее вы можете работать с устройством.


ЖЕЛЕЗО ESP8266

Если у вас нет устройства? Вы можете его легко сделать. Нужен чип ESP8266 на плате с USB-слотом, например NodeMCU или D1 mini (фото ниже). Я использую программатор, потом из него чипы вынимаются и сразу паяются куда надо. Так или иначе, чтобы не морочиться с программными системами, можно просто соединить чип кабелем OTG со смартфоном, установить туда приложение ESP8266 Loader и залить готовый бинарник. Относительно последняя версия бинарника лежит здесь: http://lleo.me/ESP8266/firmware/firmware.bin Если вам интересны исходники, то относительно свежие здесь: http://lleo.me/ESP8266/CFAQ.zip

Чип имеет 15 полноценных GPIO выходов, но 6 из них (нижние) заняты микросхемой flash памяти и никоим образом их использовать нельзя. Для использования рекомендуются: 4, 5, 12, 13, 14, имеют ограничения: 0,1,2,3,15.

GPIO 0 — FLASH, не должен быть подтянут к минусу при старте, иначе модуль перейдет в режим программирования до следующего включения
GPIO 1 — TXD
GPIO 2 — blink.pin — LED, лампочка, если нужны дополнительные светодиоды, рекомендую их вешать сюда
GPIO 3 — RXD, sound.pin — рекомендую вешать сюда пьезодинамик
GPIO 4 — poliv.pin — включение мотора полива или реле в моей системе (SDA-SS для NFC)
GPIO 5 — act.pin — включение всего остального, например дополнительного реле в моей системе (RST для NFC)
GPIO 12 — не задействован, также SPI:MISO.
GPIO 13 — не задействован, также RXD2 или SPI:MOSI.
GPIO 14 — не задействован, также SPI:SCK.
GPIO 15 — в момент старта должен подтянут к минусу через резистор 10к или напрямую, как у меня. Также это TXD2, если переключить. Или SPI:CS.
GPIO 16 — только на OUTPUT (или для пробуждения, если подключить к RESET)

Вариант готовой платы D1-mini

Вариант готовой платы Node-MCU

Если у вас вопросы по делу, пишите мне, с удовольствием отвечу.

Если вопросы не по делу, если вы попали сюда случайно и у вас острое недоумение, что это, и зачем вам нужно, то вам это точно не нужно. Это не публичный проект, он сделан для решения своих задач, а также по рабочим надобностям и по ТЗ, которое формулировали явно не вы и не для своей сферы применения. Вы можете использовать эту систему для личных нужд, но вас точно никто не уговаривал это делать.

Ниже подробное описание системы.


СИФАК

Задачи, решаемые при помощи чипа ESP628, имеют свои особенности. Чаще всего здесь не требуется мощное программирование, а нужно лишь отвечать на сигналы и производить несложные действия с довольно узким кругом оборудования, но по достаточно сложным сценариям, требующим многочисленных ветвлений, условий, циклов и четкого планирования событий по времени.

Концепция данной системы состоит в том, чтобы максимально облегчить работу с чипом, исключив программирование бинарника вообще. Бинарник может со временем усовершенствоваться и автоматически обновляться (эти инструменты, разумеется, есть в системе), но он всегда один для всех задач. Сами же задачи выполняются при помощи неограниченного количества текстовых файлов-скриптов, которые хранятся во флеш-памяти чипа, относительно безграничной для таких скриптов.

Также система включает в себя элементы админки: программировать чип, меняя скрипты, можно прямо в браузере на страницах, которые предоставляет сам чип, являющийся веб-сайтом.

Язык скриптов, которого потребовала эта задача, максимально прост и достаточно примитивен. На сегодняшний день, помимо обращений к внутреннему и внешнему оборудованию и различным сервисным протоколам (GET, MQTT, MODBUS/TCP), он позволяет делать разнообразные ветвления, осуществлять совсем простые математические вычисления, активно обрабатывать файлы внутренней флешки и управлять многочисленными таймерами. Он чем-то похож на C, но главная его задача — ставить системе задачи и получать ответы, поэтому я называю этот язык CFAQ.


ОСНОВЫ ЯЗЫКА СИФАК

Основой языка является строка, где через ОДИН ПРОБЕЛ (это важно) перечислены команды и операторы. Повторю: язык очень чувствителен к пробелам. В начале строки может стоять сколько угодно пробелов и табуляций. Все, что идет после знака #, считается комментарием и отбрасывается.

Исполняемые скрипты могут приходить несколькими разными путями:

1. В строке GET-запроса: http://192.168.4.1/MOTO?pinmode%204%20OUTPUT|echo%20{gpioA0}

2. В POST-запросе AJAX на http://192.168.4.1/ Например, так работает окно консоли на титульной странице админки.

3. В тексте, переданном внешним сайтом в ответ на запроса к нему командой ping

Разумеется, запросы GET и POST сработают только при наличии авторизации в куках. Пароль устанавливается в config.txt, по умолчанию пароль «gluki»

Если строка скрипта не распознана, она считается именем файла скрипта, и этот файл вызывается на исполнение. Если и файл такой не найден, система пропускает эту строку. Ошибки при этом подавляются (почему так — отдельная долгая дискуссия, но пока нужно было именно так). Любое имя файла является скриптом, файл открывается и запускается на исполнение. В начале имени файла может для понятности стоять /, а может и нет. Например, /SCRIPT.TXT и MOTOR-START — это всё имена скриптов, лишь бы файл с таким именем был среди файлов во флеш-памяти.

Команды условных ветвлений if и else используют либо строку, либо область действия, которая заключается в фигурных скобки.

Основным скриптом, исполняемым однократно при старте, является /config.txt в нем прописываются нужные настройки, задаются циклы и отложенные задачи, необходимые на первое время. Здесь особенное значение представляет команда loopfile — она позволяет задать скрипт, который будет, в отличие от таймеров, исполняться постоянно с наивысшей скоростью и приоритетом. Хороший пример такого скрипта — «плавное дыхание» светодиода если есть интернет, или мигание, когда интернета нет.

loopfile [действия]Главный цикл, пример:
style='color:, пример:
#0000BB'><?php

Теперь, когда мы уже немного понимаем, как работает язык, приступим к подробному описанию всех его команд. Начнем с самого простого:


РАБОТА С GPIO

pinmode [пин] [режим]Установить gpio [пин] в один из режимов: OUTPUT (выход), INPUT (вход), INPUT_PULLUP (вход, подтянутый к питанию), пример:
pinmode 5 OUTPUT ; pinmode 4 INPUT_PULLUP
blink (pin)поменять значение gpio пин pin с 0 на 1 и наоборот, если пин не указан, по умолчанию пин 2 (лампочка на корпусе, но учтите, что она обратная — 0 горит, 1 потушена), пример:
repeat 10 blink 5 ; sleep 200
pin [пин] [значение]записать в gpio пин значение 0 или 1, пример:
pin 5 0
pwm [пин] [значение]шим (analog_write) в пин, пример:
pwm 5 100
tone [пин] [значение]тон в пин, пример:
tone 5 433



Логи в консоли

ESP выводит информацию в uart. Как минимум, при старте — это свойство чипа, с котоым ничего поделать нельзя. Если нужно, чтобы в uart никогда ничего не летело, имеет смысл использовать альтернативные пины uart (TX=15,RX=13 вместо 1 и 3), переключив на них вывод командой «SERIAL.swap 1» Так можно избежать в консоли мусора при старте, но в новую консоль все равно будет сыпаться информация во время работы чипа и процедур фреймворка. И вот её можно регулировать все сразу (ALL) или по группам. Группы логов:

ALL — вообще все логи сразу
MAIN — системные логи типа старта и инициализации
ERROR — системные ошибки
WEB — логи веб-запросов
WGET — логи TCP-запросов на внешние сервера (в частности команда ping)
UPGRADE — апгрейд системы
MP3 — отдельно логи mp3
IECHO — логи команды iecho
PROG — лог выполнения любых команд и скриптов (система MOTO)
CONN — логи коммуникационных сервисов типа MQTT, MODBUS

LOG [имя] [n]Лог с именем [имя] включить (n=1) или выключить (n=0), пример:
style='color:, пример:
#0000BB'><?php


pinmode [пин] [режим]Установить gpio [пин] в один из режимов: OUTPUT (выход), INPUT (вход), INPUT_PULLUP (вход, подтянутый к питанию), пример:
pinmode 5 OUTPUT ; pinmode 4 INPUT_PULLUP
blink (pin)поменять значение gpio пин pin с 0 на 1 и наоборот, если пин не указан, по умолчанию пин 2 (лампочка на корпусе, но учтите, что она обратная — 0 горит, 1 потушена), пример:
repeat 10 blink 5 ; sleep 200
pin [пин] [значение]записать в gpio пин значение 0 или 1, пример:
pin 5 0
pwm [пин] [значение]шим (analog_write) в пин, пример:
pwm 5 100
tone [пин] [значение]тон в пин, пример:
tone 5 433


АРИФМЕТИКА И ОПЕРАТОРЫ ПРИСВАИВАНИЯ

Арифметика в нашем языке находится в зачаточном состоянии. Но её, тем не менее, вполне достаточно, чтобы выполнять несложные арифметические вычисления. Наши правила:

— Имена переменных могут быть латинскими, русскими, заглавными, строчными и неограниченной длины, и только пробел они содержать не могут.

— Вычисления можно производить только в операторе присваивания типа X = {Y} / 3 На лету арифметика не работает, нельзя написать «echo {Y} / 3»

— В строке мы перечисляем числа, имена переменных (в фигурных скобках), знаки математических операций, и всё это разделяем одним пробелом.

— В операторе присваивания = можно делать сразу несколько вычислений: X = {Y} / 3 + 1 * {K}, при этом порядок выполнения будет последовательным, без приоритета операций. Чисто физически наш интерпретатор имеет аккумулятор, значение которого в конце присвоит переменной, и двигается вперед по строке, производя с аккумулятором всё новые действия.

— У нас нет скобок. Извините за временные неудобства.

— Все незаданные пока переменные считаются пустыми строками, поэтому если их использует арифметика, то это будет 0.

— Все вычисления в ESP производятся с типом double (4 байта, фиксированная точка — 2 знака после запятой). Я точно не помню параметры, но можно оперировать достаточно громадными числами, не боясь вылезти за рамки. Плавающей точки нет — точка фиксированная: ровно два знака после запятой. «X = 3.1415925 ; echo {X}» даст 3.14 В принципе, этой точности нам должно хватать.

ОПЕРАТОРЫ ПРИСВАИВАНИЯ

[переменная] = [формула]Присвоить переменной значение, которое может быть числом, другой переменной или результатом вычисления формулы. Внимание! Имя переменной в момент присваивания указываем без фигурных скобок как в sh! Скобки понадобятся позже — когда мы читаем значение переменной, пример:
# примеры простых и сложных присваиваний
9.8
Radius 
10
Тракторов
-или-велосипедов 3
3.14 * {Radius} / {G}
echo 
результат: {Xдля {Тракторов-или-велосипедовединиц транспорта
# результат: 6.41 для 3 единиц транспорта
set [переменная] = [строка]Присвоить переменной текстовую строку. Никаких вычислений не производится, пример:

<?php
set Y 
10 + {LIMIT} + {X} * 10
echo результат: {Y}
# результат: 10 + {LIMIT} + {X} * 10
[переменная] ~ [значение]Присвоить переменной инвертированное число или переменную (тип word 16 бит). Никаких дальнейших вычислений здесь быть не может, пример:

<?php
2
~ {X}
echo 
X={XY={Y}
# X=65533 Y=2
[переменная] unsigned [значение]Присвоить переменной значение целочисленный unsigned int — без учета знака и дробной части. Никаких дальнейших вычислений здесь быть не может, пример:

<?php
X unsigned 
-1.11111
Y unsigned 3.1415
echo X={XY={Y}
# X=65535 Y=3


ОПЕРАТОРЫ МАТЕМАТИКИ

+сложение, пример:
X = 2 + 2
вычитание, пример:
X = 2 — 2
*умножение, пример:
X = 2 * 2
/деление, пример:
X = 2 / 2
+=добавление, пример:
X += 2 # увеличили X на 2
-=довычитание, пример:
X -= 2
*=доумножение, пример:
X *= 2
/=доделение, пример:
X /= 2
%остаток от деления, пример:
X = 10 % 7 # 3


ПЛАНИРОВАНИЕ ВРЕМЕНИ, ЦИКЛЫ, ЗАПУСК ЗАДАЧ

В системе можно устанавливать циклы, которые будут выполнять определенные действия через определенное количество секунд — регулярно, однократно или некоторое заданное число раз. В качестве действий указывается СТРОКА — это может быть имя файла (тогда будет исполняться он) или одна команда, или последовательность команд, разделенных ; (для команд, исполняемых по сети в GET-запросе можно также использовать разделитель |) Однако можно указать небольшой скрипт в несколько строк, разместив его в фигурных скобках, соблюдая пробелы — примерно как мы видели в примере выше с командой mainloop { ... }

[filename]Исполнить скрипт filename, пример:
/MOTOR_STOP
run [filename]То же самое, но в отличие от предыдущего примера, с этой командой можно делать вызовы сложнее, пример:
if {N} < 5 N += 1 else N = 0
run /SCRIPT_{N}.TXT
loop (номер) [time] [действия]Выполнять действия с интервалом time, который задается в секундах. Все отложенные таймеры и циклы задаются в секундах, меньше нет смысла. Если указан номер для цикла, то циклу присваивается конкретный номер, чтобы его можно было изменить, остановить или посмотреть, сколько осталось до срабатывания. Цикл номер 1 изначально зарезервирован под обновление софта. Чтобы отключить обновление используйте команду loop.del 1, пример:
loop 1 0
loop 10 blink 4 ; blink 5 ; if {gpio3} = 1 exit
loop 1 84600 /UPGRADE.txt
loops [количество] (n) [time] [действия]Запустить loop на определенное количество повторов, пример:
{2}
at [time] [действия]Выполнить действия однократно через отложенное время. Это можно записать через команды loop, но так удобней и короче., пример:
at 10 /MOTOR-STOP
at 0 play DRM
now [действия]Выполнить действия безотлагательно сразу после завершения данного скрипта (то же, что at 0). Полезно во время прерываний и во всех прочих случаях, когда не хочется тратить время сейчас, а задачу запустить надо., пример:
now play DRM
loop.del [n]Удалить цикл номер n, пример:
loop.del 1 # остановить запросы на обновления
loopfile [скрипт]Установить скрипт в качестве основного цикла (выполняющегося без задержек), пример:
loopfile /my_loop.txt

loopfile { if {gpio4} == 1 blink 3 }

sleep [секунды]выполнить паузу в несколько секунд. Внимание! Не рекомендуется использовать эут команду, потому что останавливаются все процессы! Лучше запустить отложенную задачу командой at., пример:
{2}
delay [миллисекунды]выполнить паузу (1000 миллисекунд = 1 секунда), также можно использовать синоним delay — usleep, пример:
delay 200
exitпрекратить сейчас выполнение этого скрипта, пример:
if {k} = 0 exit
stopпрекратить не только выполнение скрипта, но и его повторный запуск, если он циклически повторялся по таймеру, пример:
if {k} > 300 { stop } else { exit }
repeat [N] [действия]повторить N раз действия, пример:
repeat 10 echo привет!
repeat 10 {
k += 1
echo привет! k={k}
}
breakпрекратить repeat досрочно, пример:
{2}
echo [строка]Напечатать строку в Serial-консоль, пример:
{2}
settime [UnixTime] (Hour:Min:Sec)Установить время, пример:
settime 1524235234 23:01:59
ping (timeout) [url]выполнить скрипт, получив его с сервера url. Если первым аргументом указан timeout в мс (по умолчанию 3000), то использовать его, пример:
if {gpio4} = 1 ping http://lleo.me/robot?signal=была-нажата-кнопка-4


РАБОТА С ПЕРЕМЕННЫМИ

В нашем языке короткая конструкция в фигурных скобках без пробелов — это всегда кандидат на подстановку значения. Имя переменной должно состоять из латинских букв не менее 8 символов, обязательно содержать заглавные и строчные, цифру и хотя бы один специальный символ... Да шучу, шучу! Имя может быть любым, даже кириллицей, лишь бы не было пробелов. Но учтите, что память у чипа куцая, и чем короче имя, тем ему легче.

[имя] = [выражение]Присвоить переменной результат вычисления числового значения. При вычислении можно использовать операторы =, +, -, *, /, а также +=, -=, *=, /=. К сожалению, ни приоритет операций, ни обработка скобок пока не сделаны. Разбивайте на несколько переменных., пример:
LIMIT = {gpioA0} * 4 — 1024 + {MAXIMUM}
set [имя] [текст]Задать переменной текстовое значение, оно может содержать даже пробелы, пример:
set server = http://lleo.me
set


УСЛОВИЯ

if [ARG1] [условие] [ARG2] [действия]сравнить два аргумента, допустимы условия =, ==, !=, >, >=, <, <= Учтите, что = и == не различаются. В качестве аргумента может быть что-то в фигурных скобках — имя переменной, служебная константа, системные данные., пример:
if {gpioA0} >= 300 {
  echo 
Ток превышеннасос перегружен!
  if {
gpioA0} > 800 echo Возможноон заржавел и его вообще заело?
} else {
  if {
gpioA0} < 100 echo Слабая нагрузкавозможнов колодце кончилась вода?
  else echo 
Насос работает в штатном режиме...
}
else [действия]если не выполнилось условие предыдущего if, пример:
{2}
if.empty [arg] [действия]выполнить действия если аргумент равен пустой строке, пример:
{2}
if.!empty [arg] [действия]выполнить действия если аргумент не равен пустой строке, пример:
{2}
ifrand [N] [действия]выполнить действия если случайно выпал 1 шанс из N, пример:
ifrand 100 echo Вы попали в 1% счастливчиков!
if.WIFI [действия]выполнить действия если установлено соединение с местным WiFi, пример:
ifwifi ping http://myserver.ru?say=WiFi_connected
if.!WIFI [действия]выполнить действия если подключиться к WiFi не удалось, пример:
ifnowifi pin 4 1 # зажечь сигнальный светодиод gpio4


РАБОТА С ФАЙЛОВОЙ СИСТЕМОЙ

Здесь почти все самые необходимые команды для работы не только с файлами, а также с файлами-списками и файлами-данными. В качестве данных удобно использовать формат файла, где каждая строка записана через пробел как «КЛЮЧ ЗНАЧЕНИЕ». Так можно делать небольшие ьбазы данных, например, список бесконтактных карт с именами владельцев.

if.FILE [filename] [command]Если файл существует, выполнить команду, пример:
{2}
if.!FILE [filename] [command]Если файл не существует, выполнить команду, пример:
if.!FILE 1.txt FILE.save 1.txt 123
FILE.save [filename] [text]Записать файл, состоящий из строки или текста в фигурных скобках, пример:

<?php
FILE
.save 1.txt {
0001 товары и услуги
0002 объекты и кредиты
}
FILE.add [filename] [text]Дописать к файлу текст, пример:
FILE.add /1.txt 0003 реклама и рассылки
FILE.add.ln [filename] [string]Дописать строку к файлу, заменив в ней \n на перевод строки FILE.add /1.txt 0004 недвижимость\n0005 ремонт, пример:
{2}
FILE.save.text [filename] [string]Записать файл, состоящий из строки, заменив в ней \n на перевод строки, пример:
{2}
FILE.add.text [filename] [string]Дописать к файлу строку, заменив в ней \n на перевод строки, пример:
{2}
FILE.del [filename]удалить файл, пример:
{2}
FILE.rename [from] [to]переименовать файл, пример:
FILE.rename /1.txt /2.txt
FILE.copy [from] [to]скопировать файл, пример:
FILE.copy /ESP.jpg /mainfoto.jpg
FILE.string.del [filename] [string]удалить из файла строку по началу до пробела, если такая была, пример:
FILE.string.del /1.txt 0002 объекты и кредиты
FILE.string.add [filename] [string]добавить в файл строку, если такого начала (до пробела) не было, пример:
FILE.string.add /1.txt 0002 объекты и кредиты
FILE.key.add [filename] [key] [value]Обновить в файле значение value для ключа key (формат файла — в каждой строке первое слово — ключ, через пробел — его значение), если строки с таким ключом (первым словом) не существует, то добавить ее в конец файла, пример:
FILE.key.add /1.txt 0001 товары и продукты
FILE.key.del [filename] [key]Удалить из файла запись о ключе key, пример:
FILE.key.del /1.txt 0001
{KEY:[filename] [key]}Напомним, что так можно получить value по значению key из файла, пример:
echo Цена для «морковь» = {KEY:/baza-cen.txt морковь} руб.



РАБОТА С ПРЕРЫВАНИЯМИ ОТ GPIO

INTERRUPT.add [pin] [mode] [script]Включить аппаратное прерывание по пину pin в режиме mode: 1 или RISING, 0 или FALLING или 2 или CHANGE. При возникновении прерывания будет исполняться скрипт. Важно учесть, что в прерывании нельзя исполнять сложных и долгих операций, код скрипта (или файла, который будет исполняться) должен быть максимально краток, например обновить значение какой-то своей переменной. Все затратные действия следует задать на исполнение в следующую секунду — командой at 1 [скрипт или имя файла]., пример:

<?php
INTERRUPT
.add 12 CHANGE blink {sound.pin}
INTERRUPT.del [pin]Отключить аппаратное прерывание по пину pin, пример:
INTERRUPT.del 12


РАБОТА С ВНУТЕННИМИ ФУНКЦИЯМИ ESP

ESP.restartвыполнить ESP.restart();
ESP.resetвыполнить ESP.reset();
SPIFFS.formatотформатировать карту памяти, удалив все файлы
ESP.deepSleep [microsec] [mode]Уснуть на несколько микросекунд, возможные режимы mode: WAKE_RF_DEFAULT, WAKE_RFCAL, WAKE_NO_RFCAL и WAKE_RF_DISABLED. Контакт GPIO16 должен быть соединен с RST, чтобы вывести чип из режима глубокого сна.


РАБОТА С WIFI

WIFI [network] (password)подключиться к сети
WIFI.reconnectЧип отключается от точки доступа и делает повторное подключение.
WIFI.disconnect (true)SSID и пароль на null, отключить станцию от точки доступа. Если добавлен аргумен «true», это выключит режим станции.
WIFI.APdisconnect (true)Выставляет SSID и пароль на null, отключает станцию от точки доступа. Если true, это выключит режим станции.
if.WIFI [команда]Выполнить, если установлено соединение с интернетом
if.!WIFI [команда]Выполнить, если не установлено соединение с интернетом
WIFI.persistent (false)сохранять ли на флеш-память каждый раз пароль, по умолчанию false — не сохранять
WIFI.autoconnect (true)Чтобы при включении питания автоматически подключался к последней использованной точке доступа. Если false, автоматическое подключение будет деактивировано, иначе активировано
if.WIFI.autoconnect [команда]выполняет команду, если у модуля активировано автоматическое подключение
WIFI.autoreconnect (true)Если параметр true, модуль делает повторное подключение, а если false, то нет
WIFI.waitconnectЖдет, когда модуль подключится к точке доступа, очень нужная функция сразу после WIFI
WIFI.diagWiFi.printDiag(Serial)
WIFI.hostname [name]Устанавливает WiFi.hostname
WIFI.mode [mode]устанавливает WiFi.mode: STA — станция, AP — точка доступа, AP_STA — и то и другое
WIFI.config [ip] [gateway] [mask] (dns1) (dns2)Ручная установка параметров
WIFI.AP [name] [password] (channel) (hidden)поднять свою точку доступа WIFI.AP: логин, пароль, также можно указать номер канала и флаг true — скрывать
WIFI.APconfig[ip] [gateway] [mask]
WIFI.dns (flag)поднять свой DNS-сервис если флаг true (по умолчанию) и отключить если false
WiFi.scanNetworks (true)Запустить фоновую процедуру сканирования сетей, есkb true — то скрытые сети показывать тоже. Результат можно получить, читая переменную {WiFi.scanComplete}, пока вместо «wait» она не вернет список сетей, каждая строка соответствует сети и содержит через пробел:
style='color:
WiFi.scanDeleteОчистить результат последнего сканирования (не надо, это автоматически происходит)
echo {WIFI.scan}Вернуть список сетей одной командой (с ожиданием, устаревший способ)


РАБОТА С UDP и NTP (синхронизация часов)


NTP.update (url)Синхронизировать время по WiFi или LAN, url можно указать (по умолчанию time.nist.gov), порт всегда 123, пример:

<?php
NTP
.update mysite.com
NTP
.update 192.168.100.200
loop 600 NTP
.update
UDP.send [url:port] [Data]отправить пакет Data по UDP на url:port, ответ не принимать, пример:
UDP.send 10.8.0.72:8313 The Text Of Packet for Sending
UDP.ping [url:port] [Data]отправить пакет Data по UDP на url:port, в ответ принять консольные команды и выполнить их процедурой MOTO(), пример:
UDP.send 10.8.0.72:8313 Ask
UDP.get [url:port] [Data]отправить пакет Data по UDP на url:port, в ответ принять некие данные и сохранить их в переменной UDP_result, при получении выполнить процедуру UDP_func, пример:

<?php
set UDP_result 
=
set UDP_func = {
  if {
UDP_result} = OK play D.R.M
  
else play mmm
}
UDP.get mysite.com:8813 Erase_all


РАБОТА С MDNS

MDNS.begin [name]Запустить сервис https://[name].local или остановить если указано пустое имя. Скажем прямо — бессмысленная вещь в реальной жизни.


РАБОТА СО ЗВУКОМ

play (pin) [music]сыграть ноты music на пине pin (если не указан, берется по умолчанию soundpin), музыка кодируется в формате гаммы: DRMFSLCdrmfslc Точка и запятая обозначают паузы длинную и короткую. Если pin не указан (в нормально написанных скриптах его не надо указывать), то используется ранее установленная переменная {sound.pin}. Важно заметить, что переменная {sound.pin.0} указывает, в какое состояние вернуть pin по окончании звучания — по умолчанию это 0, но для устройств, которые используют, например, инвертер для звука, это важно., пример:
play 4 M,d,d,d,d,dd.C,C,r,r,d,C,CC.L,L,L,LS,F,MM.d,dCCC.drddd...M,d,d,d,d,dd.C,C,r,r,d,C,CC.L,L,L,LS,F,MM.d,M,M,L,CCCCC
playip (пин)высвистеть последние три цифры полученного IP в местной сети в пине (если не указан, то soundpin)"), например для 10.9.0.203 это эквивалентно цепочке команд: repeat 2 play 4 M, ; play 4 .. ; repeat 0 play 4 L, ; play 4 .. ; repeat 3 play 4 d,, пример:
{2}
mp3 [файл.mp3]Воспроизвести в эмулированном пине RX файл mp3. Увы, только очень короткие файлы можно, иначе катастрофически не хватает памяти., пример:
mp3 /pes.mp3
mp3stopОстановить воспроизведение mp3, пример:
mp3stop
mp3web [урл]Отключено, потому что чип, скомпилированный в Ардуине, да еще со всем остальным фреймфорком, висящим в памяти, банально не тянет., пример:
mp3web http://radio.4duk.ru/4duk128.mp3


РАБОТА С SERIAL

SERIAL.begin (speed)инициализировать Serial с нужной скоростью, если не указана, то 115200 по умолчанию, пример:
SERIAL.begin 9600
SERIAL.endостановить Serial, пример:
SERIAL.end
SERIAL.flushочистить буффер, пример:
SERIAL.flush
SERIAL.swap (конфигурация)только дял ESP8266: переключить GPIO Serial с RX=3,TX=1 (конфигурация 0) на RX=13,TX=15 (конфигурация 1) и обратно, но также можно строго указать номер конфигурации, пример:
SERIAL.swap 1 # RX=13,TX=15
SERIAL.swap 0 # RX=3,TX=1
echo {SERIALSWAP} # прочитать, какой именно канал сейчас включен
echo [string]напечатать строку, пример:
echo Только что пришла по Serial строка: {SERIAL}
SERIAL1.begin (скорость)Serial1.begin(115200); В отличие от Serial, в ESP12 есть Serial1, который работает только на передачу (TX) и только через GPIO2, с ним тоже реализованы команды, пример:
{2}
SERIAL1.flushSerial1.flush();, пример:
{2}
SERIAL1.endSerial1.end();, пример:
{2}
SERIAL1.setTimeout (время)Serial1.setTimeout(t);, пример:
{2}
UART.init (пин RX) (пин TX) (baud)сделать один Soft-Serial через SerialX (на ESP12 скорость до 9600), но почти на любом пине, если номер -1, то TX или соответственно RX не делать, пример:
UART.init 16 17 115200 # ESP32
UART.init 4 5 9600
UART.init 14 -1 9600
echo {UART} # прочесть, что пришло, либо пустую строку



РАБОТА С СЕРВО

Старый формат:

attach [номер серво] [пин]подключить сервопривод к gpio [пин], пример:
attach 1 5
detach [номер серво]отключить сервопривод к gpio [пин], пример:
detach 1
go [номер серво] [градус]повернуть сервопривод в нужное положение, пример:
go 1 180

Что-то я задолбался таскать с собой чужую громоздкую библиотеку, когда там всего 5 строчек кода. Вот одной командой (не забудьте выставить пину выход: pin 5 OUTPUT):

servo [пин] [градус]повернуть сервопривод в нужное положение от 0 до 180, пример:
servo 5 180


Считыватель бесконтактных карт WIEGAND

WIEGAND.start [pin0] [pin1] [mode]Активировать считыватель Wiegand. pin0 — gpio для получения 0, pin1 — gpio для получения 1, mode — битность 26 или 34, пример:
WIEGAND.start 2 3 34
WIEGAND.endОтключить считыватель WIEGAND, пример:
WIEGAND.end
{WIEGAND}Переменная, из которой считывается полученный код, если есть, пример:

<?php
set CARD 
= {WIEGAND}
if.!empty {
CARD} echo Введена картаее номер"{CARD}"!



РАБОТА С NFC-СКАНЕРОМ БЕСКОНТАКТНЫХ КАРТ RFID-RC522

RC522.initАктивировать сканер карт RC522, подключенный как RST=GPIO5, SDA(SS)=GPIO4, MOSI=GPIO13, MISO=GPIO12, SCK=GPIO14, GND=GND, 3.3V=3.3V, пример:
RC522.init
{RC522.ver}чтение байта версии в 16-ричном коде (обычно 91 или 92), пример:
if {RC522.ver} != 91 {
  echo 
Кажетсянаш сканер подвистихонько перезапустим его
  RC522
.init
}
{RC522.card}чтение карты: возвращает пустое знаечние, если карта еще не была поднесена, или ее номер, если недавно была поднесена, пример:

<?php
set CARD 
= {RC522.card}
if.!empty {
CARD} echo Введена картаее номер"{CARD}"!
{KEY:[filename] [key]}Простой способ организовать элементарные базы данных (и не только для NFC-сканнера). Если в файле filename найдется строка, первое слово которой — ключ key, то вернуть значение (остальную часть строки), иначе вернуть пустое значение. ВАЖНО: при извлечении даже цифровых переменных всегда используйте оператор set. set X = {KEY:...}, а не просто X = {KEY:...}, пример:

<?php
set CARD 
= {RC522.card}
if.!empty {
CARD} {
  echo 
Поднесли карту номер"{CARD}"
  
set NAME = {KEY:/keybasa.txt {CARD}}
  if.empty {
NAME} echo Ключа нет в списке доступа!
  else {
      echo 
Добро пожаловатьуважаемый {NAME}!
      /
DOOR_OPEN_ENGINE
  
}
}


РАБОТА MQTT

MQTT.connect [url:port] [login] [password]соединиться с сервером MQTT, если порт не указан, то 1883. Параметры при вызове этой процедуры также запоминаются в системных переменных
MQTT_server,MQTT_port,
MQTT.reconnectвыполнить пересоединение с MQTT
MQTT.publish [topic] [string]Публикация в топике
MQTT.subscribe [topic]подписка на топик
MQTT.unsubscribe [topic]отписка от топика


РАБОТА MODBUS/TCP SLAVE

MODBUS.beginзапустить иницилизацию
MODBUS.add [reg] (value)создать регистр (номер от 1 до 9999), можно указать ему сразу значение для инициализации
MODBUS.save [reg] (value)записано новое значение в созданный ранее регистр


РАБОТА C ДАТЧИКАМИ


DS18B20.beginзапустить инициализацию датчика температуры DS18B20, датчик поключают по onewire к GPIO4, и только к нему, уж извините. Схема подключения:

, пример:
style='color:, пример:
#0000BB'><?php


РАБОТА C АНАЛОГОВЫМ ВХОДОМ A0

calibrate [пин] [N] [имя]Провести калибровку: рассчитать среднее арифметическое от N измерений пина (конечно он всегда A0) каждые 10 мс и сохроанить в переменную с указанным именем, пример:
calibrate A0 20 SREDNEE
echo Сейчас среднее значение измерений = {SREDNEE}
MOTORSTOP [N]Установить значение внутренней переменной для срабатывания для системы контроля мгновенной остановки мотора, пример:
{2}
TIMER.start (ms)Запустить таймер кольцевой записи параметров всех пинов. Это сложная процедура, которая проводит очень частые (можно указать время в ms, по умолчанию 50) проверки состояния пинов. При этом проводится вычисление Z-фильтра на появление пиков, а также обработка некоторых случаев с вызовом соответствующих процедур., пример:
TIMER.start 50
TIMER.stopОстановить кольцевую запись пинов, пример:
TIMER.stop
set.FLT [lag] [TOL] [THRESHOLD] [INFLUENCE]Установить параметры сглаживающего фильтра измерений, пример:
set.FLT 15 64 6 1.5
echobuf [N]Выдать содержимое кольцевого буфера измерений, начиная с N, пример:
echobuf 0


Операции текстовых строк

{GET:[url]}загрузить страницу из сети (очень короткую! памяти не хватит!) по адресу url, также можно первым аргументом перед url через пробел указать таймаут в мс: {GET: 500 http://lenta.ru/robots.txt}, если не указан, то по умолчанию 5000мс., пример:
set unixtime = {GET: 2000 http://lleo.me/ESP8266/index.php?unixtime=1}
{FILE:[файл]}Загрузить (с внутренней флешки) содержимое файла с именем «файл», пример:
set num = {FILE:/numer.txt}
{FILEMD5:[файл]}подсчитать хэш MD5 файла с именем «файл», пример:
set md5string = {FILEMD5:/ESP.jpg}
{PARSE:[переменная] [шаблон]}ищет в строковой переменой данные по шаблону, где нужный кусок обозначен * Также понимает обозначения: \n \r, пример:
set time = 06:40
set h = {PARSE:time *:}
set m = {PARSE:time :*}
echo m={m} h={h}
{TAKE:[name] [num] [sep]}Разобрать текстовую переменную с именем [name] на аргументы по сепаратору [sep] (если не указан, то разделить по пробелам) и взять аргумент номер [num], пример:
{2}
{SET}вывести дамп всех переменных в формате «имя = [значение]\, пример:
{2}
{INFO}вывести полное инфо, как /info, пример:
{2}
{dir}дать список всех файлов на внутренней флешке в формате «[имя] [размер]\, пример:
{2}
{WIFI.scan}дать список WiFi-сетей вокруг в формате «[доступ] [имя сети]\n», где доступ «free» для открытых и «pass» для закрытых, пример:
{2}


Служебные переменные

Команда формата {имя} покажет значение пользолвательской переменной.
Но в системе есть различные предопределенные переменные, динамические значения, результаты сложных взаимодействий с внешними устройстами и так далее. У них есть свои имена, вот они:

GPIO

{gpio[N]}прочесть значение gpio 1,2,3,4,5,12,13,14,15,16 и A0

Сеть

{ip}полученные IP WiFi.localIP().toString()
{ip_mask}WiFi.subnetMask()
{ip_gateway}WiFi.gatewayIP()
{macAddress}WiFi.macAddress()
{ip_connected}1 или 0 WiFi.isConnected() ? 1 : 0
{ip_autoconnect}1 или 0 WiFi.getAutoConnect() ? 1 : 0
{ip_dns}WiFi.dnsIP(0) + WiFi.dnsIP(1)
{ip_hostname}WiFi.hostname()
{ip_status}WiFi.status()
{ip_ssid}WiFi.SSID()
{ip_psk}WiFi.psk()
{ip_bssid}WiFi.BSSIDstr()
{ip_rssi}WiFi.RSSI()
{softAPIP}WiFi.softAPIP()
{softAPmacAddress}WiFi.softAPmacAddress()
{softAPgetStationNum}WiFi.softAPgetStationNum()
{mdns}return String(mdns);
{LAN.started}Есть ли внешний Ethernet через подключенное устройство

Внутренние параметры чипа ESP

{ESP_TYPE}тип ESP, например: ESP-12, ESP-32, ESP32S2, ESP32S3, ESP32C3
{FreeHeap}ESP.getFreeHeap()
{FreeSketchSpace}ESP.getFreeSketchSpace()
{SketchSize}ESP.getSketchSize()
{chip}ESP.getChipId() HEX
{FlashChipId}ESP.getFlashChipId()
{FlashChipSize}ESP.getFlashChipSize()
{FlashChipRealSize}ESP.getFlashChipRealSize()
{FlashChipSpeed}ESP.getFlashChipSpeed()
{cycles}ESP.getCycleCount()
{CoreVersion}ESP.getCoreVersion()
{FullVersion}ESP.getFullVersion()
{BootVersion}ESP.getBootMode()
{BootMode}ESP.getCycleCount()
{CpuFreq}ESP.getCpuFreqMHz()
{FlashChipSizeByChipId}ESP.getFlashChipSizeByChipId()
{getSketchMD5}ESP.getSketchMD5()
{ResetReason}ESP.getResetReason()
{ResetInfo}ESP.getResetInfo()
{flashmode}ESP.getFlashChipMode() — возвращает QIO, QOUT, DIO, DOUT, UNKNOWN
{vcc}ESP.getVcc()

Файловая система

{Files}Список всех файлов внутренней флешки в формате " [имя]"
{Files_count}число файлов внутренней флешки
{SPIFFStotal}общее количество байт в файловой системе
{SPIFFSused}количество занятых байт в файловой системе
{SPIFFSfree}количество свободных байт в файловой системе

Прошивка и ее опции

{VER}номер версии прошивки (число)
{VERNAME}имя версии прошивки
{MOTORSTOP}флаг остановки мотора
{NBUF}константа — размер буфера
{NLOOP}константа — максимальное количество циклов
{NSET}константа — максимальное количество переменных
{NSERV}константа — максимальное количество серв
{EchoMOTO}return EchoMOTO;

Обработка данные аналогового входа A0

{MaxA0}Значение максимума для срабатывания прерывания по максимуму
{MinA0}Значение минимума для срабатывания прерывания по минимуму
{FltA0}Значение фильтра

Время

{UnixTime}текущее время UnixTime (начинает тикать с 0 в момент старта, нопозже можно записать настоящее время)
{hh}текущие часы
{mm}текущие минуты
{ss}текущие секунды
{dn}день недели, номер 0-6
{ddn}день недели su mo tu we th fr sa
{Time} или {hhmmss}время в формате hhmmss
{millis}число миллисекунд millis();

Внешние устройства

{MQTT}если сервис MQTT поднят, то 1, иначе 0
{DS18B20}считать показания температурного датчика Dallas
{WIEGAND}код последней введенной беспроводной карты
{RC522.ver}версия прошивки считывателя rc522 ( 0x91 или 0x92 )
{RC522.card}код последней прочитанной беспроводной карты со считывателя rc522
{SERIAL}прочесть строку из внутреннего Serial, если была

MODBUS

{MODBUS.started}если сервис ModBus уже был инициализирован, то 1, иначе 0
{MODBUS.last}показать дамп последнего запроса
{MODBUS:[reg]}значение регистра reg

ПРИМЕРЫ

{LOOP:[N]}Число оставшихся секунд до срабатывания цикла по его номеру, пример:
echo До обновления сфота осталось {LOOP:1} секунд
{LOOP:[действия]}Возвращает число оставшихся секунд до срабатывания цикла по его исполняемой команде (если ее помним или это было имя файла, неудобная команда), пример:
echo {LOOP:/MOTOR_STOP.txt}
{LOOP}вывести дамп всех циклов в формате «Loop #[N] [count] of [value] [тело] ONE\n» ONE добавляется — если цикл однократный, пример:
{LOOP}


Системная часть — edge

Также есть системная веб-часть по обращению к веб-сайту чипа, например http://192.168.4.1/info

GET /FM?a=login&password=MYPASSWORDлогиниться админом, получить в ответ hash пароля — доступно всем, не только админу
GET /FM?a=loop&n=3показать сколько осталось секунд до выполнения цикла номер (например 1) — доступно всем, не только админу
GET /FM?a=WIFIconn1переконнектиться по WiFI если сеть была «ESP-HELP», передает «net»+«pass», записывает их в «wifi_last.txt» — доступно всем, не только админу
GET /infoстраница полной информации о чипе и системе
GET /dirсписок файлов на флешке
POST /uploadзагрузка файлов на флешку методом POST
POST /выполнить скрипт, которые передается методом POST
GET /MOTO?scriptвыполнить скрипт, в котором разделители строк заменены на знак «
GET /MOTO?hash=5fd310ef5fd7e6ab523&scriptто же, но выполнить скрипт от незалогиненного пользователя, указав правильный парольный hash

Авторизация

Система позволяет выполнить произвольный скрипт на устройстве, но для этого надо знать пароль, установленный в config.txt («set password = ...»). Сам пароль используется только во время логина, при этом чип возвращает 32-символьный hash MD5, который зависит не только от пароля, но и от уникального серийного номера каждого чипа (для ESP12 это серийный номер чипа и памяти, для ESP32 — МАК-сдрес). В дальнейшем система считает запрос от админа, если правильный хэш передан в куках «ESP=...», либо указан в строке параметров «hash=...»

Вот один из способов управлять устройством с компьютера, зная лишь IP и пароль админа. Сперва надо получить хэш, затем исполнять скрипты — их можно передавать методом POST на эндпоинт «/», либо в строке запроса на эндпоинт «/MOTO», заменяя переводы строк на знак «|».

#!/bin/sh

# change password

hash=`wget -q -O - "http://10.9.0.133/FM?a=login&password=Zyablik123"`

wget -q -O - "http://10.9.0.133/MOTO?hash=${hash}&echo Old Password:{FILE:wifi_last.txt}|
FILE.save.text wifi_last.txt kv121\\nPassword12345|echo New Password{FILE:wifi_last.txt}|pinmode 4 OUTPUT|play 4 DRM"

 


    посещений 759