Skip to content

Instantly share code, notes, and snippets.

@ilyushchenko
Created March 9, 2018 15:25
Show Gist options
  • Save ilyushchenko/f583c59ec87e2d046383cd8ab2f13694 to your computer and use it in GitHub Desktop.
Save ilyushchenko/f583c59ec87e2d046383cd8ab2f13694 to your computer and use it in GitHub Desktop.
//#include <ESP8266WiFi.h>
//#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Ticker.h>
const char* host = "master";
const char* ssid = "unnamed";
const char* password = "answer61";
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
Ticker buttonChecker;
Ticker longPressTicker;
#define DEBUG true
// Конфигурация входов и выходов
#if DEBUG
#define RELAY1 13
#define RELAY2 15
#define BUTTON 2
#else
#define RELAY1 12
#define RELAY2 14
#define BUTTON 0
#endif
// Задержки
#define LONG_PRESS_DELAY 1000 // Задержка, для длинного нажатия
#define SHORT_PRESS_DELAY 25 // Задержка, для проверки нажатия кнопки
#define BUTTON_CD_TIME 250 // Задержка, для защиты от повторного нажатия
volatile bool IsActive = false;
volatile bool buttonPressEnd = false;
volatile unsigned long pushTime = 0;
volatile unsigned long buttonCountdownTime = 0;
volatile int statePosition = 0;
const int relay_1_state[] = {HIGH, LOW, HIGH };
const int relay_2_state[] = {LOW, HIGH, HIGH };
enum ButtonState { NotPressed = 1, UnhandledShortPress, ShortPress, UnhandledLongPress, LongPress };
enum OutTransition { Initial = 1, OnToOff, OffToOn };
volatile ButtonState buttonState = NotPressed;
volatile OutTransition outState = Initial;
void setup() {
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
Off();
Serial.begin(115200);
Serial.println();
Serial.println("Booting Sketch...");
Serial.print("Debug mode: ");
Serial.println((DEBUG) ? "ON" : "OFF");
Serial.println("Setup input's");
pinMode(BUTTON, INPUT);
Serial.println("Setup Interrupt");
attachInterrupt(BUTTON, ButtonOneInt, FALLING);
Serial.println("Setup WIFI connection");
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
WiFi.begin(ssid, password);
Serial.println("WiFi failed, retrying.");
}
MDNS.begin(host);
httpUpdater.setup(&httpServer);
httpServer.on ( "/switch", handleRoot );
httpServer.on ( "/", handleRoot );
httpServer.onNotFound ( handleNotFound );
httpServer.begin();
MDNS.addService("http", "tcp", 80);
Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
Serial.println(WiFi.localIP());
Serial.println("Done");
Serial.println();
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += httpServer.uri();
message += "\nMethod: ";
message += ( httpServer.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += httpServer.args();
message += "\n";
for ( uint8_t i = 0; i < httpServer.args(); i++ ) {
message += " " + httpServer.argName ( i ) + ": " + httpServer.arg ( i ) + "\n";
}
httpServer.send ( 404, "text/plain", message );
}
void handleRoot() {
if (httpServer.method() == HTTP_POST)
SwitchState();
char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf ( temp, 400,
"<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>ESP8266 Demo</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<form method='post'>\
<button type='submit'>Switch</button>\
</form>\
<p>Uptime: %02d:%02d:%02d</p>\
</body>\
</html>",
hr, min % 60, sec % 60
);
httpServer.send ( 200, "text/html", temp );
}
void pin_ISR_long_check(int buttonPin) {
noInterrupts();
unsigned long currentTime = millis();
unsigned long delta = currentTime - pushTime;
if (IsButtonPressed(buttonPin)) {
// Обработка UnhandledLongPress
if (buttonState == ShortPress && delta > LONG_PRESS_DELAY && currentTime > buttonCountdownTime) {
OnUnhandledLongPress();
buttonState = LongPress;
}
// Обработка LongPress
if (buttonState == LongPress && delta > LONG_PRESS_DELAY && currentTime > buttonCountdownTime) {
buttonCountdownTime = currentTime + LONG_PRESS_DELAY;
OnLongPress();
}
}
else {
longPressTicker.detach();
OnEndPress();
buttonCountdownTime = currentTime + BUTTON_CD_TIME; // Задержка, для предотвращения случайного повторного нажатия
buttonPressEnd = true; // Флаг, для дебага
}
interrupts();
}
// Блок методов-обработчиков событий нажатия
// Обработчик короткого нажатия
void OnShortPress()
{
if (outState == OffToOn) {
On();
}
}
// Обработчик длинного нажатия, срабатывающий единожды
void OnUnhandledLongPress()
{
outState = Initial;
}
// Обработчик длинного нажатия
void OnLongPress()
{
if (IsActive && buttonState == LongPress) {
SwitchMode();
On();
}
}
// Обработчик конца нажатия
void OnEndPress()
{
if (outState == OnToOff) {
Off();
}
}
void CheckButtonPosition(int buttonPin) {
noInterrupts();
// Если кнопка все еще нажата, то начинаем анализ состояния кнопки
if (IsButtonPressed(buttonPin)) {
pushTime = millis(); // Фикисруем время нажитя кнопки
buttonState = ShortPress; // Задаем состояние кнопки - короткое нажатие
outState = (IsActive) ? OnToOff : OffToOn; // Указываем, как происходит нажатие. С выключенного на включенное состояние или наоборот
buttonCountdownTime = pushTime + LONG_PRESS_DELAY; // Задаем задержку, для длинного нажатия
OnShortPress(); // Вызов обработчика первого нажатия на кнопку
longPressTicker.attach_ms(10, pin_ISR_long_check, buttonPin); // Запускаем таймер проверки нажатия
}
//TODO: Если придется отключать прерывание на пин, то здесь надо будет его включить заново
interrupts();
}
void ButtonOneInt() {
noInterrupts();
unsigned long currentTime = millis();
// Проверяем, прошло ли время задержки нажатия
if (currentTime > buttonCountdownTime) {
// Запуск таймера на проверку нажатия через 50 мс
buttonChecker.once_ms(50, CheckButtonPosition, BUTTON);
}
interrupts();
}
void SwitchState() {
if (IsActive)
Off();
else
On();
}
void SwitchMode() {
statePosition++;
if (statePosition > 2)
statePosition = 0;
}
void On() {
IsActive = true;
digitalWrite(RELAY1, relay_1_state[statePosition]);
digitalWrite(RELAY2, relay_2_state[statePosition]);
}
void Off() {
IsActive = false;
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
}
bool IsButtonPressed(int button) {
return digitalRead(button) ? false : true;
}
void loop() {
httpServer.handleClient();
if (buttonPressEnd)
{
unsigned long currentTime = millis();
unsigned long delta = currentTime - pushTime;
Serial.println("--------------------");
Serial.println("Button Press End");
Serial.println("--------------------");
Serial.println();
Serial.print("Push time: ");
Serial.print(pushTime);
Serial.println(" ms");
Serial.print("Cuttent Time: ");
Serial.print(currentTime);
Serial.println(" ms");
Serial.print("Pushing time: ");
Serial.print(delta);
Serial.println(" ms");
Serial.print("Button end state: ");
switch (buttonState) {
case NotPressed:
Serial.println("NotPressed");
break;
case UnhandledShortPress:
Serial.println("UnhandledShortPress");
break;
case ShortPress:
Serial.println("ShortPress");
break;
case LongPress:
Serial.println("LongPress");
break;
default:
Serial.println("ERROR");
break;
}
Serial.println();
buttonPressEnd = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment