////////////////////////////////////////////////////////////////////////////////
// Name: klok-op-tijd-wifi.ino //
// 01 = Ziet er leuk uit en loopt strak op tijd. Gebruikt WiFi //
// om verbinding te maken met een tijdserver. //
// http://robotigs.nl/robots/includes/parts.php?idpart=113 //
// Created by: HARB rboek2@gmail.com September 2020 GPL copyrights //
// Original: https://github.com/ThingPulse/esp8266-oled-ssd1306 //
// Platform: TTGO T-Beam V1.0 //
////////////////////////////////////////////////////////////////////////////////
// As outputs the following modules are mounted: //
// //
// As inputs the following modules are mounted: //
// //
// For communications and statistics are mounted: //
////////////////////////////////////////////////////////////////////////////////
//Define the needed header files for the precompiler, no charge if not used --
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <Wire.h> // Only needed for oled
#include "SSD1306Wire.h" // https://github.com/ThingPulse/esp8266-oled-ssd1306
#include "OLEDDisplayUi.h" // Include the UI lib
#include <WiFi.h> //Gebruikt door tijd synchronisatie
#include "axp20x.h" // https://github.com/lewisxhe/AXP202X_Library
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
#define PMU_IRQ 35
#define I2C_SDA 21
#define I2C_SCL 22
#define SSD1306_ADDRESS 0x3C
const char* ssid = "H369AAA781A";
const char* password = "mispoes";
bool pmu_irq = false;
String baChStatus = "No charging";
bool ssd1306_found = false;
bool axp192_found = false;
bool packetSent, packetQueued;
long timezone = 1;
byte daysavetime = 1;
int screenW = 128;
int screenH = 64;
int clockCenterX = screenW/2;
int clockCenterY = ((screenH-16)/2)+16; // top yellow part is 16 px height
int clockRadius = 25; //23
char buffer[20];
String twoDigits(int digits){ // utility function for digital clock display: prints leading 0
if(digits < 10) {
String i = '0'+String(digits);
return i;
}else{
return String(digits);
}
}
//const uint8_t axp_irq_pin = 35; //Ok voor T-Beam V1.0 zie ook configuration.h
const unsigned char activeSymbol[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const unsigned char inactiveSymbol[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
//Initialize OBJECTS ---------------------------------------------------------
AXP20X_Class axp;
RTC_DATA_ATTR int bootCount = 0; // deep sleep support
esp_sleep_source_t wakeCause; // the reason we booted this time
SSD1306Wire display(SSD1306_ADDRESS, I2C_SDA,I2C_SCL);//T-Beam V1.0 0x3c,21,22
OLEDDisplayUi ui (&display);
void GPSframe(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_24);
display->drawString(clockCenterX + x , clockCenterY + y, "Accustatus" );
}
// This array keeps function pointers to all frames
FrameCallback frames[] = {analogClockFrame, digitalClockFrame, GPSframe}; // frames are the single views that slide in
int frameCount = 3; // how many frames are there?
OverlayCallback overlays[] = { clockOverlay }; //Overlays are statically drawn on top of a frame eg. a clock
int overlaysCount = 1;
void setup() {
Serial.begin(115200);
Serial.println();
Wire.begin(I2C_SDA, I2C_SCL);
scanI2Cdevice();
axp192Init();
Serial.println();
Serial.print("WiFi connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Contacting Time Server");
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
struct tm tmstruct ;
delay(2000);
tmstruct.tm_year = 0;
getLocalTime(&tmstruct, 5000);
int uur = tmstruct.tm_hour;
int minuut = tmstruct.tm_min;
int sekonde = tmstruct.tm_sec;
int dag = tmstruct.tm_sec;
int maand = tmstruct.tm_mon +1;
int jaar = (tmstruct.tm_year)+1900;
// The ESP is capable of rendering 60fps in 80Mhz mode
// but that won't give you much time for anything else
// run it in 160Mhz mode or just set it to 30 fps
ui.setTargetFPS(60);
ui.setActiveSymbol(activeSymbol); // Customize the active and inactive symbol
ui.setInactiveSymbol(inactiveSymbol);
ui.setIndicatorPosition(TOP); // TOP, LEFT, BOTTOM, RIGHT
ui.setIndicatorDirection(LEFT_RIGHT); // Defines where the first frame is located in the bar.
ui.setFrameAnimation(SLIDE_RIGHT); // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN
ui.setFrames(frames, frameCount); // Add frames
ui.setOverlays(overlays, overlaysCount); // Add overlays
ui.init(); // Initialising the UI will init the display too.
display.flipScreenVertically();
setTime(uur, minuut, sekonde, dag, maand, jaar);
}
void loop() {
int remainingTimeBudget = ui.update();
if (remainingTimeBudget > 0) { // You can do some work here
delay(remainingTimeBudget); // Don't do stuff if you are below your time budget.
}
}
void clockOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {}
void analogClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
// ui.disableIndicator();
// Draw the clock face
// display->drawCircle(clockCenterX + x, clockCenterY + y, clockRadius);
display->drawCircle(clockCenterX + x, clockCenterY + y, 2);
// hour ticks
for( int z=0; z < 360;z= z + 30 ){
//Begin at 0° and stop at 360°
float angle = z ;
angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
int x2 = ( clockCenterX + ( sin(angle) * clockRadius ) );
int y2 = ( clockCenterY - ( cos(angle) * clockRadius ) );
int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
display->drawLine( x2 + x , y2 + y , x3 + x , y3 + y);
}
// display second hand
float angle = second() * 6 ;
angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
//
// display minute hand
angle = minute() * 6 ;
angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
//
// display hour hand
angle = hour() * 30 + int( ( minute() / 12 ) * 6 ) ;
angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
}
void digitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
String timenow = String(hour())+":"+twoDigits(minute())+":"+twoDigits(second());
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_24);
display->drawString(clockCenterX + x , clockCenterY + y, timenow );
}
void scanI2Cdevice(void){
byte err, addr;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
Serial.print("I2C device found at address 0x");
if (addr < 16)
Serial.print("0");
Serial.print(addr, HEX);
Serial.println(" !");
nDevices++;
if (addr == SSD1306_ADDRESS) {
ssd1306_found = true;
Serial.println("ssd1306 display found");
}
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
Serial.println("axp192 PMU found");
}
} else if (err == 4) {
Serial.print("Unknow error at address 0x");
if (addr < 16)
Serial.print("0");
Serial.println(addr, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
/**
* Init the power manager chip
*
* axp192 power
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the
// OLED and the axp192 share the same i2c bus, instead use ssd1306 sleep mode
DCDC2 -> unused
DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!)
LDO1 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS
//to power the GPS ram (for a couple of days), can not be turned off
LDO2 200mA -> LORA
LDO3 200mA -> GPS
*/
void axp192Init() { //https://github.com/kizniche/ttgo-tbeam-ttn-tracker
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
Serial.println("AXP192 Begin PASS");
} else {
Serial.println("AXP192 Begin FAIL");
}
// axp.setChgLEDMode(LED_BLINK_4HZ);
Serial.printf("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
Serial.printf("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
Serial.printf("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
Serial.printf("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
Serial.printf("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
Serial.printf("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
Serial.println("----------------------------------------");
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS main power
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
axp.setDCDC1Voltage(3300); // for the OLED power
Serial.printf("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
Serial.printf("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
Serial.printf("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
Serial.printf("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
Serial.printf("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
Serial.printf("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
axp.setChgLEDMode(AXP20X_LED_OFF); // LED off
//axp.setChgLEDMode(AXP20X_LED_BLINK_1HZ); // 1blink/sec, low rate
//axp.setChgLEDMode(AXP20X_LED_BLINK_4HZ); // 4blink/sec, high rate
//axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); // LED full on
pinMode(PMU_IRQ, INPUT_PULLUP);
attachInterrupt(PMU_IRQ, [] {
pmu_irq = true;
}, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, 1);
axp.clearIRQ();
if (axp.isChargeing()) {
baChStatus = "Charging";
}
} else {
Serial.println("AXP192 not found");
}
}