Большие часы 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);
}
е
Похожие статьи
Сделай сам – мини-переносной Лабораторный блок питания из китайских модулей LM2596 !
Сделай сам – мини Лабораторный блок питания из китайских комплектующих
При проектировании этого источника питания главная цель состояла в том, чтобы он был настолько портативным, насколько это возможно, и при надобности можно была захватить с собой.
Так же у меня
есть и другие самопальные ЛБП , но они пригодны только для стационарного
использования . На этот раз я решил использовать LM2596 вместо обычно
используемых LM317 или LM350, что бы
была регулировка тока .
Часы плоттер на ардуино или arduino-робот рисует маркером текущее время в режиме реального времени
Arduino-робот Plotclock рисует рисует последовательность цифр, отображающей текущее время в 24-часовом формате .Собрать такого робота часовщика можно самому
на базе ардуино , 3х сервоприводов и конечно нужны будут детали напечатанные на 3д принтере .
Джаммер Jammer v2 WI-FI ESP8266 nodemcu \ WEMOS обновление интерфейса куча полезного и исправление ошибок
Популярная глушилка спаммер на базе платы ESP8266 (nodemcu \WEMOS ) получила вторую версию прошивки c исправлением ошибок , улучшением интерфейса и добавлением более широкого функционала . Все это собрал до кучи и решил написать пост . Так же добавил подробный ворклог с упрощенной прошивкой через FLASHER (прошивка в 3 клика )
Рекомендуемые товары
Arduino nano 328 на базе конвертера ch340 с micro-usb
Arduino Nano V3.0 - маленькая, самодостаточная, разъемо-совместимая с макетками плата на микрок..
95грн.
Arduino UNO R3 Atmega328 ATmega328P smd AVR Ардуино Уно Р3 с кабелем для подключения USB
На этой платформе стоит точно такой же процессор как и на классической версии, отличие формфактор(ти..
140грн.