Ethernet выключатель нагрузки в локальной сети
- Войдите на сайт для отправки комментариев
Чт, 27/12/2018 - 14:12
Надоело слать SMS для удаленного включения домашнего сервера, собрал на Arduino Pro Mini и W5500 выключатель с простенькой авторизацией по паролю.
#include <avr/wdt.h> #include <SPI.h> #include <Ethernet2.h> #include <EEPROM.h> #define eeprom_pos_device_mode 241 // 26 - device is on byte deviceMode; // 1 is on #define eeprom_pos_last_relay 245 // 49 - relay 2 byte lastRelay; #define WORK_LEVEL_RELAY 0 // 1 if HIGH level ON relay, else 0 #define relay1_pin 4 // pin relay 1 #define relay2_pin 5 // pin relay 2 #if (WORK_LEVEL_RELAY == 0) #define RELAY1ON digitalWrite(relay1_pin,LOW) #define RELAY2ON digitalWrite(relay2_pin,LOW) #define RELAY1OFF digitalWrite(relay1_pin,HIGH) #define RELAY2OFF digitalWrite(relay2_pin,HIGH) #else #define RELAY1ON digitalWrite(relay1_pin,HIGH) #define RELAY2ON digitalWrite(relay2_pin,HIGH) #define RELAY1OFF digitalWrite(relay1_pin,LOW) #define RELAY2OFF digitalWrite(relay2_pin,LOW) #endif unsigned long currentMillis; // main timer byte mac[] = {0xD4, 0xA8, 0xB7, 0x6F, 0x5E, 0x4D}; EthernetServer server(80); #define maxSizeResponse 64 char resp_buf[maxSizeResponse]; // response buf from modem byte pos_buf = 0; // current pos response buf #define period_wait_pass 30000UL unsigned long timer_wait_pass; uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); void get_mcusr(void) \ __attribute__((naked)) \ __attribute__((used)) \ __attribute__((section(".init3"))); void get_mcusr(void) { mcusr_mirror = MCUSR; MCUSR = 0; wdt_disable(); } void setup() { MCUSR = 0; wdt_disable(); // put your setup code here, to run once: pinMode(relay1_pin, OUTPUT); pinMode(relay2_pin, OUTPUT); if (EEPROM.read(eeprom_pos_device_mode) == 26) deviceON(); else deviceOFF(); if (Ethernet.begin(mac)) server.begin(); wdt_enable(WDTO_4S); } void loop() { // put your main code here, to run repeatedly: wdt_reset(); //delay(5000); // test WDT currentMillis = millis(); // ----- EthernetClient client = server.available(); if (client) processServer(client); } void processServer(EthernetClient ec) { // an http request ends with a blank line boolean requestRoot = false; boolean passwordOK = false; boolean havePost = false; boolean currentLineIsBlank = true; clearRespBuf(); while (ec.connected()) { if (ec.available()) { char c = ec.read(); if ((pos_buf < (maxSizeResponse - 1)) && (c)) { resp_buf[pos_buf] = c; ++pos_buf; } if (((strPos(resp_buf, "GET / HTTP")) >= 0) || ((strPos(resp_buf, "GET /? HTTP")) >= 0)) requestRoot = true; if (((strPos(resp_buf, "POST / HTTP")) >= 0) || ((strPos(resp_buf, "POST /? HTTP")) >= 0)) havePost = true; // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { if (havePost) { clearRespBuf(); // find password while (ec.available()) { char c = ec.read(); if ((pos_buf < (maxSizeResponse - 1)) && (c)) { resp_buf[pos_buf] = c; ++pos_buf; } if (strPos(resp_buf, "password=1234") >= 0) { passwordOK = true; break; } } } if ((requestRoot) && ((currentMillis - timer_wait_pass) >= period_wait_pass)) { // show form ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("<br />"); // show enter pass page ec.print("Device is "); if (deviceMode) ec.println("ON"); else ec.println("OFF"); ec.println("<br />"); ec.println("<p></p>"); ec.println("<form action=\"?\" method=\"post\">"); ec.println("<div>"); ec.println("<label for=\"password\">Pass: <input type=\"password\" name=\"password\" id=\"password\"></label>"); ec.println("</div>"); ec.println("<p></p>"); ec.println("<div>"); ec.println("<input type=\"submit\" value=\"Enter\">"); ec.println("</div>"); ec.println("</form>"); ec.println("</html>"); timer_wait_pass = currentMillis; break; } else if (havePost) { // go to null page ec.println("HTTP/1.1 302 Found"); ec.println("Location: /"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("</html>"); timer_wait_pass = currentMillis; break; } else { // show null page ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("</html>"); break; } } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: ec.stop(); if (passwordOK) { if (deviceMode) { deviceOFF(); } else { deviceON(); } } } char* LastPos(char *str1, char *str2) { // find substring in string int L1 = strlen(str1); int L2 = strlen(str2); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (; j < L2; j++) if ((str1[i + j] != str2[j])) break; if (j == L2) return str1 + i; } return 0; } int strPos(char *str11, char *str22) { // find position in string(1) substring(2) char*p = LastPos(str11, str22); int n = p - str11; return n; } void clearRespBuf() { memset(resp_buf, 0, maxSizeResponse); pos_buf = 0; } void deviceON() { EEPROM.write(eeprom_pos_device_mode, 26); deviceMode = 1; if (EEPROM.read(eeprom_pos_last_relay) == 49) { RELAY1ON; delay(50); RELAY2ON; } else { RELAY2ON; delay(50); RELAY1ON; } } void deviceOFF() { EEPROM.write(eeprom_pos_device_mode, 0); deviceMode = 0; if (EEPROM.read(eeprom_pos_last_relay) == 49) { RELAY1OFF; delay(50); RELAY2OFF; EEPROM.write(eeprom_pos_last_relay, 0); } else { RELAY2OFF; delay(50); RELAY1OFF; EEPROM.write(eeprom_pos_last_relay, 49); } }
Поскольку большую часть времени железка простаивает, добавил к ней несколько дополнительных функций: раз в сутки берет время с NTP сервера, каждый час по MQTT получает с удаленной железки (ESP8266) в деревне температуру и показывает списком последние 10 значений. Включение/отключение нагрузки идет по случайно выбранному паролю из трех (или больше - в скетче вводится).
#include <avr/wdt.h> #include <SPI.h> #include <Ethernet2.h> #include <EEPROM.h> struct tempItem { char dateTime[18]; char currTemp[6]; }; #define max_count_temp_item 10 byte countTemp; byte posTemp; tempItem massTemp[max_count_temp_item + 1]; char mqtt_server[] = "m20.cloudmqtt.com"; // Имя сервера MQTT int mqtt_port = 19791; // Порт для подключения к серверу MQTT char mqtt_user[] = "*******"; // Логи от сервер char mqtt_pass[] = "********"; // Пароль от сервера char mqtt_id[] = "catsrv01"; char mqtt_device[] = "Chmd01"; char mqtt_topic_temp[] = "/temp"; char mqtt_topic_gettemp[] = "/gettemp"; EthernetClient clientMqtt; #define period_mqtt_request 3600000UL unsigned long timer_mqtt_request = 0; #define period_wait_mqtt 8000UL unsigned long timer_wait_mqtt; #define eeprom_pos_device_mode 241 // 26 - device is on byte deviceMode; // 1 is on #define eeprom_pos_last_relay 245 // 49 - relay 2 byte lastRelay; #define WORK_LEVEL_RELAY 0 // 1 if HIGH level ON relay, else 0 #define relay1_pin 4 // pin relay 1 #define relay2_pin 5 // pin relay 2 #if (WORK_LEVEL_RELAY == 0) #define RELAY1ON digitalWrite(relay1_pin,LOW) #define RELAY2ON digitalWrite(relay2_pin,LOW) #define RELAY1OFF digitalWrite(relay1_pin,HIGH) #define RELAY2OFF digitalWrite(relay2_pin,HIGH) #else #define RELAY1ON digitalWrite(relay1_pin,HIGH) #define RELAY2ON digitalWrite(relay2_pin,HIGH) #define RELAY1OFF digitalWrite(relay1_pin,LOW) #define RELAY2OFF digitalWrite(relay2_pin,LOW) #endif byte workMode = 0; // 0 - send ntp packet // 1 - wait response ntp // default - http web server #define period_ntp_wait 1000UL unsigned long timer_ntp_wait; #define localPort 123 // local port to listen for UDP packets char timeServer[] = "213.141.154.170"; // time.nist.gov NTP server #define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message char packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets byte posBuffer; EthernetUDP Udp; byte nDay, nMonth, nHour, nMin; word nYear; unsigned long start_ntp_time; unsigned long timer_day_ntp_time; unsigned long timer_min_ntp_time; byte daysY[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; unsigned long currentMillis; // main timer byte mac[] = {0xD4, 0xA8, 0xB7, 0x6F, 0x5E, 0x4D}; EthernetServer server(80); #define countPass 3 char* switchPassword[] = {"789", "456", "123"}; byte passID; #define maxSizeResponse 64 char resp_buf[maxSizeResponse]; // response buf from modem byte pos_buf = 0; // current pos response buf #define period_wait_pass 30000UL unsigned long timer_wait_pass = 0; uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); void get_mcusr(void) \ __attribute__((naked)) \ __attribute__((used)) \ __attribute__((section(".init3"))); void get_mcusr(void) { mcusr_mirror = MCUSR; MCUSR = 0; wdt_disable(); } void setup() { MCUSR = 0; wdt_disable(); // put your setup code here, to run once: randomSeed(analogRead(A7)); passID = random(countPass); pinMode(relay1_pin, OUTPUT); pinMode(relay2_pin, OUTPUT); if (EEPROM.read(eeprom_pos_device_mode) == 26) deviceON(); else deviceOFF(); if (Ethernet.begin(mac)) server.begin(); countTemp = 0; posTemp = 0; wdt_enable(WDTO_4S); } void loop() { // put your main code here, to run repeatedly: wdt_reset(); //delay(5000); // test WDT currentMillis = millis(); switch (workMode) { case 0: { Udp.begin(localPort); sendNTPpacket(timeServer); ++workMode; timer_ntp_wait = currentMillis; break; } case 1: { if ((currentMillis - timer_ntp_wait) >= period_ntp_wait) { if (Udp.parsePacket()) { Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer convertNTPtime(); start_ntp_time = currentMillis; timer_day_ntp_time = currentMillis; timer_min_ntp_time = currentMillis; Ethernet.maintain(); } else { nDay = 1; nMonth = 1; nYear = 1900; nHour = 0; nMin = 0; } memset(packetBuffer, 0, NTP_PACKET_SIZE); posBuffer = 0; workMode = 10; } break; } case 2: { clientMqtt.stop(); if (clientMqtt.connect(mqtt_server, mqtt_port)) { sendConnectPacket(); sendSubscribeTemp(); sendPubGetTemp(); memset(packetBuffer, 0, NTP_PACKET_SIZE); posBuffer = 0; timer_wait_mqtt = currentMillis; ++workMode; // wait response mqtt } else { clientMqtt.stop(); timer_mqtt_request = currentMillis; workMode = 10; } break; } case 3: { if ((currentMillis - timer_wait_mqtt) < period_wait_mqtt) { // wait/find data from server while (clientMqtt.available()) { char c = clientMqtt.read(); if ((posBuffer < (NTP_PACKET_SIZE - 1)) && (c)) { packetBuffer[posBuffer] = c; ++posBuffer; } } } else { sendDisConnectPacket(); clientMqtt.stop(); timer_mqtt_request = currentMillis; parseMqtt(); workMode = 10; } break; } default: { EthernetClient client = server.available(); if (client) processServer(client); // update current time if ((currentMillis - timer_day_ntp_time) >= 86400000UL) { // 1 day workMode = 0; // update date time from NTP server } else if ((currentMillis - timer_min_ntp_time) >= 60000UL) { // 1 min timer_min_ntp_time = currentMillis; updateCurrentTime(); } // mqtt actions if ((currentMillis - timer_mqtt_request) >= period_mqtt_request) { workMode = 2; // connect mqtt server } // end } } } void processServer(EthernetClient ec) { // an http request ends with a blank line boolean requestRoot = false; boolean requestSw = false; boolean passwordOK = false; boolean havePost = false; boolean currentLineIsBlank = true; char findPass[24]; findPass[0] = 0; strcat(findPass, "password="); strcat(findPass, switchPassword[passID]); clearRespBuf(); while (ec.connected()) { if (ec.available()) { char c = ec.read(); if ((pos_buf < (maxSizeResponse - 1)) && (c)) { resp_buf[pos_buf] = c; ++pos_buf; } if (((strPos(resp_buf, "GET /switch")) >= 0) || ((strPos(resp_buf, "GET /SWITCH")) >= 0)) requestSw = true; if (((strPos(resp_buf, "GET / HTTP")) >= 0) || ((strPos(resp_buf, "GET /? HTTP")) >= 0)) requestRoot = true; if (((strPos(resp_buf, "POST / HTTP")) >= 0) || ((strPos(resp_buf, "POST /? HTTP")) >= 0) || ((strPos(resp_buf, "POST /switch")) >= 0) || ((strPos(resp_buf, "POST /SWITCH")) >= 0)) havePost = true; // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { if (havePost) { clearRespBuf(); // find password while (ec.available()) { char c = ec.read(); if ((pos_buf < (maxSizeResponse - 1)) && (c)) { resp_buf[pos_buf] = c; ++pos_buf; } if (strPos(resp_buf, findPass) >= 0) { passwordOK = true; break; } } } if ((requestSw) && ((currentMillis - timer_wait_pass) >= period_wait_pass)) { passID = random(countPass); // show form ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("<br />"); // show enter pass page ec.print("Device is "); if (deviceMode) ec.println("ON"); else ec.println("OFF"); ec.print("id "); ec.println((passID + 1), DEC); ec.println("<br />"); ec.println("<p></p>"); ec.println("<form action=\"?\" method=\"post\">"); ec.println("<div>"); ec.println("<label for=\"password\">Pass: <input type=\"password\" name=\"password\" id=\"password\"></label>"); ec.println("</div>"); ec.println("<p></p>"); ec.println("<div>"); ec.println("<input type=\"submit\" value=\"Enter\">"); ec.println("</div>"); ec.println("</form>"); ec.println("</html>"); timer_wait_pass = currentMillis; break; } else if (havePost) { // go to null page ec.println("HTTP/1.1 302 Found"); ec.println("Location: /switch/"); // the connection will be closed after completion of the response /*ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("</html>");*/ timer_wait_pass = currentMillis; break; } else if (requestRoot) { // show chart mqtt page ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print(nDay, DEC); ec.print('.'); ec.print(nMonth, DEC); ec.print('.'); ec.print(nYear, DEC); ec.print(' '); ec.print(nHour, DEC); ec.print(':'); ec.println(nMin, DEC); ec.println("<br />"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("<br />"); byte idxMass; if (countTemp < max_count_temp_item) idxMass = 0; else idxMass = posTemp; for (byte i = 0; i < countTemp; ++i) { ec.println(massTemp[idxMass].dateTime); ec.println(" - "); ec.println(massTemp[idxMass].currTemp); ec.println("<br />"); if ((++idxMass) > max_count_temp_item) idxMass = 0; } ec.println("<br />"); ec.println("</html>"); break; } else { // show null page ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close"); // the connection will be closed after completion of the response ec.println(); ec.println("<!DOCTYPE HTML>"); ec.println("<html>"); ec.print("Uptime = "); unsigned long upm = currentMillis / 60000UL; ec.print(upm, DEC); ec.println(" min."); ec.println("</html>"); break; } } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: ec.stop(); if (passwordOK) { if (deviceMode) { deviceOFF(); } else { deviceON(); } } } char* LastPos(char *str1, char *str2) { // find substring in string int L1 = strlen(str1); int L2 = strlen(str2); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (; j < L2; j++) if ((str1[i + j] != str2[j])) break; if (j == L2) return str1 + i; } return 0; } int strPos(char *str11, char *str22) { // find position in string(1) substring(2) char*p = LastPos(str11, str22); int n = p - str11; return n; } void clearRespBuf() { memset(resp_buf, 0, maxSizeResponse); pos_buf = 0; } void deviceON() { EEPROM.write(eeprom_pos_device_mode, 26); deviceMode = 1; if (EEPROM.read(eeprom_pos_last_relay) == 49) { RELAY1ON; delay(50); RELAY2ON; } else { RELAY2ON; delay(50); RELAY1ON; } } void deviceOFF() { EEPROM.write(eeprom_pos_device_mode, 0); deviceMode = 0; if (EEPROM.read(eeprom_pos_last_relay) == 49) { RELAY1OFF; delay(50); RELAY2OFF; EEPROM.write(eeprom_pos_last_relay, 0); } else { RELAY2OFF; delay(50); RELAY1OFF; EEPROM.write(eeprom_pos_last_relay, 49); } } // send an NTP request to the time server at the given address void sendNTPpacket(const char * address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); // NTP requests are to port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } void convertNTPtime() { // the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, extract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; // now convert NTP time into everyday time: // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSince1900 - seventyYears; nHour = ((epoch % 86400L) / 3600) + 3 ; // print the MSK hour (86400 equals secs per day) nMin = (epoch % 3600) / 60; // print the minute (3600 equals secs per minute) // wait ten seconds before asking for the time again unsigned long daysSince1970 = epoch / 86400L; unsigned long fourYearsSince1970 = daysSince1970 / 1461; // 1461 days by 4 years unsigned long ldayYearsSince1970 = daysSince1970 % 1461; // 1461 days by 4 years unsigned long fostYearsSince1970 = ldayYearsSince1970 / 365; // 1461 days by 4 years unsigned long fdayYearsSince1970 = ldayYearsSince1970 % 365; // 1461 days by 4 years nYear = fourYearsSince1970 * 4 + fostYearsSince1970 + 1970; word msum = 0; nMonth = 1; word psum = 0; for (byte i = 0; i < 12; ++i) { psum = msum; if (i == 1) { // feb if (nYear % 4) msum += daysY[i]; else msum += 29; } else { msum += daysY[i]; } if (msum > fdayYearsSince1970) { nMonth = i + 1; nDay = fdayYearsSince1970 - psum + 1; break; } } } void updateCurrentTime() { if ((++nMin) > 59) { nMin = 0; if ((++nHour) > 23) { nHour = 0; byte pdays = daysY[nMonth - 1]; if ((nMonth == 2) && ((nYear % 4) == 0)) pdays = 29; if ((++nDay) > pdays) { nDay = 0; if ((++nMonth) > 12) { nMonth = 1; ++nYear; } } } } } void sendConnectPacket() { byte sizeDevice = strlen(mqtt_id); byte sizeUser = strlen(mqtt_user); byte sizePass = strlen(mqtt_pass); // fixed header sendByteToMQTTclient((byte)0x10); // MQTT Control Packet type 0001 connect, reserved 0000 sendByteToMQTTclient((byte)(16 + sizeDevice + sizeUser + sizePass)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)0x04); // Length LSB (4) sendByteToMQTTclient((byte)'M'); sendByteToMQTTclient((byte)'Q'); sendByteToMQTTclient((byte)'T'); sendByteToMQTTclient((byte)'T'); // protocol name sendByteToMQTTclient((byte)0x04); // Protocol Level byte sendByteToMQTTclient((byte)0xC0); // Connect Flag bits, login and pass enable sendByteToMQTTclient((byte)0x00); // Keep Alive MSB (0) sendByteToMQTTclient((byte)0x0A); // Keep Alive LSB (10) - 10 sec // payload sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeDevice); // Length LSB (4) - device for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_id[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeUser); // Length LSB (4) - user for (byte i = 0; i < sizeUser; ++i) sendByteToMQTTclient((byte)(mqtt_user[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizePass); // Length LSB (4) - pass for (byte i = 0; i < sizePass; ++i) sendByteToMQTTclient((byte)(mqtt_pass[i])); } void sendDisConnectPacket() { // fixed header sendByteToMQTTclient((byte)0xE0); // MQTT Control Packet type 1110 connect, reserved 0000 sendByteToMQTTclient((byte)0x00); // Remaining Length } void sendByteToMQTTclient(byte inByte) { clientMqtt.write((byte)(inByte)); } void sendSubscribeTemp() { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_temp); // fixed header sendByteToMQTTclient((byte)0x82); // MQTT Control Packet type (8) 0100, reserved 0010 sendByteToMQTTclient((byte)(5 + sizeDevice + sizeTopic)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)(0x0A)); // Packet Identifier LSB (10) // payload sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_temp[i])); sendByteToMQTTclient((byte)0x00); // Requested QoS(1) } void sendPubGetTemp() { char textTemp[] = "5"; byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_gettemp); byte sizeData = strlen(textTemp); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(4 + sizeDevice + sizeTopic + sizeData)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_gettemp[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i])); } void parseMqtt() { char findStr[NTP_PACKET_SIZE / 2]; findStr[0] = 0; strcpy(findStr, mqtt_device); strcat(findStr, mqtt_topic_temp); int pp = strPos(packetBuffer, findStr); byte posS = 0; packetBuffer[posS] = 0; if (pp >= 0) { pp += strlen(findStr); for (byte i = 0; i < 7; ++i) { byte c = packetBuffer[pp + i]; if (((c >= '0') && (c <= '9')) || (c == '.')) { packetBuffer[posS] = c; ++posS; } } packetBuffer[posS] = 0; } if ((strlen(packetBuffer) > 0) && (strlen(packetBuffer) <= 4)) { char tempStr[6]; // save temp to mass itoa(nDay, tempStr, 10); strcpy(massTemp[posTemp].dateTime, tempStr); strcat(massTemp[posTemp].dateTime, "."); itoa(nMonth, tempStr, 10); strcat(massTemp[posTemp].dateTime, tempStr); strcat(massTemp[posTemp].dateTime, "."); itoa(nYear, tempStr, 10); strcat(massTemp[posTemp].dateTime, tempStr); strcat(massTemp[posTemp].dateTime, " "); itoa(nHour, tempStr, 10); strcat(massTemp[posTemp].dateTime, tempStr); strcat(massTemp[posTemp].dateTime, ":"); itoa(nMin, tempStr, 10); strcat(massTemp[posTemp].dateTime, tempStr); strcpy(massTemp[posTemp].currTemp, packetBuffer); if ((++posTemp) >= max_count_temp_item) posTemp = 0; if (countTemp < max_count_temp_item) ++countTemp; } }
Т.к. жду БП с Китая, то устройство еще в разработке, если будут дополнения/исправления - выложу.
Исправленный скетч (несколько ошибок было) и готовая железка
Каков DHCP lease time в сети?
Каков DHCP lease time в сети?
Дома 8 часов, на работе где сейчас железка тестируется - сутки. Я все равно на роутере адрес для железки резервирую.
PS Что то все таки с библиотекой ethernet не то...непредсказуемо по wdt МК перезагружается при общении с mqtt сервером, бывает каждый час, а максимальный uptime который видел 6 часов.
Аренда адреса DHCP обновляется в mantain(), а он в коде вызывается раз в сутки. Если адрес не в резерве, то вероятны веселые глюки.
А то, что перезагружается - вполне логичным оказаться может быть. Если, положим, ресолв FDQN затянулся, потом при коннекте MQTT-хост проверяет PTR-запись для клиентского IP... Все 4 секунды уйдут легко. Я бы для теста сначала на локального брокера завёл клиента, а потом уже делал выводы насчет библиотек.
Хм...спасибо, буду экспериментировать
Upd: временно поставил wdt 8 секунд, помогло.
Буду или логику менять или ковырять библиотеку на предмет добавления wdt_reset
Спасибо.
Либы ковырять - сизифов труд. Я бы на данном этапе делал бы отдельно ресолв (возможно с некоторой периодичностью) и потом в процедуру MQTT уже готовый IP сдавал.
Либы ковырять - сизифов труд. Я бы на данном этапе делал бы отдельно ресолв (возможно с некоторой периодичностью) и потом в процедуру MQTT уже готовый IP сдавал.
Да, похожая мысль есть, но не факт что через минуту при коннекте / отправке адрес уже не поменяется (
Буду думать....логику менять....
Спасибо.
А чего ему меняться? Если у них там на dns балансир стоит и по кругу выдает адреса из пула, то это не говорит о том, что по старому ip стопроцентно никто не откликнется. Да и, в крайнем случае, никто не мешает сделать ресолв, потом вачдог заресетить и сразу законнектиться к mqtt с готовым ip. Логика та же, либу ковырять не требуется, вачдог сбрасывается.
В крайнем случае вообще можно оставить все как есть), сейчас аптайм 3000 минут, более 2х суток, для данной железки более чем достаточно.
Но из спортивного интереса именно хочется добавить в библиотеку wdt_reset.
Так что буду в свободное время ковырять библиотеку.