initial version

This commit is contained in:
telegnom
2019-02-23 16:44:01 +01:00
commit f6322ce050
3 changed files with 544 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 telegnom
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+22
View File
@@ -0,0 +1,22 @@
# Wordclock
Firmware für die WordClock vom c3e.
## Anleitung
1. Strom anschließen, 5V, USB-Netzeil
2. Ins WLAN `WordClock` verbinden
3. Im Browser die IP `192.168.4.1` aufrufen
4. WLAN auswählen und ggf. Passwort eingeben
5. Nach dem Speichern der Einstellungen verschwindet das WLAN
6. Uhr zeigt die Uhrzeit an
## Design
Die Idee für das Design wurden vom FabLab Nürnberg übernommen. Die Firmware ist eine Eigenentwicklung.
http://wiki.fablab-nuernberg.de/w/Ding:Wortuhr_von_Udo
## Lizenz
MIT License
+501
View File
@@ -0,0 +1,501 @@
/**
* @file wordclock.ino
* @author telegnom (ccc@telegnom.org)
* @date 2019-02-23
* @version 1.1
*
* @brief firmware for the c3e wordclock
*
* requires the time.h and timezone.h libraries
* https://github.com/PaulStoffregen/Time/
* https://github.com/JChristensen/Timezone/
*
*/
#include <FastLED.h>
#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Timezone.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#define NUM_LEDS 42
#define DATA_PIN 5
CRGB leds[NUM_LEDS];
// NTP Servers:
static const char ntpServerName[] = "pool.ntp.org";
// defining words
#define M_ES 0
#define M_IST 1
#define M_FUENF 2
#define M_ZEHN 3
#define M_VIERTEL 4
#define M_VOR 5
#define M_NACH 6
#define M_HALB 7
#define M_UHR 8
#define H_EINS 9
#define H_EIN 9
#define H_ZWEI 10
#define H_DREI 11
#define H_VIER 12
#define H_FUENF 13
#define H_SECHS 14
#define H_SIEBEN 15
#define H_ACHT 16
#define H_NEUN 17
#define H_ZEHN 18
#define H_ELF 19
#define H_ZWOELF 20
TimeChangeRule myDST = {"CEST", Last, Sun, Mar, 2, 120}; //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {"CET", Last, Sun, Oct, 2, 60}; //Standard time = UTC - 5 hours
Timezone myTZ(myDST, mySTD);
int clockWords[21][10] = {
{3,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // es 0
{2,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // ist 1
{0,1,-1,-1,-1,-1,-1,-1,-1,-1}, // fuenf 2
{4,5,-1,-1,-1,-1,-1,-1,-1,-1}, // zehn 3
{8,9,10,-1,-1,-1,-1,-1,-1,-1}, // viertel 4
{11,12,-1,-1,-1,-1,-1,-1,-1,-1}, // vor 5
{6,7,-1,-1,-1,-1,-1,-1,-1,-1}, // nach 6
{13,14,-1,-1,-1,-1,-1,-1,-1,-1}, // halb 7
{40,41,-1,-1,-1,-1,-1,-1,-1,-1}, // uhr 8
{19,20,-1,-1,-1,-1,-1,-1,-1,-1}, // ein 9
{21,22,-1,-1,-1,-1,-1,-1,-1,-1}, // zwei 10
{25,26,-1,-1,-1,-1,-1,-1,-1,-1}, // drei 11
{23,24,-1,-1,-1,-1,-1,-1,-1,-1}, // vier 12
{15,16,-1,-1,-1,-1,-1,-1,-1,-1}, // fuenf 13
{27,28,-1,-1,-1,-1,-1,-1,-1,-1}, // sechs 14
{33,34,35,-1,-1,-1,-1,-1,-1,-1}, // sieben 15
{29,30,-1,-1,-1,-1,-1,-1,-1,-1}, // acht 16
{17,18,-1,-1,-1,-1,-1,-1,-1,-1}, // neun 17
{36,37,-1,-1,-1,-1,-1,-1,-1,-1}, // zehn 18
{38,39,-1,-1,-1,-1,-1,-1,-1,-1}, // elf 19
{31,32,-1,-1,-1,-1,-1,-1,-1,-1}, // zwölf 20
};
WiFiUDP Udp;
unsigned int localPort = 8888; // local port to listen for UDP packets
time_t getNtpTime();
time_t loctime;
uint8_t color = 0;
int lastmin = 100;
void printDigits(int digits);
void sendNTPpacket(IPAddress &address);
void clear(bool show=true)
{
for(int i = 0; i<NUM_LEDS;i++) {
leds[i] = 0x000000;
}
if (show) {
FastLED.show();
}
}
void noWifi()
{
for(int i=0; i<NUM_LEDS; i++)
{
leds[i] = CHSV((255/(NUM_LEDS-1))*i, 255, 128);
FastLED.show();
}
}
void printDigits(uint8_t digits, bool colon = true)
{
// utility for digital clock display: prints preceding colon and leading 0
if (colon)
{
Serial.print(":");
}
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
void digitalClockDisplay()
{
// digital clock display of the time
printDigits((uint8_t) hour(loctime));
printDigits((uint8_t) minute(loctime));
printDigits((uint8_t) second(loctime));
Serial.print(" ");
Serial.print(day(loctime));
Serial.print(".");
Serial.print(month(loctime));
Serial.print(".");
Serial.print(year(loctime));
Serial.println();
}
void setup()
{
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
clear();
Serial.begin(115200);
WiFiManager wifiManager;
while (!Serial) ; // Needed for Leonardo only
delay(250);
Serial.println("WordClock by telegnom");
Serial.print("Setup Wifi ... ");
wifiManager.autoConnect("WordClock");
Serial.println('[ ok ]');
while (WiFi.status() != WL_CONNECTED) {
noWifi();
delay(500);
}
Serial.print("IP number assigned by DHCP is ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(Udp.localPort());
Serial.println("waiting for sync");
setSyncProvider(getNtpTime);
setSyncInterval(600);
}
int prevDisplay = 100; // when the digital clock was displayed
void loop()
{
// time_t utc = now();
loctime = myTZ.toLocal(now());
if (timeStatus() != timeNotSet) {
// if (prevDisplay != second(localtime))
if (prevDisplay != second(loctime)) { //update the display only if time has changed
prevDisplay = second(loctime);
if (second()%10 == 0)
{
digitalClockDisplay();
if (lastmin != minute(loctime))
{
setClock();
}
prevDisplay = second(loctime);
}
// }
}
}
}
void set_word(int word, time_t current_time = loctime) {
int wordlen = sizeof(clockWords[word])/sizeof(clockWords[word][0]);
if (lastmin != minute(loctime))
{
color += 40;
}
for (int i=0; i<wordlen; i++)
{
if (clockWords[word][i] >= 0)
{
leds[clockWords[word][i]] = CHSV(color, 255, 128);
Serial.print(clockWords[word][i]);
Serial.print(" ");
}
}
Serial.println();
}
void setClock() {
Serial.println("Updating display...");
time_t current_time = loctime;
clear(false);
set_word(M_ES); // switch es on
set_word(M_IST); // switch ist on
getMinuteWord(); //get word for "minute"
getHourWord(); // get word for hour
FastLED.show(); //writing to led stipe
lastmin = minute(loctime);
Serial.println("... display updated.");
}
int getHour()
{
int h = int(hour(loctime));
int m = int(minute(loctime));
/*
get current hour if minute < 20
Es ist viertel nach zehn
get next hour if minute >=20
Es ist zehn vor halb elf
adjust hour to correct word around midnight:
23:25 --> Es ist fuenf vor halb zwoelf
*/
Serial.println(m);
if (m >= 20)
{
if (h < 23)
{
return h+1;
} else
{
return 0;
}
} else
{
return h;
}
}
void getHourWord()
{
switch(getHour())
{
case 12:
case 0:
set_word(H_ZWOELF);
Serial.println("zwoelf");
break;
case 1:
case 13:
// special case to get sigular @ "ein uhr"
if (int(minute(loctime)) < 5)
{
set_word(H_EIN);
Serial.println("ein");
} else
{
set_word(H_EINS);
Serial.println("eins");
}
break;
case 2:
case 14:
set_word(H_ZWEI);
Serial.println("zwei");
break;
case 3:
case 15:
set_word(H_DREI);
Serial.println("drei");
break;
case 4:
case 16:
set_word(H_VIER);
Serial.println("vier");
break;
case 5:
case 17:
set_word(H_FUENF);
Serial.println("fuenf");
break;
case 6:
case 18:
set_word(H_SECHS);
Serial.println("sechs");
break;
case 7:
case 19:
set_word(H_SIEBEN);
Serial.println("sieben");
break;
case 8:
case 20:
set_word(H_ACHT);
Serial.println("acht");
break;
case 9:
case 21:
set_word(H_NEUN);
Serial.println("neun");
break;
case 10:
case 22:
set_word(H_ZEHN);
Serial.println("zehn");
break;
case 11:
case 23:
set_word(H_ELF);
Serial.println("elf");
break;
}
}
void getMinuteWord()
{
/*
get word for current "minute"
*/
switch(int(minute(loctime)))
{
case 0:
case 1:
case 2:
case 3:
case 4:
set_word(M_UHR);
Serial.println("uhr");
break;
case 5:
case 6:
case 7:
case 8:
case 9:
set_word(M_FUENF);
set_word(M_NACH);
Serial.println("fuenf nach");
break;
case 10:
case 11:
case 12:
case 13:
case 14:
set_word(M_ZEHN);
set_word(M_NACH);
Serial.println("zehn nach");
break;
case 15:
case 16:
case 17:
case 18:
case 19:
set_word(M_VIERTEL);
set_word(M_NACH);
Serial.println("viertel nach");
break;
case 20:
case 21:
case 22:
case 23:
case 24:
set_word(M_ZEHN);
set_word(M_VOR);
set_word(M_HALB);
Serial.println("zehn vor halb");
break;
case 25:
case 26:
case 27:
case 28:
case 29:
set_word(M_FUENF);
set_word(M_VOR);
set_word(M_HALB);
Serial.println("fuenf vor halb");
break;
case 30:
case 31:
case 32:
case 33:
case 34:
set_word(M_HALB);
Serial.println("halb");
break;
case 35:
case 36:
case 37:
case 38:
case 39:
set_word(M_FUENF);
set_word(M_NACH);
set_word(M_HALB);
Serial.println("fuenf nach halb");
break;
case 40:
case 41:
case 42:
case 43:
case 44:
set_word(M_ZEHN);
set_word(M_NACH);
set_word(M_HALB);
Serial.println("zehn nach halb");
break;
case 45:
case 46:
case 47:
case 48:
case 49:
set_word(M_VIERTEL);
set_word(M_VOR);
Serial.println("viertel vor");
break;
case 50:
case 51:
case 52:
case 53:
case 54:
set_word(M_ZEHN);
set_word(M_VOR);
Serial.println("zehn vor");
break;
case 55:
case 56:
case 57:
case 58:
case 59:
case 60:
set_word(M_FUENF);
set_word(M_VOR);
Serial.println("fuenf vor");
break;
}
}
/*-------- NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
time_t getNtpTime()
{
IPAddress ntpServerIP; // NTP server's ip address
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
// get a random server from the pool
WiFi.hostByName(ntpServerName, ntpServerIP);
Serial.print(ntpServerName);
Serial.print(": ");
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL;
}
}
Serial.println("No NTP Response :-(");
return 0; // return 0 if unable to get the time
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
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
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}