├── .gitattributes ├── .gitignore ├── PylontechMonitoring.ino ├── README.md ├── Schemetics.png └── libraries ├── Misc ├── circular_buffer.h └── circular_log.h ├── NtpTime └── ntp_time.h ├── SimpleTimer ├── README ├── SimpleTimer.cpp └── SimpleTimer.h └── Time-master ├── DateStrings.cpp ├── Readme.txt ├── Time.cpp ├── Time.h ├── TimeLib.h ├── examples ├── Processing │ └── SyncArduinoClock │ │ ├── SyncArduinoClock.pde │ │ └── readme.txt ├── TimeArduinoDue │ └── TimeArduinoDue.ino ├── TimeGPS │ └── TimeGPS.ino ├── TimeNTP │ └── TimeNTP.ino ├── TimeNTP_ESP8266WiFi │ └── TimeNTP_ESP8266WiFi.ino ├── TimeRTC │ └── TimeRTC.ino ├── TimeRTCLog │ └── TimeRTCLog.ino ├── TimeRTCSet │ └── TimeRTCSet.ino ├── TimeSerial │ └── TimeSerial.ino ├── TimeSerialDateStrings │ └── TimeSerialDateStrings.ino └── TimeTeensy3 │ └── TimeTeensy3.ino ├── keywords.txt ├── library.json └── library.properties /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # ========================= 255 | # Operating System Files 256 | # ========================= 257 | 258 | # OSX 259 | # ========================= 260 | 261 | .DS_Store 262 | .AppleDouble 263 | .LSOverride 264 | 265 | # Thumbnails 266 | ._* 267 | 268 | # Files that might appear in the root of a volume 269 | .DocumentRevisions-V100 270 | .fseventsd 271 | .Spotlight-V100 272 | .TemporaryItems 273 | .Trashes 274 | .VolumeIcon.icns 275 | 276 | # Directories potentially created on remote AFP share 277 | .AppleDB 278 | .AppleDesktop 279 | Network Trash Folder 280 | Temporary Items 281 | .apdisk 282 | 283 | # Windows 284 | # ========================= 285 | 286 | # Windows image file caches 287 | Thumbs.db 288 | ehthumbs.db 289 | 290 | # Folder config file 291 | Desktop.ini 292 | 293 | # Recycle Bin used on file shares 294 | $RECYCLE.BIN/ 295 | 296 | # Windows Installer files 297 | *.cab 298 | *.msi 299 | *.msm 300 | *.msp 301 | 302 | # Windows shortcuts 303 | *.lnk 304 | -------------------------------------------------------------------------------- /PylontechMonitoring.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include //https://github.com/PaulStoffregen/Time 8 | #include 9 | #include 10 | 11 | 12 | //IMPORTANT: Specify your WIFI settings: 13 | #define WIFI_SSID "--YOUR SSID HERE --" 14 | #define WIFI_PASS "-- YOUR PASSWORD HERE --" 15 | 16 | //IMPORTANT: Uncomment this line if you want to enable MQTT (and fill correct MQTT_ values below): 17 | //#define ENABLE_MQTT 18 | 19 | #ifdef ENABLE_MQTT 20 | //NOTE 1: if you want to change what is pushed via MQTT - edit function: pushBatteryDataToMqtt. 21 | //NOTE 2: MQTT_TOPIC_ROOT is where battery will push MQTT topics. For example "soc" will be pushed to: "home/grid_battery/soc" 22 | #define MQTT_SERVER "192.168.0.6" 23 | #define MQTT_PORT 1883 24 | #define MQTT_USER "" 25 | #define MQTT_PASSWORD "" 26 | #define MQTT_TOPIC_ROOT "home/grid_battery/" //this is where mqtt data will be pushed 27 | #define MQTT_PUSH_FREQ_SEC 2 //maximum mqtt update frequency in seconds 28 | 29 | #include 30 | WiFiClient espClient; 31 | PubSubClient mqttClient(espClient); 32 | #endif //ENABLE_MQTT 33 | 34 | char g_szRecvBuff[7000]; 35 | 36 | ESP8266WebServer server(80); 37 | SimpleTimer timer; 38 | circular_log<7000> g_log; 39 | bool ntpTimeReceived = false; 40 | int g_baudRate = 0; 41 | 42 | void Log(const char* msg) 43 | { 44 | g_log.Log(msg); 45 | } 46 | 47 | void setup() { 48 | pinMode(LED_BUILTIN, OUTPUT); 49 | digitalWrite(LED_BUILTIN, HIGH);//high is off 50 | 51 | // put your setup code here, to run once: 52 | WiFi.mode(WIFI_STA); 53 | WiFi.persistent(false); //our credentialss are hardcoded, so we don't need ESP saving those each boot (will save on flash wear) 54 | WiFi.hostname("PylontechBattery"); 55 | WiFi.begin(WIFI_SSID, WIFI_PASS); 56 | 57 | for(int ix=0; ix<10; ix++) 58 | { 59 | if(WiFi.status() == WL_CONNECTED) 60 | { 61 | break; 62 | } 63 | 64 | delay(1000); 65 | } 66 | 67 | ArduinoOTA.setHostname("GarageBattery"); 68 | ArduinoOTA.begin(); 69 | server.on("/", handleRoot); 70 | server.on("/log", handleLog); 71 | server.on("/req", handleReq); 72 | server.on("/jsonOut", handleJsonOut); 73 | server.on("/reboot", [](){ 74 | ESP.restart(); 75 | }); 76 | 77 | server.begin(); 78 | 79 | syncTime(); 80 | 81 | #ifdef ENABLE_MQTT 82 | mqttClient.setServer(MQTT_SERVER, MQTT_PORT); 83 | #endif 84 | 85 | Log("Boot event"); 86 | } 87 | 88 | void handleLog() 89 | { 90 | server.send(200, "text/html", g_log.c_str()); 91 | } 92 | 93 | void switchBaud(int newRate) 94 | { 95 | if(g_baudRate == newRate) 96 | { 97 | return; 98 | } 99 | 100 | if(g_baudRate != 0) 101 | { 102 | Serial.flush(); 103 | delay(20); 104 | Serial.end(); 105 | delay(20); 106 | } 107 | 108 | char szMsg[50]; 109 | snprintf(szMsg, sizeof(szMsg)-1, "New baud: %d", newRate); 110 | Log(szMsg); 111 | 112 | Serial.begin(newRate); 113 | g_baudRate = newRate; 114 | 115 | delay(20); 116 | } 117 | 118 | void waitForSerial() 119 | { 120 | for(int ix=0; ix<150;ix++) 121 | { 122 | if(Serial.available()) break; 123 | delay(10); 124 | } 125 | } 126 | 127 | int readFromSerial() 128 | { 129 | memset(g_szRecvBuff, 0, sizeof(g_szRecvBuff)); 130 | int recvBuffLen = 0; 131 | bool foundTerminator = true; 132 | 133 | waitForSerial(); 134 | 135 | while(Serial.available()) 136 | { 137 | char szResponse[256] = ""; 138 | const int readNow = Serial.readBytesUntil('>', szResponse, sizeof(szResponse)-1); //all commands terminate with "$$\r\n\rpylon>" (no new line at the end) 139 | if(readNow > 0 && 140 | szResponse[0] != '\0') 141 | { 142 | if(readNow + recvBuffLen + 1 >= (int)(sizeof(g_szRecvBuff))) 143 | { 144 | Log("WARNING: Read too much data on the console!"); 145 | break; 146 | } 147 | 148 | strcat(g_szRecvBuff, szResponse); 149 | recvBuffLen += readNow; 150 | 151 | if(strstr(g_szRecvBuff, "$$\r\n\rpylon")) 152 | { 153 | strcat(g_szRecvBuff, ">"); //readBytesUntil will skip this, so re-add 154 | foundTerminator = true; 155 | break; //found end of the string 156 | } 157 | 158 | if(strstr(g_szRecvBuff, "Press [Enter] to be continued,other key to exit")) 159 | { 160 | //we need to send new line character so battery continues the output 161 | Serial.write("\r"); 162 | } 163 | 164 | waitForSerial(); 165 | } 166 | } 167 | 168 | if(recvBuffLen > 0 ) 169 | { 170 | if(foundTerminator == false) 171 | { 172 | Log("Failed to find pylon> terminator"); 173 | } 174 | } 175 | 176 | return recvBuffLen; 177 | } 178 | 179 | bool readFromSerialAndSendResponse() 180 | { 181 | const int recvBuffLen = readFromSerial(); 182 | if(recvBuffLen > 0) 183 | { 184 | server.sendContent(g_szRecvBuff); 185 | return true; 186 | } 187 | 188 | return false; 189 | } 190 | 191 | bool sendCommandAndReadSerialResponse(const char* pszCommand) 192 | { 193 | switchBaud(115200); 194 | 195 | if(pszCommand[0] != '\0') 196 | { 197 | Serial.write(pszCommand); 198 | } 199 | Serial.write("\n"); 200 | 201 | const int recvBuffLen = readFromSerial(); 202 | if(recvBuffLen > 0) 203 | { 204 | return true; 205 | } 206 | 207 | //wake up console and try again: 208 | wakeUpConsole(); 209 | 210 | if(pszCommand[0] != '\0') 211 | { 212 | Serial.write(pszCommand); 213 | } 214 | Serial.write("\n"); 215 | 216 | return readFromSerial() > 0; 217 | } 218 | 219 | void handleReq() 220 | { 221 | bool respOK; 222 | if(server.hasArg("code") == false) 223 | { 224 | respOK = sendCommandAndReadSerialResponse(""); 225 | } 226 | else 227 | { 228 | respOK = sendCommandAndReadSerialResponse(server.arg("code").c_str()); 229 | } 230 | 231 | if(respOK) 232 | { 233 | server.send(200, "text/plain", g_szRecvBuff); 234 | } 235 | else 236 | { 237 | server.send(500, "text/plain", "????"); 238 | } 239 | } 240 | 241 | void handleJsonOut() 242 | { 243 | if(sendCommandAndReadSerialResponse("pwr") == false) 244 | { 245 | server.send(500, "text/plain", "Failed to get response to 'pwr' command"); 246 | return; 247 | } 248 | 249 | parsePwrResponse(g_szRecvBuff); 250 | prepareJsonOutput(g_szRecvBuff, sizeof(g_szRecvBuff)); 251 | server.send(200, "application/json", g_szRecvBuff); 252 | } 253 | 254 | void handleRoot() { 255 | unsigned long days = 0, hours = 0, minutes = 0; 256 | unsigned long val = os_getCurrentTimeSec(); 257 | 258 | days = val / (3600*24); 259 | val -= days * (3600*24); 260 | 261 | hours = val / 3600; 262 | val -= hours * 3600; 263 | 264 | minutes = val / 60; 265 | val -= minutes*60; 266 | 267 | static char szTmp[2500] = ""; 268 | snprintf(szTmp, sizeof(szTmp)-1, "Garage Battery
Time GMT: %d/%02d/%02d %02d:%02d:%02d (%s)
Uptime: %02d:%02d:%02d.%02d

free heap: %u
Wifi RSSI: %d
Wifi SSID: %s", 269 | year(), month(), day(), hour(), minute(), second(), "GMT", 270 | (int)days, (int)hours, (int)minutes, (int)val, 271 | ESP.getFreeHeap(), WiFi.RSSI(), WiFi.SSID().c_str()); 272 | 273 | 274 | strncat(szTmp, "
Runtime log
", sizeof(szTmp)-1); 275 | strncat(szTmp, "
Command:
Power | Help | Event Log | Time", sizeof(szTmp)-1); 276 | strncat(szTmp, "", sizeof(szTmp)-1); 277 | 278 | server.send(200, "text/html", szTmp); 279 | } 280 | 281 | unsigned long os_getCurrentTimeSec() 282 | { 283 | static unsigned int wrapCnt = 0; 284 | static unsigned long lastVal = 0; 285 | unsigned long currentVal = millis(); 286 | 287 | if(currentVal < lastVal) 288 | { 289 | wrapCnt++; 290 | } 291 | 292 | lastVal = currentVal; 293 | unsigned long seconds = currentVal/1000; 294 | 295 | //millis will wrap each 50 days, as we are interested only in seconds, let's keep the wrap counter 296 | return (wrapCnt*4294967) + seconds; 297 | } 298 | 299 | void syncTime() 300 | { 301 | //get time from NTP 302 | time_t currentTimeGMT = getNtpTime(); 303 | if(currentTimeGMT) 304 | { 305 | ntpTimeReceived = true; 306 | setTime(currentTimeGMT); 307 | } 308 | else 309 | { 310 | timer.setTimeout(5000, syncTime); //try again in 5 seconds 311 | } 312 | } 313 | 314 | void wakeUpConsole() 315 | { 316 | switchBaud(1200); 317 | 318 | //byte wakeUpBuff[] = {0x7E, 0x32, 0x30, 0x30, 0x31, 0x34, 0x36, 0x38, 0x32, 0x43, 0x30, 0x30, 0x34, 0x38, 0x35, 0x32, 0x30, 0x46, 0x43, 0x43, 0x33, 0x0D}; 319 | //Serial.write(wakeUpBuff, sizeof(wakeUpBuff)); 320 | Serial.write("~20014682C0048520FCC3\r"); 321 | delay(1000); 322 | 323 | byte newLineBuff[] = {0x0E, 0x0A}; 324 | switchBaud(115200); 325 | 326 | for(int ix=0; ix<10; ix++) 327 | { 328 | Serial.write(newLineBuff, sizeof(newLineBuff)); 329 | delay(1000); 330 | 331 | if(Serial.available()) 332 | { 333 | while(Serial.available()) 334 | { 335 | Serial.read(); 336 | } 337 | 338 | break; 339 | } 340 | } 341 | } 342 | 343 | #define MAX_PYLON_BATTERIES 8 344 | 345 | struct pylonBattery 346 | { 347 | bool isPresent; 348 | long soc; //Coulomb in % 349 | long voltage; //in mW 350 | long current; //in mA, negative value is discharge 351 | long tempr; //temp of case or BMS? 352 | long cellTempLow; 353 | long cellTempHigh; 354 | long cellVoltLow; 355 | long cellVoltHigh; 356 | char baseState[9]; //Charge | Dischg | Idle 357 | char voltageState[9]; //Normal 358 | char currentState[9]; //Normal 359 | char tempState[9]; //Normal 360 | char time[20]; //2019-06-08 04:00:29 361 | char b_v_st[9]; //Normal (battery voltage?) 362 | char b_t_st[9]; //Normal (battery temperature?) 363 | 364 | bool isCharging() const { return strcmp(baseState, "Charge") == 0; } 365 | bool isDischarging() const { return strcmp(baseState, "Dischg") == 0; } 366 | bool isIdle() const { return strcmp(baseState, "Idle") == 0; } 367 | bool isBalancing() const { return strcmp(baseState, "Balance") == 0; } 368 | 369 | 370 | bool isNormal() const 371 | { 372 | if(isCharging() == false && 373 | isDischarging() == false && 374 | isIdle() == false && 375 | isBalancing() == false) 376 | { 377 | return false; //base state looks wrong! 378 | } 379 | 380 | return strcmp(voltageState, "Normal") == 0 && 381 | strcmp(currentState, "Normal") == 0 && 382 | strcmp(tempState, "Normal") == 0 && 383 | strcmp(b_v_st, "Normal") == 0 && 384 | strcmp(b_t_st, "Normal") == 0 ; 385 | } 386 | }; 387 | 388 | struct batteryStack 389 | { 390 | int batteryCount; 391 | int soc; //in %, if charging: average SOC, otherwise: lowest SOC 392 | int temp; //in mC, if highest temp is > 15C, this will show the highest temp, otherwise the lowest 393 | long currentDC; //mAh current going in or out of the battery 394 | long avgVoltage; //in mV 395 | char baseState[9]; //Charge | Dischg | Idle | Balance | Alarm! 396 | 397 | pylonBattery batts[MAX_PYLON_BATTERIES]; 398 | 399 | bool isNormal() const 400 | { 401 | for(int ix=0; ix 1000) 447 | { 448 | return (long)(powerDC*1.06); 449 | } 450 | else if(powerDC > 600) 451 | { 452 | return (long)(powerDC*1.1); 453 | } 454 | else 455 | { 456 | return (long)(powerDC*1.13); 457 | } 458 | } 459 | } 460 | }; 461 | 462 | batteryStack g_stack; 463 | 464 | 465 | long extractInt(const char* pStr, int pos) 466 | { 467 | return atol(pStr+pos); 468 | } 469 | 470 | void extractStr(const char* pStr, int pos, char* strOut, int strOutSize) 471 | { 472 | strOut[strOutSize-1] = '\0'; 473 | strncpy(strOut, pStr+pos, strOutSize-1); 474 | strOutSize--; 475 | 476 | 477 | //trim right 478 | while(strOutSize > 0) 479 | { 480 | if(isspace(strOut[strOutSize-1])) 481 | { 482 | strOut[strOutSize-1] = '\0'; 483 | } 484 | else 485 | { 486 | break; 487 | } 488 | 489 | strOutSize--; 490 | } 491 | } 492 | 493 | /* Output has mixed \r and \r\n 494 | pwr 495 | 496 | @ 497 | 498 | Power Volt Curr Tempr Tlow Thigh Vlow Vhigh Base.St Volt.St Curr.St Temp.St Coulomb Time B.V.St B.T.St 499 | 500 | 1 49735 -1440 22000 19000 19000 3315 3317 Dischg Normal Normal Normal 93% 2019-06-08 04:00:30 Normal Normal 501 | 502 | .... 503 | 504 | 8 - - - - - - - Absent - - - - - - - 505 | 506 | Command completed successfully 507 | 508 | $$ 509 | 510 | pylon 511 | */ 512 | bool parsePwrResponse(const char* pStr) 513 | { 514 | if(strstr(pStr, "Command completed successfully") == NULL) 515 | { 516 | return false; 517 | } 518 | 519 | int chargeCnt = 0; 520 | int dischargeCnt = 0; 521 | int idleCnt = 0; 522 | int alarmCnt = 0; 523 | int socAvg = 0; 524 | int socLow = 0; 525 | int tempHigh = 0; 526 | int tempLow = 0; 527 | 528 | memset(&g_stack, 0, sizeof(g_stack)); 529 | 530 | for(int ix=0; ix g_stack.batts[ix].soc){socLow = g_stack.batts[ix].soc;} 587 | if(tempHigh < g_stack.batts[ix].cellTempHigh){tempHigh = g_stack.batts[ix].cellTempHigh;} 588 | if(tempLow > g_stack.batts[ix].cellTempLow){tempLow = g_stack.batts[ix].cellTempLow;} 589 | } 590 | 591 | } 592 | } 593 | 594 | //now update stack state: 595 | g_stack.avgVoltage /= g_stack.batteryCount; 596 | g_stack.soc = socLow; 597 | 598 | if(tempHigh > 15000) //15C 599 | { 600 | g_stack.temp = tempHigh; //in the summer we highlight the warmest cell 601 | } 602 | else 603 | { 604 | g_stack.temp = tempLow; //in the winter we focus on coldest cell 605 | } 606 | 607 | if(alarmCnt > 0) 608 | { 609 | strcpy(g_stack.baseState, "Alarm!"); 610 | } 611 | else if(chargeCnt == g_stack.batteryCount) 612 | { 613 | strcpy(g_stack.baseState, "Charge"); 614 | g_stack.soc = (int)(socAvg / g_stack.batteryCount); 615 | } 616 | else if(dischargeCnt == g_stack.batteryCount) 617 | { 618 | strcpy(g_stack.baseState, "Dischg"); 619 | } 620 | else if(idleCnt == g_stack.batteryCount) 621 | { 622 | strcpy(g_stack.baseState, "Idle"); 623 | } 624 | else 625 | { 626 | strcpy(g_stack.baseState, "Balance"); 627 | } 628 | 629 | 630 | return true; 631 | } 632 | 633 | void prepareJsonOutput(char* pBuff, int buffSize) 634 | { 635 | memset(pBuff, 0, buffSize); 636 | snprintf(pBuff, buffSize-1, "{\"soc\": %d, \"temp\": %d, \"currentDC\": %ld, \"avgVoltage\": %ld, \"baseState\": \"%s\", \"batteryCount\": %d, \"powerDC\": %ld, \"estPowerAC\": %ld, \"isNormal\": %s}", g_stack.soc, 637 | g_stack.temp, 638 | g_stack.currentDC, 639 | g_stack.avgVoltage, 640 | g_stack.baseState, 641 | g_stack.batteryCount, 642 | g_stack.getPowerDC(), 643 | g_stack.getEstPowerAc(), 644 | g_stack.isNormal() ? "true" : "false"); 645 | } 646 | 647 | void loop() { 648 | #ifdef ENABLE_MQTT 649 | mqttLoop(); 650 | #endif 651 | 652 | ArduinoOTA.handle(); 653 | server.handleClient(); 654 | timer.run(); 655 | 656 | //if there are bytes availbe on serial here - it's unexpected 657 | //when we send a command to battery, we read whole response 658 | //if we get anything here anyways - we will log it 659 | int bytesAv = Serial.available(); 660 | if(bytesAv > 0) 661 | { 662 | if(bytesAv > 63) 663 | { 664 | bytesAv = 63; 665 | } 666 | 667 | char buff[64+4] = "RCV:"; 668 | if(Serial.readBytes(buff+4, bytesAv) > 0) 669 | { 670 | digitalWrite(LED_BUILTIN, LOW); 671 | delay(5); 672 | digitalWrite(LED_BUILTIN, HIGH);//high is off 673 | 674 | Log(buff); 675 | } 676 | } 677 | } 678 | 679 | #ifdef ENABLE_MQTT 680 | #define ABS_DIFF(a, b) (a > b ? a-b : b-a) 681 | void mqtt_publish_f(const char* topic, float newValue, float oldValue, float minDiff, bool force) 682 | { 683 | char szTmp[16] = ""; 684 | snprintf(szTmp, 15, "%.2f", newValue); 685 | if(force || ABS_DIFF(newValue, oldValue) > minDiff) 686 | { 687 | mqttClient.publish(topic, szTmp, false); 688 | } 689 | } 690 | 691 | void mqtt_publish_i(const char* topic, int newValue, int oldValue, int minDiff, bool force) 692 | { 693 | char szTmp[16] = ""; 694 | snprintf(szTmp, 15, "%d", newValue); 695 | if(force || ABS_DIFF(newValue, oldValue) > minDiff) 696 | { 697 | mqttClient.publish(topic, szTmp, false); 698 | } 699 | } 700 | 701 | void mqtt_publish_s(const char* topic, const char* newValue, const char* oldValue, bool force) 702 | { 703 | if(force || strcmp(newValue, oldValue) != 0) 704 | { 705 | mqttClient.publish(topic, newValue, false); 706 | } 707 | } 708 | 709 | void pushBatteryDataToMqtt(const batteryStack& lastSentData, bool forceUpdate /* if true - we will send all data regardless if it's the same */) 710 | { 711 | mqtt_publish_f(MQTT_TOPIC_ROOT "soc", g_stack.soc, lastSentData.soc, 0, forceUpdate); 712 | mqtt_publish_f(MQTT_TOPIC_ROOT "temp", (float)g_stack.temp/1000.0, (float)lastSentData.temp/1000.0, 0, forceUpdate); 713 | mqtt_publish_i(MQTT_TOPIC_ROOT "estPowerAC", g_stack.getEstPowerAc(), lastSentData.getEstPowerAc(), 10, forceUpdate); 714 | mqtt_publish_i(MQTT_TOPIC_ROOT "battery_count",g_stack.batteryCount, lastSentData.batteryCount, 0, forceUpdate); 715 | mqtt_publish_s(MQTT_TOPIC_ROOT "base_state", g_stack.baseState, lastSentData.baseState , forceUpdate); 716 | mqtt_publish_i(MQTT_TOPIC_ROOT "is_normal", g_stack.isNormal() ? 1:0, lastSentData.isNormal() ? 1:0, 0, forceUpdate); 717 | } 718 | 719 | void mqttLoop() 720 | { 721 | //if we have problems with connecting to mqtt server, we will attempt to re-estabish connection each 1minute (not more than that) 722 | static unsigned long g_lastConnectionAttempt = 0; 723 | 724 | //first: let's make sure we are connected to mqtt 725 | const char* topicLastWill = MQTT_TOPIC_ROOT "availability"; 726 | if (!mqttClient.connected() && (g_lastConnectionAttempt == 0 || os_getCurrentTimeSec() - g_lastConnectionAttempt > 60)) { 727 | if(mqttClient.connect("GarageBattery", MQTT_USER, MQTT_PASSWORD, topicLastWill, 1, true, "offline")) 728 | { 729 | Log("Connected to MQTT server: " MQTT_SERVER); 730 | mqttClient.publish(topicLastWill, "online", true); 731 | } 732 | else 733 | { 734 | Log("Failed to connect to MQTT server."); 735 | } 736 | 737 | g_lastConnectionAttempt = os_getCurrentTimeSec(); 738 | } 739 | 740 | //next: read data from battery and send via MQTT (but only once per MQTT_PUSH_FREQ_SEC seconds) 741 | static unsigned long g_lastDataSent = 0; 742 | if(mqttClient.connected() && 743 | os_getCurrentTimeSec() - g_lastDataSent > MQTT_PUSH_FREQ_SEC && 744 | sendCommandAndReadSerialResponse("pwr") == true) 745 | { 746 | static batteryStack lastSentData; //this is the last state we sent to MQTT, used to prevent sending the same data over and over again 747 | static unsigned int callCnt = 0; 748 | 749 | parsePwrResponse(g_szRecvBuff); 750 | 751 | bool forceUpdate = (callCnt % 20 == 0); //push all the data every 20th call 752 | pushBatteryDataToMqtt(lastSentData, forceUpdate); 753 | 754 | callCnt++; 755 | g_lastDataSent = os_getCurrentTimeSec(); 756 | memcpy(&lastSentData, &g_stack, sizeof(batteryStack)); 757 | } 758 | 759 | mqttClient.loop(); 760 | } 761 | 762 | #endif //ENABLE_MQTT 763 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pylontech Battery Monitoring via WiFi 2 | 3 | This project allows you to control and monitor Pylontech US2000B, US2000C and US3000C batteries via console port over WiFi. 4 | It it's a great starting point to integrate battery with your home automation. 5 | 6 | **I ACCEPT NO RESPONSIBILTY FOR ANY DAMAGE CAUSED, PROCEED AT YOUR OWN RISK** 7 | 8 | # Features: 9 | * Low cost (around 20$ in total). 10 | * Adds WiFi capability to your Pylontech US2000B/C or US3000C battery. 11 | * Device exposes web interface that allows to: 12 | * send console commands and read response over WiFi (no PC needed) 13 | * battery information can be retrevied also in JSON format for easy parsing 14 | * MQTT support: 15 | * device pushes basic battery data like SOC, temperature, state, etc to selected MQTT server 16 | * Easy to modify code using Arduino IDE and flash new firmware over WiFi (no need to disconnect from the battery). 17 | 18 | See the project in action on [Youtube](https://youtu.be/7VyQjKU3MsU):
19 | See the project in action on YouTube 20 | 21 | 22 | # Parts needed and schematics: 23 | * [Wemos D1 mini microcontroller](https://www.amazon.co.uk/Makerfire-NodeMcu-Development-ESP8266-Compatible/dp/B071S8MWTY/). 24 | * [SparkFun MAX3232 Transceiver](https://www.sparkfun.com/products/11189). 25 | * US2000B: Cable with RJ10 connector (some RJ10 cables have only two wires, make sure to buy one that has all four wires present). 26 | * US2000C: Cable with RJ45 connector (see below for more details). 27 | * Capacitors C1: 10uF, C2: 0.1uF (this is not strictly required, but recommended as Wemos D1 can have large current spikes). 28 | 29 | ![Schematics](Schemetics.png) 30 | 31 | # US2000C/US3000C notes: 32 | This battery uses RJ45 cable instead of RJ10. Schematics is the same only plug differs: 33 | * RJ45 Pin 3 (white-green) = R1IN 34 | * RJ45 Pin 6 (green) = T1OUT 35 | * RJ45 Pin 8 (brown) = GND 36 | ![image](https://user-images.githubusercontent.com/19826327/146428324-29e3f9bf-6cc3-415c-9d60-fa5ee3d65613.png) 37 | 38 | 39 | # How to get going: 40 | * Get Wemos D1 mini 41 | * Install arduino IDE and ESP8266 libraries as [described here](https://averagemaker.com/2018/03/wemos-d1-mini-setup.html) 42 | * Open [PylontechMonitoring.ino](PylontechMonitoring.ino) in arduino IDE 43 | * Make sure to copy content of [libraries subdirectory](libraries) to [libraries of your Arduino IDE](https://forum.arduino.cc/index.php?topic=88380.0). 44 | * Specify your WiFi login and password at the top of the file (line 13-14) 45 | * If you want MQTT support, uncomment line 17 and fill details in lines 21-24 46 | * Upload project to your device 47 | * Connect Wemos D1 mini to the MAX3232 transreceiver 48 | * Connect transreceiver to RJ10/RJ45 as descibed in the schematics (all three lines need to be connected) 49 | * Connect RJ10/RJ45 to the serial port of the Pylontech US2000 battery. If you have multiple batteries - connect to the master one. 50 | * Connect Wemos D1 to the power via USB 51 | * Find what IP address was assigned to your Wemos by your router and open it in the web-browser 52 | * You should be able now to connunicate with the battery via WiFi 53 | -------------------------------------------------------------------------------- /Schemetics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/irekzielinski/Pylontech-Battery-Monitoring/575846445d0b9cabd34def226d280d37057ee8a3/Schemetics.png -------------------------------------------------------------------------------- /libraries/Misc/circular_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef circ_buffer_h 2 | #define circ_buffer_h 3 | 4 | #include 5 | 6 | /// 7 | /// This class allows a fixed size circular buffer. 8 | /// When push_back is called, oldest data is overwritten. 9 | /// Does not use any dynamic allocators. 10 | /// 11 | template class circular_buffer 12 | { 13 | private: 14 | ItemType m_arr[elementCnt]; 15 | int m_writePos; 16 | int m_size; 17 | 18 | void advanceWritePos() 19 | { 20 | if(m_size < elementCnt) 21 | { 22 | m_size++; 23 | } 24 | 25 | m_writePos++; 26 | if(m_writePos >= elementCnt) 27 | { 28 | m_writePos = 0; 29 | } 30 | } 31 | 32 | circular_buffer(const circular_buffer& rhs); 33 | public: 34 | circular_buffer() 35 | { 36 | clear(); 37 | } 38 | 39 | void operator=(const circular_buffer& rhs) 40 | { 41 | memcpy(m_arr, rhs.m_arr, sizeof(m_arr)); 42 | m_size = rhs.m_size; 43 | m_writePos = rhs.m_writePos; 44 | } 45 | 46 | void push_back(const ItemType& item) 47 | { 48 | m_arr[m_writePos] = item; 49 | advanceWritePos(); 50 | } 51 | 52 | void clear() 53 | { 54 | memset(m_arr,0,sizeof(m_arr)); 55 | m_size = m_writePos = 0; 56 | } 57 | 58 | void sort() 59 | { 60 | if (size() < 2) 61 | return; 62 | 63 | bool swapped; 64 | do 65 | { 66 | swapped = false; 67 | for(int ix=0; ix at(ix+1)) 70 | { 71 | ItemType tmp = at(ix); 72 | at(ix) = at(ix+1); 73 | at(ix+1) = tmp; 74 | swapped = true; 75 | } 76 | } 77 | 78 | }while(swapped); 79 | } 80 | 81 | int size() const { return m_size; } 82 | bool isFull() const { return size() == elementCnt; } 83 | ItemType& operator[](int pos) {return at(pos);} 84 | 85 | ItemType& at(int pos) 86 | { 87 | if(m_size < elementCnt) 88 | { 89 | return m_arr[pos]; 90 | } 91 | 92 | int readPos = m_writePos + pos; 93 | if(readPos >= elementCnt) 94 | { 95 | readPos -= elementCnt; 96 | } 97 | 98 | return m_arr[readPos]; 99 | } 100 | 101 | #if _DEBUG_ENABLED 102 | void print() 103 | { 104 | printf("---\n"); 105 | for(int i=0; i //https://github.com/PaulStoffregen/Time 5 | #include 6 | 7 | template class circular_log 8 | { 9 | private: 10 | char m_log[elementCnt]; 11 | 12 | bool removeLastFromLog() 13 | { 14 | char* nextLine = strstr(m_log+1, "
"); 15 | if(nextLine == NULL) 16 | { 17 | return false; 18 | } 19 | 20 | int newLineLen = strlen(nextLine); 21 | memmove(m_log, nextLine, newLineLen); 22 | m_log[newLineLen] = '\0'; 23 | 24 | return true; 25 | } 26 | 27 | public: 28 | circular_log() 29 | { 30 | memset(m_log, 0, sizeof(m_log)); 31 | } 32 | 33 | const char* c_str() const { return m_log; } 34 | int freeSpace() const { return elementCnt - strlen(m_log) - 1; } 35 | 36 | void LogXml(const char* msg) 37 | { 38 | char szNew[256] = ""; 39 | snprintf(szNew, sizeof(szNew)-1, "
%02d - %02d:%02d | ", day(), hour(), minute()); 40 | 41 | int ix = strlen(szNew); 42 | while(*msg != '\0' && ix < 250) 43 | { 44 | if(*msg == '<') 45 | { 46 | szNew[ix++] = '&'; 47 | szNew[ix++] = 'l'; 48 | szNew[ix++] = 't'; 49 | szNew[ix++] = ';'; 50 | } 51 | else if(*msg == '>') 52 | { 53 | szNew[ix++] = '&'; 54 | szNew[ix++] = 'g'; 55 | szNew[ix++] = 't'; 56 | szNew[ix++] = ';'; 57 | } 58 | else 59 | { 60 | szNew[ix++] = *msg; 61 | } 62 | 63 | msg++; 64 | } 65 | 66 | const int newLen = strlen(szNew); 67 | while(freeSpace() < newLen) 68 | { 69 | if(removeLastFromLog() == false) 70 | { 71 | return; 72 | } 73 | } 74 | 75 | strcat(m_log, szNew); 76 | } 77 | 78 | void Log(const char* msg) 79 | { 80 | char szNew[256] = ""; 81 | snprintf(szNew, sizeof(szNew)-1, "
%02d - %02d:%02d | %s", day(), hour(), minute(), msg); 82 | 83 | const int newLen = strlen(szNew); 84 | while(freeSpace() < newLen) 85 | { 86 | if(removeLastFromLog() == false) 87 | { 88 | return; 89 | } 90 | } 91 | 92 | strcat(m_log, szNew); 93 | } 94 | }; 95 | 96 | #endif //circular_log_h -------------------------------------------------------------------------------- /libraries/NtpTime/ntp_time.h: -------------------------------------------------------------------------------- 1 | #ifndef ntp_time_h 2 | #define ntp_time_h 3 | 4 | #include 5 | 6 | // NTP Servers: 7 | static const char ntpServerName[] = "0.uk.pool.ntp.org"; 8 | const int timeZone = 0; 9 | unsigned int localPort = 8888; // local port to listen for UDP packets 10 | 11 | /*-------- NTP code ----------*/ 12 | 13 | const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message 14 | byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets 15 | WiFiUDP udpNtp; 16 | 17 | // send an NTP request to the time server at the given address 18 | void sendNTPpacket(IPAddress &address) 19 | { 20 | // set all bytes in the buffer to 0 21 | memset(packetBuffer, 0, NTP_PACKET_SIZE); 22 | // Initialize values needed to form NTP request 23 | // (see URL above for details on the packets) 24 | packetBuffer[0] = 0b11100011; // LI, Version, Mode 25 | packetBuffer[1] = 0; // Stratum, or type of clock 26 | packetBuffer[2] = 6; // Polling Interval 27 | packetBuffer[3] = 0xEC; // Peer Clock Precision 28 | // 8 bytes of zero for Root Delay & Root Dispersion 29 | packetBuffer[12] = 49; 30 | packetBuffer[13] = 0x4E; 31 | packetBuffer[14] = 49; 32 | packetBuffer[15] = 52; 33 | // all NTP fields have been given values, now 34 | // you can send a packet requesting a timestamp: 35 | udpNtp.beginPacket(address, 123); //NTP requests are to port 123 36 | udpNtp.write(packetBuffer, NTP_PACKET_SIZE); 37 | udpNtp.endPacket(); 38 | } 39 | 40 | 41 | time_t getNtpTime() 42 | { 43 | if(WiFi.status() != WL_CONNECTED) 44 | { 45 | return 0; 46 | } 47 | 48 | static bool udpStarted = false; 49 | if(udpStarted == false) 50 | { 51 | udpStarted = true; 52 | udpNtp.begin(localPort); 53 | } 54 | 55 | IPAddress ntpServerIP; // NTP server's ip address 56 | 57 | while (udpNtp.parsePacket() > 0) ; // discard any previously received packets 58 | // get a random server from the pool 59 | WiFi.hostByName(ntpServerName, ntpServerIP); 60 | sendNTPpacket(ntpServerIP); 61 | delay(100); 62 | 63 | uint32_t beginWait = millis(); 64 | while (millis() - beginWait < 1500) { 65 | int size = udpNtp.parsePacket(); 66 | if (size >= NTP_PACKET_SIZE) { 67 | udpNtp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer 68 | unsigned long secsSince1900; 69 | // convert four bytes starting at location 40 to a long integer 70 | secsSince1900 = (unsigned long)packetBuffer[40] << 24; 71 | secsSince1900 |= (unsigned long)packetBuffer[41] << 16; 72 | secsSince1900 |= (unsigned long)packetBuffer[42] << 8; 73 | secsSince1900 |= (unsigned long)packetBuffer[43]; 74 | return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; 75 | } 76 | 77 | delay(10); 78 | } 79 | return 0; // return 0 if unable to get the time 80 | } 81 | #endif //ntp_time_h -------------------------------------------------------------------------------- /libraries/SimpleTimer/README: -------------------------------------------------------------------------------- 1 | Visit this page for more information: 2 | http://playground.arduino.cc/Code/SimpleTimer -------------------------------------------------------------------------------- /libraries/SimpleTimer/SimpleTimer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SimpleTimer.cpp 3 | * 4 | * SimpleTimer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * This library is free software; you can redistribute it 9 | * and/or modify it under the terms of the GNU Lesser 10 | * General Public License as published by the Free Software 11 | * Foundation; either version 2.1 of the License, or (at 12 | * your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will 15 | * be useful, but WITHOUT ANY WARRANTY; without even the 16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 18 | * License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser 21 | * General Public License along with this library; if not, 22 | * write to the Free Software Foundation, Inc., 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | */ 25 | 26 | 27 | #include "SimpleTimer.h" 28 | 29 | 30 | // Select time function: 31 | //static inline unsigned long elapsed() { return micros(); } 32 | static inline unsigned long elapsed() { return millis(); } 33 | 34 | 35 | SimpleTimer::SimpleTimer() 36 | : numTimers (-1) 37 | { 38 | } 39 | 40 | void SimpleTimer::init() { 41 | unsigned long current_millis = elapsed(); 42 | 43 | for (int i = 0; i < MAX_TIMERS; i++) { 44 | enabled[i] = false; 45 | callbacks[i] = 0; // if the callback pointer is zero, the slot is free, i.e. doesn't "contain" any timer 46 | prev_millis[i] = current_millis; 47 | numRuns[i] = 0; 48 | } 49 | 50 | numTimers = 0; 51 | } 52 | 53 | 54 | void SimpleTimer::run() { 55 | int i; 56 | unsigned long current_millis; 57 | 58 | // get current time 59 | current_millis = elapsed(); 60 | 61 | for (i = 0; i < MAX_TIMERS; i++) { 62 | 63 | toBeCalled[i] = DEFCALL_DONTRUN; 64 | 65 | // no callback == no timer, i.e. jump over empty slots 66 | if (callbacks[i]) { 67 | 68 | // is it time to process this timer ? 69 | // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 70 | 71 | if (current_millis - prev_millis[i] >= delays[i]) { 72 | 73 | // update time 74 | //prev_millis[i] = current_millis; 75 | prev_millis[i] += delays[i]; 76 | 77 | // check if the timer callback has to be executed 78 | if (enabled[i]) { 79 | 80 | // "run forever" timers must always be executed 81 | if (maxNumRuns[i] == RUN_FOREVER) { 82 | toBeCalled[i] = DEFCALL_RUNONLY; 83 | } 84 | // other timers get executed the specified number of times 85 | else if (numRuns[i] < maxNumRuns[i]) { 86 | toBeCalled[i] = DEFCALL_RUNONLY; 87 | numRuns[i]++; 88 | 89 | // after the last run, delete the timer 90 | if (numRuns[i] >= maxNumRuns[i]) { 91 | toBeCalled[i] = DEFCALL_RUNANDDEL; 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | for (i = 0; i < MAX_TIMERS; i++) { 100 | switch(toBeCalled[i]) { 101 | case DEFCALL_DONTRUN: 102 | break; 103 | 104 | case DEFCALL_RUNONLY: 105 | (*callbacks[i])(); 106 | break; 107 | 108 | case DEFCALL_RUNANDDEL: 109 | (*callbacks[i])(); 110 | deleteTimer(i); 111 | break; 112 | } 113 | } 114 | } 115 | 116 | 117 | // find the first available slot 118 | // return -1 if none found 119 | int SimpleTimer::findFirstFreeSlot() { 120 | int i; 121 | 122 | // all slots are used 123 | if (numTimers >= MAX_TIMERS) { 124 | return -1; 125 | } 126 | 127 | // return the first slot with no callback (i.e. free) 128 | for (i = 0; i < MAX_TIMERS; i++) { 129 | if (callbacks[i] == 0) { 130 | return i; 131 | } 132 | } 133 | 134 | // no free slots found 135 | return -1; 136 | } 137 | 138 | 139 | int SimpleTimer::setTimer(long d, timer_callback f, int n) { 140 | int freeTimer; 141 | 142 | if (numTimers < 0) { 143 | init(); 144 | } 145 | 146 | freeTimer = findFirstFreeSlot(); 147 | if (freeTimer < 0) { 148 | return -1; 149 | } 150 | 151 | if (f == NULL) { 152 | return -1; 153 | } 154 | 155 | delays[freeTimer] = d; 156 | callbacks[freeTimer] = f; 157 | maxNumRuns[freeTimer] = n; 158 | enabled[freeTimer] = true; 159 | prev_millis[freeTimer] = elapsed(); 160 | 161 | numTimers++; 162 | 163 | return freeTimer; 164 | } 165 | 166 | 167 | int SimpleTimer::setInterval(long d, timer_callback f) { 168 | return setTimer(d, f, RUN_FOREVER); 169 | } 170 | 171 | 172 | int SimpleTimer::setTimeout(long d, timer_callback f) { 173 | return setTimer(d, f, RUN_ONCE); 174 | } 175 | 176 | 177 | void SimpleTimer::deleteTimer(int timerId) { 178 | if (timerId >= MAX_TIMERS) { 179 | return; 180 | } 181 | 182 | // nothing to delete if no timers are in use 183 | if (numTimers == 0) { 184 | return; 185 | } 186 | 187 | // don't decrease the number of timers if the 188 | // specified slot is already empty 189 | if (callbacks[timerId] != NULL) { 190 | callbacks[timerId] = 0; 191 | enabled[timerId] = false; 192 | toBeCalled[timerId] = DEFCALL_DONTRUN; 193 | delays[timerId] = 0; 194 | numRuns[timerId] = 0; 195 | 196 | // update number of timers 197 | numTimers--; 198 | } 199 | } 200 | 201 | 202 | // function contributed by code@rowansimms.com 203 | void SimpleTimer::restartTimer(int numTimer) { 204 | if (numTimer >= MAX_TIMERS) { 205 | return; 206 | } 207 | 208 | prev_millis[numTimer] = elapsed(); 209 | } 210 | 211 | 212 | boolean SimpleTimer::isEnabled(int numTimer) { 213 | if (numTimer >= MAX_TIMERS) { 214 | return false; 215 | } 216 | 217 | return enabled[numTimer]; 218 | } 219 | 220 | 221 | void SimpleTimer::enable(int numTimer) { 222 | if (numTimer >= MAX_TIMERS) { 223 | return; 224 | } 225 | 226 | enabled[numTimer] = true; 227 | } 228 | 229 | 230 | void SimpleTimer::disable(int numTimer) { 231 | if (numTimer >= MAX_TIMERS) { 232 | return; 233 | } 234 | 235 | enabled[numTimer] = false; 236 | } 237 | 238 | 239 | void SimpleTimer::toggle(int numTimer) { 240 | if (numTimer >= MAX_TIMERS) { 241 | return; 242 | } 243 | 244 | enabled[numTimer] = !enabled[numTimer]; 245 | } 246 | 247 | 248 | int SimpleTimer::getNumTimers() { 249 | return numTimers; 250 | } 251 | -------------------------------------------------------------------------------- /libraries/SimpleTimer/SimpleTimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SimpleTimer.h 3 | * 4 | * SimpleTimer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * This library is free software; you can redistribute it 9 | * and/or modify it under the terms of the GNU Lesser 10 | * General Public License as published by the Free Software 11 | * Foundation; either version 2.1 of the License, or (at 12 | * your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will 15 | * be useful, but WITHOUT ANY WARRANTY; without even the 16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 18 | * License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser 21 | * General Public License along with this library; if not, 22 | * write to the Free Software Foundation, Inc., 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | 28 | #ifndef SIMPLETIMER_H 29 | #define SIMPLETIMER_H 30 | 31 | #if defined(ARDUINO) && ARDUINO >= 100 32 | #include 33 | #else 34 | #include 35 | #endif 36 | 37 | typedef void (*timer_callback)(void); 38 | 39 | class SimpleTimer { 40 | 41 | public: 42 | // maximum number of timers 43 | const static int MAX_TIMERS = 10; 44 | 45 | // setTimer() constants 46 | const static int RUN_FOREVER = 0; 47 | const static int RUN_ONCE = 1; 48 | 49 | // constructor 50 | SimpleTimer(); 51 | 52 | void init(); 53 | 54 | // this function must be called inside loop() 55 | void run(); 56 | 57 | // call function f every d milliseconds 58 | int setInterval(long d, timer_callback f); 59 | 60 | // call function f once after d milliseconds 61 | int setTimeout(long d, timer_callback f); 62 | 63 | // call function f every d milliseconds for n times 64 | int setTimer(long d, timer_callback f, int n); 65 | 66 | // destroy the specified timer 67 | void deleteTimer(int numTimer); 68 | 69 | // restart the specified timer 70 | void restartTimer(int numTimer); 71 | 72 | // returns true if the specified timer is enabled 73 | boolean isEnabled(int numTimer); 74 | 75 | // enables the specified timer 76 | void enable(int numTimer); 77 | 78 | // disables the specified timer 79 | void disable(int numTimer); 80 | 81 | // enables the specified timer if it's currently disabled, 82 | // and vice-versa 83 | void toggle(int numTimer); 84 | 85 | // returns the number of used timers 86 | int getNumTimers(); 87 | 88 | // returns the number of available timers 89 | int getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; 90 | 91 | private: 92 | // deferred call constants 93 | const static int DEFCALL_DONTRUN = 0; // don't call the callback function 94 | const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer 95 | const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer 96 | 97 | // find the first available slot 98 | int findFirstFreeSlot(); 99 | 100 | // value returned by the millis() function 101 | // in the previous run() call 102 | unsigned long prev_millis[MAX_TIMERS]; 103 | 104 | // pointers to the callback functions 105 | timer_callback callbacks[MAX_TIMERS]; 106 | 107 | // delay values 108 | long delays[MAX_TIMERS]; 109 | 110 | // number of runs to be executed for each timer 111 | int maxNumRuns[MAX_TIMERS]; 112 | 113 | // number of executed runs for each timer 114 | int numRuns[MAX_TIMERS]; 115 | 116 | // which timers are enabled 117 | boolean enabled[MAX_TIMERS]; 118 | 119 | // deferred function call (sort of) - N.B.: this array is only used in run() 120 | int toBeCalled[MAX_TIMERS]; 121 | 122 | // actual number of timers in use 123 | int numTimers; 124 | }; 125 | 126 | #endif -------------------------------------------------------------------------------- /libraries/Time-master/DateStrings.cpp: -------------------------------------------------------------------------------- 1 | /* DateStrings.cpp 2 | * Definitions for date strings for use with the Time library 3 | * 4 | * Updated for Arduino 1.5.7 18 July 2014 5 | * 6 | * No memory is consumed in the sketch if your code does not call any of the string methods 7 | * You can change the text of the strings, make sure the short strings are each exactly 3 characters 8 | * the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in TimeLib.h 9 | * 10 | */ 11 | 12 | #if defined(__AVR__) 13 | #include 14 | #else 15 | // for compatiblity with Arduino Due and Teensy 3.0 and maybe others? 16 | #define PROGMEM 17 | #define PGM_P const char * 18 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 19 | #define pgm_read_word(addr) (*(const unsigned char **)(addr)) 20 | #define strcpy_P(dest, src) strcpy((dest), (src)) 21 | #endif 22 | #include // for strcpy_P or strcpy 23 | #include "TimeLib.h" 24 | 25 | // the short strings for each day or month must be exactly dt_SHORT_STR_LEN 26 | #define dt_SHORT_STR_LEN 3 // the length of short strings 27 | 28 | static char buffer[dt_MAX_STRING_LEN+1]; // must be big enough for longest string and the terminating null 29 | 30 | const char monthStr0[] PROGMEM = ""; 31 | const char monthStr1[] PROGMEM = "January"; 32 | const char monthStr2[] PROGMEM = "February"; 33 | const char monthStr3[] PROGMEM = "March"; 34 | const char monthStr4[] PROGMEM = "April"; 35 | const char monthStr5[] PROGMEM = "May"; 36 | const char monthStr6[] PROGMEM = "June"; 37 | const char monthStr7[] PROGMEM = "July"; 38 | const char monthStr8[] PROGMEM = "August"; 39 | const char monthStr9[] PROGMEM = "September"; 40 | const char monthStr10[] PROGMEM = "October"; 41 | const char monthStr11[] PROGMEM = "November"; 42 | const char monthStr12[] PROGMEM = "December"; 43 | 44 | const PROGMEM char * const PROGMEM monthNames_P[] = 45 | { 46 | monthStr0,monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6, 47 | monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12 48 | }; 49 | 50 | const char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec"; 51 | 52 | const char dayStr0[] PROGMEM = "Err"; 53 | const char dayStr1[] PROGMEM = "Sunday"; 54 | const char dayStr2[] PROGMEM = "Monday"; 55 | const char dayStr3[] PROGMEM = "Tuesday"; 56 | const char dayStr4[] PROGMEM = "Wednesday"; 57 | const char dayStr5[] PROGMEM = "Thursday"; 58 | const char dayStr6[] PROGMEM = "Friday"; 59 | const char dayStr7[] PROGMEM = "Saturday"; 60 | 61 | const PROGMEM char * const PROGMEM dayNames_P[] = 62 | { 63 | dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7 64 | }; 65 | 66 | const char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThuFriSat"; 67 | 68 | /* functions to return date strings */ 69 | 70 | char* monthStr(uint8_t month) 71 | { 72 | strcpy_P(buffer, (PGM_P)pgm_read_word(&(monthNames_P[month]))); 73 | return buffer; 74 | } 75 | 76 | char* monthShortStr(uint8_t month) 77 | { 78 | for (int i=0; i < dt_SHORT_STR_LEN; i++) 79 | buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)])); 80 | buffer[dt_SHORT_STR_LEN] = 0; 81 | return buffer; 82 | } 83 | 84 | char* dayStr(uint8_t day) 85 | { 86 | strcpy_P(buffer, (PGM_P)pgm_read_word(&(dayNames_P[day]))); 87 | return buffer; 88 | } 89 | 90 | char* dayShortStr(uint8_t day) 91 | { 92 | uint8_t index = day*dt_SHORT_STR_LEN; 93 | for (int i=0; i < dt_SHORT_STR_LEN; i++) 94 | buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i])); 95 | buffer[dt_SHORT_STR_LEN] = 0; 96 | return buffer; 97 | } 98 | -------------------------------------------------------------------------------- /libraries/Time-master/Readme.txt: -------------------------------------------------------------------------------- 1 | Readme file for Arduino Time Library 2 | 3 | Time is a library that provides timekeeping functionality for Arduino. 4 | 5 | The code is derived from the Playground DateTime library but is updated 6 | to provide an API that is more flexable and easier to use. 7 | 8 | A primary goal was to enable date and time functionality that can be used with 9 | a variety of external time sources with minimum differences required in sketch logic. 10 | 11 | Example sketches illustrate how similar sketch code can be used with: a Real Time Clock, 12 | internet NTP time service, GPS time data, and Serial time messages from a computer 13 | for time synchronization. 14 | 15 | The functions available in the library include: 16 | 17 | hour(); // the hour now (0-23) 18 | minute(); // the minute now (0-59) 19 | second(); // the second now (0-59) 20 | day(); // the day now (1-31) 21 | weekday(); // day of the week, Sunday is day 0 22 | month(); // the month now (1-12) 23 | year(); // the full four digit year: (2009, 2010 etc) 24 | 25 | there are also functions to return the hour in 12 hour format 26 | hourFormat12(); // the hour now in 12 hour format 27 | isAM(); // returns true if time now is AM 28 | isPM(); // returns true if time now is PM 29 | 30 | now(); // returns the current time as seconds since Jan 1 1970 31 | 32 | The time and date functions can take an optional parameter for the time. This prevents 33 | errors if the time rolls over between elements. For example, if a new minute begins 34 | between getting the minute and second, the values will be inconsistent. Using the 35 | following functions eliminates this probglem 36 | time_t t = now(); // store the current time in time variable t 37 | hour(t); // returns the hour for the given time t 38 | minute(t); // returns the minute for the given time t 39 | second(t); // returns the second for the given time t 40 | day(t); // the day for the given time t 41 | weekday(t); // day of the week for the given time t 42 | month(t); // the month for the given time t 43 | year(t); // the year for the given time t 44 | 45 | 46 | Functions for managing the timer services are: 47 | setTime(t); // set the system time to the give time t 48 | setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr (2010 or 10 sets year to 2010) 49 | adjustTime(adjustment); // adjust system time by adding the adjustment value 50 | 51 | timeStatus(); // indicates if time has been set and recently synchronized 52 | // returns one of the following enumerations: 53 | timeNotSet // the time has never been set, the clock started at Jan 1 1970 54 | timeNeedsSync // the time had been set but a sync attempt did not succeed 55 | timeSet // the time is set and is synced 56 | Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but 57 | the returned time may have drifted if the status is timeNeedsSync. 58 | 59 | setSyncProvider(getTimeFunction); // set the external time provider 60 | setSyncInterval(interval); // set the number of seconds between re-sync 61 | 62 | 63 | There are many convenience macros in the time.h file for time constants and conversion of time units. 64 | 65 | To use the library, copy the download to the Library directory. 66 | 67 | The Time directory contains the Time library and some example sketches 68 | illustrating how the library can be used with various time sources: 69 | 70 | - TimeSerial.pde shows Arduino as a clock without external hardware. 71 | It is synchronized by time messages sent over the serial port. 72 | A companion Processing sketch will automatically provide these messages 73 | if it is running and connected to the Arduino serial port. 74 | 75 | - TimeSerialDateStrings.pde adds day and month name strings to the sketch above 76 | Short (3 character) and long strings are available to print the days of 77 | the week and names of the months. 78 | 79 | - TimeRTC uses a DS1307 real time clock to provide time synchronization. 80 | A basic RTC library named DS1307RTC is included in the download. 81 | To run this sketch the DS1307RTC library must be installed. 82 | 83 | - TimeRTCSet is similar to the above and adds the ability to set the Real Time Clock 84 | 85 | - TimeRTCLog demonstrates how to calculate the difference between times. 86 | It is a vary simple logger application that monitors events on digtial pins 87 | and prints (to the serial port) the time of an event and the time period since the previous event. 88 | 89 | - TimeNTP uses the Arduino Ethernet shield to access time using the internet NTP time service. 90 | The NTP protocol uses UDP and the UdpBytewise library is required, see: 91 | http://bitbucket.org/bjoern/arduino_osc/src/14667490521f/libraries/Ethernet/ 92 | 93 | - TimeGPS gets time from a GPS 94 | This requires the TinyGPS library from Mikal Hart: 95 | http://arduiniana.org/libraries/TinyGPS 96 | 97 | Differences between this code and the playground DateTime library 98 | although the Time library is based on the DateTime codebase, the API has changed. 99 | Changes in the Time library API: 100 | - time elements are functions returning int (they are variables in DateTime) 101 | - Years start from 1970 102 | - days of the week and months start from 1 (they start from 0 in DateTime) 103 | - DateStrings do not require a seperate library 104 | - time elements can be accessed non-atomically (in DateTime they are always atomic) 105 | - function added to automatically sync time with extrnal source 106 | - localTime and maketime parameters changed, localTime renamed to breakTime 107 | 108 | Technical notes: 109 | 110 | Internal system time is based on the standard Unix time_t. 111 | The value is the number of seconds since Jan 1 1970. 112 | System time begins at zero when the sketch starts. 113 | 114 | The internal time can be automatically synchronized at regular intervals to an external time source. 115 | This is enabled by calling the setSyncProvider(provider) function - the provider argument is 116 | the address of a function that returns the current time as a time_t. 117 | See the sketches in the examples directory for usage. 118 | 119 | The default interval for re-syncing the time is 5 minutes but can be changed by calling the 120 | setSyncInterval( interval) method to set the number of seconds between re-sync attempts. 121 | 122 | The Time library defines a structure for holding time elements that is a compact version of the C tm structure. 123 | All the members of the Arduino tm structure are bytes and the year is offset from 1970. 124 | Convenience macros provide conversion to and from the Arduino format. 125 | 126 | Low level functions to convert between system time and individual time elements are provided: 127 | breakTime( time, &tm); // break time_t into elements stored in tm struct 128 | makeTime( &tm); // return time_t from elements stored in tm struct 129 | 130 | The DS1307RTC library included in the download provides an example of how a time provider 131 | can use the low level functions to interface with the Time library. 132 | -------------------------------------------------------------------------------- /libraries/Time-master/Time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | time.c - low level time and date functions 3 | Copyright (c) Michael Margolis 2009-2014 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | 1.0 6 Jan 2010 - initial release 20 | 1.1 12 Feb 2010 - fixed leap year calculation error 21 | 1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) 22 | 1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update 23 | status, updated examples for Arduino 1.0, fixed ARM 24 | compatibility issues, added TimeArduinoDue and TimeTeensy3 25 | examples, add error checking and messages to RTC examples, 26 | add examples to DS1307RTC library. 27 | 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 28 | */ 29 | 30 | #if ARDUINO >= 100 31 | #include 32 | #else 33 | #include 34 | #endif 35 | 36 | #include "TimeLib.h" 37 | 38 | static tmElements_t tm; // a cache of time elements 39 | static time_t cacheTime; // the time the cache was updated 40 | static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds 41 | 42 | void refreshCache(time_t t) { 43 | if (t != cacheTime) { 44 | breakTime(t, tm); 45 | cacheTime = t; 46 | } 47 | } 48 | 49 | int hour() { // the hour now 50 | return hour(now()); 51 | } 52 | 53 | int hour(time_t t) { // the hour for the given time 54 | refreshCache(t); 55 | return tm.Hour; 56 | } 57 | 58 | int hourFormat12() { // the hour now in 12 hour format 59 | return hourFormat12(now()); 60 | } 61 | 62 | int hourFormat12(time_t t) { // the hour for the given time in 12 hour format 63 | refreshCache(t); 64 | if( tm.Hour == 0 ) 65 | return 12; // 12 midnight 66 | else if( tm.Hour > 12) 67 | return tm.Hour - 12 ; 68 | else 69 | return tm.Hour ; 70 | } 71 | 72 | uint8_t isAM() { // returns true if time now is AM 73 | return !isPM(now()); 74 | } 75 | 76 | uint8_t isAM(time_t t) { // returns true if given time is AM 77 | return !isPM(t); 78 | } 79 | 80 | uint8_t isPM() { // returns true if PM 81 | return isPM(now()); 82 | } 83 | 84 | uint8_t isPM(time_t t) { // returns true if PM 85 | return (hour(t) >= 12); 86 | } 87 | 88 | int minute() { 89 | return minute(now()); 90 | } 91 | 92 | int minute(time_t t) { // the minute for the given time 93 | refreshCache(t); 94 | return tm.Minute; 95 | } 96 | 97 | int second() { 98 | return second(now()); 99 | } 100 | 101 | int second(time_t t) { // the second for the given time 102 | refreshCache(t); 103 | return tm.Second; 104 | } 105 | 106 | int day(){ 107 | return(day(now())); 108 | } 109 | 110 | int day(time_t t) { // the day for the given time (0-6) 111 | refreshCache(t); 112 | return tm.Day; 113 | } 114 | 115 | int weekday() { // Sunday is day 1 116 | return weekday(now()); 117 | } 118 | 119 | int weekday(time_t t) { 120 | refreshCache(t); 121 | return tm.Wday; 122 | } 123 | 124 | int month(){ 125 | return month(now()); 126 | } 127 | 128 | int month(time_t t) { // the month for the given time 129 | refreshCache(t); 130 | return tm.Month; 131 | } 132 | 133 | int year() { // as in Processing, the full four digit year: (2009, 2010 etc) 134 | return year(now()); 135 | } 136 | 137 | int year(time_t t) { // the year for the given time 138 | refreshCache(t); 139 | return tmYearToCalendar(tm.Year); 140 | } 141 | 142 | /*============================================================================*/ 143 | /* functions to convert to and from system time */ 144 | /* These are for interfacing with time serivces and are not normally needed in a sketch */ 145 | 146 | // leap year calulator expects year argument as years offset from 1970 147 | #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) 148 | 149 | static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 150 | 151 | void breakTime(time_t timeInput, tmElements_t &tm){ 152 | // break the given time_t into time components 153 | // this is a more compact version of the C library localtime function 154 | // note that year is offset from 1970 !!! 155 | 156 | uint8_t year; 157 | uint8_t month, monthLength; 158 | uint32_t time; 159 | unsigned long days; 160 | 161 | time = (uint32_t)timeInput; 162 | tm.Second = time % 60; 163 | time /= 60; // now it is minutes 164 | tm.Minute = time % 60; 165 | time /= 60; // now it is hours 166 | tm.Hour = time % 24; 167 | time /= 24; // now it is days 168 | tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 169 | 170 | year = 0; 171 | days = 0; 172 | while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { 173 | year++; 174 | } 175 | tm.Year = year; // year is offset from 1970 176 | 177 | days -= LEAP_YEAR(year) ? 366 : 365; 178 | time -= days; // now it is days in this year, starting at 0 179 | 180 | days=0; 181 | month=0; 182 | monthLength=0; 183 | for (month=0; month<12; month++) { 184 | if (month==1) { // february 185 | if (LEAP_YEAR(year)) { 186 | monthLength=29; 187 | } else { 188 | monthLength=28; 189 | } 190 | } else { 191 | monthLength = monthDays[month]; 192 | } 193 | 194 | if (time >= monthLength) { 195 | time -= monthLength; 196 | } else { 197 | break; 198 | } 199 | } 200 | tm.Month = month + 1; // jan is month 1 201 | tm.Day = time + 1; // day of month 202 | } 203 | 204 | time_t makeTime(tmElements_t &tm){ 205 | // assemble time elements into time_t 206 | // note year argument is offset from 1970 (see macros in time.h to convert to other formats) 207 | // previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 208 | 209 | int i; 210 | uint32_t seconds; 211 | 212 | // seconds from 1970 till 1 jan 00:00:00 of the given year 213 | seconds= tm.Year*(SECS_PER_DAY * 365); 214 | for (i = 0; i < tm.Year; i++) { 215 | if (LEAP_YEAR(i)) { 216 | seconds += SECS_PER_DAY; // add extra days for leap years 217 | } 218 | } 219 | 220 | // add days for this year, months start from 1 221 | for (i = 1; i < tm.Month; i++) { 222 | if ( (i == 2) && LEAP_YEAR(tm.Year)) { 223 | seconds += SECS_PER_DAY * 29; 224 | } else { 225 | seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 226 | } 227 | } 228 | seconds+= (tm.Day-1) * SECS_PER_DAY; 229 | seconds+= tm.Hour * SECS_PER_HOUR; 230 | seconds+= tm.Minute * SECS_PER_MIN; 231 | seconds+= tm.Second; 232 | return (time_t)seconds; 233 | } 234 | /*=====================================================*/ 235 | /* Low level system time functions */ 236 | 237 | static uint32_t sysTime = 0; 238 | static uint32_t prevMillis = 0; 239 | static uint32_t nextSyncTime = 0; 240 | static timeStatus_t Status = timeNotSet; 241 | 242 | getExternalTime getTimePtr; // pointer to external sync function 243 | //setExternalTime setTimePtr; // not used in this version 244 | 245 | #ifdef TIME_DRIFT_INFO // define this to get drift data 246 | time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync 247 | #endif 248 | 249 | 250 | time_t now() { 251 | // calculate number of seconds passed since last call to now() 252 | while (millis() - prevMillis >= 1000) { 253 | // millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference 254 | sysTime++; 255 | prevMillis += 1000; 256 | #ifdef TIME_DRIFT_INFO 257 | sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift 258 | #endif 259 | } 260 | if (nextSyncTime <= sysTime) { 261 | if (getTimePtr != 0) { 262 | time_t t = getTimePtr(); 263 | if (t != 0) { 264 | setTime(t); 265 | } else { 266 | nextSyncTime = sysTime + syncInterval; 267 | Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; 268 | } 269 | } 270 | } 271 | return (time_t)sysTime; 272 | } 273 | 274 | void setTime(time_t t) { 275 | #ifdef TIME_DRIFT_INFO 276 | if(sysUnsyncedTime == 0) 277 | sysUnsyncedTime = t; // store the time of the first call to set a valid Time 278 | #endif 279 | 280 | sysTime = (uint32_t)t; 281 | nextSyncTime = (uint32_t)t + syncInterval; 282 | Status = timeSet; 283 | prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) 284 | } 285 | 286 | void setTime(int hr,int min,int sec,int dy, int mnth, int yr){ 287 | // year can be given as full four digit year or two digts (2010 or 10 for 2010); 288 | //it is converted to years since 1970 289 | if( yr > 99) 290 | yr = yr - 1970; 291 | else 292 | yr += 30; 293 | tm.Year = yr; 294 | tm.Month = mnth; 295 | tm.Day = dy; 296 | tm.Hour = hr; 297 | tm.Minute = min; 298 | tm.Second = sec; 299 | setTime(makeTime(tm)); 300 | } 301 | 302 | void adjustTime(long adjustment) { 303 | sysTime += adjustment; 304 | } 305 | 306 | // indicates if time has been set and recently synchronized 307 | timeStatus_t timeStatus() { 308 | now(); // required to actually update the status 309 | return Status; 310 | } 311 | 312 | void setSyncProvider( getExternalTime getTimeFunction){ 313 | getTimePtr = getTimeFunction; 314 | nextSyncTime = sysTime; 315 | now(); // this will sync the clock 316 | } 317 | 318 | void setSyncInterval(time_t interval){ // set the number of seconds between re-sync 319 | syncInterval = (uint32_t)interval; 320 | nextSyncTime = sysTime + syncInterval; 321 | } 322 | -------------------------------------------------------------------------------- /libraries/Time-master/Time.h: -------------------------------------------------------------------------------- 1 | #include "TimeLib.h" 2 | -------------------------------------------------------------------------------- /libraries/Time-master/TimeLib.h: -------------------------------------------------------------------------------- 1 | /* 2 | time.h - low level time and date functions 3 | */ 4 | 5 | /* 6 | July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) 7 | - fixed daysToTime_t macro (thanks maniacbug) 8 | */ 9 | 10 | #ifndef _Time_h 11 | #ifdef __cplusplus 12 | #define _Time_h 13 | 14 | #include 15 | #ifndef __AVR__ 16 | #include // for __time_t_defined, but avr libc lacks sys/types.h 17 | #endif 18 | 19 | 20 | #if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc 21 | typedef unsigned long time_t; 22 | #endif 23 | 24 | 25 | // This ugly hack allows us to define C++ overloaded functions, when included 26 | // from within an extern "C", as newlib's sys/stat.h does. Actually it is 27 | // intended to include "time.h" from the C library (on ARM, but AVR does not 28 | // have that file at all). On Mac and Windows, the compiler will find this 29 | // "Time.h" instead of the C library "time.h", so we may cause other weird 30 | // and unpredictable effects by conflicting with the C library header "time.h", 31 | // but at least this hack lets us define C++ functions as intended. Hopefully 32 | // nothing too terrible will result from overriding the C library header?! 33 | extern "C++" { 34 | typedef enum {timeNotSet, timeNeedsSync, timeSet 35 | } timeStatus_t ; 36 | 37 | typedef enum { 38 | dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday 39 | } timeDayOfWeek_t; 40 | 41 | typedef enum { 42 | tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields 43 | } tmByteFields; 44 | 45 | typedef struct { 46 | uint8_t Second; 47 | uint8_t Minute; 48 | uint8_t Hour; 49 | uint8_t Wday; // day of week, sunday is day 1 50 | uint8_t Day; 51 | uint8_t Month; 52 | uint8_t Year; // offset from 1970; 53 | } tmElements_t, TimeElements, *tmElementsPtr_t; 54 | 55 | //convenience macros to convert to and from tm years 56 | #define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year 57 | #define CalendarYrToTm(Y) ((Y) - 1970) 58 | #define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 59 | #define y2kYearToTm(Y) ((Y) + 30) 60 | 61 | typedef time_t(*getExternalTime)(); 62 | //typedef void (*setExternalTime)(const time_t); // not used in this version 63 | 64 | 65 | /*==============================================================================*/ 66 | /* Useful Constants */ 67 | #define SECS_PER_MIN ((time_t)(60UL)) 68 | #define SECS_PER_HOUR ((time_t)(3600UL)) 69 | #define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL)) 70 | #define DAYS_PER_WEEK ((time_t)(7UL)) 71 | #define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK)) 72 | #define SECS_PER_YEAR ((time_t)(SECS_PER_WEEK * 52UL)) 73 | #define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k 74 | 75 | /* Useful Macros for getting elapsed time */ 76 | #define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) 77 | #define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) 78 | #define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) 79 | #define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday 80 | #define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970 81 | #define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight 82 | // The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 83 | // Always set the correct time before settting alarms 84 | #define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day 85 | #define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day 86 | #define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // note that week starts on day 1 87 | #define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time 88 | #define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time 89 | 90 | 91 | /* Useful Macros for converting elapsed time to a time_t */ 92 | #define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) 93 | #define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) 94 | #define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 95 | #define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) 96 | 97 | /*============================================================================*/ 98 | /* time and date functions */ 99 | int hour(); // the hour now 100 | int hour(time_t t); // the hour for the given time 101 | int hourFormat12(); // the hour now in 12 hour format 102 | int hourFormat12(time_t t); // the hour for the given time in 12 hour format 103 | uint8_t isAM(); // returns true if time now is AM 104 | uint8_t isAM(time_t t); // returns true the given time is AM 105 | uint8_t isPM(); // returns true if time now is PM 106 | uint8_t isPM(time_t t); // returns true the given time is PM 107 | int minute(); // the minute now 108 | int minute(time_t t); // the minute for the given time 109 | int second(); // the second now 110 | int second(time_t t); // the second for the given time 111 | int day(); // the day now 112 | int day(time_t t); // the day for the given time 113 | int weekday(); // the weekday now (Sunday is day 1) 114 | int weekday(time_t t); // the weekday for the given time 115 | int month(); // the month now (Jan is month 1) 116 | int month(time_t t); // the month for the given time 117 | int year(); // the full four digit year: (2009, 2010 etc) 118 | int year(time_t t); // the year for the given time 119 | 120 | time_t now(); // return the current time as seconds since Jan 1 1970 121 | void setTime(time_t t); 122 | void setTime(int hr,int min,int sec,int day, int month, int yr); 123 | void adjustTime(long adjustment); 124 | 125 | /* date strings */ 126 | #define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) 127 | char* monthStr(uint8_t month); 128 | char* dayStr(uint8_t day); 129 | char* monthShortStr(uint8_t month); 130 | char* dayShortStr(uint8_t day); 131 | 132 | /* time sync functions */ 133 | timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized 134 | void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider 135 | void setSyncInterval(time_t interval); // set the number of seconds between re-sync 136 | 137 | /* low level functions to convert to and from system time */ 138 | void breakTime(time_t time, tmElements_t &tm); // break time_t into elements 139 | time_t makeTime(tmElements_t &tm); // convert time elements into time_t 140 | 141 | } // extern "C++" 142 | #endif // __cplusplus 143 | #endif /* _Time_h */ 144 | 145 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/Processing/SyncArduinoClock/SyncArduinoClock.pde: -------------------------------------------------------------------------------- 1 | /** 2 | * SyncArduinoClock. 3 | * 4 | * portIndex must be set to the port connected to the Arduino 5 | * 6 | * The current time is sent in response to request message from Arduino 7 | * or by clicking the display window 8 | * 9 | * The time message is 11 ASCII text characters; a header (the letter 'T') 10 | * followed by the ten digit system time (unix time) 11 | */ 12 | 13 | 14 | import processing.serial.*; 15 | import java.util.Date; 16 | import java.util.Calendar; 17 | import java.util.GregorianCalendar; 18 | 19 | public static final short portIndex = 0; // select the com port, 0 is the first port 20 | public static final String TIME_HEADER = "T"; //header for arduino serial time message 21 | public static final char TIME_REQUEST = 7; // ASCII bell character 22 | public static final char LF = 10; // ASCII linefeed 23 | public static final char CR = 13; // ASCII linefeed 24 | Serial myPort; // Create object from Serial class 25 | 26 | void setup() { 27 | size(200, 200); 28 | println(Serial.list()); 29 | println(" Connecting to -> " + Serial.list()[portIndex]); 30 | myPort = new Serial(this,Serial.list()[portIndex], 9600); 31 | println(getTimeNow()); 32 | } 33 | 34 | void draw() 35 | { 36 | textSize(20); 37 | textAlign(CENTER); 38 | fill(0); 39 | text("Click to send\nTime Sync", 0, 75, 200, 175); 40 | if ( myPort.available() > 0) { // If data is available, 41 | char val = char(myPort.read()); // read it and store it in val 42 | if(val == TIME_REQUEST){ 43 | long t = getTimeNow(); 44 | sendTimeMessage(TIME_HEADER, t); 45 | } 46 | else 47 | { 48 | if(val == LF) 49 | ; //igonore 50 | else if(val == CR) 51 | println(); 52 | else 53 | print(val); // echo everying but time request 54 | } 55 | } 56 | } 57 | 58 | void mousePressed() { 59 | sendTimeMessage( TIME_HEADER, getTimeNow()); 60 | } 61 | 62 | 63 | void sendTimeMessage(String header, long time) { 64 | String timeStr = String.valueOf(time); 65 | myPort.write(header); // send header and time to arduino 66 | myPort.write(timeStr); 67 | myPort.write('\n'); 68 | } 69 | 70 | long getTimeNow(){ 71 | // java time is in ms, we want secs 72 | Date d = new Date(); 73 | Calendar cal = new GregorianCalendar(); 74 | long current = d.getTime()/1000; 75 | long timezone = cal.get(cal.ZONE_OFFSET)/1000; 76 | long daylight = cal.get(cal.DST_OFFSET)/1000; 77 | return current + timezone + daylight; 78 | } 79 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/Processing/SyncArduinoClock/readme.txt: -------------------------------------------------------------------------------- 1 | SyncArduinoClock is a Processing sketch that responds to Arduino requests for 2 | time synchronization messages. 3 | 4 | The portIndex must be set the Serial port connected to Arduino. 5 | 6 | Download TimeSerial.pde onto Arduino and you should see the time 7 | message displayed when you run SyncArduinoClock in Processing. 8 | The Arduino time is set from the time on your computer through the 9 | Processing sketch. 10 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeArduinoDue/TimeArduinoDue.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeRTC.pde 3 | * example code illustrating Time library with Real Time Clock. 4 | * 5 | * This example requires Markus Lange's Arduino Due RTC Library 6 | * https://github.com/MarkusLange/Arduino-Due-RTC-Library 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | // Select the Slowclock source 13 | //RTC_clock rtc_clock(RC); 14 | RTC_clock rtc_clock(XTAL); 15 | 16 | void setup() { 17 | Serial.begin(9600); 18 | rtc_clock.init(); 19 | if (rtc_clock.date_already_set() == 0) { 20 | // Unfortunately, the Arduino Due hardware does not seem to 21 | // be designed to maintain the RTC clock state when the 22 | // board resets. Markus described it thusly: "Uhh the Due 23 | // does reset with the NRSTB pin. This resets the full chip 24 | // with all backup regions including RTC, RTT and SC. Only 25 | // if the reset is done with the NRST pin will these regions 26 | // stay with their old values." 27 | rtc_clock.set_time(__TIME__); 28 | rtc_clock.set_date(__DATE__); 29 | // However, this might work on other unofficial SAM3X boards 30 | // with different reset circuitry than Arduino Due? 31 | } 32 | setSyncProvider(getArduinoDueTime); 33 | if(timeStatus()!= timeSet) 34 | Serial.println("Unable to sync with the RTC"); 35 | else 36 | Serial.println("RTC has set the system time"); 37 | } 38 | 39 | time_t getArduinoDueTime() 40 | { 41 | return rtc_clock.unixtime(); 42 | } 43 | 44 | void loop() 45 | { 46 | digitalClockDisplay(); 47 | delay(1000); 48 | } 49 | 50 | void digitalClockDisplay(){ 51 | // digital clock display of the time 52 | Serial.print(hour()); 53 | printDigits(minute()); 54 | printDigits(second()); 55 | Serial.print(" "); 56 | Serial.print(day()); 57 | Serial.print(" "); 58 | Serial.print(month()); 59 | Serial.print(" "); 60 | Serial.print(year()); 61 | Serial.println(); 62 | } 63 | 64 | void printDigits(int digits){ 65 | // utility function for digital clock display: prints preceding colon and leading 0 66 | Serial.print(":"); 67 | if(digits < 10) 68 | Serial.print('0'); 69 | Serial.print(digits); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeGPS/TimeGPS.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeGPS.pde 3 | * example code illustrating time synced from a GPS 4 | * 5 | */ 6 | 7 | #include 8 | #include // http://arduiniana.org/libraries/TinyGPS/ 9 | #include 10 | // TinyGPS and SoftwareSerial libraries are the work of Mikal Hart 11 | 12 | SoftwareSerial SerialGPS = SoftwareSerial(10, 11); // receive on pin 10 13 | TinyGPS gps; 14 | 15 | // To use a hardware serial port, which is far more efficient than 16 | // SoftwareSerial, uncomment this line and remove SoftwareSerial 17 | //#define SerialGPS Serial1 18 | 19 | // Offset hours from gps time (UTC) 20 | const int offset = 1; // Central European Time 21 | //const int offset = -5; // Eastern Standard Time (USA) 22 | //const int offset = -4; // Eastern Daylight Time (USA) 23 | //const int offset = -8; // Pacific Standard Time (USA) 24 | //const int offset = -7; // Pacific Daylight Time (USA) 25 | 26 | // Ideally, it should be possible to learn the time zone 27 | // based on the GPS position data. However, that would 28 | // require a complex library, probably incorporating some 29 | // sort of database using Eric Muller's time zone shape 30 | // maps, at http://efele.net/maps/tz/ 31 | 32 | time_t prevDisplay = 0; // when the digital clock was displayed 33 | 34 | void setup() 35 | { 36 | Serial.begin(9600); 37 | while (!Serial) ; // Needed for Leonardo only 38 | SerialGPS.begin(4800); 39 | Serial.println("Waiting for GPS time ... "); 40 | } 41 | 42 | void loop() 43 | { 44 | while (SerialGPS.available()) { 45 | if (gps.encode(SerialGPS.read())) { // process gps messages 46 | // when TinyGPS reports new data... 47 | unsigned long age; 48 | int Year; 49 | byte Month, Day, Hour, Minute, Second; 50 | gps.crack_datetime(&Year, &Month, &Day, &Hour, &Minute, &Second, NULL, &age); 51 | if (age < 500) { 52 | // set the Time to the latest GPS reading 53 | setTime(Hour, Minute, Second, Day, Month, Year); 54 | adjustTime(offset * SECS_PER_HOUR); 55 | } 56 | } 57 | } 58 | if (timeStatus()!= timeNotSet) { 59 | if (now() != prevDisplay) { //update the display only if the time has changed 60 | prevDisplay = now(); 61 | digitalClockDisplay(); 62 | } 63 | } 64 | } 65 | 66 | void digitalClockDisplay(){ 67 | // digital clock display of the time 68 | Serial.print(hour()); 69 | printDigits(minute()); 70 | printDigits(second()); 71 | Serial.print(" "); 72 | Serial.print(day()); 73 | Serial.print(" "); 74 | Serial.print(month()); 75 | Serial.print(" "); 76 | Serial.print(year()); 77 | Serial.println(); 78 | } 79 | 80 | void printDigits(int digits) { 81 | // utility function for digital clock display: prints preceding colon and leading 0 82 | Serial.print(":"); 83 | if(digits < 10) 84 | Serial.print('0'); 85 | Serial.print(digits); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeNTP/TimeNTP.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Time_NTP.pde 3 | * Example showing time sync to NTP time source 4 | * 5 | * This sketch uses the Ethernet library 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 14 | // NTP Servers: 15 | IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov 16 | // IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov 17 | // IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov 18 | 19 | 20 | const int timeZone = 1; // Central European Time 21 | //const int timeZone = -5; // Eastern Standard Time (USA) 22 | //const int timeZone = -4; // Eastern Daylight Time (USA) 23 | //const int timeZone = -8; // Pacific Standard Time (USA) 24 | //const int timeZone = -7; // Pacific Daylight Time (USA) 25 | 26 | 27 | EthernetUDP Udp; 28 | unsigned int localPort = 8888; // local port to listen for UDP packets 29 | 30 | void setup() 31 | { 32 | Serial.begin(9600); 33 | while (!Serial) ; // Needed for Leonardo only 34 | delay(250); 35 | Serial.println("TimeNTP Example"); 36 | if (Ethernet.begin(mac) == 0) { 37 | // no point in carrying on, so do nothing forevermore: 38 | while (1) { 39 | Serial.println("Failed to configure Ethernet using DHCP"); 40 | delay(10000); 41 | } 42 | } 43 | Serial.print("IP number assigned by DHCP is "); 44 | Serial.println(Ethernet.localIP()); 45 | Udp.begin(localPort); 46 | Serial.println("waiting for sync"); 47 | setSyncProvider(getNtpTime); 48 | } 49 | 50 | time_t prevDisplay = 0; // when the digital clock was displayed 51 | 52 | void loop() 53 | { 54 | if (timeStatus() != timeNotSet) { 55 | if (now() != prevDisplay) { //update the display only if time has changed 56 | prevDisplay = now(); 57 | digitalClockDisplay(); 58 | } 59 | } 60 | } 61 | 62 | void digitalClockDisplay(){ 63 | // digital clock display of the time 64 | Serial.print(hour()); 65 | printDigits(minute()); 66 | printDigits(second()); 67 | Serial.print(" "); 68 | Serial.print(day()); 69 | Serial.print(" "); 70 | Serial.print(month()); 71 | Serial.print(" "); 72 | Serial.print(year()); 73 | Serial.println(); 74 | } 75 | 76 | void printDigits(int digits){ 77 | // utility for digital clock display: prints preceding colon and leading 0 78 | Serial.print(":"); 79 | if(digits < 10) 80 | Serial.print('0'); 81 | Serial.print(digits); 82 | } 83 | 84 | /*-------- NTP code ----------*/ 85 | 86 | const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message 87 | byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets 88 | 89 | time_t getNtpTime() 90 | { 91 | while (Udp.parsePacket() > 0) ; // discard any previously received packets 92 | Serial.println("Transmit NTP Request"); 93 | sendNTPpacket(timeServer); 94 | uint32_t beginWait = millis(); 95 | while (millis() - beginWait < 1500) { 96 | int size = Udp.parsePacket(); 97 | if (size >= NTP_PACKET_SIZE) { 98 | Serial.println("Receive NTP Response"); 99 | Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer 100 | unsigned long secsSince1900; 101 | // convert four bytes starting at location 40 to a long integer 102 | secsSince1900 = (unsigned long)packetBuffer[40] << 24; 103 | secsSince1900 |= (unsigned long)packetBuffer[41] << 16; 104 | secsSince1900 |= (unsigned long)packetBuffer[42] << 8; 105 | secsSince1900 |= (unsigned long)packetBuffer[43]; 106 | return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; 107 | } 108 | } 109 | Serial.println("No NTP Response :-("); 110 | return 0; // return 0 if unable to get the time 111 | } 112 | 113 | // send an NTP request to the time server at the given address 114 | void sendNTPpacket(IPAddress &address) 115 | { 116 | // set all bytes in the buffer to 0 117 | memset(packetBuffer, 0, NTP_PACKET_SIZE); 118 | // Initialize values needed to form NTP request 119 | // (see URL above for details on the packets) 120 | packetBuffer[0] = 0b11100011; // LI, Version, Mode 121 | packetBuffer[1] = 0; // Stratum, or type of clock 122 | packetBuffer[2] = 6; // Polling Interval 123 | packetBuffer[3] = 0xEC; // Peer Clock Precision 124 | // 8 bytes of zero for Root Delay & Root Dispersion 125 | packetBuffer[12] = 49; 126 | packetBuffer[13] = 0x4E; 127 | packetBuffer[14] = 49; 128 | packetBuffer[15] = 52; 129 | // all NTP fields have been given values, now 130 | // you can send a packet requesting a timestamp: 131 | Udp.beginPacket(address, 123); //NTP requests are to port 123 132 | Udp.write(packetBuffer, NTP_PACKET_SIZE); 133 | Udp.endPacket(); 134 | } 135 | 136 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeNTP_ESP8266WiFi/TimeNTP_ESP8266WiFi.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeNTP_ESP8266WiFi.ino 3 | * Example showing time sync to NTP time source 4 | * 5 | * This sketch uses the ESP8266WiFi library 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | const char ssid[] = "*************"; // your network SSID (name) 13 | const char pass[] = "********"; // your network password 14 | 15 | // NTP Servers: 16 | static const char ntpServerName[] = "us.pool.ntp.org"; 17 | //static const char ntpServerName[] = "time.nist.gov"; 18 | //static const char ntpServerName[] = "time-a.timefreq.bldrdoc.gov"; 19 | //static const char ntpServerName[] = "time-b.timefreq.bldrdoc.gov"; 20 | //static const char ntpServerName[] = "time-c.timefreq.bldrdoc.gov"; 21 | 22 | const int timeZone = 1; // Central European Time 23 | //const int timeZone = -5; // Eastern Standard Time (USA) 24 | //const int timeZone = -4; // Eastern Daylight Time (USA) 25 | //const int timeZone = -8; // Pacific Standard Time (USA) 26 | //const int timeZone = -7; // Pacific Daylight Time (USA) 27 | 28 | 29 | WiFiUDP Udp; 30 | unsigned int localPort = 8888; // local port to listen for UDP packets 31 | 32 | time_t getNtpTime(); 33 | void digitalClockDisplay(); 34 | void printDigits(int digits); 35 | void sendNTPpacket(IPAddress &address); 36 | 37 | void setup() 38 | { 39 | Serial.begin(9600); 40 | while (!Serial) ; // Needed for Leonardo only 41 | delay(250); 42 | Serial.println("TimeNTP Example"); 43 | Serial.print("Connecting to "); 44 | Serial.println(ssid); 45 | WiFi.begin(ssid, pass); 46 | 47 | while (WiFi.status() != WL_CONNECTED) { 48 | delay(500); 49 | Serial.print("."); 50 | } 51 | 52 | Serial.print("IP number assigned by DHCP is "); 53 | Serial.println(WiFi.localIP()); 54 | Serial.println("Starting UDP"); 55 | Udp.begin(localPort); 56 | Serial.print("Local port: "); 57 | Serial.println(Udp.localPort()); 58 | Serial.println("waiting for sync"); 59 | setSyncProvider(getNtpTime); 60 | setSyncInterval(300); 61 | } 62 | 63 | time_t prevDisplay = 0; // when the digital clock was displayed 64 | 65 | void loop() 66 | { 67 | if (timeStatus() != timeNotSet) { 68 | if (now() != prevDisplay) { //update the display only if time has changed 69 | prevDisplay = now(); 70 | digitalClockDisplay(); 71 | } 72 | } 73 | } 74 | 75 | void digitalClockDisplay() 76 | { 77 | // digital clock display of the time 78 | Serial.print(hour()); 79 | printDigits(minute()); 80 | printDigits(second()); 81 | Serial.print(" "); 82 | Serial.print(day()); 83 | Serial.print("."); 84 | Serial.print(month()); 85 | Serial.print("."); 86 | Serial.print(year()); 87 | Serial.println(); 88 | } 89 | 90 | void printDigits(int digits) 91 | { 92 | // utility for digital clock display: prints preceding colon and leading 0 93 | Serial.print(":"); 94 | if (digits < 10) 95 | Serial.print('0'); 96 | Serial.print(digits); 97 | } 98 | 99 | /*-------- NTP code ----------*/ 100 | 101 | const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message 102 | byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets 103 | 104 | time_t getNtpTime() 105 | { 106 | IPAddress ntpServerIP; // NTP server's ip address 107 | 108 | while (Udp.parsePacket() > 0) ; // discard any previously received packets 109 | Serial.println("Transmit NTP Request"); 110 | // get a random server from the pool 111 | WiFi.hostByName(ntpServerName, ntpServerIP); 112 | Serial.print(ntpServerName); 113 | Serial.print(": "); 114 | Serial.println(ntpServerIP); 115 | sendNTPpacket(ntpServerIP); 116 | uint32_t beginWait = millis(); 117 | while (millis() - beginWait < 1500) { 118 | int size = Udp.parsePacket(); 119 | if (size >= NTP_PACKET_SIZE) { 120 | Serial.println("Receive NTP Response"); 121 | Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer 122 | unsigned long secsSince1900; 123 | // convert four bytes starting at location 40 to a long integer 124 | secsSince1900 = (unsigned long)packetBuffer[40] << 24; 125 | secsSince1900 |= (unsigned long)packetBuffer[41] << 16; 126 | secsSince1900 |= (unsigned long)packetBuffer[42] << 8; 127 | secsSince1900 |= (unsigned long)packetBuffer[43]; 128 | return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; 129 | } 130 | } 131 | Serial.println("No NTP Response :-("); 132 | return 0; // return 0 if unable to get the time 133 | } 134 | 135 | // send an NTP request to the time server at the given address 136 | void sendNTPpacket(IPAddress &address) 137 | { 138 | // set all bytes in the buffer to 0 139 | memset(packetBuffer, 0, NTP_PACKET_SIZE); 140 | // Initialize values needed to form NTP request 141 | // (see URL above for details on the packets) 142 | packetBuffer[0] = 0b11100011; // LI, Version, Mode 143 | packetBuffer[1] = 0; // Stratum, or type of clock 144 | packetBuffer[2] = 6; // Polling Interval 145 | packetBuffer[3] = 0xEC; // Peer Clock Precision 146 | // 8 bytes of zero for Root Delay & Root Dispersion 147 | packetBuffer[12] = 49; 148 | packetBuffer[13] = 0x4E; 149 | packetBuffer[14] = 49; 150 | packetBuffer[15] = 52; 151 | // all NTP fields have been given values, now 152 | // you can send a packet requesting a timestamp: 153 | Udp.beginPacket(address, 123); //NTP requests are to port 123 154 | Udp.write(packetBuffer, NTP_PACKET_SIZE); 155 | Udp.endPacket(); 156 | } 157 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeRTC/TimeRTC.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeRTC.pde 3 | * example code illustrating Time library with Real Time Clock. 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include // a basic DS1307 library that returns time as a time_t 10 | 11 | void setup() { 12 | Serial.begin(9600); 13 | while (!Serial) ; // wait until Arduino Serial Monitor opens 14 | setSyncProvider(RTC.get); // the function to get the time from the RTC 15 | if(timeStatus()!= timeSet) 16 | Serial.println("Unable to sync with the RTC"); 17 | else 18 | Serial.println("RTC has set the system time"); 19 | } 20 | 21 | void loop() 22 | { 23 | if (timeStatus() == timeSet) { 24 | digitalClockDisplay(); 25 | } else { 26 | Serial.println("The time has not been set. Please run the Time"); 27 | Serial.println("TimeRTCSet example, or DS1307RTC SetTime example."); 28 | Serial.println(); 29 | delay(4000); 30 | } 31 | delay(1000); 32 | } 33 | 34 | void digitalClockDisplay(){ 35 | // digital clock display of the time 36 | Serial.print(hour()); 37 | printDigits(minute()); 38 | printDigits(second()); 39 | Serial.print(" "); 40 | Serial.print(day()); 41 | Serial.print(" "); 42 | Serial.print(month()); 43 | Serial.print(" "); 44 | Serial.print(year()); 45 | Serial.println(); 46 | } 47 | 48 | void printDigits(int digits){ 49 | // utility function for digital clock display: prints preceding colon and leading 0 50 | Serial.print(":"); 51 | if(digits < 10) 52 | Serial.print('0'); 53 | Serial.print(digits); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeRTCLog/TimeRTCLog.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeRTCLogger.pde 3 | * example code illustrating adding and subtracting Time. 4 | * 5 | * this sketch logs pin state change events 6 | * the time of the event and time since the previous event is calculated and sent to the serial port. 7 | */ 8 | 9 | #include 10 | #include 11 | #include // a basic DS1307 library that returns time as a time_t 12 | 13 | const int nbrInputPins = 6; // monitor 6 digital pins 14 | const int inputPins[nbrInputPins] = {2,3,4,5,6,7}; // pins to monitor 15 | boolean state[nbrInputPins] ; // the state of the monitored pins 16 | time_t prevEventTime[nbrInputPins] ; // the time of the previous event 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | setSyncProvider(RTC.get); // the function to sync the time from the RTC 21 | for(int i=0; i < nbrInputPins; i++){ 22 | pinMode( inputPins[i], INPUT); 23 | // uncomment these lines if pull-up resistors are wanted 24 | // pinMode( inputPins[i], INPUT_PULLUP); 25 | // state[i] = HIGH; 26 | } 27 | } 28 | 29 | void loop() 30 | { 31 | for(int i=0; i < nbrInputPins; i++) 32 | { 33 | boolean val = digitalRead(inputPins[i]); 34 | if(val != state[i]) 35 | { 36 | time_t duration = 0; // the time since the previous event 37 | state[i] = val; 38 | time_t timeNow = now(); 39 | if(prevEventTime[i] > 0) 40 | // if this was not the first state change, calculate the time from the previous change 41 | duration = duration = timeNow - prevEventTime[i]; 42 | logEvent(inputPins[i], val, timeNow, duration ); // log the event 43 | prevEventTime[i] = timeNow; // store the time for this event 44 | } 45 | } 46 | } 47 | 48 | void logEvent( int pin, boolean state, time_t timeNow, time_t duration) 49 | { 50 | Serial.print("Pin "); 51 | Serial.print(pin); 52 | if( state == HIGH) 53 | Serial.print(" went High at "); 54 | else 55 | Serial.print(" went Low at "); 56 | showTime(timeNow); 57 | if(duration > 0){ 58 | // only display duration if greater than 0 59 | Serial.print(", Duration was "); 60 | showDuration(duration); 61 | } 62 | Serial.println(); 63 | } 64 | 65 | 66 | void showTime(time_t t){ 67 | // display the given time 68 | Serial.print(hour(t)); 69 | printDigits(minute(t)); 70 | printDigits(second(t)); 71 | Serial.print(" "); 72 | Serial.print(day(t)); 73 | Serial.print(" "); 74 | Serial.print(month(t)); 75 | Serial.print(" "); 76 | Serial.print(year(t)); 77 | } 78 | 79 | void printDigits(int digits){ 80 | // utility function for digital clock display: prints preceding colon and leading 0 81 | Serial.print(":"); 82 | if(digits < 10) 83 | Serial.print('0'); 84 | Serial.print(digits); 85 | } 86 | 87 | void showDuration(time_t duration){ 88 | // prints the duration in days, hours, minutes and seconds 89 | if(duration >= SECS_PER_DAY){ 90 | Serial.print(duration / SECS_PER_DAY); 91 | Serial.print(" day(s) "); 92 | duration = duration % SECS_PER_DAY; 93 | } 94 | if(duration >= SECS_PER_HOUR){ 95 | Serial.print(duration / SECS_PER_HOUR); 96 | Serial.print(" hour(s) "); 97 | duration = duration % SECS_PER_HOUR; 98 | } 99 | if(duration >= SECS_PER_MIN){ 100 | Serial.print(duration / SECS_PER_MIN); 101 | Serial.print(" minute(s) "); 102 | duration = duration % SECS_PER_MIN; 103 | } 104 | Serial.print(duration); 105 | Serial.print(" second(s) "); 106 | } 107 | 108 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeRTCSet/TimeRTCSet.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeRTCSet.pde 3 | * example code illustrating Time library with Real Time Clock. 4 | * 5 | * RTC clock is set in response to serial port time message 6 | * A Processing example sketch to set the time is included in the download 7 | * On Linux, you can use "date +T%s > /dev/ttyACM0" (UTC time zone) 8 | */ 9 | 10 | #include 11 | #include 12 | #include // a basic DS1307 library that returns time as a time_t 13 | 14 | 15 | void setup() { 16 | Serial.begin(9600); 17 | while (!Serial) ; // Needed for Leonardo only 18 | setSyncProvider(RTC.get); // the function to get the time from the RTC 19 | if (timeStatus() != timeSet) 20 | Serial.println("Unable to sync with the RTC"); 21 | else 22 | Serial.println("RTC has set the system time"); 23 | } 24 | 25 | void loop() 26 | { 27 | if (Serial.available()) { 28 | time_t t = processSyncMessage(); 29 | if (t != 0) { 30 | RTC.set(t); // set the RTC and the system time to the received value 31 | setTime(t); 32 | } 33 | } 34 | digitalClockDisplay(); 35 | delay(1000); 36 | } 37 | 38 | void digitalClockDisplay(){ 39 | // digital clock display of the time 40 | Serial.print(hour()); 41 | printDigits(minute()); 42 | printDigits(second()); 43 | Serial.print(" "); 44 | Serial.print(day()); 45 | Serial.print(" "); 46 | Serial.print(month()); 47 | Serial.print(" "); 48 | Serial.print(year()); 49 | Serial.println(); 50 | } 51 | 52 | void printDigits(int digits){ 53 | // utility function for digital clock display: prints preceding colon and leading 0 54 | Serial.print(":"); 55 | if(digits < 10) 56 | Serial.print('0'); 57 | Serial.print(digits); 58 | } 59 | 60 | /* code to process time sync messages from the serial port */ 61 | #define TIME_HEADER "T" // Header tag for serial time sync message 62 | 63 | unsigned long processSyncMessage() { 64 | unsigned long pctime = 0L; 65 | const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 66 | 67 | if(Serial.find(TIME_HEADER)) { 68 | pctime = Serial.parseInt(); 69 | return pctime; 70 | if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013) 71 | pctime = 0L; // return 0 to indicate that the time is not valid 72 | } 73 | } 74 | return pctime; 75 | } 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeSerial/TimeSerial.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeSerial.pde 3 | * example code illustrating Time library set through serial port messages. 4 | * 5 | * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970) 6 | * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2013 7 | T1357041600 8 | * 9 | * A Processing example sketch to automatically send the messages is included in the download 10 | * On Linux, you can use "date +T%s\n > /dev/ttyACM0" (UTC time zone) 11 | */ 12 | 13 | #include 14 | 15 | #define TIME_HEADER "T" // Header tag for serial time sync message 16 | #define TIME_REQUEST 7 // ASCII bell character requests a time sync message 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | while (!Serial) ; // Needed for Leonardo only 21 | pinMode(13, OUTPUT); 22 | setSyncProvider( requestSync); //set function to call when sync required 23 | Serial.println("Waiting for sync message"); 24 | } 25 | 26 | void loop(){ 27 | if (Serial.available()) { 28 | processSyncMessage(); 29 | } 30 | if (timeStatus()!= timeNotSet) { 31 | digitalClockDisplay(); 32 | } 33 | if (timeStatus() == timeSet) { 34 | digitalWrite(13, HIGH); // LED on if synced 35 | } else { 36 | digitalWrite(13, LOW); // LED off if needs refresh 37 | } 38 | delay(1000); 39 | } 40 | 41 | void digitalClockDisplay(){ 42 | // digital clock display of the time 43 | Serial.print(hour()); 44 | printDigits(minute()); 45 | printDigits(second()); 46 | Serial.print(" "); 47 | Serial.print(day()); 48 | Serial.print(" "); 49 | Serial.print(month()); 50 | Serial.print(" "); 51 | Serial.print(year()); 52 | Serial.println(); 53 | } 54 | 55 | void printDigits(int digits){ 56 | // utility function for digital clock display: prints preceding colon and leading 0 57 | Serial.print(":"); 58 | if(digits < 10) 59 | Serial.print('0'); 60 | Serial.print(digits); 61 | } 62 | 63 | 64 | void processSyncMessage() { 65 | unsigned long pctime; 66 | const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 67 | 68 | if(Serial.find(TIME_HEADER)) { 69 | pctime = Serial.parseInt(); 70 | if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013) 71 | setTime(pctime); // Sync Arduino clock to the time received on the serial port 72 | } 73 | } 74 | } 75 | 76 | time_t requestSync() 77 | { 78 | Serial.write(TIME_REQUEST); 79 | return 0; // the time will be sent later in response to serial mesg 80 | } 81 | 82 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeSerialDateStrings/TimeSerialDateStrings.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeSerialDateStrings.pde 3 | * example code illustrating Time library date strings 4 | * 5 | * This sketch adds date string functionality to TimeSerial sketch 6 | * Also shows how to handle different messages 7 | * 8 | * A message starting with a time header sets the time 9 | * A Processing example sketch to automatically send the messages is inclided in the download 10 | * On Linux, you can use "date +T%s\n > /dev/ttyACM0" (UTC time zone) 11 | * 12 | * A message starting with a format header sets the date format 13 | 14 | * send: Fs\n for short date format 15 | * send: Fl\n for long date format 16 | */ 17 | 18 | #include 19 | 20 | // single character message tags 21 | #define TIME_HEADER 'T' // Header tag for serial time sync message 22 | #define FORMAT_HEADER 'F' // Header tag indicating a date format message 23 | #define FORMAT_SHORT 's' // short month and day strings 24 | #define FORMAT_LONG 'l' // (lower case l) long month and day strings 25 | 26 | #define TIME_REQUEST 7 // ASCII bell character requests a time sync message 27 | 28 | static boolean isLongFormat = true; 29 | 30 | void setup() { 31 | Serial.begin(9600); 32 | while (!Serial) ; // Needed for Leonardo only 33 | setSyncProvider( requestSync); //set function to call when sync required 34 | Serial.println("Waiting for sync message"); 35 | } 36 | 37 | void loop(){ 38 | if (Serial.available() > 1) { // wait for at least two characters 39 | char c = Serial.read(); 40 | if( c == TIME_HEADER) { 41 | processSyncMessage(); 42 | } 43 | else if( c== FORMAT_HEADER) { 44 | processFormatMessage(); 45 | } 46 | } 47 | if (timeStatus()!= timeNotSet) { 48 | digitalClockDisplay(); 49 | } 50 | delay(1000); 51 | } 52 | 53 | void digitalClockDisplay() { 54 | // digital clock display of the time 55 | Serial.print(hour()); 56 | printDigits(minute()); 57 | printDigits(second()); 58 | Serial.print(" "); 59 | if(isLongFormat) 60 | Serial.print(dayStr(weekday())); 61 | else 62 | Serial.print(dayShortStr(weekday())); 63 | Serial.print(" "); 64 | Serial.print(day()); 65 | Serial.print(" "); 66 | if(isLongFormat) 67 | Serial.print(monthStr(month())); 68 | else 69 | Serial.print(monthShortStr(month())); 70 | Serial.print(" "); 71 | Serial.print(year()); 72 | Serial.println(); 73 | } 74 | 75 | void printDigits(int digits) { 76 | // utility function for digital clock display: prints preceding colon and leading 0 77 | Serial.print(":"); 78 | if(digits < 10) 79 | Serial.print('0'); 80 | Serial.print(digits); 81 | } 82 | 83 | void processFormatMessage() { 84 | char c = Serial.read(); 85 | if( c == FORMAT_LONG){ 86 | isLongFormat = true; 87 | Serial.println(F("Setting long format")); 88 | } 89 | else if( c == FORMAT_SHORT) { 90 | isLongFormat = false; 91 | Serial.println(F("Setting short format")); 92 | } 93 | } 94 | 95 | void processSyncMessage() { 96 | unsigned long pctime; 97 | const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 - paul, perhaps we define in time.h? 98 | 99 | pctime = Serial.parseInt(); 100 | if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013) 101 | setTime(pctime); // Sync Arduino clock to the time received on the serial port 102 | } 103 | } 104 | 105 | time_t requestSync() { 106 | Serial.write(TIME_REQUEST); 107 | return 0; // the time will be sent later in response to serial mesg 108 | } 109 | -------------------------------------------------------------------------------- /libraries/Time-master/examples/TimeTeensy3/TimeTeensy3.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * TimeRTC.pde 3 | * example code illustrating Time library with Real Time Clock. 4 | * 5 | */ 6 | 7 | #include 8 | 9 | void setup() { 10 | // set the Time library to use Teensy 3.0's RTC to keep time 11 | setSyncProvider(getTeensy3Time); 12 | 13 | Serial.begin(115200); 14 | while (!Serial); // Wait for Arduino Serial Monitor to open 15 | delay(100); 16 | if (timeStatus()!= timeSet) { 17 | Serial.println("Unable to sync with the RTC"); 18 | } else { 19 | Serial.println("RTC has set the system time"); 20 | } 21 | } 22 | 23 | void loop() { 24 | if (Serial.available()) { 25 | time_t t = processSyncMessage(); 26 | if (t != 0) { 27 | Teensy3Clock.set(t); // set the RTC 28 | setTime(t); 29 | } 30 | } 31 | digitalClockDisplay(); 32 | delay(1000); 33 | } 34 | 35 | void digitalClockDisplay() { 36 | // digital clock display of the time 37 | Serial.print(hour()); 38 | printDigits(minute()); 39 | printDigits(second()); 40 | Serial.print(" "); 41 | Serial.print(day()); 42 | Serial.print(" "); 43 | Serial.print(month()); 44 | Serial.print(" "); 45 | Serial.print(year()); 46 | Serial.println(); 47 | } 48 | 49 | time_t getTeensy3Time() 50 | { 51 | return Teensy3Clock.get(); 52 | } 53 | 54 | /* code to process time sync messages from the serial port */ 55 | #define TIME_HEADER "T" // Header tag for serial time sync message 56 | 57 | unsigned long processSyncMessage() { 58 | unsigned long pctime = 0L; 59 | const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 60 | 61 | if(Serial.find(TIME_HEADER)) { 62 | pctime = Serial.parseInt(); 63 | return pctime; 64 | if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013) 65 | pctime = 0L; // return 0 to indicate that the time is not valid 66 | } 67 | } 68 | return pctime; 69 | } 70 | 71 | void printDigits(int digits){ 72 | // utility function for digital clock display: prints preceding colon and leading 0 73 | Serial.print(":"); 74 | if(digits < 10) 75 | Serial.print('0'); 76 | Serial.print(digits); 77 | } 78 | 79 | -------------------------------------------------------------------------------- /libraries/Time-master/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Time 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | time_t KEYWORD1 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | now KEYWORD2 13 | second KEYWORD2 14 | minute KEYWORD2 15 | hour KEYWORD2 16 | day KEYWORD2 17 | month KEYWORD2 18 | year KEYWORD2 19 | isAM KEYWORD2 20 | isPM KEYWORD2 21 | weekday KEYWORD2 22 | setTime KEYWORD2 23 | adjustTime KEYWORD2 24 | setSyncProvider KEYWORD2 25 | setSyncInterval KEYWORD2 26 | timeStatus KEYWORD2 27 | TimeLib KEYWORD2 28 | ####################################### 29 | # Instances (KEYWORD2) 30 | ####################################### 31 | 32 | ####################################### 33 | # Constants (LITERAL1) 34 | ####################################### 35 | -------------------------------------------------------------------------------- /libraries/Time-master/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Time", 3 | "frameworks": "Arduino", 4 | "keywords": "Time, date, hour, minute, second, day, week, month, year, RTC", 5 | "description": "Time keeping library", 6 | "url": "http://playground.arduino.cc/Code/Time", 7 | "authors": 8 | [ 9 | { 10 | "name": "Michael Margolis" 11 | }, 12 | { 13 | "name": "Paul Stoffregen" 14 | } 15 | ], 16 | "repository": 17 | { 18 | "type": "git", 19 | "url": "https://github.com/PaulStoffregen/Time" 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /libraries/Time-master/library.properties: -------------------------------------------------------------------------------- 1 | name=Time 2 | version=1.5 3 | author=Michael Margolis 4 | maintainer=Paul Stoffregen 5 | sentence=Timekeeping functionality for Arduino 6 | paragraph=Date and Time functions, with provisions to synchronize to external time sources like GPS and NTP (Internet). This library is often used together with TimeAlarms and DS1307RTC. 7 | category=Timing 8 | url=http://playground.arduino.cc/code/time 9 | architectures=* 10 | 11 | --------------------------------------------------------------------------------