// Wall Clock 2022
// WallClock3_02 by Koji Ohashi @MaDA Lab
// 2022.05.30
// for BTF-LIGHTING 8x32
#include <WiFi.h>
#include "time.h"
const char* ssid = "**********";
const char* password = "**********";
const char* ntpServer = "ntp.nict.jp";
const long gmtOffset_sec = 9*3600;
const int daylightOffset_sec = 0;
int SecCount=300;
int ntpIntervalSec=1200;//sec
//------------------------------
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
//------------------------------
#include <FastLED.h>
#define DATA_PIN 16
#define WIDTH 32
#define HEIGHT 8
#define NUM_LEDS (WIDTH * HEIGHT)
CRGBArray<NUM_LEDS> leds;
int Pos[HEIGHT][WIDTH];
int imageArray[HEIGHT][WIDTH];
//int Pos[WIDTH][HEIGHT];
const int FontWidth=7;
const int FontHeight=8;
const int ColWidth=2;
byte CF_hue=0;
boolean End_Minute=false;
boolean DayTime=true;
int DAY_START=6;
int DAY_END=22;
int DAY_BRIGHTNESS=255;
int NIGHT_BRIGHTNESS=40;
int NIGHT_HUE=70;
byte ColonFont[FontHeight][ColWidth]={{0,0},{100,100},{100,100},{0,0},{0,0},{100,100},{100,100},{0,0}};
//FontWidth=7,FontHeight=8
byte NumFont[10][FontHeight][FontWidth]={
//-0-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{100,0,0,100,100,100,0},
{100,0,100,0,100,100,0},{100,100,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0}},
//-1-
{{0,0,100,100,100,0,0},{0,100,0,100,100,0,0},{0,0,0,100,100,0,0},{0,0,0,100,100,0,0},
{0,0,0,100,100,0,0},{0,0,0,100,100,0,0},{0,0,0,100,100,0,0},{00,100,100,100,100,100,0}},
//-2-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{0,0,0,0,100,100,0},{0,0,0,0,100,100,0},
{0,0,0,100,100,0,0},{0,0,100,100,0,0,0},{100,100,100,0,0,0,0},{100,100,100,100,100,100,0}},
//-3-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{0,0,0,0,100,100,0},{0,0,100,100,100,0,0},
{0,0,0,0,100,100,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0}},
//-4-
{{0,0,0,100,100,0,0},{0,0,100,100,100,0,0},{0,100,0,100,100,0,0},{100,0,0,100,100,0,0},
{100,0,0,100,100,0,0},{100,100,100,100,100,100,0},{0,0,0,100,100,00,0},{0,0,0,100,100,0,0}},
//-5-
{{100,100,100,100,100,100,0},{100,100,0,0,0,0,0},{100,100,0,0,0,0,0},{100,100,100,100,100,0,0},
{0,0,0,0,100,100,00},{0,0,0,0,100,100,00},{100,0,0,0,100,100,00},{100,100,100,100,100,0,0}},
//-6-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{100,0,0,0,0,0,0},{100,100,100,100,100,0,0},
{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0}},
//-7-
{{100,100,100,100,100,100,0},{100,0,0,0,0,100,0},{100,0,0,0,100,100,0},{0,0,0,0,100,0,0},
{0,0,0,100,100,0,0},{0,0,0,100,100,0,0},{0,0,0,100,100,0,0},{0,0,0,100,100,0,0}},
//-8-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0},
{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0}},
//-9-
{{0,100,100,100,100,0,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},{100,0,0,0,100,100,0},
{0,100,100,100,100,100,0},{0,0,0,0,100,100,0},{100,0,0,0,100,100,0},{0,100,100,100,100,0,0}}
};
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("WallClock3_02 by Koji Ohashi @MaDA Lab");
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
//---------------
onTimerSetup();
//---------------
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
setPosArray();
clearDisplay();
delay(3000);
}
void loop(){
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
printLocalTime();
SecCount=SecCount+1;
}
if(SecCount>=ntpIntervalSec){
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.print("Updated to ");
printLocalTime();
SecCount=0;
}
if(DayTime){
if(End_Minute){
showImageArrayColorFlow();
} else {
showImageArray(CF_hue);
}
} else {
showImageArray(NIGHT_HUE);
}
}
void printLocalTime(){
struct tm timeInfo;
getLocalTime(&timeInfo);
int time_h=timeInfo.tm_hour;;
int time_m=timeInfo.tm_min;
int time_s=timeInfo.tm_sec;
End_Minute=(time_s>50);//colorChange
DayTime=(time_h>=DAY_START)&&(time_h<=DAY_END);//Day or Night
if(DayTime){
LEDS.setBrightness(DAY_BRIGHTNESS);
} else {
LEDS.setBrightness(NIGHT_BRIGHTNESS);
}
Serial.print(time_h);
Serial.print(":");
Serial.print(time_m);
Serial.print(":");
Serial.println(time_s);
int h1=time_h/10;
int h0=time_h%10;
int m1=time_m/10;
int m0=time_m%10;
setImageArray(h1,h0,m1,m0);
}
void showImageArrayColorFlow(){
for(int j=0;j<WIDTH;j++){
for(int i=0; i < HEIGHT; i++){
byte FontBrightness=imageArray[i][j];
int led_num=Pos[i][j];
leds[led_num] = CHSV(CF_hue,255,FontBrightness);
}
FastLED.show();
delay(100);
CF_hue=CF_hue+5;
}
}
void showImageArray(byte hue){
for(int j=0;j<WIDTH;j++){
for(int i=0; i < HEIGHT; i++){
byte FontBrightness=imageArray[i][j];
int led_num=Pos[i][j];
leds[led_num] = CHSV(hue,255,FontBrightness);
}
FastLED.show();
delay(1);
}
}
void setImageArray(int h1,int h0,int m1, int m0){
int PosH1=0;
int PosH0=7;
int PosCol=14;
int PosM1=17;
int PosM0=25;
for(int j=0;j<WIDTH;j++){
for(int i=0; i < HEIGHT; i++){
imageArray[i][j]=0;
}
}
//Hour1
if(h1>0){
for(int j=0;j<FontWidth;j++){
for(int i=0; i < FontHeight; i++){
imageArray[i][j+PosH1]=NumFont[h1][i][j];
}
}
}
//Hour0
for(int j=0;j<FontWidth;j++){
for(int i=0; i < FontHeight; i++){
imageArray[i][j+PosH0]=NumFont[h0][i][j];
}
}
//:
for(int j=0;j<ColWidth;j++){
for(int i=0; i < FontHeight; i++){
imageArray[i][j+PosCol]=ColonFont[i][j];
}
}
//Min1
for(int j=0;j<FontWidth;j++){
for(int i=0; i < FontHeight; i++){
imageArray[i][j+PosM1]=NumFont[m1][i][j];
}
}
//Min0
for(int j=0;j<FontWidth;j++){
for(int i=0; i < FontHeight; i++){
imageArray[i][j+PosM0]=NumFont[m0][i][j];
}
}
}
// for BTF-LIGHTING 8x32
void setPosArray(){
for(int i=0; i < HEIGHT; i++){
for(int j=0; j < WIDTH; j++){
if(j%2==0){
Pos[i][j]=j*HEIGHT+i;
} else{
Pos[i][j]=(j+1)*HEIGHT-i-1;
}
}
}
}
/*
void setPosArray(){
for(int i=0; i < HEIGHT; i++){
for(int j=0; j < WIDTH; j++){
if(i%2==0){
Pos[i][j]=i*WIDTH+j;
} else{
Pos[i][j]=(i+1)*WIDTH-j-1;
}
}
}
}
*/
void clearDisplay(){
for(int i=0;i<NUM_LEDS;i++){
leds[i] = CRGB::Black;
}
FastLED.show();
}
void IRAM_ATTR onTimer(){
portENTER_CRITICAL_ISR(&timerMux);
portEXIT_CRITICAL_ISR(&timerMux);
xSemaphoreGiveFromISR(timerSemaphore, NULL);//Give a semaphore that we can check in the loop
}
void onTimerSetup(){
timerSemaphore = xSemaphoreCreateBinary();
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);//Attach onTimer function to our timer.
timerAlarmWrite(timer, 1000000, true);//alarm 1sec interval
timerAlarmEnable(timer);//Start an alarm
}