#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "Timer.h" // Замена стандартному delay
// ~~~ Для обновления по воздуху - BEGIN ~~~
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "hw_timer.h" //Либа для robodyn диммера
//Для robodyn диммера
const byte zcPin = 12; // Zero-cross pin
const byte pwmPin = 13; // PWM pin
byte fade = 1;
byte state = 1;
volatile uint8_t tarDimmerVal = 255;
volatile uint8_t curDimmerVal = 0;
volatile uint8_t zcState = 0; // 0 = ready; 1 = processing;
const char* host = "esp8266-webupdate";
ESP8266WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
// ~~~ Для обновления по воздуху - END ~~~
// ~~~ Чтобы избавиться от delay - BEGIN ~~~
Timer t;
// ~~~ Чтобы избавиться от delay - END ~~~
const char* ssid = "ssid";
const char* password = "password";
const char* mqtt_server = "192.168.1.160";
const char* topicForSubscribe = "esp8266_wifi-dimmer-fan/cmnd/tarDimmerVal"; // Топик, который слушаем
WiFiClient espClient;
PubSubClient client(espClient);
char msgBufferPPM[10]; // буфер для отправки на MQTT сервер
String msg; // Переменная для отправки по MQTT
void setup() {
Serial.println("Starting ...");
Serial.begin(9600);
// ~~~ Dimmer BEGIN ~~~
pinMode(zcPin, INPUT_PULLUP); //Инициализируем порт для zero-cross
pinMode(pwmPin, OUTPUT); //Инициализируем PWM (ШИМ)
attachInterrupt(zcPin, zcDetectISR, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
hw_timer_init(NMI_SOURCE, 0);
hw_timer_set_func(dimTimerISR);
// ~~~ Dimmer END ~~~
// We start by connecting to a WiFi network
wifi_station_set_hostname("WiFi_Dimmer_Fan"); // Задаем имя устройству
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
/* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
would try to act as both a client and an access-point and could cause
network-issues with your other WiFi-devices on your WiFi-network. */
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Инициализируем MQTT сервер
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
// ~~~ Настраиваем обновление по воздуху - BEGIN ~~~
Serial.println();
Serial.println("Booting Sketch...");
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() == WL_CONNECTED) {
MDNS.begin(host);
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.setDebugOutput(true);
WiFiUDP::stopAll();
Serial.printf("Update: %s\n", upload.filename.c_str());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin(maxSketchSpace)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
yield();
});
server.begin();
MDNS.addService("http", "tcp", 80);
Serial.printf("Ready! Open http://%s.local in your browser\n", host);
Serial.print("If doesn't work, for update firmware go to " + WiFi.localIP());
} else {
Serial.println("WiFi Failed");
}
// ~~~ Настраиваем обновление по воздуху - END ~~~
client.setCallback(callback); // Для получения ответа по MQTT
pinMode(2, OUTPUT); // Инициируем внутренний светодиод
t.oscillate(2, 500, HIGH, 5); // Моргаем 5 раз встроенным светодиодом
}
void loop() {
if (!client.connected()) {
delay(1000);
reconnect();
}
client.loop();
server.handleClient(); // Обрабатываем запрос с вебсерверу
t.update(); // Необходимо для нормальной работы Timer
}
// Функция отправки значений диммера
void SendDimmerStatus(){
msg = String(tarDimmerVal);
msg.toCharArray(msgBufferPPM, msg.length()+1);
client.publish("esp8266_wifi-dimmer-fan/dimmer/tarDimmerVal", msgBufferPPM); // отправляем в топик целевое значение диммера
msg = String(curDimmerVal);
msg.toCharArray(msgBufferPPM, msg.length()+1);
client.publish("esp8266_wifi-dimmer-fan/dimmer/curDimmerVal", msgBufferPPM); // отправляем в топик текущее значение диммера
}
void reconnect(){
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
// client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe(topicForSubscribe);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// Метод для получения сообщения по MQTT в Nodemcu
void callback(char *topic, byte *payload, unsigned int length) { //payload - массивы byte (byte[])
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
String stringMsg; // Получаем сообщение в виде String
for (int i = 0; i < length; i++) {
stringMsg += (char)payload[i];
}
tarDimmerVal = stringMsg.toInt();
Serial.print("tarDimmerVal - ");
Serial.println(tarDimmerVal);
stringMsg = "";
if(sizeof(payload) > 1){ // Проверяем длину массива в байтах
t.oscillate(2, 500, HIGH, 2); // Моргаем 5 раз встроенным светодиодом
SendDimmerStatus(); // Отправляем данные
}
}
// Метод для моргания
void blinks() {
digitalWrite(2, HIGH);
delay(500);
digitalWrite(2, LOW);
delay(500);
}
// Функция для WiFi диммера
void dimTimerISR() {
if (fade == 1) {
if (curDimmerVal > tarDimmerVal || (state == 0 && curDimmerVal > 0)) {
--curDimmerVal;
}
else if (curDimmerVal < tarDimmerVal && state == 1 && curDimmerVal < 255) {
++curDimmerVal;
}
}
else {
if (state == 1) {
curDimmerVal = tarDimmerVal;
}
else {
curDimmerVal = 0;
}
}
if (curDimmerVal == 0) {
state = 0;
digitalWrite(pwmPin, 0);
}
else if (curDimmerVal == 255) {
state = 1;
digitalWrite(pwmPin, 1);
}
else {
digitalWrite(pwmPin, 1);
}
zcState = 0;
}
// Функция для WiFi диммера
void zcDetectISR() {
if (zcState == 0) {
zcState = 1;
if (curDimmerVal < 255 && curDimmerVal > 0) {
digitalWrite(pwmPin, 0);
int dimDelay = 30 * (255 - curDimmerVal) + 400;//400
hw_timer_arm(dimDelay);
}
}
}