ABB Aurora web inverter monitor (WIM): set time and manage battery UPS – 5
You must consider a lot of factor when you try to create a generic device, time and power can be very important and not so simple to manage.
Datetime
A problem that must be managed is how to retrieve date and how to manage It.
There a lot of choiche you can apply, some use UTC time and convert It in locale WEB app, some store initial timestamp in the local device and so on.
In my centraline I’d like to store directly initial local time for logging, and I don’t add RTC device.
So I’m going to get time from NTP server (Network Time Protocol) than I’m going to apply specified DST (Daily Saving Time).
WiFiUDP ntpUDP;
// By default 'pool.ntp.org' is used with 60 seconds update interval and
// no offset
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 0*60*60, 60*60*1000);
[...]
timeClient.begin();
[...]
timeClient.update();
[...]
if (timeClient.forceUpdate()){
unsigned long epoch = timeClient.getEpochTime();
DEBUG_PRINTLN(epoch);
DEBUG_PRINTLN(F("NTP Time retrieved."));
adjustTime(epoch);
fixedTime = true;
}
I don’t implement all DST configurations, so if you need to add your Timezone with DST manage ask to me and I add It to esp8266 and WEB part.
You can find all information of Arduino Timezone manage in my article “Network Time Protocol (NTP), Timezone and Daylight saving time (DST) with esp8266, esp32 or Arduino“.
To partially manage the time I add GTM but if you select DST It’s going to override GTM.
time_t getLocalTime(void){
Timezone tz = getTimezoneData(codeDST);
return tz.toLocal(now());
}
Timezone getTimezoneData(const String code){
// DEBUG_PRINT("CODE DST RETRIEVED: ");
// DEBUG_PRINTLN(code);
if (code==F("AETZ")){
// Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660}; // UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600}; // UTC + 10 hours
Timezone tzTmp = Timezone(aEDT, aEST);
return tzTmp;
}else if (code==F("CET")){
// DEBUG_PRINTLN(F("CET FIND"));
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
Timezone tzTmp = Timezone(CEST, CET);
return tzTmp;
}else if(code==F("MSK")){
// Moscow Standard Time (MSK, does not observe DST)
TimeChangeRule msk = {"MSK", Last, Sun, Mar, 1, 180};
Timezone tzTmp = Timezone(msk);
return tzTmp;
}else if(code==F("UK")){
// United Kingdom (London, Belfast)
TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60}; // British Summer Time
TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0}; // Standard Time
Timezone tzTmp = Timezone(BST, GMT);
return tzTmp;
}else if(code==F("USCTZ")){
// US Central Time Zone (Chicago, Houston)
TimeChangeRule usCDT = {"CDT", Second, Sun, Mar, 2, -300};
TimeChangeRule usCST = {"CST", First, Sun, Nov, 2, -360};
Timezone tzTmp = Timezone(usCDT, usCST);
return tzTmp;
}else if(code==F("USMTZ")){
// US Mountain Time Zone (Denver, Salt Lake City)
TimeChangeRule usMDT = {"MDT", Second, Sun, Mar, 2, -360};
TimeChangeRule usMST = {"MST", First, Sun, Nov, 2, -420};
Timezone tzTmp = Timezone(usMDT, usMST);
return tzTmp;
}else if(code==F("ARIZONA")){
// Arizona is US Mountain Time Zone but does not use DST
TimeChangeRule usMST = {"MST", First, Sun, Nov, 2, -420};
Timezone tzTmp = Timezone(usMST);
return tzTmp;
}else if(code==F("USPTZ")){
// US Pacific Time Zone (Las Vegas, Los Angeles)
TimeChangeRule usPDT = {"PDT", Second, Sun, Mar, 2, -420};
TimeChangeRule usPST = {"PST", First, Sun, Nov, 2, -480};
Timezone tzTmp = Timezone(usPDT, usPST);
return tzTmp;
}else if(code==F("UTC")){
// UTC
TimeChangeRule utcRule = {"UTC", Last, Sun, Mar, 1, 0}; // UTC
Timezone tzTmp = Timezone(utcRule);
return tzTmp;
}else{
// UTC
// DEBUG_PRINT("TIME_OFFSET ");
int to = timeOffset/60;
// DEBUG_PRINTLN(to);
TimeChangeRule utcRule = {"GTM", Last, Sun, Mar, 1, to}; // UTC
Timezone tzTmp = Timezone(utcRule);
return tzTmp;
}
}
Another step that I want to manage is to grab Datetime from Inverter.
Inverter have an internal RTC (Real Time Clock), and I manage a call to get this data, as you can see on the article ABB Aurora PV communication protocol via MAX485/MAX3485
The code is quite simple:
Aurora inverter = Aurora(2, &Serial, 5);
[...]
inverter.begin();
[...]
Aurora::DataTimeDate timeDate = inverter.readTimeDate();
Timezone tz = getTimezoneData(codeDST);
tm tempTime = timeDate.getDateTime();
time_t currentUTCTime = tz.toUTC(mktime(&tempTime));
adjustTime(currentUTCTime);
Learn more about how to recover data from Aurora inverter on the article “ABB Aurora PV inverter library for Arduino, esp8266 and esp32”
Power source
I crete this centraline in substitution of the old one. The power supply of previous centraline is grab from Inverter directly so when there isn’t sun there isn’t power, this is quite good for previous centraline that use an MQTT protocol to send data directly to a central site, but I’d like to create an “autonomous” centraline without external site or other, so I use my old idea of UPS created with simple material, you can see It in this article Emergency power bank homemade, so It’s work for hours without power supply.
To reduce dimension I use a shield created for D1 Wemos, very compact:
You can find It here on AliExpress
The last version of this shield with a little solder directly put analog value of battery in the A0 pin with a voltage divider, so you can directly test the charge value, but It’s probably that you find the older version, and than you must use a voltage divider to put analog value on pin, more information in this article “Voltage divider: calculator and application“.
For the battery I use a 10kΩ and 20kΩ resistor.
float getBatteryVoltage(){
//************ Measuring Battery Voltage ***********
float sample1 = 0;
for (int i = 0; i < 100; i++) {
sample1 = sample1 + analogRead(A0); //read the voltage from the divider circuit
delay(2);
}
sample1 = sample1 / 100;
DEBUG_PRINT(F("AnalogRead..."));
DEBUG_PRINTLN(sample1);
float batVolt = (sample1 * 3.3 * (BAT_RES_VALUE_VCC + BAT_RES_VALUE_GND) / BAT_RES_VALUE_GND) / 1023;
return batVolt;
}
I also rework a design of battery holder to standardize the solution.
So I use dupont to divided value and XH2.54 2p 2.54mm to connect on shield.
You can buy dupont box here AliExpress
You can buy XH2.54 pins box here AliExpress XH2.54 2.54mm AliExpress PH2.0 2.0mm
Now you can expose the charging value and create a chart.
Thanks
- ABB Aurora Web Inverter Monitor (WIM): project introduction
- ABB Aurora Web Inverter Monitor (WIM): wiring Arduino to RS-485
- ABB Aurora Web Inverter Monitor (WIM): storage devices
- ABB Aurora Web Inverter Monitor (WIM): debug and notification
- ABB Aurora Web Inverter Monitor (WIM): set time and UPS
- ABB Aurora Web Inverter Monitor (WIM): WIFI configuration and REST Server
- ABB Aurora Web Inverter Monitor (WIM): WebSocket and Web Server
- ABB Aurora Web Inverter Monitor (WIM): Wiring and PCB soldering
- ABB Aurora Web Inverter Monitor (WIM): upload the sketch and front end
- ABB Aurora web inverter Monitor (WIM): 3D printed case to complete project
- ABB Aurora web inverter monitor (WIM): repair E013 error
GitHub repository with all code BE and FE transpiled