Большие часы ESP8266 WIFI +погода + часы + новостная лента + счетчики подписчиков и много другое .

На просторах интернета в последнее время стали очень популярны часы на базе ESP8266 Nodemcu и пиксельных матрицах max7219 . Все из за того что данные часы очень просты в сборке , имеют широкий функционал и возможности с обновлением времени , получением различных данных с интернета и вывод на бегущую строку всех этих данных .


Время (с использованием NTP сервера для обновления данных),
Дата,
Обновления погоды (например, температура, влажность, давление, облачность, восход солнца, закат),
Прогноз погоды,
данных с Facebook  и уведомления,
Счетчик подписчиков Youtube
Настроить свои всплывающие сообщения и многое другое
Прошивка часов может обновляться через Wi-Fi. 

Комплектующие для сборки проекта я заказывал на Алиэкспресс :

Плата ЕSP82666 nodemcu (для упрощения процесса прошивки рекомендую именно эту плату ) http://ali.pub/2ocib4 


2 штуки матриц мах7219 (есть зеленые и красные на выбор) http://ali.pub/2ocihx 


И блок питания 5в 2А (не меньше) я брал технический http://ali.pub/2ociyn

Но если в корпусе не хватает места ,можно и выносной http://ali.pub/2ocj16  

Инструмент :

Паяльник , кусачки ,припой , 3д принтер для печати корпуса . Так же можно корпус сделать из дерева .


В обычном проекте Arduino используется  RTC модуль  - модуль часов реального времени ,  но т.к это сетевые часы - нам он будет не нужен , а время будет синхронизировано с интернета

На ESP8266 все, что вам нужно, это подключение к Интернету. Для этого используется протокол сетевого времени (NTP). NTP основан на UDP


Получение времени

Давайте рассмотрим пример, который использует UDP для запроса времени с сервера NTP. Библиотеки, константы и глобальные

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>

ESP8266WiFiMulti wifiMulti;      // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'

WiFiUDP UDP;                     // Create an instance of the WiFiUDP class to send and receive

IPAddress timeServerIP;          // time.nist.gov NTP server address
const char* NTPServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;  // NTP time stamp is in the first 48 bytes of the message

byte NTPBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets

Чтобы использовать UDP, мы должны включить библиотеку WiFiUdp, и создать объект UDP. Нам также потребуется выделить память для буфера для хранения UDP-пакетов. Для NTP нам нужен буфер длиной 48 байт. Чтобы узнать, куда отправить UDP-пакеты, нам нужно имя хоста NTP-сервера, это time.nist.gov.

void setup() {
  Serial.begin(115200);          // Start the Serial communication to send messages to the computer
  delay(10);
  Serial.println("\r\n");

  startWiFi();                   // Try to connect to some given access points. Then wait for a connection

  startUDP();

  if(!WiFi.hostByName(NTPServerName, timeServerIP)) { // Get the IP address of the NTP server
    Serial.println("DNS lookup failed. Rebooting.");
    Serial.flush();
    ESP.reset();
  }
  Serial.print("Time server IP:\t");
  Serial.println(timeServerIP);
  
  Serial.println("\r\nSending NTP request ...");
  sendNTPpacket(timeServerIP);  
}


В настройке запускаем  Serial и Wi-Fi, как обычно, и активируем  UDP. Мы рассмотрим реализацию этой функции позже. Нам нужен IP-адрес NTP-сервера, поэтому мы выполняем поиск DNS с именем сервера. Мы не можем обойтись без IP-адреса сервера времени, поэтому, если поиск не выполняется, перезагрузите ESP. Если мы получили IP, отправляем запрос  NTP и и начинаем цикл

unsigned long intervalNTP = 60000; // Request NTP time every minute
unsigned long prevNTP = 0;
unsigned long lastNTPResponse = millis();
uint32_t timeUNIX = 0;

unsigned long prevActualTime = 0;

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - prevNTP > intervalNTP) { // If a minute has passed since last NTP request
    prevNTP = currentMillis;
    Serial.println("\r\nSending NTP request ...");
    sendNTPpacket(timeServerIP);               // Send an NTP request
  }

  uint32_t time = getTime();                   // Check if an NTP response has arrived and get the (UNIX) time
  if (time) {                                  // If a new timestamp has been received
    timeUNIX = time;
    Serial.print("NTP response:\t");
    Serial.println(timeUNIX);
    lastNTPResponse = currentMillis;
  } else if ((currentMillis - lastNTPResponse) > 3600000) {
    Serial.println("More than 1 hour since last NTP response. Rebooting.");
    Serial.flush();
    ESP.reset();
  }

  uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse)/1000;
  if (actualTime != prevActualTime && timeUNIX != 0) { // If a second has passed since last print
    prevActualTime = actualTime;
    Serial.printf("\rUTC time:\t%d:%d:%d   ", getHours(actualTime), getMinutes(actualTime), getSeconds(actualTime));
  }  
}

Первая часть цикла каждую минуту отправляет новый запрос NTP на сервер времени. Затем мы вызываем функцию getTime, чтобы проверить, есть ли у нас новый ответ с сервера. Если это так, мы обновляем переменную timeUNIX с новой меткой времени с сервера (синхронизация времени прошла успешно) , если же не проверьте подключение к интернету или перезагрузите ЕСП .

Схема подключения :

Далее переходим к скетчу и загрузке прошивки на плату ЕСП :

Для начала добавьте эти библиотека ,что бы скетч компилировался без ошибок :

https://github.com/nickgammon/MAX7219_Dot_Matrix 

https://github.com/nickgammon/bitBangedSPI 

(Скачиваем с гихаба и добавляем в среду ардуино )

// Demo of MAX7219_Dot_Matrix library - sideways scrolling
// Author: Md. Khairul Alam
// Date: 5 July 2018

#include <SPI.h>
#include <bitBangedSPI.h>
#include <MAX7219_Dot_Matrix.h>

#include "Arduino.h"
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

const byte chips = 8; //number of matrix in the display

// for NodeMCU 1.0
#define DIN_PIN 15  // D8
#define CS_PIN  13  // D7
#define CLK_PIN 12  // D6

MAX7219_Dot_Matrix display (chips, CS_PIN, DIN_PIN, CLK_PIN);  // 2 chips, then specify the LOAD, DIN, CLK pins

WiFiClient client;

String weatherMain = "";
String weatherDescription = "";
String weatherLocation = "";
String country;
int humidity;
int pressure;
float temp;
float tempMin, tempMax;
int clouds;
float windSpeed;
String date;
int h,m,s;
int sunrise, sunset;

String currencyRates;
String weatherString;

// =======================================================================
// CHANGE YOUR CONFIG HERE:
// =======================================================================
const char* ssid     = "taifur&mafi";     // SSID of local network
const char* password = "University";   // Password on network
String weatherKey = "deb88f35850ad1216f787bc647c4939f";
String weatherLang = "&lang=en";
String cityID = "1185241"; //Dhaka
// read OpenWeather api description for more info
// =======================================================================

char message1 [] = "This is a testing display. Designed by Md. Khairul Alam";
char weather_message[300];
char time_message[50];
char date_message[50];

void setup ()
  {
  display.begin ();
  display.setIntensity (1);

  Serial.begin(115200);
  Serial.print("Connecting WiFi ");
  WiFi.begin(ssid, password);
  //printStringWithShift("Connecting",15);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected: "); Serial.println(WiFi.localIP());

  getWeatherData();
  String str = weatherString;
  int str_len = str.length() + 1; 
  str.toCharArray(weather_message, str_len) ;   

  getTime();
  
}  // end of setup

unsigned long lastMoved = 0;
unsigned long MOVE_INTERVAL = 2;  // mS
int  messageOffset;

void updateDisplay (char *msg)
  {
  //String message = msg;
  display.sendSmooth (msg, messageOffset);
  
  // next time show one pixel onwards
  if (messageOffset++ >= (int) (strlen (msg) * 8))
    messageOffset = - chips * 8;
  }  // end of updateDisplay
  
long last = millis();
long lastTime = millis();

void loop () 
  { 
  if((millis()- last)>1000*60*15){  //update weather every 15 minutes 
    getWeatherData();
    getTime();
    String str = weatherString;
    int str_len = str.length() + 1;
    str.toCharArray(weather_message, str_len) ;
    last = millis();
   }
   
  // update display if time is up
  if(s>0 && s<40){
  if (millis () - lastMoved >= MOVE_INTERVAL)
    {
      updateDisplay(weather_message);
      lastMoved = millis ();
    }  
  }

  if(s>40 && s<55){
  if (millis () - lastMoved >= MOVE_INTERVAL)
    {
      updateDisplay(date_message);
      lastMoved = millis ();
    }  
  }
  /*
  // do other stuff here    
  if(millis()-lastTime>65000){ 
    long now = millis();
    do{
      updateTime();
      showTime();
      }while(millis()-now<40000);
    now = millis();
    lastTime = millis();
  }  
   */
   if(s>55){
      showTime(); 
    }
   
 updateTime();
       
}  // end of loop


// =======================================================================
// retrive weather data

const char *weatherHost = "api.openweathermap.org";

void getWeatherData()
{
  Serial.print("connecting to "); Serial.println(weatherHost);
  if (client.connect(weatherHost, 80)) {
    client.println(String("GET /data/2.5/weather?id=") + cityID + "&units=metric&appid=" + weatherKey + weatherLang + "\r\n" +
                "Host: " + weatherHost + "\r\nUser-Agent: ArduinoWiFi/1.1\r\n" +
                "Connection: close\r\n\r\n");
  } else {
    Serial.println("connection failed");
    return;
  }
  String line;
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    Serial.println("w.");
    repeatCounter++;
  }
  while (client.connected() && client.available()) {
    char c = client.read(); 
    if (c == '[' || c == ']') c = ' ';
    line += c;
  }

  client.stop();

  DynamicJsonBuffer jsonBuf;
  JsonObject &root = jsonBuf.parseObject(line);
  if (!root.success())
  {
    Serial.println("parseObject() failed");
    return;
  }
  //weatherMain = root["weather"]["main"].as<String>();
  weatherDescription = root["weather"]["description"].as<String>();
  weatherDescription.toLowerCase();
  Serial.println(weatherDescription);
  //  weatherLocation = root["name"].as<String>();
  //  country = root["sys"]["country"].as<String>();
  sunrise = root["sys"]["sunrise"];
  sunset = root["sys"]["sunset"];
  temp = root["main"]["temp"];
  humidity = root["main"]["humidity"];
  pressure = root["main"]["pressure"];
  tempMin = root["main"]["temp_min"];
  tempMax = root["main"]["temp_max"];
  windSpeed = root["wind"]["speed"];
  clouds = root["clouds"]["all"];
  //String deg = String(char('~')+131);
  //weatherString = "  Temp: " + String(temp,1) /*+ deg*/ + "C (" + String(tempMin,1) /*+ deg*/ + "-" + String(tempMax,1) /*+ deg*/ + ")  ";
  weatherString = "  Temp: " + String(temp,1) /*+ deg*/ + "C";
  //weatherString += weatherDescription;
  weatherString += "  Humidity: " + String(humidity) + "% ";
  weatherString += "  Pressure: " + String(pressure) + "hPa ";
  weatherString += "  Clouds: " + String(clouds) + "%  ";
  weatherString += "  Wind: " + String(windSpeed,1) + "m/s   ";
  Serial.println(weatherString);
}

// =======================================================================
// retrive curency rate

const char* currencyHost = "cinkciarz.pl";

void getCurrencyRates()
{
  WiFiClientSecure client;
  Serial.print("connecting to "); Serial.println(currencyHost);
  if (!client.connect(currencyHost, 443)) {
    Serial.println("connection failed");
    return;
  }
  client.print(String("GET / HTTP/1.1\r\n") +
               "Host: " + currencyHost + "\r\nConnection: close\r\n\r\n");

  //Serial.print("request sent");
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    Serial.println("c.");
    repeatCounter++;
  }
  Serial.println("connected");
  while (client.connected() && client.available()) {
    String line = client.readStringUntil('\n');
    //      Serial.println(line);
    int currIdx = line.indexOf("/kantor/kursy-walut-cinkciarz-pl/usd");
    if (currIdx > 0) {
      String curr = line.substring(currIdx + 33, currIdx + 33 + 3);
      curr.toUpperCase();
      line = client.readStringUntil('\n');
      int rateIdx = line.indexOf("\">");
      if (rateIdx <= 0) {
        Serial.println("Found rate but wrong structure!");
        return;
      }
      currencyRates = "        PLN/" + curr + ": ";
      if (line[rateIdx - 1] == 'n') currencyRates += char('~'+24); else currencyRates += char('~'+23); // down/up
      currencyRates += line.substring(rateIdx + 2, rateIdx + 8) + " ";

      line = client.readStringUntil('\n');
      rateIdx = line.indexOf("\">");
      if (rateIdx <= 0) {
        Serial.println("Found rate but wrong structure!");
        return;
      }
      if (line[rateIdx - 1] == 'n') currencyRates += char('~'+24); else currencyRates += char('~'+23); // down/up
      currencyRates += line.substring(rateIdx + 2, rateIdx + 8);
      currencyRates.replace(',', '.');
      break;
    }
  }
  client.stop();
}

// =======================================================================

float utcOffset = 2;
long localEpoc = 0;
long localMillisAtUpdate = 0;

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.google.com", 80)) {
    Serial.println("connection to google failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.google.com\r\n") +
               String("Connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    //Serial.println(".");
    repeatCounter++;
  }

  String line;
  client.setNoDelay(false);
  while(client.connected() && client.available()) {
    line = client.readStringUntil('\n');
    line.toUpperCase();
    if (line.startsWith("DATE: ")) {
      date = ""+line.substring(6, 22);
      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt();
      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);

      String clock_date = date;
      int date_len = clock_date.length() + 1; 
      clock_date.toCharArray(date_message, date_len) ;
    
    }
  }
  client.stop();
}

// =======================================================================

void updateTime()
{
  long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
  long epoch = round(curEpoch + 3600 * utcOffset + 86400L) % 86400L;
  h = ((epoch  % 86400L) / 3600) % 24;
  m = (epoch % 3600) / 60;
  s = epoch % 60;
}

// =======================================================================
long lastmillis=millis();
void showTime()
{
    String timeString = "";
    timeString+= h/10 ? h/10 : 0;
    timeString+= h%10;
    timeString+= ":";
    timeString+= m/10;
    timeString+= m%10;
    timeString+= ":";
    timeString+= s/10;
    timeString+= s%10;   
    String clock_time = timeString;
    int clock_len = clock_time.length() + 1; 
    clock_time.toCharArray(time_message, clock_len) ;
    display.sendString(time_message);
}


Arduino Sketch с поддержкой OTA

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

#include <SPI.h>
#include <bitBangedSPI.h>
#include <MAX7219_Dot_Matrix.h>

#include "Arduino.h"
#include <ArduinoJson.h>

const byte chips = 8; //number of matrix in the display

// for NodeMCU 1.0
#define DIN_PIN 15  // D8
#define CS_PIN  13  // D7
#define CLK_PIN 12  // D6

MAX7219_Dot_Matrix display (chips, CS_PIN, DIN_PIN, CLK_PIN);  // 2 chips, then specify the LOAD, DIN, CLK pins

WiFiClient client;

String weatherMain = "";
String weatherDescription = "";
String weatherLocation = "";
String country;
int humidity;
int pressure;
float temp;
float tempMin, tempMax;
int clouds;
float windSpeed;
String date;
int h,m,s;
int sunrise, sunset;

String currencyRates;
String weatherString;

const char* ssid = "taifur&mafi";
const char* password = "University";

String weatherKey = "deb88f35850ad1216f787bc647c4939f";
String weatherLang = "&lang=en";
String cityID = "1185241"; //Dhaka
// read OpenWeather api description for more info
// =======================================================================

char message1 [] = "This is a testing display. Designed by Md. Khairul Alam";
char weather_message[300];
char time_message[50];
char date_message[50];

int LED = 2;

void setup() {
  Serial.begin(115200);

  display.begin ();
  display.setIntensity (1);
  Serial.print("Connecting WiFi ");
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  // ArduinoOTA.setHostname("myesp8266");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(LED, OUTPUT);     // Initialize the LED_BUILTIN pin as an output

  getWeatherData();
  String str = weatherString;
  int str_len = str.length() + 1; 
  str.toCharArray(weather_message, str_len) ;   

  getTime();
}

unsigned long lastMoved = 0;
unsigned long MOVE_INTERVAL = 2;  // mS
int  messageOffset;

void updateDisplay (char *msg)
  {
  //String message = msg;
  display.sendSmooth (msg, messageOffset);
  
  // next time show one pixel onwards
  if (messageOffset++ >= (int) (strlen (msg) * 8))
    messageOffset = - chips * 8;
  }  // end of updateDisplay
  
long last = millis();
long lastTime = millis();

void loop() {
  ArduinoOTA.handle();

  if((millis()- last)>1000*60*15){  //update weather every 15 minutes 
    getWeatherData();
    getTime();
    String str = weatherString;
    int str_len = str.length() + 1;
    str.toCharArray(weather_message, str_len) ;
    last = millis();
   }
   
  // update display if time is up
  if(s>0 && s<40){
  if (millis () - lastMoved >= MOVE_INTERVAL)
    {
      updateDisplay(weather_message);
      lastMoved = millis ();
    }  
  }

  if(s>40 && s<55){
  if (millis () - lastMoved >= MOVE_INTERVAL)
    {
      updateDisplay(date_message);
      lastMoved = millis ();
    }  
  }
  /*
  // do other stuff here    
  if(millis()-lastTime>65000){ 
    long now = millis();
    do{
      updateTime();
      showTime();
      }while(millis()-now<40000);
    now = millis();
    lastTime = millis();
  }  
   */
   if(s>55){
      showTime(); 
    }
   
 updateTime();                  // Wait for two seconds (to demonstrate the active low LED)
}

// =======================================================================
// retrive weather data

const char *weatherHost = "api.openweathermap.org";

void getWeatherData()
{
  Serial.print("connecting to "); Serial.println(weatherHost);
  if (client.connect(weatherHost, 80)) {
    client.println(String("GET /data/2.5/weather?id=") + cityID + "&units=metric&appid=" + weatherKey + weatherLang + "\r\n" +
                "Host: " + weatherHost + "\r\nUser-Agent: ArduinoWiFi/1.1\r\n" +
                "Connection: close\r\n\r\n");
  } else {
    Serial.println("connection failed");
    return;
  }
  String line;
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    Serial.println("w.");
    repeatCounter++;
  }
  while (client.connected() && client.available()) {
    char c = client.read(); 
    if (c == '[' || c == ']') c = ' ';
    line += c;
  }

  client.stop();

  DynamicJsonBuffer jsonBuf;
  JsonObject &root = jsonBuf.parseObject(line);
  if (!root.success())
  {
    Serial.println("parseObject() failed");
    return;
  }
  //weatherMain = root["weather"]["main"].as<String>();
  weatherDescription = root["weather"]["description"].as<String>();
  weatherDescription.toLowerCase();
  Serial.println(weatherDescription);
  //  weatherLocation = root["name"].as<String>();
  //  country = root["sys"]["country"].as<String>();
  sunrise = root["sys"]["sunrise"];
  sunset = root["sys"]["sunset"];
  temp = root["main"]["temp"];
  humidity = root["main"]["humidity"];
  pressure = root["main"]["pressure"];
  tempMin = root["main"]["temp_min"];
  tempMax = root["main"]["temp_max"];
  windSpeed = root["wind"]["speed"];
  clouds = root["clouds"]["all"];
  //String deg = String(char('~')+131);
  //weatherString = "  Temp: " + String(temp,1) /*+ deg*/ + "C (" + String(tempMin,1) /*+ deg*/ + "-" + String(tempMax,1) /*+ deg*/ + ")  ";
  weatherString = "  Temp: " + String(temp,1) /*+ deg*/ + "C";
  //weatherString += weatherDescription;
  weatherString += "  Humidity: " + String(humidity) + "% ";
  weatherString += "  Pressure: " + String(pressure) + "hPa ";
  weatherString += "  Clouds: " + String(clouds) + "%  ";
  weatherString += "  Wind: " + String(windSpeed,1) + "m/s   ";
  Serial.println(weatherString);
}

// =======================================================================
// retrive curency rate

const char* currencyHost = "cinkciarz.pl";

void getCurrencyRates()
{
  WiFiClientSecure client;
  Serial.print("connecting to "); Serial.println(currencyHost);
  if (!client.connect(currencyHost, 443)) {
    Serial.println("connection failed");
    return;
  }
  client.print(String("GET / HTTP/1.1\r\n") +
               "Host: " + currencyHost + "\r\nConnection: close\r\n\r\n");

  //Serial.print("request sent");
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    Serial.println("c.");
    repeatCounter++;
  }
  Serial.println("connected");
  while (client.connected() && client.available()) {
    String line = client.readStringUntil('\n');
    //      Serial.println(line);
    int currIdx = line.indexOf("/kantor/kursy-walut-cinkciarz-pl/usd");
    if (currIdx > 0) {
      String curr = line.substring(currIdx + 33, currIdx + 33 + 3);
      curr.toUpperCase();
      line = client.readStringUntil('\n');
      int rateIdx = line.indexOf("\">");
      if (rateIdx <= 0) {
        Serial.println("Found rate but wrong structure!");
        return;
      }
      currencyRates = "        PLN/" + curr + ": ";
      if (line[rateIdx - 1] == 'n') currencyRates += char('~'+24); else currencyRates += char('~'+23); // down/up
      currencyRates += line.substring(rateIdx + 2, rateIdx + 8) + " ";

      line = client.readStringUntil('\n');
      rateIdx = line.indexOf("\">");
      if (rateIdx <= 0) {
        Serial.println("Found rate but wrong structure!");
        return;
      }
      if (line[rateIdx - 1] == 'n') currencyRates += char('~'+24); else currencyRates += char('~'+23); // down/up
      currencyRates += line.substring(rateIdx + 2, rateIdx + 8);
      currencyRates.replace(',', '.');
      break;
    }
  }
  client.stop();
}

// =======================================================================

float utcOffset = 2;
long localEpoc = 0;
long localMillisAtUpdate = 0;

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.google.com", 80)) {
    Serial.println("connection to google failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.google.com\r\n") +
               String("Connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    //Serial.println(".");
    repeatCounter++;
  }

  String line;
  client.setNoDelay(false);
  while(client.connected() && client.available()) {
    line = client.readStringUntil('\n');
    line.toUpperCase();
    if (line.startsWith("DATE: ")) {
      date = ""+line.substring(6, 22);
      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt();
      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);

      String clock_date = date;
      int date_len = clock_date.length() + 1; 
      clock_date.toCharArray(date_message, date_len) ;
    
    }
  }
  client.stop();
}

// =======================================================================

void updateTime()
{
  long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
  long epoch = round(curEpoch + 3600 * utcOffset + 86400L) % 86400L;
  h = ((epoch  % 86400L) / 3600) % 24;
  m = (epoch % 3600) / 60;
  s = epoch % 60;
}

// =======================================================================
long lastmillis=millis();
void showTime()
{
    String timeString = "";
    timeString+= h/10 ? h/10 : 0;
    timeString+= h%10;
    timeString+= ":";
    timeString+= m/10;
    timeString+= m%10;
    timeString+= ":";
    timeString+= s/10;
    timeString+= s%10;   
    String clock_time = timeString;
    int clock_len = clock_time.length() + 1; 
    clock_time.toCharArray(time_message, clock_len) ;
    display.sendString(time_message);
}


е


  • Большие часы ESP8266 WIFI  +погода + часы + новостная лента + счетчики подписчиков и много другое .

Похожие статьи

Сделай сам – мини-переносной Лабораторный блок питания из китайских модулей LM2596 !

Сделай сам – мини-переносной Лабораторный блок питания из китайских модулей LM2596 !

Сделай сам – мини Лабораторный блок питания из китайских комплектующих

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

Так же у меня есть и другие самопальные ЛБП , но они пригодны только для стационарного использования . На этот раз я решил использовать LM2596 вместо обычно используемых LM317 или LM350, что бы была регулировка тока .

Часы плоттер на ардуино или arduino-робот рисует маркером текущее время в режиме реального времени

Часы плоттер на ардуино или arduino-робот рисует маркером текущее время в режиме реального времени

Arduino-робот Plotclock рисует рисует последовательность цифр, отображающей текущее время  в 24-часовом формате .Собрать такого робота часовщика можно самому

на базе ардуино , 3х сервоприводов и конечно нужны будут детали напечатанные на 3д принтере . 


Джаммер Jammer v2 WI-FI ESP8266 nodemcu \ WEMOS  обновление интерфейса куча полезного и исправление ошибок

Джаммер Jammer v2 WI-FI ESP8266 nodemcu \ WEMOS обновление интерфейса куча полезного и исправление ошибок

Популярная глушилка спаммер  на базе платы ESP8266 (nodemcu \WEMOS ) получила вторую версию прошивки c исправлением ошибок , улучшением интерфейса и добавлением более широкого функционала . Все это собрал до кучи и решил написать пост . Так же добавил подробный ворклог с упрощенной прошивкой через FLASHER (прошивка в 3 клика )

Рекомендуемые товары

ARDUINO starter kit набор ардуино для новичков в пластиковом боксе!

ARDUINO starter kit набор ардуино для новичков в пластиковом боксе!

Данный комплект поможет вам на практике ознакомиться с основными принципами использования Ардуи..

350грн.

Arduino nano 328 на базе конвертера ch340 с micro-usb

Arduino nano 328 на базе конвертера ch340 с micro-usb

Arduino Nano V3.0 - маленькая, самодостаточная, разъемо-совместимая с макетками плата на микрок..

95грн.

Arduino UNO R3 Atmega328  ATmega328P smd AVR Ардуино Уно Р3 с кабелем для подключения USB

Arduino UNO R3 Atmega328 ATmega328P smd AVR Ардуино Уно Р3 с кабелем для подключения USB

На этой платформе стоит точно такой же процессор как и на классической версии, отличие формфактор(ти..

140грн.