Ethernet выключатель нагрузки в локальной сети

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Надоело слать 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;
  }
}

 

Т.к. жду БП с Китая, то устройство еще в разработке, если будут дополнения/исправления - выложу.

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Исправленный скетч (несколько ошибок было) и готовая железка

#include <avr/wdt.h>
#include <SPI.h>
#include <Ethernet2.h>
#include <EEPROM.h>

#define max_count_temp_item 14
struct tempItem {
  char dateTime[18]; char currTemp[6];
};
byte countTemp, posTemp;
tempItem massTemp[max_count_temp_item];

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";
#define period_mqtt_request 3600000UL
#define period_wait_mqtt 6000UL
EthernetClient clientMqtt;
unsigned long timer_mqtt_request = 0; unsigned long timer_wait_mqtt;

#define eeprom_pos_device_mode 146 // 26 - device is on
#define eeprom_pos_last_relay 71 // 49 - relay 2
byte lastRelay, deviceMode; // 1 is on

#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
// 2 - send mqtt request
// 3 - wait mqtt response
// default - http web server
unsigned long currentMillis; // main timer

#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
byte posBuffer; char packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
EthernetUDP Udp;
byte nDay, nMonth, nHour, nMin; word nYear;
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};

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]; byte pos_buf = 0;

#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(); currentMillis = millis();
  //delay(5000); // test WDT
  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); convertNTPtime(); 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);
        if ((currentMillis - timer_day_ntp_time) >= 86400000UL) { // 1 day // update current time
          workMode = 0; // update date time from NTP server
        } else if ((currentMillis - timer_min_ntp_time) >= 60000UL) { // 1 min // correct time
          timer_min_ntp_time = currentMillis; updateCurrentTime();
        }
        if ((currentMillis - timer_mqtt_request) >= period_mqtt_request) { // mqtt actions
          workMode = 2; // connect mqtt server
        } // end other action
      }
  }
}

void processServer(EthernetClient ec) {
  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 (c == '\n' && currentLineIsBlank) {
        if (havePost) {
          clearRespBuf();
          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);
          ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close");
          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 />"); 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) {
          ec.println("HTTP/1.1 302 Found"); ec.println("Location: /switch/");
          timer_wait_pass = currentMillis; break;
        } else if (requestRoot) {
          ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close");
          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 {
          ec.println("HTTP/1.1 200 OK"); ec.println("Content-Type: text/html"); ec.println("Connection: close");
          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') currentLineIsBlank = true;
      else if (c != '\r') currentLineIsBlank = false;
    }
  }
  delay(1); 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(100); RELAY2ON;
  } else {
    RELAY2ON; delay(100); RELAY1ON;
  }
}

void deviceOFF() {
  EEPROM.write(eeprom_pos_device_mode, 0); deviceMode = 0;
  if (EEPROM.read(eeprom_pos_last_relay) == 49) {
    RELAY1OFF; delay(100); RELAY2OFF; EEPROM.write(eeprom_pos_last_relay, 0);
  } else {
    RELAY2OFF; delay(100); RELAY1OFF; EEPROM.write(eeprom_pos_last_relay, 49);
  }
}

void sendNTPpacket(const char * address) {
  memset(packetBuffer, 0, NTP_PACKET_SIZE); packetBuffer[0] = 0b11100011; packetBuffer[1] = 0;
  packetBuffer[2] = 6; packetBuffer[3] = 0xEC; packetBuffer[12]  = 49; packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49; packetBuffer[15]  = 52; Udp.beginPacket(address, 123);
  Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket();
}

void convertNTPtime() {
  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  unsigned long secsSince1900 = highWord << 16 | lowWord; const unsigned long seventyYears = 2208988800UL; unsigned long epoch = secsSince1900 - seventyYears;
  nHour = ((epoch  % 86400L) / 3600) + 3 ; nMin = (epoch  % 3600) / 60;
  unsigned long daysSince1970 = epoch / 86400L; unsigned long fourYearsSince1970 = daysSince1970 / 1461;
  unsigned long ldayYearsSince1970 = daysSince1970 % 1461; unsigned long fostYearsSince1970 = ldayYearsSince1970 / 365;
  unsigned long fdayYearsSince1970 = ldayYearsSince1970 % 365;
  nYear = fourYearsSince1970 * 4 + fostYearsSince1970 + 1970; word msum = 0; nMonth = 1; word psum;
  for (byte i = 0; i < 12; ++i) {
    psum = msum;
    if (i == 1) {
      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 = 1;
        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];
    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;
  }
}

sadman41
Offline
Зарегистрирован: 19.10.2016

Каков DHCP lease time в сети?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

sadman41 пишет:

Каков DHCP lease time в сети?

Дома 8 часов, на работе где сейчас железка тестируется - сутки. Я все равно на роутере адрес для железки резервирую.

PS Что то все таки с библиотекой ethernet не то...непредсказуемо по wdt МК перезагружается при общении с mqtt сервером, бывает каждый час, а максимальный uptime который видел 6 часов.

sadman41
Offline
Зарегистрирован: 19.10.2016

Аренда адреса DHCP обновляется в mantain(), а он в коде вызывается раз в сутки. Если адрес не в резерве, то вероятны веселые глюки. 

А то, что перезагружается - вполне логичным оказаться может быть. Если, положим, ресолв FDQN затянулся, потом при коннекте MQTT-хост проверяет PTR-запись для клиентского IP... Все 4 секунды уйдут легко. Я бы для теста сначала на локального брокера завёл клиента, а потом уже делал выводы насчет библиотек.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Хм...спасибо, буду экспериментировать

Upd: временно поставил wdt 8 секунд, помогло.

Буду или логику менять или ковырять библиотеку на предмет добавления wdt_reset

Спасибо. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Либы ковырять - сизифов труд. Я бы на данном этапе делал бы отдельно ресолв (возможно с некоторой периодичностью) и потом в процедуру MQTT уже готовый IP сдавал. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

sadman41 пишет:

Либы ковырять - сизифов труд. Я бы на данном этапе делал бы отдельно ресолв (возможно с некоторой периодичностью) и потом в процедуру MQTT уже готовый IP сдавал. 

Да, похожая мысль есть, но не факт что через минуту при коннекте / отправке адрес уже не поменяется (

Буду думать....логику менять....

Спасибо.

sadman41
Offline
Зарегистрирован: 19.10.2016

А чего ему меняться? Если у них там на dns балансир стоит и по кругу выдает адреса из пула, то это не говорит о том, что по старому ip стопроцентно никто не откликнется.  Да и, в крайнем случае, никто не мешает сделать ресолв, потом вачдог заресетить и сразу законнектиться к mqtt с готовым ip. Логика та же, либу ковырять не требуется, вачдог сбрасывается.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

В крайнем случае вообще можно оставить все как есть), сейчас аптайм 3000 минут, более 2х суток, для данной железки более чем достаточно.

Но из спортивного интереса именно хочется добавить в библиотеку wdt_reset.

Так что буду в свободное время ковырять библиотеку.