esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Подключение исполнительных устройств, датчиков, контроллеров.

Модератор: immortal

Ответить
Nastvivl
Сообщения: 3
Зарегистрирован: Ср фев 15, 2017 11:23 am
Благодарил (а): 1 раз
Поблагодарили: 0

esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение Nastvivl » Вт май 30, 2017 9:21 am

Добрый день! Хочу сделать управление рулонными шторами из majordomo при помощи esp8266 + 28BYJ.
Помогите разобраться со скетчем, где ошибка?

Код: Выделить всё

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Stepper.h>

const char* ssid = "ASUS58";                  //Название сети
const char* password = "13591354";           //пароль
const char* mqtt_server = "192.168.1.10";    //ip брокера mqtt

const int stepsPerRevolution = 64;                             // число шагов за оборот
Stepper myStepper(stepsPerRevolution, D1, D2, D5, D6);         // Инициализировать библиотеку степпинга на D1, D2, D5, D6
                                                               // myStepper - название шагового двигателяg
                                                               
WiFiClient espClient;                                          //инициализация WiFi клиента
PubSubClient client(espClient);                                //инициализация MQTT клиента

int max_steps = 640;                                           //максимальное число шагов для открытия шторы по умолчанию (настроить по размеру окна)
int max_level_step = 10;                                       //максимальное число уровней положений открытия шторы по умолчанию (настроить по размеру окна)
int last_level_step = 0;                                       //последенне число уровня положения, по умолчанию всегда 0 

void setup()                                 //Выполняется при запуске 1 раз
{
  Serial.begin(115200);                      //инициализация монитора порта
  client.setServer(mqtt_server, 1883);       //подключаемся к MQTT
  client.setCallback(callback);              //функция получения топиков с брокера
  delay(100);                                //ждем 100 милисекунд
  WiFi.begin(ssid, password);                //подключаемся к WiFi
  delay(2000);                               //ждем 2 секунд
  client.connect("ESP8266Client");           //конектимся с брокером как клиент
  client.subscribe(level_topic);             //подписываемся на топик
  myStepper.setSpeed(80);                    //устанавливаем скорость шагового двигателя на 80 rpm:
}



void callback(char* topic, byte* payload, unsigned int length)    //читаем топики
{                                            
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  int level_step =(char)payload[0]-'0';                              // level_step равен значению из топика

  last_level_step = level_step - last_level_step;                    // определяем на сколько уровней надо изменить от последнего положения
  step_level = last_level_step * max_steps / max_level_step;          // определяем количество шагов для level_step из топика
  myStepper.step(steps_level);                                      // делаем шаги на открытие или закрытие шторки 

}


void reconnect_server()                      //функция проверки подключения
{

  if (WiFi.status() != WL_CONNECTED)         //если нет подключения с сети
  {
    WiFi.begin(ssid, password);   
    Serial.println("");
    Serial.println("WiFi connect...");       //выводим в монитор порта что пытаемся подключиться
  } else                                     //если есть подключение
  {   
    //Serial.println("");
    //Serial.println("WiFi connected");        //выводим в монитор порта что подключились
   // Serial.println("IP address: ");          //выводим в монитор порта наш IP
   // Serial.println(WiFi.localIP());          //выводим в монитор порта наш IP
   // Serial.println(WiFi.RSSI());             //выводим в монитор порта уровень сети
    
  }

  if (!client.connected() && WiFi.status() == WL_CONNECTED) //если к сети подключились но к MQTT нет
  {
    if (client.connect("ESP8266Client"))     //если с брокером уже конектились
  {
      Serial.println("Mosquitto connect...");//выводим в монитор порта что пытаемся подключиться 
      client.subscribe(level_topic);        //подписываемся на топик
    } else                                   //если не получилось
    {
      Serial.print("failed connect Mosquitto, rc="); //пишем ошибку
      Serial.print(client.state());
      Serial.println("");
    }
  }
}

void loop() {                                  //основной цикл
  if (!client.connected()) {
    delay(5000);
    reconnect();
  }
  client.loop();

} 
Вложения
esp+28BYJ.jpg
esp+28BYJ.jpg (51.1 КБ) 11203 просмотра
AlexFox
Сообщения: 55
Зарегистрирован: Пн апр 24, 2017 12:58 pm
Благодарил (а): 9 раз
Поблагодарили: 4 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение AlexFox » Вт май 30, 2017 3:01 pm

Концевик для калибровки двигателя, наверно, не помешал бы. В чем проявляется ошибка
За это сообщение автора AlexFox поблагодарил:
Nastvivl (Вт май 30, 2017 4:15 pm)
Рейтинг: 1.16%
Nastvivl
Сообщения: 3
Зарегистрирован: Ср фев 15, 2017 11:23 am
Благодарил (а): 1 раз
Поблагодарили: 0

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение Nastvivl » Вт май 30, 2017 4:14 pm

не управляется из majordomo, возможно тогда ошибка там или в брокере.
Да, нужно добавить концевик.
Для калибровки думаю оттягивать шторку до закрытия максимально вниз и нажимать кнопку.
При этом шаговик будет крутится до полного открытия, пока не сработает концевик.
если приравнивнять max_steps количеству сосчитаных шагов, то можно применять для окна любого размера.

А как сосчитать количество шагов от нажатия кнопки до срабатывания концевика?
AlexFox
Сообщения: 55
Зарегистрирован: Пн апр 24, 2017 12:58 pm
Благодарил (а): 9 раз
Поблагодарили: 4 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение AlexFox » Вт июн 06, 2017 11:45 am

Nastvivl писал(а):Добрый день! Хочу сделать управление рулонными шторами из majordomo при помощи esp8266 + 28BYJ.
Помогите разобраться со скетчем, где ошибка?

Код: Выделить всё

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Stepper.h>

const char* ssid = "ASUS58";                  //Название сети
const char* password = "13591354";           //пароль
const char* mqtt_server = "192.168.1.10";    //ip брокера mqtt

const int stepsPerRevolution = 64;                             // число шагов за оборот
Stepper myStepper(stepsPerRevolution, D1, D2, D5, D6);         // Инициализировать библиотеку степпинга на D1, D2, D5, D6
                                                               // myStepper - название шагового двигателяg
                                                               
WiFiClient espClient;                                          //инициализация WiFi клиента
PubSubClient client(espClient);                                //инициализация MQTT клиента

int max_steps = 640;                                           //максимальное число шагов для открытия шторы по умолчанию (настроить по размеру окна)
int max_level_step = 10;                                       //максимальное число уровней положений открытия шторы по умолчанию (настроить по размеру окна)
int last_level_step = 0;                                       //последенне число уровня положения, по умолчанию всегда 0 

void setup()                                 //Выполняется при запуске 1 раз
{
  Serial.begin(115200);                      //инициализация монитора порта
  client.setServer(mqtt_server, 1883);       //подключаемся к MQTT
  client.setCallback(callback);              //функция получения топиков с брокера
  delay(100);                                //ждем 100 милисекунд
  WiFi.begin(ssid, password);                //подключаемся к WiFi
  delay(2000);                               //ждем 2 секунд
  client.connect("ESP8266Client");           //конектимся с брокером как клиент
  client.subscribe(level_topic);             //подписываемся на топик
  myStepper.setSpeed(80);                    //устанавливаем скорость шагового двигателя на 80 rpm:
}



void callback(char* topic, byte* payload, unsigned int length)    //читаем топики
{                                            
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  int level_step =(char)payload[0]-'0';                              // level_step равен значению из топика

  last_level_step = level_step - last_level_step;                    // определяем на сколько уровней надо изменить от последнего положения
  step_level = last_level_step * max_steps / max_level_step;          // определяем количество шагов для level_step из топика
  myStepper.step(steps_level);                                      // делаем шаги на открытие или закрытие шторки 

}


void reconnect_server()                      //функция проверки подключения
{

  if (WiFi.status() != WL_CONNECTED)         //если нет подключения с сети
  {
    WiFi.begin(ssid, password);   
    Serial.println("");
    Serial.println("WiFi connect...");       //выводим в монитор порта что пытаемся подключиться
  } else                                     //если есть подключение
  {   
    //Serial.println("");
    //Serial.println("WiFi connected");        //выводим в монитор порта что подключились
   // Serial.println("IP address: ");          //выводим в монитор порта наш IP
   // Serial.println(WiFi.localIP());          //выводим в монитор порта наш IP
   // Serial.println(WiFi.RSSI());             //выводим в монитор порта уровень сети
    
  }

  if (!client.connected() && WiFi.status() == WL_CONNECTED) //если к сети подключились но к MQTT нет
  {
    if (client.connect("ESP8266Client"))     //если с брокером уже конектились
  {
      Serial.println("Mosquitto connect...");//выводим в монитор порта что пытаемся подключиться 
      client.subscribe(level_topic);        //подписываемся на топик
    } else                                   //если не получилось
    {
      Serial.print("failed connect Mosquitto, rc="); //пишем ошибку
      Serial.print(client.state());
      Serial.println("");
    }
  }
}

void loop() {                                  //основной цикл
  if (!client.connected()) {
    delay(5000);
    reconnect();
  }
  client.loop();

}
Я то не андруинщик, но
у меня ошибка выпала при компиляции
client.subscribe(level_topic); нет ""
client.subscribe("level_topic");

Переменная не задана
exit status 1
'step_level' was not declared in this scope

step_level = last_level_step * max_steps / max_level_step; // определяем количество шагов для level_step из топика
AlexFox
Сообщения: 55
Зарегистрирован: Пн апр 24, 2017 12:58 pm
Благодарил (а): 9 раз
Поблагодарили: 4 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение AlexFox » Вт июн 06, 2017 11:51 am

вот исправил вроде, проверить пока не могу



int max_steps = 640; //максимальное число шагов для открытия шторы по умолчанию (настроить по размеру окна)
int max_level_step = 10; //максимальное число уровней положений открытия шторы по умолчанию (настроить по размеру окна)
int last_level_step = 0; //последенне число уровня положения, по умолчанию всегда 0
int level_step;

void setup() //Выполняется при запуске 1 раз
{
Serial.begin(115200); //инициализация монитора порта
client.setServer(mqtt_server, 1883); //подключаемся к MQTT
client.setCallback(callback); //функция получения топиков с брокера
delay(100); //ждем 100 милисекунд
WiFi.begin(ssid, password); //подключаемся к WiFi
delay(2000); //ждем 2 секунд
client.connect("ESP8266Client"); //конектимся с брокером как клиент
client.subscribe("level_topic"); //подписываемся на топик
myStepper.setSpeed(80); //устанавливаем скорость шагового двигателя на 80 rpm:
}



void callback(char* topic, byte* payload, unsigned int length) //читаем топики
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
int level_step =(char)payload[0]-'0'; // level_step равен значению из топика

last_level_step = level_step - last_level_step; // определяем на сколько уровней надо изменить от последнего положения
level_step = last_level_step * max_steps / max_level_step; // определяем количество шагов для level_step из топика
myStepper.step(level_step); // делаем шаги на открытие или закрытие шторки

}


void reconnect() //функция проверки подключения
{

if (WiFi.status() != WL_CONNECTED) //если нет подключения с сети
{
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("WiFi connect..."); //выводим в монитор порта что пытаемся подключиться
} else //если есть подключение
{
//Serial.println("");
//Serial.println("WiFi connected"); //выводим в монитор порта что подключились
// Serial.println("IP address: "); //выводим в монитор порта наш IP
// Serial.println(WiFi.localIP()); //выводим в монитор порта наш IP
// Serial.println(WiFi.RSSI()); //выводим в монитор порта уровень сети

}

if (!client.connected() && WiFi.status() == WL_CONNECTED) //если к сети подключились но к MQTT нет
{
if (client.connect("ESP8266Client")) //если с брокером уже конектились
{
Serial.println("Mosquitto connect...");//выводим в монитор порта что пытаемся подключиться
client.subscribe("level_topic"); //подписываемся на топик
} else //если не получилось
{
Serial.print("failed connect Mosquitto, rc="); //пишем ошибку
Serial.print(client.state());
Serial.println("");
}
}
}

void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();

}
AlexFox
Сообщения: 55
Зарегистрирован: Пн апр 24, 2017 12:58 pm
Благодарил (а): 9 раз
Поблагодарили: 4 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение AlexFox » Пн сен 18, 2017 9:58 am

Добрался я до штор, к сожалению такой способ не пойдет, мотору не хватает тяги(((. Буду пробывать непосредственно через вал штор крутить, хотя тоже сомнения что вытянет.
Вложения
IMG_20170916_20230911.jpg
IMG_20170916_20230911.jpg (21.32 КБ) 10197 просмотров
Aven
Сообщения: 529
Зарегистрирован: Сб мар 12, 2016 6:33 pm
Откуда: Ухта, Россия
Благодарил (а): 3 раза
Поблагодарили: 154 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение Aven » Пн сен 18, 2017 10:09 am

Вот неплохое видео по шторам:
https://www.youtube.com/watch?v=oTfA9c2-ztM
AlexFox
Сообщения: 55
Зарегистрирован: Пн апр 24, 2017 12:58 pm
Благодарил (а): 9 раз
Поблагодарили: 4 раза

Re: esp8266 + шаговый двигатель 28BYJ (рулонные шторы)

Сообщение AlexFox » Чт дек 28, 2017 9:48 pm

Короче и через вал не тянет.
Подогнали мне немовский шаговик, купил драйвер drv8825 https://ru.aliexpress.com/item/3d-print ... 0.0.KYibM2, и блок питания 12В, 3 А и повесил на esp8266 через преобразователь 12/5. Вот тогда завелось!!!
Все работает - красота!!
Единственное я все get-запросами сделал. Геркон не зависимо от алисы контролирует штору, ну и управлять можно не только алисой, но и выключателем 433Мгц https://ru.aliexpress.com/item/86-Wall- ... 0.0.Coj0Jd
Заодно они и свет выключают. На штору только одну кнопку заюзал - нажал открылась, еще нажал - закрылась. А и еще освещенность измеряю, фоторезистором на аналоговый вход

Код: Выделить всё

#include <ESP8266WiFi.h> 
#include <RCSwitch.h> 
RCSwitch mySwitch = RCSwitch(); 

int val; 
int valtest; 

int stp = D5; //connect pin  D5 
int dir = D6; // connect pin  D6 
int led = D4; // connect pin  D4 
int ena = D7; // connect pin  D7 
int D8in = D8; // connect pin  D8 
int a = 0; // gen counter 

const char* ssid = "myssid"; 
const char* password = "mypsw"; 
int stepdelay=10; 
boolean x = false;
boolean PIR = false;
 

WiFiServer server(80); 

void setup() { 
mySwitch.enableReceive(D2); 
Serial.begin(115200); 
delay(10); 
Serial.println(); 
Serial.println(); 
Serial.print("Connecting to "); 
Serial.println(ssid); 

pinMode(stp, OUTPUT); //D5 
pinMode(dir, OUTPUT); //D6 
pinMode(led, OUTPUT); //D4 
pinMode(ena, OUTPUT); //D7 
digitalWrite(ena, HIGH); 
pinMode(D8in, INPUT); //D8 pir 
digitalWrite(D4, HIGH);
////////////////////////////////////////////////////// 
pinMode(D1, INPUT); //switch UP 
WiFi.softAPdisconnect(true); 
WiFi.mode(WIFI_STA); 
WiFi.begin(ssid, password); 

while (WiFi.status() != WL_CONNECTED) { 
delay(500); 
Serial.print("."); 
} 
Serial.println(""); 
Serial.println("WiFi connected"); 

// Start the server 
server.begin(); 
Serial.println("Server started"); 

// Print the IP address 
Serial.println(WiFi.localIP()); 
} 

void loop() { 

////////////////////////////BBBBB UP///////po chasovoj///////////////////////////////////////// 
if (mySwitch.available()) { 
int value = mySwitch.getReceivedValue(); 
int valueD1 = digitalRead(D1); //switch UP 
if (value == 14379832 && valueD1 == LOW && x==false) { 
Serial.println("buttonB UP"); 
digitalWrite(dir, HIGH);//направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1600; i++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == HIGH) 
{ 
i=0; 
break; 
} 
} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//ставит тормоз 
mySwitch.resetAvailable(); 
x=true; 
val = 1; 
delay(500); 
} 

////////////////////////////BBBBB DOWN up///////protiv chasovoj///////////////////////////////////////// 
else if (value == 14379832 && valueD1 == LOW & x==true) { 
Serial.println("buttonB UP"); 
digitalWrite(dir, HIGH);//направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1600; i++) //поднимаем до сработки геркона или 1600 шагов 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == HIGH) 
{ 
i=0; 
break; 
} 
} 
Serial.println("buttonB down"); 
digitalWrite(dir, LOW); //направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int n=0; n <= 1600; n++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//снимает тормоз 
mySwitch.resetAvailable(); 
x=false; 
val = 0; 
delay(500); 
}


////////////////////////////BBBBB DOWN///////protiv chasovoj///////////////////////////////////////// 
else if (value == 14379832 && valueD1 == HIGH) { 
Serial.println("buttonB down"); 
digitalWrite(dir, LOW); //направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1700; i++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == LOW) 
{ 
i=0; 
break; 
} 
} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//снимает тормоз 
mySwitch.resetAvailable();
x=false; 
val = 0; 
delay(500); 
} 
} 
// Check if a client has connected 
WiFiClient client = server.available(); 
if (!client) { 
return; 
} 

// Read the first line of the request 
String req = client.readStringUntil('\r'); 

int valueD1 = digitalRead(D1); //switch UP 
///////////////////////////////////////////////////////UP////////////// 
if (req.indexOf("/gpio/open") >0 && valueD1 == LOW && x==false)
{ 
Serial.println("buttonB UP"); 
digitalWrite(dir, HIGH);//направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1600; i++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == HIGH) 
{ 
i=0; 
break; 
} 
} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//ставит тормоз 
x=true; 
val = 1; 
delay(500); 
} 


////////////////////////////////////////////////////DOWN up////////// 
if (req.indexOf("/gpio/close") >0 && valueD1 == LOW & x==true) { 
Serial.println("buttonB UP"); 
digitalWrite(dir, HIGH);//направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1600; i++) //поднимаем до сработки геркона или 1600 шагов 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == HIGH) 
{ 
i=0; 
break; 
} 
} 
Serial.println("buttonB down"); 
digitalWrite(dir, LOW); //направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int n=0; n <= 1600; n++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//снимает тормоз 
x=false; 
val = 0; 
delay(500); 
}
////////////////////////////////////////////////////DOWN///////////////////////// 
if (req.indexOf("/gpio/close") >0 && valueD1 == HIGH) { 
Serial.println("buttonB down"); 
digitalWrite(dir, LOW); //направление задает 
digitalWrite(ena, LOW);//снимает тормоз 
for (int i=0; i <= 1700; i++) 
{ 
digitalWrite(stp, HIGH); 
delay(stepdelay); 
digitalWrite(stp, LOW); 
delay(stepdelay); 

int valueD1 = digitalRead(D1); //switch UP 
if (valueD1 == LOW) 
{ 
i=0; 
break; 
} 
} 
digitalWrite(stp, LOW); digitalWrite(stp, LOW); 
digitalWrite(ena, HIGH);//снимает тормоз 
x=false; 
val = 0; 
delay(500); 
} 
 

if (req.indexOf("/reset") >0) { 
ESP.restart(); 
} 

client.flush(); 
client.println("<HTML>"); client.println("<HEAD>"); client.println("<TITLE>ESPwindow</TITLE>"); client.println("</HEAD>"); client.println("<BODY>"); 
// followed by the HTML for the customised button GUI. 
client.println("<br>"); // new line 
client.print("<input type=button style=width:100px;height:45px value= Open onmousedown=location.href='/gpio/open'>"); 
client.print("<input type=button style=width:100px;height:45px value= Close onmousedown=location.href='/gpio/close'>"); 
client.print("<input type=button style=width:100px;height:45px value= Reset onmousedown=location.href='/reset'>"); 
client.println("<br>"); 
client.print("Analog input A0: "); //analog light 
client.print("<level>"); 
client.print(analogRead(A0)); 
client.print("</level>"); 
client.println("<br>"); 
client.print("Digital output D0 GPIO16: "); //
client.print("<D0>"); 
client.print(digitalRead(D0)); 
client.print("</D0>"); 
client.println("<br>"); 
client.print("Digital input D1 GPIO05 switch UP: "); //button DOWN 
client.print("<D1>"); 
client.print(digitalRead(D1)); 
client.print("</D1>"); 
client.println("<br>"); 
client.print("Digital input D8 PIR: "); //PIR 
client.print("<D8>"); 
client.print(digitalRead(D8)); 
client.print("</D8>"); 
client.println("<br>"); 
client.print("Virtual switch B: "); //button B 
client.print("<V1>"); 
client.print(x); 
client.print("</V1>"); 
client.println("</BODY>"); 
client.println("</HTML>"); 
//stopping client 
client.stop(); 
return; 
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now "; 
s += (val)?"high":"low"; 
s += (valtest)?"high":"low"; 
s += "</html>\n"; 
}
Ответить