Components and supplies
Positioning (GNSS, GPS, Glonass, Galileo, Beidou)
Arduino Ethernet Shield 2
Perspex Sheet
DS3231 I2C RTC
LED Matrix I2C interface
IP65 Enclosure
Resistor 1k ohm
10 DOF gyro / accelerometer board
Buck Power Supply
HC-05 Bluetooth Module
Arduino Mega 2560
DUAL H-Bridge motor drive
ESP8266 ESP-12E
Capacitor 100 nF
Resistor 2.21k ohm
Cable Gland
Tools and machines
Hole Punch or Hole saw
Hand Drill
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
Code
TRACKER_MEGA_TOP_GPS_PWM_SOFT.ino
c_cpp
Tracker for Ethernet shield uses both GPS and NTP to retrieve time
1#include <SFE_BMP180.h> 2#include <avr/wdt.h> 3#include <Wire.h> 4#include <SPI.h> 5#include <LSM303.h> // modified ... fixed a couple of bugs 6#include <LiquidCrystal_I2C.h> 7#include <L3G.h> 8#include "ds3231.h" 9#include <TimeLib.h> 10#include "ht16k33.h" 11#include <ModbusRtu.h> // Modified ... this no longer a stock lib - Slave supports register translation/mapping 12#include <EEPROM.h> 13#include <math.h> 14#include <Ethernet.h> 15#include <SD.h> 16#include <EthernetUdp.h> 17#include <TinyGPS.h> 18 19#define ID 1 20 21#define BUFF_MAX 32 22#define PARK_EAST 1 23#define PARK_WEST 2 24#define PARK_NORTH 3 25#define PARK_SOUTH 4 26#define PARK_FLAT 5 27 28#define MOTOR_DWELL 100 29 30#define MAX_MODBUS_DATA 70 31 32#define HT16K33_DSP_NOBLINK 0 // constants for the half arsed cheapo display 33#define HT16K33_DSP_BLINK1HZ 4 34#define HT16K33_DSP_BLINK2HZ 2 35#define HT16K33_DSP_BLINK05HZ 6 36 37 38const byte ENCODER_PINA = 2; // encoder connects - interupt pin 39const byte ENCODER_PINB = 3; // non interupt pin 40const byte ENCODER_PB = 8; 41 42const byte RELAY_YZ_DIR = 8; // DIR 1 Y+ Y- East / West Was the X+ N relay BROWN 43const byte RELAY_YZ_PWM = 7; // PWM 2 Speed East / West Was the Y- E relay ORANGE 44const byte RELAY_XZ_PWM = 6; // PWM 2 Speed North / South Was the Y+ W relay YELLOW 45const byte RELAY_XZ_DIR = 5; // DIR 1 X+ X- North / South Was the X- S relay BLUE 46 47 48const int chipSelect = 4; 49 50const byte UNUSED09 = 9; // cycle timer 26 Hz 38ms period 51const byte UNUSED10 = 10; 52const byte UNUSED11 = 11; 53const byte WATCHDOG = 12; 54 55IPAddress ip(192,168,2,177) ; 56IPAddress MyDNS(139,130,4,4) ; 57unsigned int localPort = 8888; // local port to listen for UDP packets 58EthernetServer server(80) ; 59EthernetClient client ; 60 61byte mac[] = { 0x44, 0x6f, 0x75, 0x67, 0x61, 0x6c }; // Dougal in ASCII 62char timeServer[] = "au.pool.ntp.org"; // time.nist.gov NTP server 63const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 64byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets 65 66 67EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP 68 69static bool hasSD = false; 70static bool hasNet = false; 71static bool hasGyro = false; 72static bool hasRTC = false; 73static bool hasPres = false ; 74 75L3G gyro; 76LSM303 compass; 77LiquidCrystal_I2C lcd(0x27); // Set the LCD I2C address I modified the lib for default wiring 78 79SFE_BMP180 pressure; 80HT16K33 HT; 81 82TinyGPS gps; 83 84float ha ; 85float sunX ; 86float sunrise ; 87float sunset ; 88Modbus mb_slave(ID, 2, 0); // this is slave ID and RS-232 or USB-FTDI 89time_t chiptime ; 90uint8_t rtc_status ; 91//uint8_t time[8]; 92int motor_recycle = 0 ; 93char recv[BUFF_MAX]; 94unsigned int recv_size = 0; 95unsigned long prev_millis; 96uint8_t u8state; // machine state 97uint8_t u8query; // pointer to message query 98char buff[BUFF_MAX]; 99char trackername[18] ; 100unsigned long gpschars ; 101float heading ; // MODBUS MAP 102struct ts t; // 103struct ts td; // 104struct ts tg; // 105struct ts tc; // 106int iNightShutdown ; // 107time_t setchiptime ; // 68 if set to non zero this will trigger a time set event 108float zAng ; // 66 109float xMul = 1.0 ; // 64 110float yMul = 1.0 ; // 62 111float zMul = 1.0 ; // 60 112int iXYS = 0 ; // 59 113int iSave = 0 ; // 58 114int iDoSave = 0 ; // 57 115int iGPSLock = 0 ; // 56 116unsigned long fixage ; // 54 117float xRoll = 0.0 ; // 52 118float yRoll = 0.0 ; // 50 119float zRoll = 0.0 ; // 48 120float gT ; // 46 temp from sensor 121float Pr ; // 44 presure sensor 122float alt ; // 42 altitude from GPS 123float T; // 40 temperature of board (if has RTC) 124float xzTarget ; // 38 target for angles 125float yzTarget ; // 36 126float xzH ; // 34 hyserisis zone 127float yzH ; // 32 128float xzAng; // 30 current angles 129float yzAng; // 28 130float xzOffset; // 26 offset xz 131float yzOffset; // 24 offset yz 132float dyPark; // 22 parking position 133float dxPark; // 20 134float xMinVal ; // 18 Min and Max values X - N/S 135float xMaxVal ; // 16 136float yMinVal ; // 14 Y -- E/W 137float yMaxVal ; // 12 138float latitude; // 10 139float longitude; // 8 140int timezone; // 7 141int iDayNight ; // 6 142float solar_az_deg; // 4 143float solar_el_deg; // 2 144int iTrackMode ; // 1 145int iMode ; // 0 146 147int iPMode; 148int iPWM_YZ ; 149int iPWM_XZ ; 150int iPowerUp = 0 ; 151 152unsigned long tempus; 153int8_t state1 = 0; 154int8_t rtc_hour = 0; 155int8_t rtc_min = 0 ; 156int8_t rtc_sec = 0 ; 157 158void LoadParamsFromEEPROM(bool bLoad){ 159 if ( bLoad ) { 160 xzH = LoadFloatFromEEPROM(0,0.1,20.0,4.0); // hysterisis NS 161 yzH = LoadFloatFromEEPROM(1,0.1,20.0,4.0); // "" EW 162 163 dyPark = LoadFloatFromEEPROM(2,-70.0,50.0,0); 164 dxPark = LoadFloatFromEEPROM(3,-5.0,50.0,0.0); 165 166 xzOffset = LoadFloatFromEEPROM(4,-90.0,90.0,0); // NS 167 yzOffset = LoadFloatFromEEPROM(5,-90.0,90.0,0); // EW 168 169 xzTarget = LoadFloatFromEEPROM(6,-90.0,90.0,0); // NS 170 yzTarget = LoadFloatFromEEPROM(7,-90.0,90.0,0); // EW 171 172 xMinVal = LoadFloatFromEEPROM(8,-10.0,60.0,0.0); // NS 173 xMaxVal = LoadFloatFromEEPROM(9,-10.0,60.0,45); 174 175 yMinVal = LoadFloatFromEEPROM(10,-70.0,50.0,-65); // EW 176 yMaxVal = LoadFloatFromEEPROM(11,-70.0,50.0,45); 177 178 iTrackMode = LoadIntFromEEPROM(12,-1,4,0); 179 180 latitude = LoadFloatFromEEPROM(13,-90.0,90.0,-34.051219); 181 longitude = LoadFloatFromEEPROM(14,-180.0,180.0,142.013618); 182 timezone = LoadIntFromEEPROM(15,0,23,10); 183 xMul = LoadFloatFromEEPROM(16,-10,10,1); 184 yMul = LoadFloatFromEEPROM(17,-10,10,1); 185 zMul = LoadFloatFromEEPROM(18,-10,10,1); 186 iXYS = LoadIntFromEEPROM(19,0,1,0); 187 if ( xMul == 0.0 ) // zero is rubbish value so take 1.0 as the default 188 xMul = 1.0 ; 189 if ( yMul == 0.0 ) 190 yMul = 1.0 ; 191 if ( zMul == 0.0 ) 192 zMul = 1.0 ; 193 iNightShutdown = LoadIntFromEEPROM(20,0,1,1); 194 EEPROM.get(0 + (30 * sizeof(float)) , trackername ); 195 }else{ 196 EEPROM.put( 0 , xzH ); 197 EEPROM.put(0 + (1 * sizeof(float)) , yzH ); 198 EEPROM.put(0 + (2 * sizeof(float)) , dyPark ); 199 EEPROM.put(0 + (3 * sizeof(float)) , dxPark ); 200 EEPROM.put(0 + (4 * sizeof(float)) , xzOffset ); 201 EEPROM.put(0 + (5 * sizeof(float)) , yzOffset ); 202 EEPROM.put(0 + (6 * sizeof(float)) , xzTarget ); 203 EEPROM.put(0 + (7 * sizeof(float)) , yzTarget ); 204 EEPROM.put(0 + (8 * sizeof(float)) , xMinVal ); 205 EEPROM.put(0 + (9 * sizeof(float)) , xMaxVal ); 206 EEPROM.put(0 + (10 * sizeof(float)) , yMinVal ); 207 EEPROM.put(0 + (11 * sizeof(float)) , yMaxVal ); 208 EEPROM.put(0 + (12 * sizeof(float)) , iTrackMode ); 209 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 210 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 211 EEPROM.put(0 + (15 * sizeof(float)) , timezone ); 212 EEPROM.put(0 + (16 * sizeof(float)) , xMul ); 213 EEPROM.put(0 + (17 * sizeof(float)) , yMul ); 214 EEPROM.put(0 + (18 * sizeof(float)) , zMul ); 215 EEPROM.put(0 + (19 * sizeof(float)) , iXYS ); 216 EEPROM.put(0 + (20 * sizeof(float)) , iNightShutdown ); 217 EEPROM.put(0 + (30 * sizeof(float)) , trackername); 218 } 219} 220 221void setup() { 222 int led ; 223 224 Wire.begin(); 225 lcd.begin(20, 4); 226 lcd.home(); 227 lcd.setBacklightPin(3, NEGATIVE); 228 lcd.noCursor(); 229 lcd.clear(); 230 231 MCUSR &= ~_BV(WDRF); 232 wdt_disable(); 233 234 compass.init(); 235 compass.enableDefault(); 236 compass.setTimeout(1000); 237 238 Serial.begin(115200); // program/debug port 239 Serial1.begin(9600); // GPS port 240// Serial2.begin(115200); // Modbus Port to esp 241 Serial3.begin(115200); // EPS8266 serial converter 242 243 if (gyro.init()) { 244 gyro.enableDefault(); 245 hasGyro = true ; 246 } 247 if (pressure.begin()){ 248 Serial.println("BMP180 init success"); 249 hasPres = true ; 250 } 251 pinMode(RELAY_XZ_DIR, OUTPUT); // Outputs for PWM motor control 252 pinMode(RELAY_XZ_PWM, OUTPUT); // 253 pinMode(RELAY_YZ_PWM, OUTPUT); // 254 pinMode(RELAY_YZ_DIR, OUTPUT); // 255 iPWM_YZ = 0 ; 256 iPWM_XZ = 0 ; 257 pinMode(13, OUTPUT); // 258 digitalWrite(13, HIGH ); 259 ActivateRelays(0); // call an all stop first 260 261 mb_slave.begin( 9600 ); // RS-232 to base of tower 262 tempus = millis() + 100; 263 264 pinMode(UNUSED09, OUTPUT); // unused so dont leave floating set as output 265 pinMode(UNUSED10, OUTPUT); // 266 pinMode(UNUSED11, OUTPUT); // 267 pinMode(WATCHDOG, OUTPUT); // 268 digitalWrite(WATCHDOG,HIGH); 269 270 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical 271 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300}; 272 273 LoadParamsFromEEPROM(true); 274 275 DS3231_init(DS3231_INTCN); // look for a rtc 276 DS3231_get(&tc); 277 DS3231_get(&td); 278 rtc_status = DS3231_get_sreg(); 279 if ((tc.mon == 0 )&& (tc.mday==0)){ // no rtc to load off 280 setTime (0,0,0,21,9,2017) ; // midnight on the equinox (will deactivae motors till gets a valid time) ; 281 }else{ 282 setTime((int)tc.hour,(int)tc.min,(int)tc.sec,(int)tc.mday,(int)tc.mon,(int)tc.year ) ; // set the internal RTC 283 hasRTC = true ; 284 } 285 286 HT.begin(0x00); 287 for (led = 0; led < 127; led++) { 288 HT.clearLedNow(led); 289 } 290 291 Serial.println("EtherNet init"); 292 if (SD.begin(chipSelect) || true){ 293 hasSD = true; 294 Serial.println("SD OK"); 295 Ethernet.begin(mac,ip,MyDNS); 296// Ethernet.begin(mac,ip); 297 if (Udp.begin(localPort)==1){ 298 hasNet = true ; 299 } 300 server.begin(); 301 } 302 Serial.print("server is at "); 303 Serial.println(Ethernet.localIP()); 304 305 306// wdt_enable(WDTO_8S); 307} 308 309// Arduino doesnt have these to we define from a sandard libruary 310float arcsin(float x) { 311 return (atan(x / sqrt(-x * x + 1))); 312} 313float arccos(float x) { 314 return (atan(x / sqrt(-x * x + 1)) + (2 * atan(1))); 315} 316// fractional orbital rotation in radians 317float gama(struct ts *tm) { 318 return ((2 * PI / 365 ) * DayOfYear(tm->year , tm->mon , tm->mday , tm->hour , tm->min )); 319} 320// equation of rime 321float eqTime(float g) { 322 return (229.18 * ( 0.000075 + ( 0.001868 * cos(g)) - (0.032077 * sin(g)) - (0.014615 * cos (2 * g)) - (0.040849 * sin(2 * g)))); 323} 324// declination of sun in radians 325float Decl(float g) { 326 return ( 0.006918 - (0.399912 * cos(g)) + (0.070257 * sin(g)) - (0.006758 * cos(2 * g)) + ( 0.000907 * sin(2 * g)) - ( 0.002697 * cos(3 * g)) + (0.00148 * sin(3 * g)) ); 327} 328float TimeOffset(float longitude , struct ts *tm , int timezone ) { 329 float dTmp ; 330 dTmp = (-4.0 * longitude ) + (60 * timezone) - eqTime(gama(tm)) ; 331 return (dTmp); 332} 333 334float TrueSolarTime(float longitude , struct ts *tm , int timezone ) { 335 float dTmp ; 336 dTmp = ( 60.0 * tm->hour ) + (1.0 * tm->min) + (1.0 * tm->sec / 60) - TimeOffset(longitude, tm, timezone) ; 337 return (dTmp); 338} 339float HourAngle(float longitude , struct ts *tm , int timezone) { 340 float dTmp; 341 dTmp = (TrueSolarTime(longitude, tm, timezone) / 4 ) - 180 ; // 720 minutes is solar noon -- div 4 is 180 342 return (dTmp); 343} 344// Hour angle for sunrise and sunset only 345float HA (float lat , struct ts *tm ) { 346 float latRad ; 347 latRad = lat * 2 * PI / 360 ; 348 return ( acos((cos(90.833 * PI / 180 ) / ( cos(latRad) * cos(Decl(gama(tm)))) - (tan(latRad) * tan(Decl(gama(tm)))))) / PI * 180 ); 349} 350 351float Sunrise(float longitude , float lat , struct ts *tm , int timezone) { 352 return (720 - ( 4.0 * (longitude + HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 353} 354float Sunset(float longitude , float lat , struct ts *tm , int timezone) { 355 return (720 - ( 4.0 * (longitude - HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 356} 357float SNoon(float longitude , float lat , struct ts *tm , int timezone) { 358 return (720 - ( 4.0 * (longitude + (60 * timezone) - eqTime(gama(tm)))) ) ; 359} 360 361float SolarZenithRad(float longitude , float lat , struct ts *tm , int timezone) { 362 float latRad ; 363 float decRad ; 364 float HourAngleRad ; 365 float dTmp ; 366 367 latRad = lat * 2 * PI / 360 ; 368 decRad = Decl(gama(tm)); 369 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 370 dTmp = acos((sin(latRad) * sin(decRad)) + (cos(latRad) * cos(decRad) * cos(HourAngleRad))); 371 return (dTmp) ; 372 373} 374float SolarElevationRad(float longitude , float lat , struct ts *tm , int timezone ) { 375 return ((PI / 2) - SolarZenithRad(longitude , lat , tm , timezone )) ; 376} 377 378float SolarAzimouthRad(float longitude , float lat , struct ts *tm , int timezone) { 379 float latRad ; 380 float decRad ; 381 float solarzenRad ; 382 float HourAngleRad ; 383 float dTmp ; 384 latRad = lat * 2 * PI / 360 ; 385 decRad = Decl(gama(tm)); 386 solarzenRad = SolarZenithRad ( longitude , lat , tm , timezone ) ; 387 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 388 dTmp = acos(((sin(decRad) * cos(latRad)) - (cos(HourAngleRad) * cos(decRad) * sin(latRad))) / sin(solarzenRad)) ; 389 if ( HourAngleRad < 0 ) { 390 return (dTmp) ; 391 } else { 392 return ((2 * PI) - dTmp) ; 393 } 394} 395 396 397void StopYZ(){ 398 iPWM_YZ=0 ; 399 motor_recycle = MOTOR_DWELL ; 400} 401void StopXZ(){ 402 iPWM_XZ=0 ; 403 motor_recycle = MOTOR_DWELL ; 404} 405 406void ActivateRelays(int iAllStop) { 407 if (motor_recycle > 0 ){ 408 motor_recycle-- ; 409 } 410 if ( iAllStop == 0 ) { 411 StopYZ() ; 412 StopXZ() ; 413 } else { 414 if (( iPWM_YZ==0 ) && (motor_recycle == 0 )){ 415 if (((yzAng ) < ( yzTarget - yzH )) ) { // do Y ie E/W before N/S 416 digitalWrite(RELAY_YZ_DIR, LOW) ; 417 iPWM_YZ=2 ; 418 } 419 if (((yzAng ) > (yzTarget + yzH )) ) { 420 digitalWrite(RELAY_YZ_DIR, HIGH) ; 421 iPWM_YZ=2 ; 422 } 423 } 424 if ( iPWM_YZ>0 ){ 425 if ((yzAng > yzTarget) && ( digitalRead(RELAY_YZ_DIR)==LOW )) { 426 StopYZ() ; 427 } 428 if ((yzAng < yzTarget) && ( digitalRead(RELAY_YZ_DIR)==HIGH )) { 429 StopYZ() ; 430 } 431 } 432 433 if (( iPWM_YZ==0)) { // if finished on E/W you can do N/S 434 if (( iPWM_XZ==0 ) && (motor_recycle == 0 )){ 435 if ((xzAng < ( xzTarget - xzH )) ) { // turn on if not in tolerance 436 digitalWrite(RELAY_XZ_DIR, LOW) ; 437 iPWM_XZ=2 ; 438 } 439 if ((xzAng > ( xzTarget + xzH )) ) { // turn on if not in tolerance 440 digitalWrite(RELAY_XZ_DIR, HIGH) ; 441 iPWM_XZ=2 ; 442 } 443 } 444 }else{ 445 if ((iPWM_XZ>0 )){ 446 StopXZ() ; 447 } 448 } 449 if ( iPWM_XZ>0 ){ 450 if ((xzAng > xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==LOW )) { // if on turn off 451 StopXZ() ; 452 } 453 if ((xzAng < xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==HIGH )) { // if on turn off 454 StopXZ() ; 455 } 456 } 457 } 458 if (iPWM_XZ>0){ 459 iPWM_XZ += 3 ; 460 } 461 if (iPWM_YZ>0){ 462 iPWM_YZ += 3 ; 463 } 464 iPWM_XZ = constrain(iPWM_XZ,0,254); 465 iPWM_YZ = constrain(iPWM_YZ,0,254); 466 analogWrite(RELAY_XZ_PWM,iPWM_XZ); 467 analogWrite(RELAY_YZ_PWM,iPWM_YZ); 468} 469 470void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 471 uint16_t tempdata[2] ; 472 float *tf ; 473 tf = (float * )&tempdata[0] ; 474 *tf = src_value ; 475 *dest_lo = tempdata[1] ; 476 *dest_hi = tempdata[0] ; 477} 478float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 479 uint16_t tempdata[2] ; 480 float *tf ; 481 tf = (float * )&tempdata[0] ; 482 tempdata[1] = dest_lo ; 483 tempdata[0] = dest_hi ; 484 return (*tf) ; 485} 486 487 488float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 489float tmp ; 490 EEPROM.get(0 + (address * sizeof(float)) , tmp ); 491 if (( tmp < minval ) || ( tmp > maxval )|| (NumberOK(tmp) == 1)) { 492 tmp = defaultval ; 493 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 494 } 495 return(tmp); 496} 497int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 498int tmp ; 499 EEPROM.get(0 + (address * sizeof(float)) , tmp ); // float.. yeah yeah I know... but it makes it compatible with the one above (easy on the brain) 500 if (( tmp < minval ) || ( tmp > maxval )) { 501 tmp = defaultval ; 502 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 503 } 504 return(tmp); 505} 506 507int NumberOK (float target) { 508 int tmp = 0 ; 509 tmp = isnan(target); 510 if ( tmp != 1 ) { 511 tmp = isinf(target); 512 } 513 return (tmp); 514} 515 516int SetTimeFromGPS(){ 517 byte hundredths ; 518 519 gps.crack_datetime((int *)&tg.year,(byte *)&tg.mon,(byte *) &tg.mday,(byte *) &tg.hour,(byte *) &tg.min,(byte *) &tg.sec , &hundredths, &fixage); 520 setTime((int)tg.hour,(int)tg.min,(int)tg.sec,(int)tg.mday,(int)tg.mon,(int)tg.year ) ; // set the internal RTC from last GPS time 521 chiptime = now() ; // get it back again 522 chiptime += (( timezone * SECS_PER_HOUR ) + ( fixage / 1000 )) ; // add the offset plus the fix age 523 setTime(chiptime); // set it again 524 if (hasRTC) { 525 tg.year = year(); 526 tg.mon = month() ; 527 tg.mday = day(); 528 tg.hour = hour() ; 529 tg.min = minute(); 530 tg.sec = second(); 531 DS3231_set(tg); //should also update this 532 } 533 return(0); 534} 535 536 537void loop() { 538 float P; 539 float sunInc; 540 float sunAng; 541 float xzRatio; 542 float yzRatio; 543 float decl ; 544 float eqtime ; 545 float dTmp ; 546 float heading ; 547 float tst ; 548 float flat, flon; 549 unsigned short goodsent; 550 unsigned short failcs; 551// int iYear , iMon , iMday , iHour , iMin , iSec ; 552 553 554 if (minute() != rtc_min) { // do onlyonce a minute 555 gps.stats(&gpschars, &goodsent , &failcs ); 556 gps.f_get_position(&flat, &flon,(long unsigned *) &fixage); // return in degrees 557 if (hasPres){ 558 Pr = getPressure((double *)&gT) ; 559 } 560 if (hasRTC) { 561 T = DS3231_get_treg(); 562 } 563 rtc_min = minute() ; 564 565 if ((fixage > 0 ) && ( fixage < 40000 )) { // wait till our fix is valid before we use the values 566 latitude = flat ; 567 longitude = flon ; 568 iGPSLock = gps.satellites() ; 569 alt = gps.f_altitude() ; 570 if (iPowerUp==0) { // only do this at startup so we have a better position ref for next time 571 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 572 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 573 iPowerUp = 1 ; 574 if (!hasNet ){ 575 SetTimeFromGPS(); 576 } 577 } 578 }else{ 579 iGPSLock = 0 ; // if no lock loook at internal clock 580 } 581 } 582 tc.year = year(); 583 tc.mon = month() ; 584 tc.mday = day(); 585 tc.hour = hour() ; 586 tc.min = minute(); 587 tc.sec = second(); 588 589 compass.read(); // this reads all 6 channels 590 if ( hasGyro ){ 591 gyro.read(); 592 xRoll = gyro.g.x ; 593 yRoll = gyro.g.y ; 594 zRoll = gyro.g.z ; 595 } 596 597 digitalWrite(UNUSED09,!digitalRead(UNUSED09)); // toggle this output so I can measure the cycle time with a scope 598 599 heading = compass.heading((LSM303::vector<int>) { 1, 0, 0 }); 600 601 if (( compass.a.z != 0) && (!compass.timeoutOccurred() )) { 602 zAng = (float)compass.a.z ; 603 if (iXYS == 0 ){ // Proper Job make it configurable 604 xzRatio = (float)compass.a.x * xMul / abs(zAng) ; // Normal 605 yzRatio = (float)compass.a.y * yMul / abs(zAng) ; 606 }else{ 607 xzRatio = (float)compass.a.y * xMul / abs(zAng) ; // Swapped 608 yzRatio = (float)compass.a.x * yMul / abs(zAng) ; 609 } 610 xzAng = ((float)atan(xzRatio) / PI * 180 ) + xzOffset ; // good old offsets or fudge factors 611 yzAng = ((float)atan(yzRatio) / PI * 180 ) + yzOffset ; 612// digitalWrite(13, LOW); 613 }else{ // try restarting the compass/accelerometer modual - cos he gone walkabout... 614 Wire.begin(); // reset the I2C 615 compass.init(); 616 compass.enableDefault(); 617 compass.setTimeout(1000); // BTW I fixed up the int / long issue in the time out function in the LM303 lib I was using 618 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical (just whirl it around a bit and records the min max !!) 619 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300 }; 620/* if (tc.sec % 2 == 0 ) { 621 digitalWrite(13, HIGH); 622 } else { 623 digitalWrite(13, LOW); 624 }*/ 625 HT.begin(0x00); 626 } 627 628 if (setchiptime > 0) { // update the arduino time from the modbus register then clear it... also set RTC if fitted 629 setTime(setchiptime) ; 630 if (hasRTC) { 631 tc.year = year(); 632 tc.mon = month() ; 633 tc.mday = day(); 634 tc.hour = hour() ; 635 tc.min = minute(); 636 tc.sec = second(); 637 DS3231_set(tc); //should also update this 638 } 639 setchiptime = 0 ; 640 } 641 642 if ( hour() != rtc_hour){ // update our time every hour if we can 643 if (iGPSLock == 0){ 644 if( hasNet ){ 645 sendNTPpacket(timeServer); // send an NTP packet to a time server every hour 646 }else{ 647 if (hasRTC) { 648 DS3231_get(&td); 649 setTime((int)td.hour,(int)td.min,(int)td.sec,(int)td.mday,(int)td.mon,(int)td.year ) ; // set the internal RTC from Dallas RTC 650 } 651 } 652 }else{ 653 if ((fixage > 0 ) && ( fixage < 10000 )) { // if the lock is less than 10 second old 654 SetTimeFromGPS(); 655 } 656 } 657 rtc_hour = hour() ; 658 } 659 660 if ( rtc_sec != second() ) { //only update once a second 661 wdt_reset(); // reset internal watchdog - good puppy 662 663 if (( tc.sec > 8 ) && ( tc.sec < 58 )) { // dont calculate arround the minute when time is updating from NTP or GPS as might get a not so funny result 664 digitalWrite(13,!digitalRead(13)); 665 solar_az_deg = SolarAzimouthRad(longitude, latitude, &tc, timezone) * 180 / PI ; 666 solar_el_deg = SolarElevationRad(longitude, latitude, &tc, timezone) * 180 / PI ; 667 668 decl = Decl(gama(&tc)) * 180 / PI ; 669 ha = HourAngle (longitude , &tc , timezone ) ; 670 sunrise = Sunrise(longitude, latitude, &tc, timezone) ; 671 sunset = Sunset(longitude, latitude, &tc, timezone); 672 tst = TrueSolarTime(longitude, &tc, timezone); 673 sunX = abs(latitude) + decl ; 674 if (solar_el_deg >= 0 ){ // day 675 iDayNight = 1 ; 676 }else{ // night 677 iDayNight = 0 ; 678 } 679 } 680 switch (iTrackMode) { 681 case 4: // both axis to park 682 yzTarget = dyPark ; // night park position E/W 683 xzTarget = dxPark ; // night park position N/S 684 break ; 685 case 3: // both axis off no tracking 686 break ; 687 case 2: // xz tracking NS 688 if ( iDayNight == 1 ) { 689 xzTarget = sunX ; // need to map the coordinate system correctly 690 } else { 691 xzTarget = dxPark ; // night park position 692 } 693 break; 694 case 1: // yz tracking EW 695 if (iDayNight == 1) { 696 yzTarget = ha ; 697 } else { 698 yzTarget = dyPark ; // night park position 699 } 700 break; 701 case -1: // set target to tracking and park both at nigh 702 if (iDayNight == 1) { 703 yzTarget = ha ; 704 xzTarget = sunX ; // need to map the coordinate system correctly 705 } else { 706 yzTarget = dyPark ; // night park position E/W 707 xzTarget = dxPark ; // night park position N/S 708 } 709 break; 710 default: // set target to tracking 711 if (iDayNight == 1) { 712 yzTarget = ha ; 713 xzTarget = sunX ; // need to map the coordinate system correctly 714 } else { 715 yzTarget = dyPark ; // night park position (dont park the other - leave till morning) 716 } 717 break; 718 } 719 xzTarget = constrain(xzTarget,xMinVal,xMaxVal); // constain function... very cool - dont leave home without it ! 720 yzTarget = constrain(yzTarget,yMinVal,yMaxVal); 721 722 lcd.setCursor ( 0, 0 ); // Diags in case there is an LCD display attached 723 lcd.print("X/Z "); 724 if ( xzAng > 0 ) { 725 lcd.print("+"); 726 } 727 lcd.print(xzAng); 728 lcd.setCursor ( 10, 0 ); 729 lcd.print("Y/Z "); 730 if ( yzAng > 0 ) { 731 lcd.print("+"); 732 } 733 lcd.print(yzAng); 734 lcd.setCursor ( 0, 1 ); 735 lcd.print("TX "); 736 if (( xzTarget) > 0 ) { 737 lcd.print("+"); 738 } 739 lcd.print(( xzTarget)); 740 lcd.setCursor ( 10, 1 ); 741 lcd.print("TY "); 742 if (( yzTarget) > 0 ) { 743 lcd.print("+"); 744 } 745 lcd.print(( yzTarget)); 746 lcd.setCursor ( 0, 2 ); 747 lcd.print("DX "); 748 dTmp = ( xzAng - xzTarget) ; 749 if (dTmp > 0 ) { 750 lcd.print("+"); 751 } 752 lcd.print(dTmp); 753 lcd.setCursor ( 10, 2 ); 754 lcd.print("DY "); 755 dTmp = ( yzAng - yzTarget) ; 756 if (dTmp > 0 ) { 757 lcd.print("+"); 758 } 759 lcd.print(dTmp); 760 761 lcd.setCursor ( 0, 3 ); // line 3 762 snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", tc.hour, tc.min, tc.sec); 763 lcd.print(buff) ; 764 765 lcd.setCursor ( 9, 3 ); // line 3 766 lcd.print( "S") ; 767 if ( iDayNight == 0 ) { 768 lcd.print( "-") ; 769 }else{ 770 if (( tc.sec % 2 ) == 0 ) { 771 lcd.print( "<") ; 772 }else{ 773 lcd.print( ">") ; 774 } 775 } 776 if ( gps.satellites() > 9 ){ 777 lcd.print( "-" ); 778 }else{ 779 lcd.print(gps.satellites()) ; 780 } 781 782 lcd.setCursor ( 13, 3 ); // line 3 783 snprintf(buff, BUFF_MAX, "%04X", fixage); 784 lcd.print(buff) ; 785 786 lcd.setCursor ( 18, 3 ); // line 3 787 if ( iPWM_YZ == 0 ) { 788 lcd.print( " ") ; 789 }else{ 790 if (( digitalRead(RELAY_YZ_DIR) == LOW )) { 791 lcd.print( "W") ; 792 }else{ 793 lcd.print( "E") ; 794 } 795 } 796 lcd.setCursor ( 19, 3 ); // line 3 797 if ( iPWM_XZ == 0 ) { 798 lcd.print( " ") ; 799 }else{ 800 if (( digitalRead(RELAY_XZ_DIR) == LOW )) { 801 lcd.print( "N") ; 802 }else{ 803 lcd.print( "S") ; 804 } 805 } 806 807 rtc_sec = second() ; 808 DisplayMeatBall() ; 809 } 810 811 if ( iDoSave == 2 ) { // save them Active via web or 812 LoadParamsFromEEPROM(false); 813 iDoSave = 0 ; // only do once 814 } 815 if ( iDoSave == 3 ) { // load them 816 LoadParamsFromEEPROM(true); 817 iDoSave = 0 ; // only do once 818 } 819 820 if (((tc.hour > 19 ) || ( tc.hour < 5 )) && (iTrackMode < 3)) { 821 if ( iNightShutdown != 0 ){ 822 ActivateRelays(1) ; 823 }else{ 824 ActivateRelays(0) ; // power down at night if in tracking mode 825 } 826 }else{ 827 ActivateRelays(1) ; 828 } 829 830 831 state1 = mb_slave.poll( (uint16_t*)&iMode, MAX_MODBUS_DATA ); 832 833 switch (state1) { 834 case EXC_ADDR_RANGE: 835 Serial.println("EXC_ADDR_RANGE PORT 2"); 836 break; 837 case EXC_FUNC_CODE: 838 Serial.println("EXC_FUNC_CODE PORT 2"); 839 break; 840 case EXC_REGS_QUANT: 841 Serial.println("EXC_REGS_QUANT PORT 2"); 842 break; 843 } 844 845 if ( hasNet ) { 846 if ( Udp.parsePacket() ) { // check if NTP packet arrived back 847 processNTPpacket(); 848 } 849 850 client = server.available(); // process web server 851 if (client) { 852 processTCPClient(client); 853 } 854 } 855 856 while (Serial1.available()){ // process the gps buffer 857 gps.encode(Serial1.read()); 858 } 859} // end of loop 860 861 862 863 864 865 866float DayOfYear(uint16_t iYear , uint8_t iMon , uint8_t iDay , uint8_t iHour , uint8_t iMin ) { 867 int i ; 868 float iTDay ; 869 870 iTDay = iDay - 1 ; // this is zero referenced 871 for ( i = 1 ; i < iMon ; i++ ) { 872 switch (i) { 873 case 1: 874 case 3: 875 case 5: 876 case 7: 877 case 8: 878 case 10: 879 case 12: 880 iTDay += 31 ; 881 break; 882 case 4: 883 case 6: 884 case 9: 885 case 11: 886 iTDay += 30 ; 887 break; 888 case 2 : 889 if ((iYear % 4) == 0 ) { 890 iTDay += 29 ; 891 } else { 892 iTDay += 28 ; 893 } 894 break; 895 } 896 } 897 iTDay += (( 1.0 * iHour - 12 ) / 24 ) ; 898 // iDay += 1.0 * iMin / 1440 ; 899 return (iTDay); 900} 901 902 903int HrsSolarTime(float target) { 904 int i ; 905 i = target ; 906 return ( i / 60 ); 907} 908int MinSolarTime(float target) { 909 int i ; 910 i = target ; 911 return ( i % 60 ); 912} 913 914float sign(float target) { 915 if (target > 0 ) { 916 return (1); 917 } else { 918 if (target < 0 ) { 919 return (-1); 920 } else { 921 return (0); 922 } 923 } 924} 925 926void DisplayMeatBall() { 927 int pos , led , x , y; 928 float dx , dy ; 929 float dxa , dya ; 930 931 HT.setBrightness(15); 932 933 dx = xzAng - xzTarget ; 934 dy = yzAng - yzTarget ; 935 dxa = abs(dx) ; 936 dya = abs(dy) ; 937 if (dxa < 6) { 938 x = 0 ; 939 } else { 940 if (dxa < 12) { 941 x = sign(dx); 942 } else { 943 if (dxa < 50) { 944 x = 2 * sign(dx); 945 } else { 946 x = 3 * sign(dx); 947 } 948 } 949 } 950 if (dya < 6) { 951 y = 0 ; 952 } else { 953 if (dya < 12) { 954 y = sign(dy); 955 } else { 956 if (dya < 25) { 957 y = 2 * sign(dy); 958 } else { 959 y = 3 * sign(dy); 960 } 961 } 962 } 963 pos = 27 ; // netral position 964 pos += (y * 8) ; // add or sumtract the x in range of -3 to +3 965 pos += (x ) ; // add or sumtract 8 * y or y in range of -3 to +3 966 for (led = 0; led < 63; led++) { 967 switch (led){ 968 case 0: 969 case 7: 970 case 56: 971 case 63: 972 break; 973 default: 974 HT.clearLedNow(MapLedNo(led)); 975 break; 976 } 977 } 978 979 if ( ++iPMode > 100 ) { 980 iPMode = 1 ; 981 } 982 switch(gps.satellites()){ 983 case 255: 984 HT.clearLedNow(MapLedNo(0)); // turn off four courners 985 HT.clearLedNow(MapLedNo(7)); // turn off four courners 986 HT.clearLedNow(MapLedNo(63)); // turn off four courners 987 HT.clearLedNow(MapLedNo(56)); // turn off four courners 988 break; 989 case 1: 990 case 2: 991 HT.setLedNow(MapLedNo(0)); // turn on four courners 992 HT.clearLedNow(MapLedNo(7)); // turn on four courners 993 HT.clearLedNow(MapLedNo(63)); // turn on four courners 994 HT.clearLedNow(MapLedNo(56)); // turn on four courners 995 break; 996 case 3: 997 HT.setLedNow(MapLedNo(0)); // turn on four courners 998 HT.setLedNow(MapLedNo(7)); 999 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1000 HT.clearLedNow(MapLedNo(56)); // turn on four courners 1001 break; 1002 case 4: 1003 HT.setLedNow(MapLedNo(0)); // turn on four courners 1004 HT.setLedNow(MapLedNo(7)); 1005 HT.setLedNow(MapLedNo(56)); 1006 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1007 break; 1008 default: 1009 HT.setLedNow(MapLedNo(0)); // turn on four courners 1010 HT.setLedNow(MapLedNo(7)); 1011 HT.setLedNow(MapLedNo(56)); 1012 HT.setLedNow(MapLedNo(63)); 1013 break; 1014 } 1015 1016 1017 // HT.setLedNow(MapLedNo(tc.sec)); 1018 if ((iPWM_YZ == 0) && (iPWM_XZ == 0)) { 1019// HT.setBlinkRate(HT16K33_DSP_NOBLINK); // not attempting to move 1020 if ((tc.sec % 2) == 0 ) { 1021 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1022 HT.setLedNow(MapLedNo(pos + 9)); 1023 }else{ 1024 HT.setLedNow(MapLedNo(pos + 1)); 1025 HT.setLedNow(MapLedNo(pos + 8)); 1026 } 1027 } else { 1028// HT.setBlinkRate(HT16K33_DSP_BLINK2HZ); //moving so blink meat ball 1029 if (( iPMode % 2 ) == 0 ){ 1030 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1031 HT.setLedNow(MapLedNo(pos + 1)); 1032 HT.setLedNow(MapLedNo(pos + 8)); 1033 HT.setLedNow(MapLedNo(pos + 9)); 1034 } 1035 } 1036} 1037 1038 1039int MapLedNo(int target) // this compensates for the screwy setup of the matrix driver to the chip 1040{ 1041 int row ; 1042 int col ; 1043 row = target / 8 ; 1044 col = target % 8 ; 1045 if (col == 0 ) { 1046 return ((row * 16 ) + 7) ; 1047 } else { 1048 return ((row * 16 ) + col - 1) ; 1049 } 1050} 1051 1052 1053unsigned long sendNTPpacket(char* address) // send an NTP request to the time server at the given address 1054{ 1055 memset(packetBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0 1056 // Initialize values needed to form NTP request 1057 // (see URL above for details on the packets) 1058 packetBuffer[0] = 0b11100011; // LI, Version, Mode 1059 packetBuffer[1] = 0; // Stratum, or type of clock 1060 packetBuffer[2] = 6; // Polling Interval 1061 packetBuffer[3] = 0xEC; // Peer Clock Precision 1062 // 8 bytes of zero for Root Delay & Root Dispersion 1063 packetBuffer[12] = 49; 1064 packetBuffer[13] = 0x4E; 1065 packetBuffer[14] = 49; 1066 packetBuffer[15] = 52; 1067 1068 // all NTP fields have been given values, now 1069 // you can send a packet requesting a timestamp: 1070 Udp.beginPacket(address, 123); //NTP requests are to port 123 1071 Udp.write(packetBuffer, NTP_PACKET_SIZE); 1072 Udp.endPacket(); 1073} 1074 1075 1076unsigned long processNTPpacket(void){ 1077 struct ts tntp; 1078 Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer 1079 1080 //the timestamp starts at byte 40 of the received packet and is four bytes, 1081 // or two words, long. First, esxtract the two words: 1082 1083 unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); 1084 unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 1085 // combine the four bytes (two words) into a long integer 1086 // this is NTP time (seconds since Jan 1 1900): 1087 unsigned long secsSince1900 = highWord << 16 | lowWord; 1088 Serial.print(F("Seconds since Jan 1 1900 = " )); 1089 Serial.println(secsSince1900); 1090 1091 // now convert NTP time into everyday time: 1092 Serial.print(F("Unix time = ")); 1093 // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: 1094 const unsigned long seventyYears = 2208988800UL; 1095 // subtract seventy years: 1096 unsigned long epoch = secsSince1900 - seventyYears + (timezone * SECS_PER_HOUR); 1097 // print Unix time: 1098 Serial.println(epoch); 1099 setTime((time_t)epoch); // update the clock 1100 t.year = year(); // record the last NTP time set 1101 t.mon = month() ; 1102 t.mday = day(); 1103 t.hour = hour(); 1104 t.min = minute(); 1105 t.sec = second(); 1106 1107 // print the hour, minute and second: 1108 Serial.print(F("In time zone ")); 1109 Serial.print(timezone); 1110 Serial.print(F(" the time is ")); 1111 Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) 1112 Serial.print(':'); 1113 if ( ((epoch % 3600) / 60) < 10 ) { 1114 // In the first 10 minutes of each hour, we'll want a leading '0' 1115 Serial.print('0'); 1116 } 1117 Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) 1118 Serial.print(':'); 1119 if ( (epoch % 60) < 10 ) { 1120 // In the first 10 seconds of each minute, we'll want a leading '0' 1121 Serial.print('0'); 1122 } 1123 Serial.println(epoch % 60); // print the second 1124} 1125 1126void sendTDTREnd(){ 1127 client.println(F("</td></tr>")); 1128} 1129 1130void processTCPClient(EthernetClient Target){ 1131 boolean currentLineIsBlank = true; 1132 long j , i = 0 ; 1133 while (Target.connected()) { 1134 if (Target.available()) { 1135 String req = Target.readStringUntil('\r'); 1136 // so you can send a reply 1137 // send a standard http response header 1138 i = req.indexOf("?tname="); // wanta do this one BEFORE we dick with captialisation of the request 1139 if (i != -1){ // have a request to set the time zone 1140 j = req.indexOf("&"); 1141 req.substring(i+7,j).toCharArray(trackername , 16) ; 1142 for (j=0 ; j < 16 ; j++){ 1143 if (trackername[j] == '+' ) { 1144 trackername[j] = ' ' ; 1145 } 1146 } 1147 } 1148 1149 i = req.indexOf("/gpio/"); 1150// Serial.println(req); 1151// Serial.println(req.charAt(i+6)); 1152 if (i != -1){ 1153 switch(req.charAt(i+6)){ 1154 case '0': 1155 break; 1156 case '1': 1157 break; 1158 case '2': 1159 break; 1160 case '3': 1161 break; 1162 case '4': 1163 break; 1164 case '5': 1165 break; 1166 case '6': 1167 break; 1168 case '7': 1169 break; 1170 case 'A': 1171 break; 1172 case 'B': 1173 break; 1174 case 'C': 1175 break; 1176 case 'T': // TssmmhhWDDMMYYYY aka set time same format as example eg T001513624032017 1177 t.sec = req.substring(i+7,i+9).toInt(); // 1 1178 t.min = req.substring(i+9,i+11).toInt(); // 3 1179 t.hour = req.substring(i+11,i+13).toInt(); // 5 1180 t.wday = req.charAt(i+13) - 48; // 7 1181 t.mday = req.substring(i+14,i+16).toInt(); // 8 1182 t.mon = req.substring(i+16,i+18).toInt();; // 10 1183 t.year = req.substring(i+18).toInt(); // 12 1184// snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", t.year, t.mon, t.mday , t.hour, t.min, t.sec); 1185// Serial.println(buff) ; 1186 DS3231_set(t); // set external RTC 1187 setTime((int)t.hour,(int)t.min,(int)t.sec,(int)t.mday,(int)t.mon,(int)t.year ) ; // set the internal RTC 1188 1189 break; 1190 case 't': // force NTP packet 1191 sendNTPpacket(timeServer); // send an NTP packet if requested to 1192 break; 1193 case 'S': // save all the params 1194 iDoSave = 2 ; 1195 break; 1196 case 'R': // read params back from eeprom 1197 iDoSave = 3 ; 1198 break; 1199 case 'Y': 1200 break; 1201 case 'X': 1202 break; 1203 default: 1204 break; 1205 } 1206 }else{ 1207 req.toLowerCase(); 1208 i = req.indexOf(".csv"); 1209 if (i != -1){ // have a request get a CSV filefrom the SD card 1210 i = req.indexOf(".csv"); 1211 Target.flush(); 1212 Target.println(F("HTTP/1.1 200 OK")); 1213 Target.println(F("Content-Type: text/csv")); 1214 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1215 Target.println(""); // this blank line be important 1216 SendFile(req.substring(4,i+4),Target); 1217 break; 1218 }else{ 1219 i = req.indexOf(".jpg"); 1220 if (i != -1){ // have a request get a CSV filefrom the SD card 1221 i = req.indexOf(".jpg"); 1222 Serial.println(req); 1223 Serial.println(req.substring(4,i+4)); 1224 Target.flush(); 1225 Target.println(F("HTTP/1.1 200 OK")); 1226 Target.println(F("Content-Type: image/jpeg")); 1227 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1228 Target.println(""); // this blank line be important 1229 SendFile(req.substring(4,i+4),Target); 1230 break; 1231 }else{ 1232 i = req.indexOf("index.htm"); 1233 if (i != -1){ // have a request get a CSV filefrom the SD card 1234 Target.flush(); 1235 Target.println(F("HTTP/1.1 200 OK")); 1236 Target.println(F("Content-Type: text/html")); 1237 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1238 Target.println(""); // this blank line be important 1239 Target.println(F("<!DOCTYPE HTML>")); 1240 Target.println(F("<head><title>Team Trouble SD Card</title>")); 1241 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1242 Target.print(F("</head><body><html><center><b><h2>Team Trouble SD Card</h2></b><br><pre>")); 1243 File root = SD.open("/"); 1244 printDirectory(root,0,Target,"/"); 1245 root.close(); 1246 Target.println("</pre><br><br><a href=''>Home Page</a></body></html>"); 1247 break; 1248 }else{ 1249 i = req.indexOf("stats.htm"); 1250 if (i != -1){ // have a request get a status.htm 1251 Target.flush(); 1252 Target.println(F("HTTP/1.1 200 OK")); 1253 Target.println(F("Content-Type: text/html")); 1254 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1255 Target.println(""); // this blank line be important 1256 Target.println(F("<!DOCTYPE HTML>")); 1257 Target.println(F("<head><title>Stats Page</title>")); 1258 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1259 Target.print(F("</head><body><html><center><b><h2>Stats Page</h2></b>")); 1260 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", tc.year, tc.mon, tc.mday , tc.hour, tc.min, tc.sec); 1261 Target.println(buff) ; 1262 Target.println(F("</table><br><br><a href=''>Home Page</a></body></html>")); 1263 break; 1264 } 1265 } 1266 } 1267 } 1268 } 1269 1270 i = req.indexOf("?tmode="); 1271 if (i != -1){ // have a request to set the tracking mode 1272 iTrackMode = req.substring(i+7).toInt() ; 1273 if (( iTrackMode < -1) || ( iTrackMode > 4 )){ 1274 iTrackMode = -1 ; 1275 } 1276 } 1277 i = req.indexOf("?tzone="); 1278 if (i != -1){ // have a request to set the time zone 1279 timezone = req.substring(i+7).toInt() ; 1280 if (( timezone < -23) || ( timezone > 23 )){ 1281 timezone = 10 ; 1282 } 1283 } 1284 i = req.indexOf("?mylat="); //lat 1285 if (i != -1){ // have a request to set the latitude 1286 latitude = req.substring(i+7).toFloat() ; 1287 if (( latitude < -90) || ( latitude > 90 )){ 1288 latitude = -34.051219 ; 1289 } 1290 } 1291 i = req.indexOf("?mylon="); // long 1292 if (i != -1){ // have a request to set the logitude 1293 longitude = req.substring(i+7).toFloat() ; 1294 if (( longitude < -180) || ( longitude > 180 )){ 1295 longitude = 142.013618 ; 1296 } 1297 } 1298 i = req.indexOf("?minay="); 1299 if (i != -1){ // have a request to set minimum angle Y 1300 yMinVal = req.substring(i+7).toFloat() ; 1301 if (( yMinVal < -70) || ( yMinVal > 50 )){ 1302 yMinVal = -65 ; // set to default 1303 } 1304 } 1305 i = req.indexOf("?minax="); 1306 if (i != -1){ // have a request to set minimum angle X 1307 xMinVal = req.substring(i+7).toFloat() ; 1308 if (( xMinVal < -10) || ( xMinVal > 60 )){ 1309 xMinVal = 0 ; // set to default 1310 } 1311 } 1312 i = req.indexOf("?maxay="); 1313 if (i != -1){ // have a request to set maximum angle Y 1314 yMaxVal = req.substring(i+7).toFloat() ; 1315 if (( yMaxVal < -70) || ( yMaxVal > 50 )){ 1316 yMaxVal = 45 ; // set to default 1317 } 1318 } 1319 i = req.indexOf("?maxax="); 1320 if (i != -1){ // have a request to set maximum angle X 1321 xMaxVal = req.substring(i+7).toFloat() ; 1322 if (( xMaxVal < -10) || ( xMaxVal > 60 )){ 1323 xMaxVal = 50 ; // set to default 1324 } 1325 } 1326 i = req.indexOf("?paray="); 1327 if (i != -1){ // have a request to set park angle Y 1328 dyPark = req.substring(i+7).toFloat() ; 1329 if (( dyPark < -70) || ( dyPark > 50 )){ 1330 dyPark = 0 ; // set to default 1331 } 1332 } 1333 i = req.indexOf("?parax="); 1334 if (i != -1){ // have a request to set park angle X 1335 dxPark = req.substring(i+7).toFloat() ; 1336 if (( dxPark < -10) || ( dxPark > 60 )){ 1337 dxPark = 6 ; // set to default 1338 } 1339 } 1340 i = req.indexOf("?offay="); 1341 if (i != -1){ // have a request to set offset angle Y 1342 yzOffset = req.substring(i+7).toFloat() ; 1343 if (( yzOffset < -20) || ( yzOffset > 20 )){ 1344 yzOffset = 0 ; // set to default 1345 } 1346 } 1347 i = req.indexOf("?offax="); 1348 if (i != -1){ // have a request to set offset angle X 1349 xzOffset = req.substring(i+7).toFloat() ; 1350 if (( xzOffset < -20) || ( xzOffset > 20 )){ 1351 xzOffset = 0 ; // set to default 1352 } 1353 } 1354 i = req.indexOf("?hysay="); 1355 if (i != -1){ // have a request to set Hysterisis angle 1356 yzH = req.substring(i+7).toFloat() ; 1357 if (( yzH < -20) || ( yzH > 20 )){ 1358 yzH = 4 ; // set to default 1359 } 1360 } 1361 i = req.indexOf("?hysax="); 1362 if (i != -1){ // have a request to set Hysterisis angle 1363 xzH = req.substring(i+7).toFloat() ; 1364 if (( xzH < -20) || ( xzH > 20 )){ 1365 xzH = 4 ; // set to default 1366 } 1367 } 1368 i = req.indexOf("?taray="); 1369 if (i != -1){ // have a request to set Hysterisis angle 1370 yzTarget = req.substring(i+7).toFloat() ; 1371 if (( yzTarget < -70) || ( yzTarget > 50 )){ 1372 yzTarget = 0 ; // set to default 1373 } 1374 } 1375 i = req.indexOf("?tarax="); 1376 if (i != -1){ // have a request to set Hysterisis angle 1377 xzTarget = req.substring(i+7).toFloat() ; 1378 if (( xzTarget < -10) || ( xzTarget > 60 )){ 1379 xzTarget = 0 ; // set to default 1380 } 1381 } 1382 1383 i = req.indexOf("?mulax="); 1384 if (i != -1){ // have a request to set Axis Multiplier 1385 xMul = req.substring(i+7).toFloat() ; 1386 if (( xMul < -10) || ( xMul > 10 )){ 1387 xMul = 1.0 ; // set to default 1388 } 1389 } 1390 i = req.indexOf("?mulay="); 1391 if (i != -1){ // have a request to set Axis Multiplier 1392 yMul = req.substring(i+7).toFloat() ; 1393 if (( yMul < -10) || ( yMul > 10 )){ 1394 yMul = 1.0 ; // set to default 1395 } 1396 } 1397 i = req.indexOf("?mulaz="); 1398 if (i != -1){ // have a request to set Axis Multiplier 1399 zMul = req.substring(i+7).toFloat() ; 1400 if (( zMul < -10) || ( zMul > 10 )){ 1401 zMul = 1.0 ; // set to default 1402 } 1403 } 1404 i = req.indexOf("?xyswp="); 1405 if (i != -1){ // have a request to set the time zone 1406 iXYS = req.substring(i+7).toInt() ; 1407 if (( iXYS < 0) || ( iXYS > 1 )){ 1408 iXYS = 0 ; 1409 } 1410 } 1411 i = req.indexOf("?nisht="); 1412 if (i != -1){ // have a request to set the time zone 1413 iNightShutdown = req.substring(i+7).toInt() ; 1414 if (( iNightShutdown < 0) || ( iNightShutdown > 1 )){ 1415 iNightShutdown = 0 ; 1416 } 1417 } 1418 1419 1420 1421 Target.flush(); 1422 Target.println(F("HTTP/1.1 200 OK")); 1423 Target.println(F("Content-Type: text/html")); 1424 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1425 Target.println(""); // this blank line be important 1426 Target.println(F("<!DOCTYPE HTML>")); 1427 Target.println(F("<head><title>Team Trouble - Solar Tracker</title>")); 1428 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1429 1430 Target.print(F("</head><body><html><center><h2>")); 1431 Target.print(String(trackername).substring(0,16)); 1432 Target.print(F(" Solar Tracker</h2>")); 1433 1434 if (hasRTC){ 1435 DS3231_get(&td); 1436 } 1437 Target.println(F("<b>Clocks</b>")) ; 1438 Target.println(F("<table border=1 title='Clocks'>")); 1439 Target.println(F("<tr><th>Clock Source</th><th>Time</th></tr>")); 1440 Target.print(F("<tr><td>Dallas RTC</td><td>")); 1441 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", td.year, td.mon, td.mday , tc.hour, tc.min, tc.sec); 1442 Target.print(buff) ; 1443 sendTDTREnd(); 1444 Target.println(F("</td></tr>")); 1445 Target.print(F("<tr><td>Last NTP</td><td>")); 1446 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", t.year, t.mon, t.mday , t.hour, t.min, t.sec); 1447 Target.print(buff) ; 1448 sendTDTREnd(); 1449 Target.print(F("<tr><td>Last GPS</td><td>")); 1450 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", tg.year, tg.mon, tg.mday , tg.hour, tg.min, tg.sec); 1451 Target.print(buff) ; 1452 sendTDTREnd(); 1453 Target.print(F("<tr><td><b>Arduino Time</b></td><td><b>")); 1454 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", year(), month(), day() , hour(), minute(), second()); 1455 Target.print(buff) ; 1456 sendTDTREnd(); 1457 Target.println(F("</table>")); 1458 1459 Target.println(F("<br><b>Tracker Control System</b>")) ; 1460 1461 Target.println(F("<table border=1 title='Tracker Control'>")); 1462 Target.println(F("<tr><th> Parameter</th><th>Value</th></tr>")); 1463// Target.println("<tr><td>Tracking Mode</td><td align=center>" + String(iTrackMode) + "</td></tr>" ) ; 1464 1465 Target.print(F("<form method=get action=/><tr><td>Tracking Mode</td><td align=center>")) ; 1466 Target.print(F("<select name='tmode'>")); 1467 for (i = -1 ; i < 5 ; i++ ){ 1468 Target.print(F("<option value='")); 1469 Target.print(i) ; 1470 if ( iTrackMode == i ){ 1471 Target.print(F("' SELECTED>")); 1472 }else{ 1473 Target.print(F("'>")); 1474 } 1475 Target.print(i); 1476 Target.print(" "); 1477 switch (i){ 1478 case -1: 1479 Target.print(F("Track Both Park Both")); 1480 break; 1481 case 0: 1482 Target.print(F("Track Both Park Only E/W")); 1483 break; 1484 case 1: 1485 Target.print(F("Track and Park E/W Only")); 1486 break; 1487 case 2: 1488 Target.print(F("Track and Park N/S Only")); 1489 break; 1490 case 3: 1491 Target.print(F("Dont Track Dont Park")); 1492 break; 1493 case 4: 1494 Target.print(F("Dont Track Park Both")); 1495 break; 1496 } 1497 } 1498 Target.print(F("</select>")) ; 1499 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1500 1501 Target.print(F("<form method=get action=/><tr><td>Time Zone</td><td align=center>")) ; 1502 Target.print(F("<input type='text' name='tzone' value='")); 1503 Target.print(timezone); 1504 Target.print(F("' size=6 maxlength=2>")) ; 1505 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1506 1507 Target.print(F("<form method=get action=/><tr><td>Latitude +N -S</td><td align=center>")) ; 1508 Target.print(F("<input type='text' name='mylat' value='")); 1509 Target.print(latitude,8); 1510 Target.print(F("' size=12>")) ; 1511 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1512 1513 Target.print(F("<form method=get action=/><tr><td>Longitude</td><td align=center>")) ; 1514 Target.print(F("<input type='text' name='mylon' value='")); 1515 Target.print(longitude,8); 1516 Target.print(F("' size=12>")) ; 1517 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1518 1519 Target.print(F("<form method=get action=/><tr><td>X (N/S) Axis Multiplier</td><td align=center>")) ; 1520 Target.print(F("<input type='text' name='mulax' value='")); 1521 Target.print(xMul,2); 1522 Target.print(F("' size=5>")) ; 1523 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1524 1525 Target.print(F("<form method=get action=/><tr><td>Y (E/W) Axis Multiplier</td><td align=center>")) ; 1526 Target.print(F("<input type='text' name='mulay' value='")); 1527 Target.print(yMul,2); 1528 Target.print(F("' size=5>")) ; 1529 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1530 1531 Target.print(F("<form method=get action=/><tr><td>Z (Vert) Axis Multiplier</td><td align=center>")) ; 1532 Target.print(F("<input type='text' name='mulaz' value='")); 1533 Target.print(zMul,2); 1534 Target.print(F("' size=5>")) ; 1535 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1536 1537 Target.print(F("<form method=get action=/><tr><td>X<->Y Axis Swap</td><td align=center>")) ; 1538 Target.print(F("<select name='xyswp'>")); 1539 if (iXYS == 0 ){ 1540 Target.print(F("<option value='0' SELECTED>0 Normal")); 1541 Target.print(F("<option value='1'>1 Swapped")); 1542 }else{ 1543 Target.print(F("<option value='0'>0 Normal")); 1544 Target.print(F("<option value='1' SELECTED>1 Swapped")); 1545 } 1546 Target.println(F("</select></td><td><input type='submit' value='SET'></td></tr></form>")); 1547 1548 Target.print(F("<form method=get action=/><tr><td>Night Shutdown</td><td align=center>")) ; 1549 Target.print(F("<select name='nisht'>")); 1550 if (iNightShutdown == 0 ){ 1551 Target.print(F("<option value='0' SELECTED>0 Shutdown at Night")); 1552 Target.print(F("<option value='1'>1 Always Active")); 1553 }else{ 1554 Target.print(F("<option value='0'>0 Shutdown at Night")); 1555 Target.print(F("<option value='1' SELECTED>1 Always Active")); 1556 } 1557 Target.println(F("</select></td><td><input type='submit' value='SET'></td></tr></form>")); 1558 1559 Target.println(F("<form method=get action=/><tr><td>Tracker Name</td><td align=center><input type='text' name='tname' value='")); 1560 Target.println(String(trackername)) ; 1561 Target.println(F("' size=16 maxlength=16><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>")); 1562 1563 Target.println(F("<tr><td>Solar Elevation Deg</td><td align=center>")); 1564 Target.println(String(solar_el_deg,3)) ; 1565 Target.println(F("</td><td>(Deg)")); 1566 sendTDTREnd(); 1567 1568 Target.println(F("<tr><td>Solar Azomuth</td><td align=center>")); 1569 Target.println(String(solar_az_deg,3)) ; 1570 Target.println(F("</td><td>(Deg)")); 1571 sendTDTREnd(); 1572 1573 Target.println(F("<tr><td>Sunrise</td><td align=center>")); 1574 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunrise), MinSolarTime(sunrise)); 1575 Target.println(buff) ; 1576 Target.println(F("</td><td>(hh:mm)")); 1577 sendTDTREnd(); 1578 1579 Target.println(F("<tr><td>Sunset</td><td align=center>")); 1580 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunset), MinSolarTime(sunset)); 1581 Target.println(buff) ; 1582 Target.println(F("</td><td>(hh:mm)")); 1583 sendTDTREnd(); 1584 1585 Target.println(F("<tr><td>Day or Night</td><td align=center>")); 1586 if ( iDayNight == 1 ){ 1587 Target.println(F("DAY")); 1588 }else{ 1589 Target.println(F("NIGHT")); 1590 } 1591 sendTDTREnd(); 1592 1593 Target.println(F("<tr><td>GPS lock age</td><td align=center>")); 1594 if ( fixage < 10000 ) { 1595 Target.println(String(fixage)) ; 1596 }else{ 1597 Target.println(F("-- No Lock --")) ; 1598 } 1599 Target.println(F("</td><td>(ms)")); 1600 sendTDTREnd(); 1601 1602 Target.println(F("<tr><td>GPS Satellites</td><td align=center>")); 1603 if ( gps.satellites() == 255 ){ 1604 Target.println(F("-- No Lock --")) ; 1605 }else{ 1606 Target.println(String(gps.satellites())) ; 1607 } 1608 sendTDTREnd(); 1609 1610 Target.println(F("<tr><td>GPS Chars</td><td align=center>")); 1611 Target.println(String(gpschars)) ; 1612 sendTDTREnd(); 1613 1614 Target.println(F("<tr><td>RTC Temperature</td><td align=center>")); 1615 Target.println(String(T,2)) ; 1616 Target.println(F("</td><td>(C)")); 1617 sendTDTREnd(); 1618 1619 Target.println(F("<tr><td>P/T temp</td><td align=center>")); 1620 Target.println(String(gT)) ; 1621 Target.println(F("</td><td>(C)")); 1622 sendTDTREnd(); 1623 1624 Target.println(F("<tr><td>Pressue</td><td align=center>")); 1625 Target.println(String(Pr)) ; 1626 Target.println(F("</td><td>(mBar)")); 1627 sendTDTREnd(); 1628 1629 Target.println(F("<tr><td>Gyro X</td><td align=center>")); 1630 Target.println(String(xRoll)) ; 1631 sendTDTREnd(); 1632 1633 Target.println(F("<tr><td>Gyro Y</td><td align=center>")); 1634 Target.println(String(yRoll)) ; 1635 sendTDTREnd(); 1636 1637 Target.println(F("<tr><td>Gyro Z</td><td align=center>")); 1638 Target.println(String(zRoll)) ; 1639 sendTDTREnd(); 1640 Target.println(F("</table><br>")); 1641 1642 Target.println(F("<table border=1 title='Stracker Status'>")); 1643 Target.println(F("<tr><th>Parameter</th><th>E/W Value</th><th>.</th><th>N/S Value</th><th>.</th></tr>")); 1644 1645 Target.print(F("<tr><td>Min Angle</td><td><form method=get action=/><input type='text' name='minay' value='")); 1646 Target.print(String(yMinVal)); 1647 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='minax' value='")); 1648 Target.print(String(xMinVal)); 1649 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1650 1651 Target.print(F("<tr><td>Max Angle</td><td><form method=get action=/><input type='text' name='maxay' value='")); 1652 Target.print( String(yMaxVal)); 1653 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='maxax' value='")); 1654 Target.print( String(xMaxVal)); 1655 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1656 1657 Target.print(F("<tr><td>Park Angle</td><td><form method=get action=/><input type='text' name='paray' value='")); 1658 Target.print(String(dyPark)); 1659 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='parax' value='")); 1660 Target.print(String(dxPark)); 1661 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1662 1663 Target.print(F("<tr><td>Offest Angle</td><td><form method=get action=/><input type='text' name='offay' value='")); 1664 Target.print(String(yzOffset)); 1665 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='offax' value='")); 1666 Target.print(String(xzOffset)); 1667 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1668 1669 Target.print(F("<tr><td>Hysteris Angle</td><td><form method=get action=/><input type='text' name='hysay' value='")); 1670 Target.print(String(yzH)); 1671 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='hysax' value='")); 1672 Target.print(String(xzH)); 1673 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1674 1675 if ( iTrackMode == 3 ){ 1676 Target.print(F("<tr><td>Target Angle</td><td><form method=get action=/><input type='text' name='taray' value='")); 1677 Target.print(String(yzTarget)); 1678 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='tarax' value='")); 1679 Target.print(String(xzTarget)); 1680 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1681 }else{ 1682 Target.print(F("<tr><td>Target Angle</td><td>")); 1683 Target.print(String(yzTarget)); 1684 Target.print(F("</td><td>(Deg)</td><td>")) ; 1685 Target.print(String(xzTarget)); 1686 Target.println(F("</td><td>(Deg)</td></tr>")) ; 1687 } 1688 1689 Target.print(F("<tr><td>Current Sensor Angle</td><td>")); 1690 Target.print(String(yzAng)); 1691 Target.print(F("</td><td>(Deg)</td><td>")) ; 1692 Target.print(String(xzAng)); 1693 Target.println(F("</td><td>(Deg)</td></tr>")) ; 1694 1695 Target.println(F("</table><br>")) ; 1696 1697// Target.println("<br><br>"); 1698// Target.println("<br><br>"); 1699 if ( hasSD ) { 1700 Target.println(F("<br><br><a href='index.htm'>Data Logs Files</a><br>")) ; 1701 Target.println(F("<a href='stats.htm'>Last 24 Hours Stats</a><br>")) ; 1702 } 1703 Target.println(F("<a href='/gpio/t'>Force NTP request</a><br>")) ; 1704 Target.println(F("<a href='/gpio/S'>Save Parameters to EEPROM</a><br>")) ; 1705 Target.println(F("<a href='/gpio/R'>Load Parameters from EEPROM</a><br>")) ; 1706 Target.println(F("</body></html>")); 1707 break; 1708 } 1709 } 1710 1711 delay(1); // give the web browser time to receive the data 1712 Target.stop(); // close the connection: 1713 Serial.println("Target disconnected"); 1714} 1715 1716 1717void printDirectory(File dir, int numTabs, EthernetClient Target, String MyFolder) { 1718File entry ; 1719long lTB ; 1720// Serial.println("Called " + String(numTabs)); 1721 if( numTabs == 0 ) { 1722 lTB = 0 ; 1723 dir.rewindDirectory(); // start at the begining 1724 Target.println("<table border=0>"); 1725 } 1726 while(entry = dir.openNextFile()) { // single = very subtle assign and test 1727// Serial.println(entry.name()); 1728 if (entry.isDirectory()) { 1729 MyFolder = String("/") + entry.name() ; 1730 Target.println("<tr><td><b>" + MyFolder + "</td></tr>" ); 1731 printDirectory(entry, numTabs+1,Target, MyFolder); 1732// Serial.println("Returned "); 1733 }else{ 1734 Target.print("<tr><td><A href='"); 1735 Target.print(MyFolder+ "/" + entry.name()); 1736 Target.print("'>"); 1737 Target.print(entry.name()); 1738 Target.print("</a></td><td> </td><td align=right>"); 1739 Target.print(entry.size(), DEC); 1740 lTB += entry.size() ; 1741 Target.println("</td></tr>"); 1742 } 1743 } 1744 if( numTabs == 0 ) { 1745 Target.println("<tr><td> </td></tr>"); 1746 Target.print("<tr><td><b>Total Bytes</td><td> </td><td align=right><b>"); 1747 Target.print(lTB, DEC); 1748 Target.println("</td></tr>"); 1749 Target.println("</table>"); 1750 } 1751} 1752 1753int SendFile (String FileName , EthernetClient Target ){ 1754 File dataFile = SD.open(FileName); 1755 if (dataFile) { // if the file is available, write to it: 1756 while (dataFile.available()) { 1757 Target.write(dataFile.read()); 1758 } 1759 dataFile.close(); 1760 }else { // if the file isn't open, pop up an error: 1761 Target.println("error opening " + FileName); 1762 } 1763} 1764 1765 1766float getPressure(double* Temp) 1767{ 1768 char status; 1769 double T,P; 1770 1771 status = pressure.startTemperature(); 1772 if (status != 0){ 1773 delay(status); // Wait for the measurement to complete: 1774 status = pressure.getTemperature(*Temp); 1775 if (status != 0){ 1776 status = pressure.startPressure(3); 1777 if (status != 0){ 1778 // Wait for the measurement to complete: 1779 delay(status); 1780 status = pressure.getPressure(P,*Temp); 1781 if (status != 0){ 1782 return(float(P)); 1783 } 1784 } 1785 } 1786 } 1787} 1788 1789
TRACKER_MEGA_TOP_GPS_PWM_SOFT.ino
c_cpp
Tracker for Ethernet shield uses both GPS and NTP to retrieve time
1#include <SFE_BMP180.h> 2#include <avr/wdt.h> 3#include <Wire.h> 4#include <SPI.h> 5#include <LSM303.h> // modified ... fixed a couple of bugs 6#include <LiquidCrystal_I2C.h> 7#include <L3G.h> 8#include "ds3231.h" 9#include <TimeLib.h> 10#include "ht16k33.h" 11#include <ModbusRtu.h> // Modified ... this no longer a stock lib - Slave supports register translation/mapping 12#include <EEPROM.h> 13#include <math.h> 14#include <Ethernet.h> 15#include <SD.h> 16#include <EthernetUdp.h> 17#include <TinyGPS.h> 18 19#define ID 1 20 21#define BUFF_MAX 32 22#define PARK_EAST 1 23#define PARK_WEST 2 24#define PARK_NORTH 3 25#define PARK_SOUTH 4 26#define PARK_FLAT 5 27 28#define MOTOR_DWELL 100 29 30#define MAX_MODBUS_DATA 70 31 32#define HT16K33_DSP_NOBLINK 0 // constants for the half arsed cheapo display 33#define HT16K33_DSP_BLINK1HZ 4 34#define HT16K33_DSP_BLINK2HZ 2 35#define HT16K33_DSP_BLINK05HZ 6 36 37 38const byte ENCODER_PINA = 2; // encoder connects - interupt pin 39const byte ENCODER_PINB = 3; // non interupt pin 40const byte ENCODER_PB = 8; 41 42const byte RELAY_YZ_DIR = 8; // DIR 1 Y+ Y- East / West Was the X+ N relay BROWN 43const byte RELAY_YZ_PWM = 7; // PWM 2 Speed East / West Was the Y- E relay ORANGE 44const byte RELAY_XZ_PWM = 6; // PWM 2 Speed North / South Was the Y+ W relay YELLOW 45const byte RELAY_XZ_DIR = 5; // DIR 1 X+ X- North / South Was the X- S relay BLUE 46 47 48const int chipSelect = 4; 49 50const byte UNUSED09 = 9; // cycle timer 26 Hz 38ms period 51const byte UNUSED10 = 10; 52const byte UNUSED11 = 11; 53const byte WATCHDOG = 12; 54 55IPAddress ip(192,168,2,177) ; 56IPAddress MyDNS(139,130,4,4) ; 57unsigned int localPort = 8888; // local port to listen for UDP packets 58EthernetServer server(80) ; 59EthernetClient client ; 60 61byte mac[] = { 0x44, 0x6f, 0x75, 0x67, 0x61, 0x6c }; // Dougal in ASCII 62char timeServer[] = "au.pool.ntp.org"; // time.nist.gov NTP server 63const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 64byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets 65 66 67EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP 68 69static bool hasSD = false; 70static bool hasNet = false; 71static bool hasGyro = false; 72static bool hasRTC = false; 73static bool hasPres = false ; 74 75L3G gyro; 76LSM303 compass; 77LiquidCrystal_I2C lcd(0x27); // Set the LCD I2C address I modified the lib for default wiring 78 79SFE_BMP180 pressure; 80HT16K33 HT; 81 82TinyGPS gps; 83 84float ha ; 85float sunX ; 86float sunrise ; 87float sunset ; 88Modbus mb_slave(ID, 2, 0); // this is slave ID and RS-232 or USB-FTDI 89time_t chiptime ; 90uint8_t rtc_status ; 91//uint8_t time[8]; 92int motor_recycle = 0 ; 93char recv[BUFF_MAX]; 94unsigned int recv_size = 0; 95unsigned long prev_millis; 96uint8_t u8state; // machine state 97uint8_t u8query; // pointer to message query 98char buff[BUFF_MAX]; 99char trackername[18] ; 100unsigned long gpschars ; 101float heading ; // MODBUS MAP 102struct ts t; // 103struct ts td; // 104struct ts tg; // 105struct ts tc; // 106int iNightShutdown ; // 107time_t setchiptime ; // 68 if set to non zero this will trigger a time set event 108float zAng ; // 66 109float xMul = 1.0 ; // 64 110float yMul = 1.0 ; // 62 111float zMul = 1.0 ; // 60 112int iXYS = 0 ; // 59 113int iSave = 0 ; // 58 114int iDoSave = 0 ; // 57 115int iGPSLock = 0 ; // 56 116unsigned long fixage ; // 54 117float xRoll = 0.0 ; // 52 118float yRoll = 0.0 ; // 50 119float zRoll = 0.0 ; // 48 120float gT ; // 46 temp from sensor 121float Pr ; // 44 presure sensor 122float alt ; // 42 altitude from GPS 123float T; // 40 temperature of board (if has RTC) 124float xzTarget ; // 38 target for angles 125float yzTarget ; // 36 126float xzH ; // 34 hyserisis zone 127float yzH ; // 32 128float xzAng; // 30 current angles 129float yzAng; // 28 130float xzOffset; // 26 offset xz 131float yzOffset; // 24 offset yz 132float dyPark; // 22 parking position 133float dxPark; // 20 134float xMinVal ; // 18 Min and Max values X - N/S 135float xMaxVal ; // 16 136float yMinVal ; // 14 Y -- E/W 137float yMaxVal ; // 12 138float latitude; // 10 139float longitude; // 8 140int timezone; // 7 141int iDayNight ; // 6 142float solar_az_deg; // 4 143float solar_el_deg; // 2 144int iTrackMode ; // 1 145int iMode ; // 0 146 147int iPMode; 148int iPWM_YZ ; 149int iPWM_XZ ; 150int iPowerUp = 0 ; 151 152unsigned long tempus; 153int8_t state1 = 0; 154int8_t rtc_hour = 0; 155int8_t rtc_min = 0 ; 156int8_t rtc_sec = 0 ; 157 158void LoadParamsFromEEPROM(bool bLoad){ 159 if ( bLoad ) { 160 xzH = LoadFloatFromEEPROM(0,0.1,20.0,4.0); // hysterisis NS 161 yzH = LoadFloatFromEEPROM(1,0.1,20.0,4.0); // "" EW 162 163 dyPark = LoadFloatFromEEPROM(2,-70.0,50.0,0); 164 dxPark = LoadFloatFromEEPROM(3,-5.0,50.0,0.0); 165 166 xzOffset = LoadFloatFromEEPROM(4,-90.0,90.0,0); // NS 167 yzOffset = LoadFloatFromEEPROM(5,-90.0,90.0,0); // EW 168 169 xzTarget = LoadFloatFromEEPROM(6,-90.0,90.0,0); // NS 170 yzTarget = LoadFloatFromEEPROM(7,-90.0,90.0,0); // EW 171 172 xMinVal = LoadFloatFromEEPROM(8,-10.0,60.0,0.0); // NS 173 xMaxVal = LoadFloatFromEEPROM(9,-10.0,60.0,45); 174 175 yMinVal = LoadFloatFromEEPROM(10,-70.0,50.0,-65); // EW 176 yMaxVal = LoadFloatFromEEPROM(11,-70.0,50.0,45); 177 178 iTrackMode = LoadIntFromEEPROM(12,-1,4,0); 179 180 latitude = LoadFloatFromEEPROM(13,-90.0,90.0,-34.051219); 181 longitude = LoadFloatFromEEPROM(14,-180.0,180.0,142.013618); 182 timezone = LoadIntFromEEPROM(15,0,23,10); 183 xMul = LoadFloatFromEEPROM(16,-10,10,1); 184 yMul = LoadFloatFromEEPROM(17,-10,10,1); 185 zMul = LoadFloatFromEEPROM(18,-10,10,1); 186 iXYS = LoadIntFromEEPROM(19,0,1,0); 187 if ( xMul == 0.0 ) // zero is rubbish value so take 1.0 as the default 188 xMul = 1.0 ; 189 if ( yMul == 0.0 ) 190 yMul = 1.0 ; 191 if ( zMul == 0.0 ) 192 zMul = 1.0 ; 193 iNightShutdown = LoadIntFromEEPROM(20,0,1,1); 194 EEPROM.get(0 + (30 * sizeof(float)) , trackername ); 195 }else{ 196 EEPROM.put( 0 , xzH ); 197 EEPROM.put(0 + (1 * sizeof(float)) , yzH ); 198 EEPROM.put(0 + (2 * sizeof(float)) , dyPark ); 199 EEPROM.put(0 + (3 * sizeof(float)) , dxPark ); 200 EEPROM.put(0 + (4 * sizeof(float)) , xzOffset ); 201 EEPROM.put(0 + (5 * sizeof(float)) , yzOffset ); 202 EEPROM.put(0 + (6 * sizeof(float)) , xzTarget ); 203 EEPROM.put(0 + (7 * sizeof(float)) , yzTarget ); 204 EEPROM.put(0 + (8 * sizeof(float)) , xMinVal ); 205 EEPROM.put(0 + (9 * sizeof(float)) , xMaxVal ); 206 EEPROM.put(0 + (10 * sizeof(float)) , yMinVal ); 207 EEPROM.put(0 + (11 * sizeof(float)) , yMaxVal ); 208 EEPROM.put(0 + (12 * sizeof(float)) , iTrackMode ); 209 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 210 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 211 EEPROM.put(0 + (15 * sizeof(float)) , timezone ); 212 EEPROM.put(0 + (16 * sizeof(float)) , xMul ); 213 EEPROM.put(0 + (17 * sizeof(float)) , yMul ); 214 EEPROM.put(0 + (18 * sizeof(float)) , zMul ); 215 EEPROM.put(0 + (19 * sizeof(float)) , iXYS ); 216 EEPROM.put(0 + (20 * sizeof(float)) , iNightShutdown ); 217 EEPROM.put(0 + (30 * sizeof(float)) , trackername); 218 } 219} 220 221void setup() { 222 int led ; 223 224 Wire.begin(); 225 lcd.begin(20, 4); 226 lcd.home(); 227 lcd.setBacklightPin(3, NEGATIVE); 228 lcd.noCursor(); 229 lcd.clear(); 230 231 MCUSR &= ~_BV(WDRF); 232 wdt_disable(); 233 234 compass.init(); 235 compass.enableDefault(); 236 compass.setTimeout(1000); 237 238 Serial.begin(115200); // program/debug port 239 Serial1.begin(9600); // GPS port 240// Serial2.begin(115200); // Modbus Port to esp 241 Serial3.begin(115200); // EPS8266 serial converter 242 243 if (gyro.init()) { 244 gyro.enableDefault(); 245 hasGyro = true ; 246 } 247 if (pressure.begin()){ 248 Serial.println("BMP180 init success"); 249 hasPres = true ; 250 } 251 pinMode(RELAY_XZ_DIR, OUTPUT); // Outputs for PWM motor control 252 pinMode(RELAY_XZ_PWM, OUTPUT); // 253 pinMode(RELAY_YZ_PWM, OUTPUT); // 254 pinMode(RELAY_YZ_DIR, OUTPUT); // 255 iPWM_YZ = 0 ; 256 iPWM_XZ = 0 ; 257 pinMode(13, OUTPUT); // 258 digitalWrite(13, HIGH ); 259 ActivateRelays(0); // call an all stop first 260 261 mb_slave.begin( 9600 ); // RS-232 to base of tower 262 tempus = millis() + 100; 263 264 pinMode(UNUSED09, OUTPUT); // unused so dont leave floating set as output 265 pinMode(UNUSED10, OUTPUT); // 266 pinMode(UNUSED11, OUTPUT); // 267 pinMode(WATCHDOG, OUTPUT); // 268 digitalWrite(WATCHDOG,HIGH); 269 270 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical 271 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300}; 272 273 LoadParamsFromEEPROM(true); 274 275 DS3231_init(DS3231_INTCN); // look for a rtc 276 DS3231_get(&tc); 277 DS3231_get(&td); 278 rtc_status = DS3231_get_sreg(); 279 if ((tc.mon == 0 )&& (tc.mday==0)){ // no rtc to load off 280 setTime (0,0,0,21,9,2017) ; // midnight on the equinox (will deactivae motors till gets a valid time) ; 281 }else{ 282 setTime((int)tc.hour,(int)tc.min,(int)tc.sec,(int)tc.mday,(int)tc.mon,(int)tc.year ) ; // set the internal RTC 283 hasRTC = true ; 284 } 285 286 HT.begin(0x00); 287 for (led = 0; led < 127; led++) { 288 HT.clearLedNow(led); 289 } 290 291 Serial.println("EtherNet init"); 292 if (SD.begin(chipSelect) || true){ 293 hasSD = true; 294 Serial.println("SD OK"); 295 Ethernet.begin(mac,ip,MyDNS); 296// Ethernet.begin(mac,ip); 297 if (Udp.begin(localPort)==1){ 298 hasNet = true ; 299 } 300 server.begin(); 301 } 302 Serial.print("server is at "); 303 Serial.println(Ethernet.localIP()); 304 305 306// wdt_enable(WDTO_8S); 307} 308 309// Arduino doesnt have these to we define from a sandard libruary 310float arcsin(float x) { 311 return (atan(x / sqrt(-x * x + 1))); 312} 313float arccos(float x) { 314 return (atan(x / sqrt(-x * x + 1)) + (2 * atan(1))); 315} 316// fractional orbital rotation in radians 317float gama(struct ts *tm) { 318 return ((2 * PI / 365 ) * DayOfYear(tm->year , tm->mon , tm->mday , tm->hour , tm->min )); 319} 320// equation of rime 321float eqTime(float g) { 322 return (229.18 * ( 0.000075 + ( 0.001868 * cos(g)) - (0.032077 * sin(g)) - (0.014615 * cos (2 * g)) - (0.040849 * sin(2 * g)))); 323} 324// declination of sun in radians 325float Decl(float g) { 326 return ( 0.006918 - (0.399912 * cos(g)) + (0.070257 * sin(g)) - (0.006758 * cos(2 * g)) + ( 0.000907 * sin(2 * g)) - ( 0.002697 * cos(3 * g)) + (0.00148 * sin(3 * g)) ); 327} 328float TimeOffset(float longitude , struct ts *tm , int timezone ) { 329 float dTmp ; 330 dTmp = (-4.0 * longitude ) + (60 * timezone) - eqTime(gama(tm)) ; 331 return (dTmp); 332} 333 334float TrueSolarTime(float longitude , struct ts *tm , int timezone ) { 335 float dTmp ; 336 dTmp = ( 60.0 * tm->hour ) + (1.0 * tm->min) + (1.0 * tm->sec / 60) - TimeOffset(longitude, tm, timezone) ; 337 return (dTmp); 338} 339float HourAngle(float longitude , struct ts *tm , int timezone) { 340 float dTmp; 341 dTmp = (TrueSolarTime(longitude, tm, timezone) / 4 ) - 180 ; // 720 minutes is solar noon -- div 4 is 180 342 return (dTmp); 343} 344// Hour angle for sunrise and sunset only 345float HA (float lat , struct ts *tm ) { 346 float latRad ; 347 latRad = lat * 2 * PI / 360 ; 348 return ( acos((cos(90.833 * PI / 180 ) / ( cos(latRad) * cos(Decl(gama(tm)))) - (tan(latRad) * tan(Decl(gama(tm)))))) / PI * 180 ); 349} 350 351float Sunrise(float longitude , float lat , struct ts *tm , int timezone) { 352 return (720 - ( 4.0 * (longitude + HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 353} 354float Sunset(float longitude , float lat , struct ts *tm , int timezone) { 355 return (720 - ( 4.0 * (longitude - HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 356} 357float SNoon(float longitude , float lat , struct ts *tm , int timezone) { 358 return (720 - ( 4.0 * (longitude + (60 * timezone) - eqTime(gama(tm)))) ) ; 359} 360 361float SolarZenithRad(float longitude , float lat , struct ts *tm , int timezone) { 362 float latRad ; 363 float decRad ; 364 float HourAngleRad ; 365 float dTmp ; 366 367 latRad = lat * 2 * PI / 360 ; 368 decRad = Decl(gama(tm)); 369 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 370 dTmp = acos((sin(latRad) * sin(decRad)) + (cos(latRad) * cos(decRad) * cos(HourAngleRad))); 371 return (dTmp) ; 372 373} 374float SolarElevationRad(float longitude , float lat , struct ts *tm , int timezone ) { 375 return ((PI / 2) - SolarZenithRad(longitude , lat , tm , timezone )) ; 376} 377 378float SolarAzimouthRad(float longitude , float lat , struct ts *tm , int timezone) { 379 float latRad ; 380 float decRad ; 381 float solarzenRad ; 382 float HourAngleRad ; 383 float dTmp ; 384 latRad = lat * 2 * PI / 360 ; 385 decRad = Decl(gama(tm)); 386 solarzenRad = SolarZenithRad ( longitude , lat , tm , timezone ) ; 387 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 388 dTmp = acos(((sin(decRad) * cos(latRad)) - (cos(HourAngleRad) * cos(decRad) * sin(latRad))) / sin(solarzenRad)) ; 389 if ( HourAngleRad < 0 ) { 390 return (dTmp) ; 391 } else { 392 return ((2 * PI) - dTmp) ; 393 } 394} 395 396 397void StopYZ(){ 398 iPWM_YZ=0 ; 399 motor_recycle = MOTOR_DWELL ; 400} 401void StopXZ(){ 402 iPWM_XZ=0 ; 403 motor_recycle = MOTOR_DWELL ; 404} 405 406void ActivateRelays(int iAllStop) { 407 if (motor_recycle > 0 ){ 408 motor_recycle-- ; 409 } 410 if ( iAllStop == 0 ) { 411 StopYZ() ; 412 StopXZ() ; 413 } else { 414 if (( iPWM_YZ==0 ) && (motor_recycle == 0 )){ 415 if (((yzAng ) < ( yzTarget - yzH )) ) { // do Y ie E/W before N/S 416 digitalWrite(RELAY_YZ_DIR, LOW) ; 417 iPWM_YZ=2 ; 418 } 419 if (((yzAng ) > (yzTarget + yzH )) ) { 420 digitalWrite(RELAY_YZ_DIR, HIGH) ; 421 iPWM_YZ=2 ; 422 } 423 } 424 if ( iPWM_YZ>0 ){ 425 if ((yzAng > yzTarget) && ( digitalRead(RELAY_YZ_DIR)==LOW )) { 426 StopYZ() ; 427 } 428 if ((yzAng < yzTarget) && ( digitalRead(RELAY_YZ_DIR)==HIGH )) { 429 StopYZ() ; 430 } 431 } 432 433 if (( iPWM_YZ==0)) { // if finished on E/W you can do N/S 434 if (( iPWM_XZ==0 ) && (motor_recycle == 0 )){ 435 if ((xzAng < ( xzTarget - xzH )) ) { // turn on if not in tolerance 436 digitalWrite(RELAY_XZ_DIR, LOW) ; 437 iPWM_XZ=2 ; 438 } 439 if ((xzAng > ( xzTarget + xzH )) ) { // turn on if not in tolerance 440 digitalWrite(RELAY_XZ_DIR, HIGH) ; 441 iPWM_XZ=2 ; 442 } 443 } 444 }else{ 445 if ((iPWM_XZ>0 )){ 446 StopXZ() ; 447 } 448 } 449 if ( iPWM_XZ>0 ){ 450 if ((xzAng > xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==LOW )) { // if on turn off 451 StopXZ() ; 452 } 453 if ((xzAng < xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==HIGH )) { // if on turn off 454 StopXZ() ; 455 } 456 } 457 } 458 if (iPWM_XZ>0){ 459 iPWM_XZ += 3 ; 460 } 461 if (iPWM_YZ>0){ 462 iPWM_YZ += 3 ; 463 } 464 iPWM_XZ = constrain(iPWM_XZ,0,254); 465 iPWM_YZ = constrain(iPWM_YZ,0,254); 466 analogWrite(RELAY_XZ_PWM,iPWM_XZ); 467 analogWrite(RELAY_YZ_PWM,iPWM_YZ); 468} 469 470void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 471 uint16_t tempdata[2] ; 472 float *tf ; 473 tf = (float * )&tempdata[0] ; 474 *tf = src_value ; 475 *dest_lo = tempdata[1] ; 476 *dest_hi = tempdata[0] ; 477} 478float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 479 uint16_t tempdata[2] ; 480 float *tf ; 481 tf = (float * )&tempdata[0] ; 482 tempdata[1] = dest_lo ; 483 tempdata[0] = dest_hi ; 484 return (*tf) ; 485} 486 487 488float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 489float tmp ; 490 EEPROM.get(0 + (address * sizeof(float)) , tmp ); 491 if (( tmp < minval ) || ( tmp > maxval )|| (NumberOK(tmp) == 1)) { 492 tmp = defaultval ; 493 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 494 } 495 return(tmp); 496} 497int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 498int tmp ; 499 EEPROM.get(0 + (address * sizeof(float)) , tmp ); // float.. yeah yeah I know... but it makes it compatible with the one above (easy on the brain) 500 if (( tmp < minval ) || ( tmp > maxval )) { 501 tmp = defaultval ; 502 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 503 } 504 return(tmp); 505} 506 507int NumberOK (float target) { 508 int tmp = 0 ; 509 tmp = isnan(target); 510 if ( tmp != 1 ) { 511 tmp = isinf(target); 512 } 513 return (tmp); 514} 515 516int SetTimeFromGPS(){ 517 byte hundredths ; 518 519 gps.crack_datetime((int *)&tg.year,(byte *)&tg.mon,(byte *) &tg.mday,(byte *) &tg.hour,(byte *) &tg.min,(byte *) &tg.sec , &hundredths, &fixage); 520 setTime((int)tg.hour,(int)tg.min,(int)tg.sec,(int)tg.mday,(int)tg.mon,(int)tg.year ) ; // set the internal RTC from last GPS time 521 chiptime = now() ; // get it back again 522 chiptime += (( timezone * SECS_PER_HOUR ) + ( fixage / 1000 )) ; // add the offset plus the fix age 523 setTime(chiptime); // set it again 524 if (hasRTC) { 525 tg.year = year(); 526 tg.mon = month() ; 527 tg.mday = day(); 528 tg.hour = hour() ; 529 tg.min = minute(); 530 tg.sec = second(); 531 DS3231_set(tg); //should also update this 532 } 533 return(0); 534} 535 536 537void loop() { 538 float P; 539 float sunInc; 540 float sunAng; 541 float xzRatio; 542 float yzRatio; 543 float decl ; 544 float eqtime ; 545 float dTmp ; 546 float heading ; 547 float tst ; 548 float flat, flon; 549 unsigned short goodsent; 550 unsigned short failcs; 551// int iYear , iMon , iMday , iHour , iMin , iSec ; 552 553 554 if (minute() != rtc_min) { // do onlyonce a minute 555 gps.stats(&gpschars, &goodsent , &failcs ); 556 gps.f_get_position(&flat, &flon,(long unsigned *) &fixage); // return in degrees 557 if (hasPres){ 558 Pr = getPressure((double *)&gT) ; 559 } 560 if (hasRTC) { 561 T = DS3231_get_treg(); 562 } 563 rtc_min = minute() ; 564 565 if ((fixage > 0 ) && ( fixage < 40000 )) { // wait till our fix is valid before we use the values 566 latitude = flat ; 567 longitude = flon ; 568 iGPSLock = gps.satellites() ; 569 alt = gps.f_altitude() ; 570 if (iPowerUp==0) { // only do this at startup so we have a better position ref for next time 571 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 572 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 573 iPowerUp = 1 ; 574 if (!hasNet ){ 575 SetTimeFromGPS(); 576 } 577 } 578 }else{ 579 iGPSLock = 0 ; // if no lock loook at internal clock 580 } 581 } 582 tc.year = year(); 583 tc.mon = month() ; 584 tc.mday = day(); 585 tc.hour = hour() ; 586 tc.min = minute(); 587 tc.sec = second(); 588 589 compass.read(); // this reads all 6 channels 590 if ( hasGyro ){ 591 gyro.read(); 592 xRoll = gyro.g.x ; 593 yRoll = gyro.g.y ; 594 zRoll = gyro.g.z ; 595 } 596 597 digitalWrite(UNUSED09,!digitalRead(UNUSED09)); // toggle this output so I can measure the cycle time with a scope 598 599 heading = compass.heading((LSM303::vector<int>) { 1, 0, 0 }); 600 601 if (( compass.a.z != 0) && (!compass.timeoutOccurred() )) { 602 zAng = (float)compass.a.z ; 603 if (iXYS == 0 ){ // Proper Job make it configurable 604 xzRatio = (float)compass.a.x * xMul / abs(zAng) ; // Normal 605 yzRatio = (float)compass.a.y * yMul / abs(zAng) ; 606 }else{ 607 xzRatio = (float)compass.a.y * xMul / abs(zAng) ; // Swapped 608 yzRatio = (float)compass.a.x * yMul / abs(zAng) ; 609 } 610 xzAng = ((float)atan(xzRatio) / PI * 180 ) + xzOffset ; // good old offsets or fudge factors 611 yzAng = ((float)atan(yzRatio) / PI * 180 ) + yzOffset ; 612// digitalWrite(13, LOW); 613 }else{ // try restarting the compass/accelerometer modual - cos he gone walkabout... 614 Wire.begin(); // reset the I2C 615 compass.init(); 616 compass.enableDefault(); 617 compass.setTimeout(1000); // BTW I fixed up the int / long issue in the time out function in the LM303 lib I was using 618 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical (just whirl it around a bit and records the min max !!) 619 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300 }; 620/* if (tc.sec % 2 == 0 ) { 621 digitalWrite(13, HIGH); 622 } else { 623 digitalWrite(13, LOW); 624 }*/ 625 HT.begin(0x00); 626 } 627 628 if (setchiptime > 0) { // update the arduino time from the modbus register then clear it... also set RTC if fitted 629 setTime(setchiptime) ; 630 if (hasRTC) { 631 tc.year = year(); 632 tc.mon = month() ; 633 tc.mday = day(); 634 tc.hour = hour() ; 635 tc.min = minute(); 636 tc.sec = second(); 637 DS3231_set(tc); //should also update this 638 } 639 setchiptime = 0 ; 640 } 641 642 if ( hour() != rtc_hour){ // update our time every hour if we can 643 if (iGPSLock == 0){ 644 if( hasNet ){ 645 sendNTPpacket(timeServer); // send an NTP packet to a time server every hour 646 }else{ 647 if (hasRTC) { 648 DS3231_get(&td); 649 setTime((int)td.hour,(int)td.min,(int)td.sec,(int)td.mday,(int)td.mon,(int)td.year ) ; // set the internal RTC from Dallas RTC 650 } 651 } 652 }else{ 653 if ((fixage > 0 ) && ( fixage < 10000 )) { // if the lock is less than 10 second old 654 SetTimeFromGPS(); 655 } 656 } 657 rtc_hour = hour() ; 658 } 659 660 if ( rtc_sec != second() ) { //only update once a second 661 wdt_reset(); // reset internal watchdog - good puppy 662 663 if (( tc.sec > 8 ) && ( tc.sec < 58 )) { // dont calculate arround the minute when time is updating from NTP or GPS as might get a not so funny result 664 digitalWrite(13,!digitalRead(13)); 665 solar_az_deg = SolarAzimouthRad(longitude, latitude, &tc, timezone) * 180 / PI ; 666 solar_el_deg = SolarElevationRad(longitude, latitude, &tc, timezone) * 180 / PI ; 667 668 decl = Decl(gama(&tc)) * 180 / PI ; 669 ha = HourAngle (longitude , &tc , timezone ) ; 670 sunrise = Sunrise(longitude, latitude, &tc, timezone) ; 671 sunset = Sunset(longitude, latitude, &tc, timezone); 672 tst = TrueSolarTime(longitude, &tc, timezone); 673 sunX = abs(latitude) + decl ; 674 if (solar_el_deg >= 0 ){ // day 675 iDayNight = 1 ; 676 }else{ // night 677 iDayNight = 0 ; 678 } 679 } 680 switch (iTrackMode) { 681 case 4: // both axis to park 682 yzTarget = dyPark ; // night park position E/W 683 xzTarget = dxPark ; // night park position N/S 684 break ; 685 case 3: // both axis off no tracking 686 break ; 687 case 2: // xz tracking NS 688 if ( iDayNight == 1 ) { 689 xzTarget = sunX ; // need to map the coordinate system correctly 690 } else { 691 xzTarget = dxPark ; // night park position 692 } 693 break; 694 case 1: // yz tracking EW 695 if (iDayNight == 1) { 696 yzTarget = ha ; 697 } else { 698 yzTarget = dyPark ; // night park position 699 } 700 break; 701 case -1: // set target to tracking and park both at nigh 702 if (iDayNight == 1) { 703 yzTarget = ha ; 704 xzTarget = sunX ; // need to map the coordinate system correctly 705 } else { 706 yzTarget = dyPark ; // night park position E/W 707 xzTarget = dxPark ; // night park position N/S 708 } 709 break; 710 default: // set target to tracking 711 if (iDayNight == 1) { 712 yzTarget = ha ; 713 xzTarget = sunX ; // need to map the coordinate system correctly 714 } else { 715 yzTarget = dyPark ; // night park position (dont park the other - leave till morning) 716 } 717 break; 718 } 719 xzTarget = constrain(xzTarget,xMinVal,xMaxVal); // constain function... very cool - dont leave home without it ! 720 yzTarget = constrain(yzTarget,yMinVal,yMaxVal); 721 722 lcd.setCursor ( 0, 0 ); // Diags in case there is an LCD display attached 723 lcd.print("X/Z "); 724 if ( xzAng > 0 ) { 725 lcd.print("+"); 726 } 727 lcd.print(xzAng); 728 lcd.setCursor ( 10, 0 ); 729 lcd.print("Y/Z "); 730 if ( yzAng > 0 ) { 731 lcd.print("+"); 732 } 733 lcd.print(yzAng); 734 lcd.setCursor ( 0, 1 ); 735 lcd.print("TX "); 736 if (( xzTarget) > 0 ) { 737 lcd.print("+"); 738 } 739 lcd.print(( xzTarget)); 740 lcd.setCursor ( 10, 1 ); 741 lcd.print("TY "); 742 if (( yzTarget) > 0 ) { 743 lcd.print("+"); 744 } 745 lcd.print(( yzTarget)); 746 lcd.setCursor ( 0, 2 ); 747 lcd.print("DX "); 748 dTmp = ( xzAng - xzTarget) ; 749 if (dTmp > 0 ) { 750 lcd.print("+"); 751 } 752 lcd.print(dTmp); 753 lcd.setCursor ( 10, 2 ); 754 lcd.print("DY "); 755 dTmp = ( yzAng - yzTarget) ; 756 if (dTmp > 0 ) { 757 lcd.print("+"); 758 } 759 lcd.print(dTmp); 760 761 lcd.setCursor ( 0, 3 ); // line 3 762 snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", tc.hour, tc.min, tc.sec); 763 lcd.print(buff) ; 764 765 lcd.setCursor ( 9, 3 ); // line 3 766 lcd.print( "S") ; 767 if ( iDayNight == 0 ) { 768 lcd.print( "-") ; 769 }else{ 770 if (( tc.sec % 2 ) == 0 ) { 771 lcd.print( "<") ; 772 }else{ 773 lcd.print( ">") ; 774 } 775 } 776 if ( gps.satellites() > 9 ){ 777 lcd.print( "-" ); 778 }else{ 779 lcd.print(gps.satellites()) ; 780 } 781 782 lcd.setCursor ( 13, 3 ); // line 3 783 snprintf(buff, BUFF_MAX, "%04X", fixage); 784 lcd.print(buff) ; 785 786 lcd.setCursor ( 18, 3 ); // line 3 787 if ( iPWM_YZ == 0 ) { 788 lcd.print( " ") ; 789 }else{ 790 if (( digitalRead(RELAY_YZ_DIR) == LOW )) { 791 lcd.print( "W") ; 792 }else{ 793 lcd.print( "E") ; 794 } 795 } 796 lcd.setCursor ( 19, 3 ); // line 3 797 if ( iPWM_XZ == 0 ) { 798 lcd.print( " ") ; 799 }else{ 800 if (( digitalRead(RELAY_XZ_DIR) == LOW )) { 801 lcd.print( "N") ; 802 }else{ 803 lcd.print( "S") ; 804 } 805 } 806 807 rtc_sec = second() ; 808 DisplayMeatBall() ; 809 } 810 811 if ( iDoSave == 2 ) { // save them Active via web or 812 LoadParamsFromEEPROM(false); 813 iDoSave = 0 ; // only do once 814 } 815 if ( iDoSave == 3 ) { // load them 816 LoadParamsFromEEPROM(true); 817 iDoSave = 0 ; // only do once 818 } 819 820 if (((tc.hour > 19 ) || ( tc.hour < 5 )) && (iTrackMode < 3)) { 821 if ( iNightShutdown != 0 ){ 822 ActivateRelays(1) ; 823 }else{ 824 ActivateRelays(0) ; // power down at night if in tracking mode 825 } 826 }else{ 827 ActivateRelays(1) ; 828 } 829 830 831 state1 = mb_slave.poll( (uint16_t*)&iMode, MAX_MODBUS_DATA ); 832 833 switch (state1) { 834 case EXC_ADDR_RANGE: 835 Serial.println("EXC_ADDR_RANGE PORT 2"); 836 break; 837 case EXC_FUNC_CODE: 838 Serial.println("EXC_FUNC_CODE PORT 2"); 839 break; 840 case EXC_REGS_QUANT: 841 Serial.println("EXC_REGS_QUANT PORT 2"); 842 break; 843 } 844 845 if ( hasNet ) { 846 if ( Udp.parsePacket() ) { // check if NTP packet arrived back 847 processNTPpacket(); 848 } 849 850 client = server.available(); // process web server 851 if (client) { 852 processTCPClient(client); 853 } 854 } 855 856 while (Serial1.available()){ // process the gps buffer 857 gps.encode(Serial1.read()); 858 } 859} // end of loop 860 861 862 863 864 865 866float DayOfYear(uint16_t iYear , uint8_t iMon , uint8_t iDay , uint8_t iHour , uint8_t iMin ) { 867 int i ; 868 float iTDay ; 869 870 iTDay = iDay - 1 ; // this is zero referenced 871 for ( i = 1 ; i < iMon ; i++ ) { 872 switch (i) { 873 case 1: 874 case 3: 875 case 5: 876 case 7: 877 case 8: 878 case 10: 879 case 12: 880 iTDay += 31 ; 881 break; 882 case 4: 883 case 6: 884 case 9: 885 case 11: 886 iTDay += 30 ; 887 break; 888 case 2 : 889 if ((iYear % 4) == 0 ) { 890 iTDay += 29 ; 891 } else { 892 iTDay += 28 ; 893 } 894 break; 895 } 896 } 897 iTDay += (( 1.0 * iHour - 12 ) / 24 ) ; 898 // iDay += 1.0 * iMin / 1440 ; 899 return (iTDay); 900} 901 902 903int HrsSolarTime(float target) { 904 int i ; 905 i = target ; 906 return ( i / 60 ); 907} 908int MinSolarTime(float target) { 909 int i ; 910 i = target ; 911 return ( i % 60 ); 912} 913 914float sign(float target) { 915 if (target > 0 ) { 916 return (1); 917 } else { 918 if (target < 0 ) { 919 return (-1); 920 } else { 921 return (0); 922 } 923 } 924} 925 926void DisplayMeatBall() { 927 int pos , led , x , y; 928 float dx , dy ; 929 float dxa , dya ; 930 931 HT.setBrightness(15); 932 933 dx = xzAng - xzTarget ; 934 dy = yzAng - yzTarget ; 935 dxa = abs(dx) ; 936 dya = abs(dy) ; 937 if (dxa < 6) { 938 x = 0 ; 939 } else { 940 if (dxa < 12) { 941 x = sign(dx); 942 } else { 943 if (dxa < 50) { 944 x = 2 * sign(dx); 945 } else { 946 x = 3 * sign(dx); 947 } 948 } 949 } 950 if (dya < 6) { 951 y = 0 ; 952 } else { 953 if (dya < 12) { 954 y = sign(dy); 955 } else { 956 if (dya < 25) { 957 y = 2 * sign(dy); 958 } else { 959 y = 3 * sign(dy); 960 } 961 } 962 } 963 pos = 27 ; // netral position 964 pos += (y * 8) ; // add or sumtract the x in range of -3 to +3 965 pos += (x ) ; // add or sumtract 8 * y or y in range of -3 to +3 966 for (led = 0; led < 63; led++) { 967 switch (led){ 968 case 0: 969 case 7: 970 case 56: 971 case 63: 972 break; 973 default: 974 HT.clearLedNow(MapLedNo(led)); 975 break; 976 } 977 } 978 979 if ( ++iPMode > 100 ) { 980 iPMode = 1 ; 981 } 982 switch(gps.satellites()){ 983 case 255: 984 HT.clearLedNow(MapLedNo(0)); // turn off four courners 985 HT.clearLedNow(MapLedNo(7)); // turn off four courners 986 HT.clearLedNow(MapLedNo(63)); // turn off four courners 987 HT.clearLedNow(MapLedNo(56)); // turn off four courners 988 break; 989 case 1: 990 case 2: 991 HT.setLedNow(MapLedNo(0)); // turn on four courners 992 HT.clearLedNow(MapLedNo(7)); // turn on four courners 993 HT.clearLedNow(MapLedNo(63)); // turn on four courners 994 HT.clearLedNow(MapLedNo(56)); // turn on four courners 995 break; 996 case 3: 997 HT.setLedNow(MapLedNo(0)); // turn on four courners 998 HT.setLedNow(MapLedNo(7)); 999 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1000 HT.clearLedNow(MapLedNo(56)); // turn on four courners 1001 break; 1002 case 4: 1003 HT.setLedNow(MapLedNo(0)); // turn on four courners 1004 HT.setLedNow(MapLedNo(7)); 1005 HT.setLedNow(MapLedNo(56)); 1006 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1007 break; 1008 default: 1009 HT.setLedNow(MapLedNo(0)); // turn on four courners 1010 HT.setLedNow(MapLedNo(7)); 1011 HT.setLedNow(MapLedNo(56)); 1012 HT.setLedNow(MapLedNo(63)); 1013 break; 1014 } 1015 1016 1017 // HT.setLedNow(MapLedNo(tc.sec)); 1018 if ((iPWM_YZ == 0) && (iPWM_XZ == 0)) { 1019// HT.setBlinkRate(HT16K33_DSP_NOBLINK); // not attempting to move 1020 if ((tc.sec % 2) == 0 ) { 1021 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1022 HT.setLedNow(MapLedNo(pos + 9)); 1023 }else{ 1024 HT.setLedNow(MapLedNo(pos + 1)); 1025 HT.setLedNow(MapLedNo(pos + 8)); 1026 } 1027 } else { 1028// HT.setBlinkRate(HT16K33_DSP_BLINK2HZ); //moving so blink meat ball 1029 if (( iPMode % 2 ) == 0 ){ 1030 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1031 HT.setLedNow(MapLedNo(pos + 1)); 1032 HT.setLedNow(MapLedNo(pos + 8)); 1033 HT.setLedNow(MapLedNo(pos + 9)); 1034 } 1035 } 1036} 1037 1038 1039int MapLedNo(int target) // this compensates for the screwy setup of the matrix driver to the chip 1040{ 1041 int row ; 1042 int col ; 1043 row = target / 8 ; 1044 col = target % 8 ; 1045 if (col == 0 ) { 1046 return ((row * 16 ) + 7) ; 1047 } else { 1048 return ((row * 16 ) + col - 1) ; 1049 } 1050} 1051 1052 1053unsigned long sendNTPpacket(char* address) // send an NTP request to the time server at the given address 1054{ 1055 memset(packetBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0 1056 // Initialize values needed to form NTP request 1057 // (see URL above for details on the packets) 1058 packetBuffer[0] = 0b11100011; // LI, Version, Mode 1059 packetBuffer[1] = 0; // Stratum, or type of clock 1060 packetBuffer[2] = 6; // Polling Interval 1061 packetBuffer[3] = 0xEC; // Peer Clock Precision 1062 // 8 bytes of zero for Root Delay & Root Dispersion 1063 packetBuffer[12] = 49; 1064 packetBuffer[13] = 0x4E; 1065 packetBuffer[14] = 49; 1066 packetBuffer[15] = 52; 1067 1068 // all NTP fields have been given values, now 1069 // you can send a packet requesting a timestamp: 1070 Udp.beginPacket(address, 123); //NTP requests are to port 123 1071 Udp.write(packetBuffer, NTP_PACKET_SIZE); 1072 Udp.endPacket(); 1073} 1074 1075 1076unsigned long processNTPpacket(void){ 1077 struct ts tntp; 1078 Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer 1079 1080 //the timestamp starts at byte 40 of the received packet and is four bytes, 1081 // or two words, long. First, esxtract the two words: 1082 1083 unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); 1084 unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 1085 // combine the four bytes (two words) into a long integer 1086 // this is NTP time (seconds since Jan 1 1900): 1087 unsigned long secsSince1900 = highWord << 16 | lowWord; 1088 Serial.print(F("Seconds since Jan 1 1900 = " )); 1089 Serial.println(secsSince1900); 1090 1091 // now convert NTP time into everyday time: 1092 Serial.print(F("Unix time = ")); 1093 // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: 1094 const unsigned long seventyYears = 2208988800UL; 1095 // subtract seventy years: 1096 unsigned long epoch = secsSince1900 - seventyYears + (timezone * SECS_PER_HOUR); 1097 // print Unix time: 1098 Serial.println(epoch); 1099 setTime((time_t)epoch); // update the clock 1100 t.year = year(); // record the last NTP time set 1101 t.mon = month() ; 1102 t.mday = day(); 1103 t.hour = hour(); 1104 t.min = minute(); 1105 t.sec = second(); 1106 1107 // print the hour, minute and second: 1108 Serial.print(F("In time zone ")); 1109 Serial.print(timezone); 1110 Serial.print(F(" the time is ")); 1111 Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) 1112 Serial.print(':'); 1113 if ( ((epoch % 3600) / 60) < 10 ) { 1114 // In the first 10 minutes of each hour, we'll want a leading '0' 1115 Serial.print('0'); 1116 } 1117 Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) 1118 Serial.print(':'); 1119 if ( (epoch % 60) < 10 ) { 1120 // In the first 10 seconds of each minute, we'll want a leading '0' 1121 Serial.print('0'); 1122 } 1123 Serial.println(epoch % 60); // print the second 1124} 1125 1126void sendTDTREnd(){ 1127 client.println(F("</td></tr>")); 1128} 1129 1130void processTCPClient(EthernetClient Target){ 1131 boolean currentLineIsBlank = true; 1132 long j , i = 0 ; 1133 while (Target.connected()) { 1134 if (Target.available()) { 1135 String req = Target.readStringUntil('\ '); 1136 // so you can send a reply 1137 // send a standard http response header 1138 i = req.indexOf("?tname="); // wanta do this one BEFORE we dick with captialisation of the request 1139 if (i != -1){ // have a request to set the time zone 1140 j = req.indexOf("&"); 1141 req.substring(i+7,j).toCharArray(trackername , 16) ; 1142 for (j=0 ; j < 16 ; j++){ 1143 if (trackername[j] == '+' ) { 1144 trackername[j] = ' ' ; 1145 } 1146 } 1147 } 1148 1149 i = req.indexOf("/gpio/"); 1150// Serial.println(req); 1151// Serial.println(req.charAt(i+6)); 1152 if (i != -1){ 1153 switch(req.charAt(i+6)){ 1154 case '0': 1155 break; 1156 case '1': 1157 break; 1158 case '2': 1159 break; 1160 case '3': 1161 break; 1162 case '4': 1163 break; 1164 case '5': 1165 break; 1166 case '6': 1167 break; 1168 case '7': 1169 break; 1170 case 'A': 1171 break; 1172 case 'B': 1173 break; 1174 case 'C': 1175 break; 1176 case 'T': // TssmmhhWDDMMYYYY aka set time same format as example eg T001513624032017 1177 t.sec = req.substring(i+7,i+9).toInt(); // 1 1178 t.min = req.substring(i+9,i+11).toInt(); // 3 1179 t.hour = req.substring(i+11,i+13).toInt(); // 5 1180 t.wday = req.charAt(i+13) - 48; // 7 1181 t.mday = req.substring(i+14,i+16).toInt(); // 8 1182 t.mon = req.substring(i+16,i+18).toInt();; // 10 1183 t.year = req.substring(i+18).toInt(); // 12 1184// snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", t.year, t.mon, t.mday , t.hour, t.min, t.sec); 1185// Serial.println(buff) ; 1186 DS3231_set(t); // set external RTC 1187 setTime((int)t.hour,(int)t.min,(int)t.sec,(int)t.mday,(int)t.mon,(int)t.year ) ; // set the internal RTC 1188 1189 break; 1190 case 't': // force NTP packet 1191 sendNTPpacket(timeServer); // send an NTP packet if requested to 1192 break; 1193 case 'S': // save all the params 1194 iDoSave = 2 ; 1195 break; 1196 case 'R': // read params back from eeprom 1197 iDoSave = 3 ; 1198 break; 1199 case 'Y': 1200 break; 1201 case 'X': 1202 break; 1203 default: 1204 break; 1205 } 1206 }else{ 1207 req.toLowerCase(); 1208 i = req.indexOf(".csv"); 1209 if (i != -1){ // have a request get a CSV filefrom the SD card 1210 i = req.indexOf(".csv"); 1211 Target.flush(); 1212 Target.println(F("HTTP/1.1 200 OK")); 1213 Target.println(F("Content-Type: text/csv")); 1214 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1215 Target.println(""); // this blank line be important 1216 SendFile(req.substring(4,i+4),Target); 1217 break; 1218 }else{ 1219 i = req.indexOf(".jpg"); 1220 if (i != -1){ // have a request get a CSV filefrom the SD card 1221 i = req.indexOf(".jpg"); 1222 Serial.println(req); 1223 Serial.println(req.substring(4,i+4)); 1224 Target.flush(); 1225 Target.println(F("HTTP/1.1 200 OK")); 1226 Target.println(F("Content-Type: image/jpeg")); 1227 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1228 Target.println(""); // this blank line be important 1229 SendFile(req.substring(4,i+4),Target); 1230 break; 1231 }else{ 1232 i = req.indexOf("index.htm"); 1233 if (i != -1){ // have a request get a CSV filefrom the SD card 1234 Target.flush(); 1235 Target.println(F("HTTP/1.1 200 OK")); 1236 Target.println(F("Content-Type: text/html")); 1237 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1238 Target.println(""); // this blank line be important 1239 Target.println(F("<!DOCTYPE HTML>")); 1240 Target.println(F("<head><title>Team Trouble SD Card</title>")); 1241 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1242 Target.print(F("</head><body><html><center><b><h2>Team Trouble SD Card</h2></b><br><pre>")); 1243 File root = SD.open("/"); 1244 printDirectory(root,0,Target,"/"); 1245 root.close(); 1246 Target.println("</pre><br><br><a href=''>Home Page</a></body></html>"); 1247 break; 1248 }else{ 1249 i = req.indexOf("stats.htm"); 1250 if (i != -1){ // have a request get a status.htm 1251 Target.flush(); 1252 Target.println(F("HTTP/1.1 200 OK")); 1253 Target.println(F("Content-Type: text/html")); 1254 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1255 Target.println(""); // this blank line be important 1256 Target.println(F("<!DOCTYPE HTML>")); 1257 Target.println(F("<head><title>Stats Page</title>")); 1258 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1259 Target.print(F("</head><body><html><center><b><h2>Stats Page</h2></b>")); 1260 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", tc.year, tc.mon, tc.mday , tc.hour, tc.min, tc.sec); 1261 Target.println(buff) ; 1262 Target.println(F("</table><br><br><a href=''>Home Page</a></body></html>")); 1263 break; 1264 } 1265 } 1266 } 1267 } 1268 } 1269 1270 i = req.indexOf("?tmode="); 1271 if (i != -1){ // have a request to set the tracking mode 1272 iTrackMode = req.substring(i+7).toInt() ; 1273 if (( iTrackMode < -1) || ( iTrackMode > 4 )){ 1274 iTrackMode = -1 ; 1275 } 1276 } 1277 i = req.indexOf("?tzone="); 1278 if (i != -1){ // have a request to set the time zone 1279 timezone = req.substring(i+7).toInt() ; 1280 if (( timezone < -23) || ( timezone > 23 )){ 1281 timezone = 10 ; 1282 } 1283 } 1284 i = req.indexOf("?mylat="); //lat 1285 if (i != -1){ // have a request to set the latitude 1286 latitude = req.substring(i+7).toFloat() ; 1287 if (( latitude < -90) || ( latitude > 90 )){ 1288 latitude = -34.051219 ; 1289 } 1290 } 1291 i = req.indexOf("?mylon="); // long 1292 if (i != -1){ // have a request to set the logitude 1293 longitude = req.substring(i+7).toFloat() ; 1294 if (( longitude < -180) || ( longitude > 180 )){ 1295 longitude = 142.013618 ; 1296 } 1297 } 1298 i = req.indexOf("?minay="); 1299 if (i != -1){ // have a request to set minimum angle Y 1300 yMinVal = req.substring(i+7).toFloat() ; 1301 if (( yMinVal < -70) || ( yMinVal > 50 )){ 1302 yMinVal = -65 ; // set to default 1303 } 1304 } 1305 i = req.indexOf("?minax="); 1306 if (i != -1){ // have a request to set minimum angle X 1307 xMinVal = req.substring(i+7).toFloat() ; 1308 if (( xMinVal < -10) || ( xMinVal > 60 )){ 1309 xMinVal = 0 ; // set to default 1310 } 1311 } 1312 i = req.indexOf("?maxay="); 1313 if (i != -1){ // have a request to set maximum angle Y 1314 yMaxVal = req.substring(i+7).toFloat() ; 1315 if (( yMaxVal < -70) || ( yMaxVal > 50 )){ 1316 yMaxVal = 45 ; // set to default 1317 } 1318 } 1319 i = req.indexOf("?maxax="); 1320 if (i != -1){ // have a request to set maximum angle X 1321 xMaxVal = req.substring(i+7).toFloat() ; 1322 if (( xMaxVal < -10) || ( xMaxVal > 60 )){ 1323 xMaxVal = 50 ; // set to default 1324 } 1325 } 1326 i = req.indexOf("?paray="); 1327 if (i != -1){ // have a request to set park angle Y 1328 dyPark = req.substring(i+7).toFloat() ; 1329 if (( dyPark < -70) || ( dyPark > 50 )){ 1330 dyPark = 0 ; // set to default 1331 } 1332 } 1333 i = req.indexOf("?parax="); 1334 if (i != -1){ // have a request to set park angle X 1335 dxPark = req.substring(i+7).toFloat() ; 1336 if (( dxPark < -10) || ( dxPark > 60 )){ 1337 dxPark = 6 ; // set to default 1338 } 1339 } 1340 i = req.indexOf("?offay="); 1341 if (i != -1){ // have a request to set offset angle Y 1342 yzOffset = req.substring(i+7).toFloat() ; 1343 if (( yzOffset < -20) || ( yzOffset > 20 )){ 1344 yzOffset = 0 ; // set to default 1345 } 1346 } 1347 i = req.indexOf("?offax="); 1348 if (i != -1){ // have a request to set offset angle X 1349 xzOffset = req.substring(i+7).toFloat() ; 1350 if (( xzOffset < -20) || ( xzOffset > 20 )){ 1351 xzOffset = 0 ; // set to default 1352 } 1353 } 1354 i = req.indexOf("?hysay="); 1355 if (i != -1){ // have a request to set Hysterisis angle 1356 yzH = req.substring(i+7).toFloat() ; 1357 if (( yzH < -20) || ( yzH > 20 )){ 1358 yzH = 4 ; // set to default 1359 } 1360 } 1361 i = req.indexOf("?hysax="); 1362 if (i != -1){ // have a request to set Hysterisis angle 1363 xzH = req.substring(i+7).toFloat() ; 1364 if (( xzH < -20) || ( xzH > 20 )){ 1365 xzH = 4 ; // set to default 1366 } 1367 } 1368 i = req.indexOf("?taray="); 1369 if (i != -1){ // have a request to set Hysterisis angle 1370 yzTarget = req.substring(i+7).toFloat() ; 1371 if (( yzTarget < -70) || ( yzTarget > 50 )){ 1372 yzTarget = 0 ; // set to default 1373 } 1374 } 1375 i = req.indexOf("?tarax="); 1376 if (i != -1){ // have a request to set Hysterisis angle 1377 xzTarget = req.substring(i+7).toFloat() ; 1378 if (( xzTarget < -10) || ( xzTarget > 60 )){ 1379 xzTarget = 0 ; // set to default 1380 } 1381 } 1382 1383 i = req.indexOf("?mulax="); 1384 if (i != -1){ // have a request to set Axis Multiplier 1385 xMul = req.substring(i+7).toFloat() ; 1386 if (( xMul < -10) || ( xMul > 10 )){ 1387 xMul = 1.0 ; // set to default 1388 } 1389 } 1390 i = req.indexOf("?mulay="); 1391 if (i != -1){ // have a request to set Axis Multiplier 1392 yMul = req.substring(i+7).toFloat() ; 1393 if (( yMul < -10) || ( yMul > 10 )){ 1394 yMul = 1.0 ; // set to default 1395 } 1396 } 1397 i = req.indexOf("?mulaz="); 1398 if (i != -1){ // have a request to set Axis Multiplier 1399 zMul = req.substring(i+7).toFloat() ; 1400 if (( zMul < -10) || ( zMul > 10 )){ 1401 zMul = 1.0 ; // set to default 1402 } 1403 } 1404 i = req.indexOf("?xyswp="); 1405 if (i != -1){ // have a request to set the time zone 1406 iXYS = req.substring(i+7).toInt() ; 1407 if (( iXYS < 0) || ( iXYS > 1 )){ 1408 iXYS = 0 ; 1409 } 1410 } 1411 i = req.indexOf("?nisht="); 1412 if (i != -1){ // have a request to set the time zone 1413 iNightShutdown = req.substring(i+7).toInt() ; 1414 if (( iNightShutdown < 0) || ( iNightShutdown > 1 )){ 1415 iNightShutdown = 0 ; 1416 } 1417 } 1418 1419 1420 1421 Target.flush(); 1422 Target.println(F("HTTP/1.1 200 OK")); 1423 Target.println(F("Content-Type: text/html")); 1424 Target.println(F("Connection: close")); // the connection will be closed after completion of the response 1425 Target.println(""); // this blank line be important 1426 Target.println(F("<!DOCTYPE HTML>")); 1427 Target.println(F("<head><title>Team Trouble - Solar Tracker</title>")); 1428 Target.println(F("<meta name=viewport content='width=320, auto inital-scale=1'>")); 1429 1430 Target.print(F("</head><body><html><center><h2>")); 1431 Target.print(String(trackername).substring(0,16)); 1432 Target.print(F(" Solar Tracker</h2>")); 1433 1434 if (hasRTC){ 1435 DS3231_get(&td); 1436 } 1437 Target.println(F("<b>Clocks</b>")) ; 1438 Target.println(F("<table border=1 title='Clocks'>")); 1439 Target.println(F("<tr><th>Clock Source</th><th>Time</th></tr>")); 1440 Target.print(F("<tr><td>Dallas RTC</td><td>")); 1441 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", td.year, td.mon, td.mday , tc.hour, tc.min, tc.sec); 1442 Target.print(buff) ; 1443 sendTDTREnd(); 1444 Target.println(F("</td></tr>")); 1445 Target.print(F("<tr><td>Last NTP</td><td>")); 1446 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", t.year, t.mon, t.mday , t.hour, t.min, t.sec); 1447 Target.print(buff) ; 1448 sendTDTREnd(); 1449 Target.print(F("<tr><td>Last GPS</td><td>")); 1450 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", tg.year, tg.mon, tg.mday , tg.hour, tg.min, tg.sec); 1451 Target.print(buff) ; 1452 sendTDTREnd(); 1453 Target.print(F("<tr><td><b>Arduino Time</b></td><td><b>")); 1454 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", year(), month(), day() , hour(), minute(), second()); 1455 Target.print(buff) ; 1456 sendTDTREnd(); 1457 Target.println(F("</table>")); 1458 1459 Target.println(F("<br><b>Tracker Control System</b>")) ; 1460 1461 Target.println(F("<table border=1 title='Tracker Control'>")); 1462 Target.println(F("<tr><th> Parameter</th><th>Value</th></tr>")); 1463// Target.println("<tr><td>Tracking Mode</td><td align=center>" + String(iTrackMode) + "</td></tr>" ) ; 1464 1465 Target.print(F("<form method=get action=/><tr><td>Tracking Mode</td><td align=center>")) ; 1466 Target.print(F("<select name='tmode'>")); 1467 for (i = -1 ; i < 5 ; i++ ){ 1468 Target.print(F("<option value='")); 1469 Target.print(i) ; 1470 if ( iTrackMode == i ){ 1471 Target.print(F("' SELECTED>")); 1472 }else{ 1473 Target.print(F("'>")); 1474 } 1475 Target.print(i); 1476 Target.print(" "); 1477 switch (i){ 1478 case -1: 1479 Target.print(F("Track Both Park Both")); 1480 break; 1481 case 0: 1482 Target.print(F("Track Both Park Only E/W")); 1483 break; 1484 case 1: 1485 Target.print(F("Track and Park E/W Only")); 1486 break; 1487 case 2: 1488 Target.print(F("Track and Park N/S Only")); 1489 break; 1490 case 3: 1491 Target.print(F("Dont Track Dont Park")); 1492 break; 1493 case 4: 1494 Target.print(F("Dont Track Park Both")); 1495 break; 1496 } 1497 } 1498 Target.print(F("</select>")) ; 1499 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1500 1501 Target.print(F("<form method=get action=/><tr><td>Time Zone</td><td align=center>")) ; 1502 Target.print(F("<input type='text' name='tzone' value='")); 1503 Target.print(timezone); 1504 Target.print(F("' size=6 maxlength=2>")) ; 1505 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1506 1507 Target.print(F("<form method=get action=/><tr><td>Latitude +N -S</td><td align=center>")) ; 1508 Target.print(F("<input type='text' name='mylat' value='")); 1509 Target.print(latitude,8); 1510 Target.print(F("' size=12>")) ; 1511 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1512 1513 Target.print(F("<form method=get action=/><tr><td>Longitude</td><td align=center>")) ; 1514 Target.print(F("<input type='text' name='mylon' value='")); 1515 Target.print(longitude,8); 1516 Target.print(F("' size=12>")) ; 1517 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1518 1519 Target.print(F("<form method=get action=/><tr><td>X (N/S) Axis Multiplier</td><td align=center>")) ; 1520 Target.print(F("<input type='text' name='mulax' value='")); 1521 Target.print(xMul,2); 1522 Target.print(F("' size=5>")) ; 1523 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1524 1525 Target.print(F("<form method=get action=/><tr><td>Y (E/W) Axis Multiplier</td><td align=center>")) ; 1526 Target.print(F("<input type='text' name='mulay' value='")); 1527 Target.print(yMul,2); 1528 Target.print(F("' size=5>")) ; 1529 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1530 1531 Target.print(F("<form method=get action=/><tr><td>Z (Vert) Axis Multiplier</td><td align=center>")) ; 1532 Target.print(F("<input type='text' name='mulaz' value='")); 1533 Target.print(zMul,2); 1534 Target.print(F("' size=5>")) ; 1535 Target.println(F("</td><td><input type='submit' value='SET'></td></tr></form>")); 1536 1537 Target.print(F("<form method=get action=/><tr><td>X<->Y Axis Swap</td><td align=center>")) ; 1538 Target.print(F("<select name='xyswp'>")); 1539 if (iXYS == 0 ){ 1540 Target.print(F("<option value='0' SELECTED>0 Normal")); 1541 Target.print(F("<option value='1'>1 Swapped")); 1542 }else{ 1543 Target.print(F("<option value='0'>0 Normal")); 1544 Target.print(F("<option value='1' SELECTED>1 Swapped")); 1545 } 1546 Target.println(F("</select></td><td><input type='submit' value='SET'></td></tr></form>")); 1547 1548 Target.print(F("<form method=get action=/><tr><td>Night Shutdown</td><td align=center>")) ; 1549 Target.print(F("<select name='nisht'>")); 1550 if (iNightShutdown == 0 ){ 1551 Target.print(F("<option value='0' SELECTED>0 Shutdown at Night")); 1552 Target.print(F("<option value='1'>1 Always Active")); 1553 }else{ 1554 Target.print(F("<option value='0'>0 Shutdown at Night")); 1555 Target.print(F("<option value='1' SELECTED>1 Always Active")); 1556 } 1557 Target.println(F("</select></td><td><input type='submit' value='SET'></td></tr></form>")); 1558 1559 Target.println(F("<form method=get action=/><tr><td>Tracker Name</td><td align=center><input type='text' name='tname' value='")); 1560 Target.println(String(trackername)) ; 1561 Target.println(F("' size=16 maxlength=16><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>")); 1562 1563 Target.println(F("<tr><td>Solar Elevation Deg</td><td align=center>")); 1564 Target.println(String(solar_el_deg,3)) ; 1565 Target.println(F("</td><td>(Deg)")); 1566 sendTDTREnd(); 1567 1568 Target.println(F("<tr><td>Solar Azomuth</td><td align=center>")); 1569 Target.println(String(solar_az_deg,3)) ; 1570 Target.println(F("</td><td>(Deg)")); 1571 sendTDTREnd(); 1572 1573 Target.println(F("<tr><td>Sunrise</td><td align=center>")); 1574 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunrise), MinSolarTime(sunrise)); 1575 Target.println(buff) ; 1576 Target.println(F("</td><td>(hh:mm)")); 1577 sendTDTREnd(); 1578 1579 Target.println(F("<tr><td>Sunset</td><td align=center>")); 1580 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunset), MinSolarTime(sunset)); 1581 Target.println(buff) ; 1582 Target.println(F("</td><td>(hh:mm)")); 1583 sendTDTREnd(); 1584 1585 Target.println(F("<tr><td>Day or Night</td><td align=center>")); 1586 if ( iDayNight == 1 ){ 1587 Target.println(F("DAY")); 1588 }else{ 1589 Target.println(F("NIGHT")); 1590 } 1591 sendTDTREnd(); 1592 1593 Target.println(F("<tr><td>GPS lock age</td><td align=center>")); 1594 if ( fixage < 10000 ) { 1595 Target.println(String(fixage)) ; 1596 }else{ 1597 Target.println(F("-- No Lock --")) ; 1598 } 1599 Target.println(F("</td><td>(ms)")); 1600 sendTDTREnd(); 1601 1602 Target.println(F("<tr><td>GPS Satellites</td><td align=center>")); 1603 if ( gps.satellites() == 255 ){ 1604 Target.println(F("-- No Lock --")) ; 1605 }else{ 1606 Target.println(String(gps.satellites())) ; 1607 } 1608 sendTDTREnd(); 1609 1610 Target.println(F("<tr><td>GPS Chars</td><td align=center>")); 1611 Target.println(String(gpschars)) ; 1612 sendTDTREnd(); 1613 1614 Target.println(F("<tr><td>RTC Temperature</td><td align=center>")); 1615 Target.println(String(T,2)) ; 1616 Target.println(F("</td><td>(C)")); 1617 sendTDTREnd(); 1618 1619 Target.println(F("<tr><td>P/T temp</td><td align=center>")); 1620 Target.println(String(gT)) ; 1621 Target.println(F("</td><td>(C)")); 1622 sendTDTREnd(); 1623 1624 Target.println(F("<tr><td>Pressue</td><td align=center>")); 1625 Target.println(String(Pr)) ; 1626 Target.println(F("</td><td>(mBar)")); 1627 sendTDTREnd(); 1628 1629 Target.println(F("<tr><td>Gyro X</td><td align=center>")); 1630 Target.println(String(xRoll)) ; 1631 sendTDTREnd(); 1632 1633 Target.println(F("<tr><td>Gyro Y</td><td align=center>")); 1634 Target.println(String(yRoll)) ; 1635 sendTDTREnd(); 1636 1637 Target.println(F("<tr><td>Gyro Z</td><td align=center>")); 1638 Target.println(String(zRoll)) ; 1639 sendTDTREnd(); 1640 Target.println(F("</table><br>")); 1641 1642 Target.println(F("<table border=1 title='Stracker Status'>")); 1643 Target.println(F("<tr><th>Parameter</th><th>E/W Value</th><th>.</th><th>N/S Value</th><th>.</th></tr>")); 1644 1645 Target.print(F("<tr><td>Min Angle</td><td><form method=get action=/><input type='text' name='minay' value='")); 1646 Target.print(String(yMinVal)); 1647 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='minax' value='")); 1648 Target.print(String(xMinVal)); 1649 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1650 1651 Target.print(F("<tr><td>Max Angle</td><td><form method=get action=/><input type='text' name='maxay' value='")); 1652 Target.print( String(yMaxVal)); 1653 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='maxax' value='")); 1654 Target.print( String(xMaxVal)); 1655 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1656 1657 Target.print(F("<tr><td>Park Angle</td><td><form method=get action=/><input type='text' name='paray' value='")); 1658 Target.print(String(dyPark)); 1659 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='parax' value='")); 1660 Target.print(String(dxPark)); 1661 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1662 1663 Target.print(F("<tr><td>Offest Angle</td><td><form method=get action=/><input type='text' name='offay' value='")); 1664 Target.print(String(yzOffset)); 1665 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='offax' value='")); 1666 Target.print(String(xzOffset)); 1667 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1668 1669 Target.print(F("<tr><td>Hysteris Angle</td><td><form method=get action=/><input type='text' name='hysay' value='")); 1670 Target.print(String(yzH)); 1671 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='hysax' value='")); 1672 Target.print(String(xzH)); 1673 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1674 1675 if ( iTrackMode == 3 ){ 1676 Target.print(F("<tr><td>Target Angle</td><td><form method=get action=/><input type='text' name='taray' value='")); 1677 Target.print(String(yzTarget)); 1678 Target.print(F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='tarax' value='")); 1679 Target.print(String(xzTarget)); 1680 Target.println(F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>")) ; 1681 }else{ 1682 Target.print(F("<tr><td>Target Angle</td><td>")); 1683 Target.print(String(yzTarget)); 1684 Target.print(F("</td><td>(Deg)</td><td>")) ; 1685 Target.print(String(xzTarget)); 1686 Target.println(F("</td><td>(Deg)</td></tr>")) ; 1687 } 1688 1689 Target.print(F("<tr><td>Current Sensor Angle</td><td>")); 1690 Target.print(String(yzAng)); 1691 Target.print(F("</td><td>(Deg)</td><td>")) ; 1692 Target.print(String(xzAng)); 1693 Target.println(F("</td><td>(Deg)</td></tr>")) ; 1694 1695 Target.println(F("</table><br>")) ; 1696 1697// Target.println("<br><br>"); 1698// Target.println("<br><br>"); 1699 if ( hasSD ) { 1700 Target.println(F("<br><br><a href='index.htm'>Data Logs Files</a><br>")) ; 1701 Target.println(F("<a href='stats.htm'>Last 24 Hours Stats</a><br>")) ; 1702 } 1703 Target.println(F("<a href='/gpio/t'>Force NTP request</a><br>")) ; 1704 Target.println(F("<a href='/gpio/S'>Save Parameters to EEPROM</a><br>")) ; 1705 Target.println(F("<a href='/gpio/R'>Load Parameters from EEPROM</a><br>")) ; 1706 Target.println(F("</body></html>")); 1707 break; 1708 } 1709 } 1710 1711 delay(1); // give the web browser time to receive the data 1712 Target.stop(); // close the connection: 1713 Serial.println("Target disconnected"); 1714} 1715 1716 1717void printDirectory(File dir, int numTabs, EthernetClient Target, String MyFolder) { 1718File entry ; 1719long lTB ; 1720// Serial.println("Called " + String(numTabs)); 1721 if( numTabs == 0 ) { 1722 lTB = 0 ; 1723 dir.rewindDirectory(); // start at the begining 1724 Target.println("<table border=0>"); 1725 } 1726 while(entry = dir.openNextFile()) { // single = very subtle assign and test 1727// Serial.println(entry.name()); 1728 if (entry.isDirectory()) { 1729 MyFolder = String("/") + entry.name() ; 1730 Target.println("<tr><td><b>" + MyFolder + "</td></tr>" ); 1731 printDirectory(entry, numTabs+1,Target, MyFolder); 1732// Serial.println("Returned "); 1733 }else{ 1734 Target.print("<tr><td><A href='"); 1735 Target.print(MyFolder+ "/" + entry.name()); 1736 Target.print("'>"); 1737 Target.print(entry.name()); 1738 Target.print("</a></td><td> </td><td align=right>"); 1739 Target.print(entry.size(), DEC); 1740 lTB += entry.size() ; 1741 Target.println("</td></tr>"); 1742 } 1743 } 1744 if( numTabs == 0 ) { 1745 Target.println("<tr><td> </td></tr>"); 1746 Target.print("<tr><td><b>Total Bytes</td><td> </td><td align=right><b>"); 1747 Target.print(lTB, DEC); 1748 Target.println("</td></tr>"); 1749 Target.println("</table>"); 1750 } 1751} 1752 1753int SendFile (String FileName , EthernetClient Target ){ 1754 File dataFile = SD.open(FileName); 1755 if (dataFile) { // if the file is available, write to it: 1756 while (dataFile.available()) { 1757 Target.write(dataFile.read()); 1758 } 1759 dataFile.close(); 1760 }else { // if the file isn't open, pop up an error: 1761 Target.println("error opening " + FileName); 1762 } 1763} 1764 1765 1766float getPressure(double* Temp) 1767{ 1768 char status; 1769 double T,P; 1770 1771 status = pressure.startTemperature(); 1772 if (status != 0){ 1773 delay(status); // Wait for the measurement to complete: 1774 status = pressure.getTemperature(*Temp); 1775 if (status != 0){ 1776 status = pressure.startPressure(3); 1777 if (status != 0){ 1778 // Wait for the measurement to complete: 1779 delay(status); 1780 status = pressure.getPressure(P,*Temp); 1781 if (status != 0){ 1782 return(float(P)); 1783 } 1784 } 1785 } 1786 } 1787} 1788 1789
TRACKER_MEGA_TOP_GPS_PWM_SOFT_ESP.ino
c_cpp
This is the ESP version .. ie shand Alone Soft AP no NTP requires GPS or RTC
1#include <SFE_BMP180.h> 2#include <avr/wdt.h> 3#include <Wire.h> 4#include <SPI.h> 5#include <LSM303.h> // modified ... fixed a couple of bugs 6#include <LiquidCrystal_I2C.h> 7#include <L3G.h> 8#include "ds3231.h" 9#include <TimeLib.h> 10#include "ht16k33.h" 11#include <ModbusRtu.h> // Modified ... this no longer a stock lib - Slave supports register translation/mapping 12#include <EEPROM.h> 13#include <math.h> 14#include <Ethernet.h> 15#include <SD.h> 16#include <EthernetUdp.h> 17#include <TinyGPS.h> 18#include "WiFiEsp.h" 19 20#define ID 1 21 22#define BUFF_MAX 32 23#define PARK_EAST 1 24#define PARK_WEST 2 25#define PARK_NORTH 3 26#define PARK_SOUTH 4 27#define PARK_FLAT 5 28 29#define MOTOR_DWELL 100 30 31#define MAX_MODBUS_DATA 70 32 33#define HT16K33_DSP_NOBLINK 0 // constants for the half arsed cheapo display 34#define HT16K33_DSP_BLINK1HZ 4 35#define HT16K33_DSP_BLINK2HZ 2 36#define HT16K33_DSP_BLINK05HZ 6 37 38 39const byte SPARE1 = 2; 40const byte FACTORY_RESET = 3; 41const byte SPARE2 = 8; 42 43const byte RELAY_YZ_DIR = 8; // DIR 1 Y+ Y- East / West Was the X+ N relay BROWN 44const byte RELAY_YZ_PWM = 7; // PWM 2 Speed East / West Was the Y- E relay ORANGE 45const byte RELAY_XZ_PWM = 6; // PWM 2 Speed North / South Was the Y+ W relay YELLOW 46const byte RELAY_XZ_DIR = 5; // DIR 1 X+ X- North / South Was the X- S relay BLUE 47 48const int chipSelect = 4; 49 50const byte UNUSED09 = 9; // cycle timer 26 Hz 38ms period 51const byte UNUSED10 = 10; 52const byte UNUSED11 = 11; 53const byte WATCHDOG = 12; 54 55IPAddress ip(192,168,42,1) ; 56IPAddress CurrentIP ; 57 58char ssid[24] = {"North_Tracker\\0"}; // your network SSID (name) 59char pass[16] = {"password\\0" }; // your network password 60int status = WL_IDLE_STATUS; // the Wifi radio's status 61int reqCount = 0; // number of requests received 62 63static bool hasSD = false; 64static bool hasNet = false; 65static bool hasGyro = false; 66static bool hasRTC = false; 67static bool hasPres = false ; 68 69L3G gyro; 70LSM303 compass; 71LiquidCrystal_I2C lcd(0x27); // Set the LCD I2C address I modified the lib for default wiring 72 73SFE_BMP180 pressure; 74HT16K33 HT; 75 76TinyGPS gps; 77 78WiFiEspServer server(80); 79RingBuffer buf(8); 80 81Modbus mb_slave(ID, 2, 0); // this is slave ID and RS-232 or USB-FTDI 82time_t chiptime ; 83uint8_t rtc_status ; 84uint8_t time[8]; 85int motor_recycle_x = 0 ; 86int motor_recycle_y = 0 ; 87char recv[BUFF_MAX]; 88unsigned int recv_size = 0; 89unsigned long prev_millis; 90uint8_t u8state; // machine state 91uint8_t u8query; // pointer to message query 92char buff[BUFF_MAX]; 93char trackername[18] ; 94unsigned long gpschars ; 95float heading ; // MODBUS MAP 96struct ts t; // 97struct ts td; // 98struct ts tg; // 99struct ts tc; // 100float ha ; 101float sunX ; 102float sunrise ; 103float sunset ; 104int iNightShutdown ; // 105int iMultiDrive ; // 69 do the axis drives run together 106time_t setchiptime ; // 68 if set to non zero this will trigger a time set event 107float zAng ; // 66 108float xMul = 1.0 ; // 64 109float yMul = 1.0 ; // 62 110float zMul = 1.0 ; // 60 111int iXYS = 0 ; // 59 112int iSave = 0 ; // 58 113int iDoSave = 0 ; // 57 114int iGPSLock = 0 ; // 56 115unsigned long fixage ; // 54 116float xRoll = 0.0 ; // 52 117float yRoll = 0.0 ; // 50 118float zRoll = 0.0 ; // 48 119float gT ; // 46 temp from sensor 120float Pr ; // 44 presure sensor 121float alt ; // 42 altitude from GPS 122float T; // 40 temperature of board (if has RTC) 123float xzTarget ; // 38 target for angles 124float yzTarget ; // 36 125float xzH ; // 34 hyserisis zone 126float yzH ; // 32 127float xzAng; // 30 current angles 128float yzAng; // 28 129float xzOffset; // 26 offset xz 130float yzOffset; // 24 offset yz 131float dyPark; // 22 parking position 132float dxPark; // 20 133float xMinVal ; // 18 Min and Max values X - N/S 134float xMaxVal ; // 16 135float yMinVal ; // 14 Y -- E/W 136float yMaxVal ; // 12 137float latitude; // 10 138float longitude; // 8 139int timezone; // 7 140int iDayNight ; // 6 141float solar_az_deg; // 4 142float solar_el_deg; // 2 143int iTrackMode ; // 1 144int iMode ; // 0 145 146int iPMode; 147int iPWM_YZ ; 148int iPWM_XZ ; 149int iPowerUp = 0 ; 150 151unsigned long tempus; 152int8_t state1 = 0; 153int8_t rtc_hour = 0; 154int8_t rtc_min = 0 ; 155int8_t rtc_sec = 0 ; 156 157void LoadParamsFromEEPROM(bool bLoad){ 158 if ( bLoad ) { 159 xzH = LoadFloatFromEEPROM(0,0.1,20.0,4.0); // hysterisis NS 160 yzH = LoadFloatFromEEPROM(1,0.1,20.0,4.0); // "" EW 161 162 dyPark = LoadFloatFromEEPROM(2,-70.0,50.0,0); 163 dxPark = LoadFloatFromEEPROM(3,-5.0,50.0,0.0); 164 165 xzOffset = LoadFloatFromEEPROM(4,-90.0,90.0,0); // NS 166 yzOffset = LoadFloatFromEEPROM(5,-90.0,90.0,0); // EW 167 168 xzTarget = LoadFloatFromEEPROM(6,-90.0,90.0,0); // NS 169 yzTarget = LoadFloatFromEEPROM(7,-90.0,90.0,0); // EW 170 171 xMinVal = LoadFloatFromEEPROM(8,-10.0,60.0,0.0); // NS 172 xMaxVal = LoadFloatFromEEPROM(9,-10.0,60.0,45); 173 174 yMinVal = LoadFloatFromEEPROM(10,-70.0,50.0,-65); // EW 175 yMaxVal = LoadFloatFromEEPROM(11,-70.0,50.0,45); 176 177 iTrackMode = LoadIntFromEEPROM(12,-1,4,0); 178 179 latitude = LoadFloatFromEEPROM(13,-90.0,90.0,-34.051219); 180 longitude = LoadFloatFromEEPROM(14,-180.0,180.0,142.013618); 181 timezone = LoadIntFromEEPROM(15,0,23,10); 182 xMul = LoadFloatFromEEPROM(16,-10,10,1); 183 yMul = LoadFloatFromEEPROM(17,-10,10,1); 184 zMul = LoadFloatFromEEPROM(18,-10,10,1); 185 iXYS = LoadIntFromEEPROM(19,0,1,0); 186 if ( xMul == 0.0 ) // zero is rubbish value so take 1.0 as the default 187 xMul = 1.0 ; 188 if ( yMul == 0.0 ) 189 yMul = 1.0 ; 190 if ( zMul == 0.0 ) 191 zMul = 1.0 ; 192 iNightShutdown = LoadIntFromEEPROM(20,0,1,1); 193 iMultiDrive = LoadIntFromEEPROM(21,0,1,0); 194 if (digitalRead(FACTORY_RESET)== LOW) { 195 ip= IPAddress(192,168,42,1); 196 sprintf(trackername,"Most Excellent\\0"); 197 sprintf(ssid , "Configure\\0") ; 198 sprintf(pass, "password\\0"); 199 }else{ 200 EEPROM.get(0 + (22 * sizeof(float)) , ip ); 201 if ((( ip[0] == 255 ) && ( ip[1] == 255 ))) { 202 ip= IPAddress(192,168,42,1); 203 } 204 EEPROM.get(0 + (30 * sizeof(float)) , trackername ); 205 if ( String(trackername).length() < 2 ){ 206 sprintf(trackername,"Most Excellent\\0"); 207 } 208 EEPROM.get(0 + (35 * sizeof(float)) , ssid ); 209 if (( String(ssid).length() < 2 ) || ((ssid[0] == ssid[11]) && (ssid[14] == ssid[15]) ) ){ 210 sprintf(ssid , "Configure\\0") ; 211 sprintf(pass, "password\\0"); 212 }else{ 213 EEPROM.get(0 + (42 * sizeof(float)) , pass ); 214 } 215 } 216 }else{ 217 EEPROM.put( 0 , xzH ); 218 EEPROM.put(0 + (1 * sizeof(float)) , yzH ); 219 EEPROM.put(0 + (2 * sizeof(float)) , dyPark ); 220 EEPROM.put(0 + (3 * sizeof(float)) , dxPark ); 221 EEPROM.put(0 + (4 * sizeof(float)) , xzOffset ); 222 EEPROM.put(0 + (5 * sizeof(float)) , yzOffset ); 223 EEPROM.put(0 + (6 * sizeof(float)) , xzTarget ); 224 EEPROM.put(0 + (7 * sizeof(float)) , yzTarget ); 225 EEPROM.put(0 + (8 * sizeof(float)) , xMinVal ); 226 EEPROM.put(0 + (9 * sizeof(float)) , xMaxVal ); 227 EEPROM.put(0 + (10 * sizeof(float)) , yMinVal ); 228 EEPROM.put(0 + (11 * sizeof(float)) , yMaxVal ); 229 EEPROM.put(0 + (12 * sizeof(float)) , iTrackMode ); 230 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 231 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 232 EEPROM.put(0 + (15 * sizeof(float)) , timezone ); 233 EEPROM.put(0 + (16 * sizeof(float)) , xMul ); 234 EEPROM.put(0 + (17 * sizeof(float)) , yMul ); 235 EEPROM.put(0 + (18 * sizeof(float)) , zMul ); 236 EEPROM.put(0 + (19 * sizeof(float)) , iXYS ); 237 EEPROM.put(0 + (20 * sizeof(float)) , iNightShutdown ); 238 EEPROM.put(0 + (21 * sizeof(float)) , iMultiDrive ); 239 EEPROM.put(0 + (22 * sizeof(float)) , ip ); 240 EEPROM.put(0 + (30 * sizeof(float)) , trackername); 241 EEPROM.put(0 + (35 * sizeof(float)) , ssid); 242 EEPROM.put(0 + (42 * sizeof(float)) , pass); 243 } 244} 245 246void setup() { 247 int led ; 248 249 Wire.begin(); 250 lcd.begin(20, 4); 251 lcd.home(); 252 lcd.setBacklightPin(3, NEGATIVE); 253 lcd.noCursor(); 254 lcd.clear(); 255 256 MCUSR &= ~_BV(WDRF); 257 wdt_disable(); 258 259 compass.init(); 260 compass.enableDefault(); 261 compass.setTimeout(1000); 262 263 Serial.begin(115200); // program/debug port 264 Serial1.begin(9600); // GPS port 265// Serial2.begin(9600); // Modbus Port 266 Serial3.begin(115200); // EPS8266 serial converter 267 268 if (gyro.init()) { 269 gyro.enableDefault(); 270 hasGyro = true ; 271 } 272 if (pressure.begin()){ 273 Serial.println("BMP180 init success"); 274 hasPres = true ; 275 } 276 pinMode(FACTORY_RESET,INPUT_PULLUP); 277 pinMode(RELAY_XZ_DIR, OUTPUT); // Outputs for PWM motor control 278 pinMode(RELAY_XZ_PWM, OUTPUT); // 279 pinMode(RELAY_YZ_PWM, OUTPUT); // 280 pinMode(RELAY_YZ_DIR, OUTPUT); // 281 iPWM_YZ = 0 ; 282 iPWM_XZ = 0 ; 283 pinMode(13, OUTPUT); // 284 digitalWrite(13, HIGH ); 285 ActivateRelays(0); // call an all stop first 286 287 mb_slave.begin( 9600 ); // RS-232 to base of tower 288 tempus = millis() + 100; 289 290 pinMode(UNUSED09, OUTPUT); // unused so dont leave floating set as output 291 pinMode(UNUSED10, OUTPUT); // 292 pinMode(UNUSED11, OUTPUT); // 293 pinMode(WATCHDOG, OUTPUT); // 294 digitalWrite(WATCHDOG,HIGH); 295 296 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical 297 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300}; 298 299 LoadParamsFromEEPROM(true); 300 301 DS3231_init(DS3231_INTCN); // look for a rtc 302 DS3231_get(&tc); 303 DS3231_get(&td); 304 rtc_status = DS3231_get_sreg(); 305 if ((tc.mon == 0 )&& (tc.mday==0)){ // no rtc to load off 306 setTime (0,0,0,21,9,2017) ; // midnight on the equinox (will deactivae motors till gets a valid time) ; 307 }else{ 308 setTime((int)tc.hour,(int)tc.min,(int)tc.sec,(int)tc.mday,(int)tc.mon,(int)tc.year ) ; // set the internal RTC 309 hasRTC = true ; 310 } 311 312 HT.begin(0x00); 313 for (led = 0; led < 127; led++) { 314 HT.clearLedNow(led); 315 } 316 317 Serial3.begin(115200); // initialize serial for ESP module 318 WiFi.init(&Serial3); // initialize ESP module 319 320 // check for the presence of the shield 321 if (WiFi.status() == WL_NO_SHIELD) { 322 Serial.println("WiFi shield not present"); 323// while (true); // don't continue 324 } 325 326 Serial.print("Attempting to start AP "); 327 Serial.println(ssid); 328 329 if (( ip[0] == 0 )&&( ip[1] == 0 )&&( ip[2] == 0 )&&( ip[3] == 0 ) && (digitalRead(FACTORY_RESET)== HIGH)){ 330 WiFi.begin((char*)ssid, (char*)pass) ; 331 }else{ 332 WiFi.configAP(ip); // start access point 333 if ( String(pass).length() == 0 ) { 334 status = WiFi.beginAP(ssid, 10); 335 }else{ 336 status = WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK); 337 } 338 } 339 340 Serial.println("Access point started"); 341// printWifiStatus(); 342 Serial.println("IP address: "); 343 CurrentIP = WiFi.localIP() ; 344 Serial.println(CurrentIP); 345 346 // start the web server on port 80 347 server.begin(); 348 Serial.println("Server started"); 349 350// wdt_enable(WDTO_8S); 351} 352 353// Arduino doesnt have these to we define from a sandard libruary 354float arcsin(float x) { 355 return (atan(x / sqrt(-x * x + 1))); 356} 357float arccos(float x) { 358 return (atan(x / sqrt(-x * x + 1)) + (2 * atan(1))); 359} 360// fractional orbital rotation in radians 361float gama(struct ts *tm) { 362 return ((2 * PI / 365 ) * DayOfYear(tm->year , tm->mon , tm->mday , tm->hour , tm->min )); 363} 364// equation of rime 365float eqTime(float g) { 366 return (229.18 * ( 0.000075 + ( 0.001868 * cos(g)) - (0.032077 * sin(g)) - (0.014615 * cos (2 * g)) - (0.040849 * sin(2 * g)))); 367} 368// declination of sun in radians 369float Decl(float g) { 370 return ( 0.006918 - (0.399912 * cos(g)) + (0.070257 * sin(g)) - (0.006758 * cos(2 * g)) + ( 0.000907 * sin(2 * g)) - ( 0.002697 * cos(3 * g)) + (0.00148 * sin(3 * g)) ); 371} 372float TimeOffset(float longitude , struct ts *tm , int timezone ) { 373 float dTmp ; 374 dTmp = (-4.0 * longitude ) + (60 * timezone) - eqTime(gama(tm)) ; 375 return (dTmp); 376} 377 378float TrueSolarTime(float longitude , struct ts *tm , int timezone ) { 379 float dTmp ; 380 dTmp = ( 60.0 * tm->hour ) + (1.0 * tm->min) + (1.0 * tm->sec / 60) - TimeOffset(longitude, tm, timezone) ; 381 return (dTmp); 382} 383float HourAngle(float longitude , struct ts *tm , int timezone) { 384 float dTmp; 385 dTmp = (TrueSolarTime(longitude, tm, timezone) / 4 ) - 180 ; // 720 minutes is solar noon -- div 4 is 180 386 return (dTmp); 387} 388// Hour angle for sunrise and sunset only 389float HA (float lat , struct ts *tm ) { 390 float latRad ; 391 latRad = lat * 2 * PI / 360 ; 392 return ( acos((cos(90.833 * PI / 180 ) / ( cos(latRad) * cos(Decl(gama(tm)))) - (tan(latRad) * tan(Decl(gama(tm)))))) / PI * 180 ); 393} 394 395float Sunrise(float longitude , float lat , struct ts *tm , int timezone) { 396 return (720 - ( 4.0 * (longitude + HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 397} 398float Sunset(float longitude , float lat , struct ts *tm , int timezone) { 399 return (720 - ( 4.0 * (longitude - HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ; 400} 401float SNoon(float longitude , float lat , struct ts *tm , int timezone) { 402 return (720 - ( 4.0 * (longitude + (60 * timezone) - eqTime(gama(tm)))) ) ; 403} 404 405float SolarZenithRad(float longitude , float lat , struct ts *tm , int timezone) { 406 float latRad ; 407 float decRad ; 408 float HourAngleRad ; 409 float dTmp ; 410 411 latRad = lat * 2 * PI / 360 ; 412 decRad = Decl(gama(tm)); 413 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 414 dTmp = acos((sin(latRad) * sin(decRad)) + (cos(latRad) * cos(decRad) * cos(HourAngleRad))); 415 return (dTmp) ; 416 417} 418float SolarElevationRad(float longitude , float lat , struct ts *tm , int timezone ) { 419 return ((PI / 2) - SolarZenithRad(longitude , lat , tm , timezone )) ; 420} 421 422float SolarAzimouthRad(float longitude , float lat , struct ts *tm , int timezone) { 423 float latRad ; 424 float decRad ; 425 float solarzenRad ; 426 float HourAngleRad ; 427 float dTmp ; 428 latRad = lat * 2 * PI / 360 ; 429 decRad = Decl(gama(tm)); 430 solarzenRad = SolarZenithRad ( longitude , lat , tm , timezone ) ; 431 HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ; 432 dTmp = acos(((sin(decRad) * cos(latRad)) - (cos(HourAngleRad) * cos(decRad) * sin(latRad))) / sin(solarzenRad)) ; 433 if ( HourAngleRad < 0 ) { 434 return (dTmp) ; 435 } else { 436 return ((2 * PI) - dTmp) ; 437 } 438} 439 440 441void StopYZ(){ 442 iPWM_YZ=0 ; 443 motor_recycle_y = MOTOR_DWELL ; 444} 445void StopXZ(){ 446 iPWM_XZ=0 ; 447 motor_recycle_x = MOTOR_DWELL ; 448} 449 450void ActivateRelays(int iAllStop) { 451 if (motor_recycle_y > 0 ){ 452 motor_recycle_y-- ; 453 } 454 if (motor_recycle_x > 0 ){ 455 motor_recycle_x-- ; 456 } 457 if ( iAllStop == 0 ) { 458 StopYZ() ; 459 StopXZ() ; 460 } else { 461 if (( iPWM_YZ==0 ) && (motor_recycle_y == 0 )){ 462 if ((( yzAng ) < ( yzTarget - yzH )) ) { // do Y ie E/W before N/S 463 digitalWrite(RELAY_YZ_DIR, LOW) ; 464 iPWM_YZ=2 ; 465 } 466 if ((( yzAng ) > ( yzTarget + yzH )) ) { 467 digitalWrite(RELAY_YZ_DIR, HIGH) ; 468 iPWM_YZ=2 ; 469 } 470 } 471 if ( iPWM_YZ>0 ){ 472 if ((yzAng > yzTarget) && ( digitalRead(RELAY_YZ_DIR)==LOW )) { 473 StopYZ() ; 474 } 475 if ((yzAng < yzTarget) && ( digitalRead(RELAY_YZ_DIR)==HIGH )) { 476 StopYZ() ; 477 } 478 } 479 480 if (( iPWM_YZ==0) || ( iMultiDrive == 1 )) { // if finished on E/W you can do N/S or if we are doing multidrive 481 if (( iPWM_XZ==0 ) && (motor_recycle_x == 0 )){ 482 if ((xzAng < ( xzTarget - xzH )) ) { // turn on if not in tolerance 483 digitalWrite(RELAY_XZ_DIR, LOW) ; 484 iPWM_XZ=2 ; 485 } 486 if ((xzAng > ( xzTarget + xzH )) ) { // turn on if not in tolerance 487 digitalWrite(RELAY_XZ_DIR, HIGH) ; 488 iPWM_XZ=2 ; 489 } 490 } 491 }else{ 492 if ((iPWM_XZ>0 )){ 493 StopXZ() ; 494 } 495 } 496 if ( iPWM_XZ>0 ){ 497 if ((xzAng > xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==LOW )) { // if on turn off 498 StopXZ() ; 499 } 500 if ((xzAng < xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==HIGH )) { // if on turn off 501 StopXZ() ; 502 } 503 } 504 } 505 if (iPWM_XZ>0){ 506 iPWM_XZ += 2 ; 507 } 508 if (iPWM_YZ>0){ 509 iPWM_YZ += 2 ; 510 } 511 iPWM_XZ = constrain(iPWM_XZ,0,254); 512 iPWM_YZ = constrain(iPWM_YZ,0,254); 513 analogWrite(RELAY_XZ_PWM,iPWM_XZ); 514 analogWrite(RELAY_YZ_PWM,iPWM_YZ); 515} 516 517void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 518 uint16_t tempdata[2] ; 519 float *tf ; 520 tf = (float * )&tempdata[0] ; 521 *tf = src_value ; 522 *dest_lo = tempdata[1] ; 523 *dest_hi = tempdata[0] ; 524} 525float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 526 uint16_t tempdata[2] ; 527 float *tf ; 528 tf = (float * )&tempdata[0] ; 529 tempdata[1] = dest_lo ; 530 tempdata[0] = dest_hi ; 531 return (*tf) ; 532} 533 534 535float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 536float tmp ; 537 EEPROM.get(0 + (address * sizeof(float)) , tmp ); 538 if (( tmp < minval ) || ( tmp > maxval )|| (NumberOK(tmp) == 1)) { 539 tmp = defaultval ; 540 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 541 } 542 return(tmp); 543} 544int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 545int tmp ; 546 EEPROM.get(0 + (address * sizeof(float)) , tmp ); // float.. yeah yeah I know... but it makes it compatible with the one above (easy on the brain) 547 if (( tmp < minval ) || ( tmp > maxval )) { 548 tmp = defaultval ; 549 EEPROM.put(0 + (address * sizeof(float)) , tmp ); 550 } 551 return(tmp); 552} 553 554int NumberOK (float target) { 555 int tmp = 0 ; 556 tmp = isnan(target); 557 if ( tmp != 1 ) { 558 tmp = isinf(target); 559 } 560 return (tmp); 561} 562 563int SetTimeFromGPS(){ 564 byte hundredths ; 565 tmElements_t tmegps; 566 gps.crack_datetime((int *)&tg.year,(byte *)&tg.mon,(byte *) &tg.mday,(byte *) &tg.hour,(byte *) &tg.min,(byte *) &tg.sec , &hundredths, &fixage); 567 tmegps.Year = tg.year - 1970 ; 568 tmegps.Month = tg.mon ; 569 tmegps.Day = tg.mday ; 570 tmegps.Hour = tg.hour ; 571 tmegps.Minute = tg.min ; 572 tmegps.Second = tg.sec ; 573// setTime((int)tg.hour,(int)tg.min,(int)tg.sec,(int)tg.mday,(int)tg.mon,(int)tg.year ) ; // set the internal RTC from last GPS time 574// chiptime = now() ; // get it back again 575 chiptime = makeTime(tmegps); // get the GPS as time_t 576 chiptime += (( timezone * SECS_PER_HOUR ) + ( fixage / 1000 )) ; // add the offset plus the fix age 577 setTime(chiptime); // set it again 578 if (hasRTC) { 579 tg.year = year(); 580 tg.mon = month() ; 581 tg.mday = day(); 582 tg.hour = hour() ; 583 tg.min = minute(); 584 tg.sec = second(); 585 DS3231_set(tg); //should also update this 586 } 587 return(0); 588} 589 590 591void loop() { 592 float P; 593 float sunInc; 594 float sunAng; 595 float xzRatio; 596 float yzRatio; 597 float decl ; 598 float eqtime ; 599 float dTmp ; 600 float heading ; 601 float tst ; 602 float flat, flon; 603 unsigned short goodsent; 604 unsigned short failcs; 605 String request ; 606 607// int iYear , iMon , iMday , iHour , iMin , iSec ; 608 609 610 if (minute() != rtc_min) { // do onlyonce a minute 611 gps.stats(&gpschars, &goodsent , &failcs ); 612 gps.f_get_position(&flat, &flon,(long unsigned *) &fixage); // return in degrees 613 if (hasPres){ 614 Pr = getPressure((double *)&gT) ; 615 } 616 if (hasRTC) { 617 T = DS3231_get_treg(); 618 } 619 rtc_min = minute() ; 620 621 if ((fixage > 0 ) && ( fixage < 40000 )) { // wait till our fix is valid before we use the values 622 latitude = flat ; 623 longitude = flon ; 624 iGPSLock = gps.satellites() ; 625 alt = gps.f_altitude() ; 626 if (iPowerUp==0) { // only do this at startup so we have a better position ref for next time 627 EEPROM.put(0 + (13 * sizeof(float)) , latitude ); 628 EEPROM.put(0 + (14 * sizeof(float)) , longitude ); 629 iPowerUp = 1 ; 630 if (!hasNet ){ 631 SetTimeFromGPS(); 632 } 633 } 634 }else{ 635 iGPSLock = 0 ; // if no lock loook at internal clock 636 } 637 } 638 tc.year = year(); 639 tc.mon = month() ; 640 tc.mday = day(); 641 tc.hour = hour() ; 642 tc.min = minute(); 643 tc.sec = second(); 644 645 compass.read(); // this reads all 6 channels 646 if ( hasGyro ){ 647 gyro.read(); 648 xRoll = gyro.g.x ; 649 yRoll = gyro.g.y ; 650 zRoll = gyro.g.z ; 651 } 652 653 digitalWrite(UNUSED09,!digitalRead(UNUSED09)); // toggle this output so I can measure the cycle time with a scope 654 655 heading = compass.heading((LSM303::vector<int>) { 1, 0, 0 }); 656 657 if (( compass.a.z != 0) && (!compass.timeoutOccurred() )) { 658 zAng = (float)compass.a.z ; 659 if (iXYS == 0 ){ // Proper Job make it configurable 660 xzRatio = (float)compass.a.x * xMul / abs(zAng) ; // Normal 661 yzRatio = (float)compass.a.y * yMul / abs(zAng) ; 662 }else{ 663 xzRatio = (float)compass.a.y * xMul / abs(zAng) ; // Swapped 664 yzRatio = (float)compass.a.x * yMul / abs(zAng) ; 665 } 666 xzAng = ((float)atan(xzRatio) / PI * 180 ) + xzOffset ; // good old offsets or fudge factors 667 yzAng = ((float)atan(yzRatio) / PI * 180 ) + yzOffset ; 668// digitalWrite(13, LOW); 669 }else{ // try restarting the compass/accelerometer modual - cos he gone walkabout... 670 Wire.begin(); // reset the I2C 671 compass.init(); 672 compass.enableDefault(); 673 compass.setTimeout(1000); // BTW I fixed up the int / long issue in the time out function in the LM303 lib I was using 674 compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical (just whirl it around a bit and records the min max !!) 675 compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300 }; 676/* if (tc.sec % 2 == 0 ) { 677 digitalWrite(13, HIGH); 678 } else { 679 digitalWrite(13, LOW); 680 }*/ 681 HT.begin(0x00); 682 } 683 684 if (setchiptime > 0) { // update the arduino time from the modbus register then clear it... also set RTC if fitted 685 setTime(setchiptime) ; 686 if (hasRTC) { 687 tc.year = year(); 688 tc.mon = month() ; 689 tc.mday = day(); 690 tc.hour = hour() ; 691 tc.min = minute(); 692 tc.sec = second(); 693 DS3231_set(tc); //should also update this 694 } 695 setchiptime = 0 ; 696 } 697 698 if ( hour() != rtc_hour){ // update our time every hour if we can 699 if (iGPSLock == 0){ 700 if (hasRTC) { 701 DS3231_get(&td); 702 setTime((int)td.hour,(int)td.min,(int)td.sec,(int)td.mday,(int)td.mon,(int)td.year ) ; // set the internal RTC from Dallas RTC 703 } 704 }else{ 705 if ((fixage > 0 ) && ( fixage < 10000 )) { // if the lock is less than 10 second old 706 SetTimeFromGPS(); 707 } 708 } 709 rtc_hour = hour() ; 710 } 711 712 if ( rtc_sec != second() ) { //only update once a second 713 wdt_reset(); // reset internal watchdog - good puppy 714 715 if (( tc.sec > 8 ) && ( tc.sec < 58 )) { // dont calculate arround the minute when time is updating from NTP or GPS as might get a not so funny result 716 digitalWrite(13,!digitalRead(13)); 717 solar_az_deg = SolarAzimouthRad(longitude, latitude, &tc, timezone) * 180 / PI ; 718 solar_el_deg = SolarElevationRad(longitude, latitude, &tc, timezone) * 180 / PI ; 719 720 decl = Decl(gama(&tc)) * 180 / PI ; 721 ha = HourAngle (longitude , &tc , timezone ) ; 722 sunrise = Sunrise(longitude, latitude, &tc, timezone) ; 723 sunset = Sunset(longitude, latitude, &tc, timezone); 724 tst = TrueSolarTime(longitude, &tc, timezone); 725 sunX = abs(latitude) + decl ; 726 if (solar_el_deg >= 0 ){ // day 727 iDayNight = 1 ; 728 }else{ // night 729 iDayNight = 0 ; 730 } 731 } 732 switch (iTrackMode) { 733 case 4: // both axis to park 734 yzTarget = dyPark ; // night park position E/W 735 xzTarget = dxPark ; // night park position N/S 736 break ; 737 case 3: // both axis off no tracking 738 break ; 739 case 2: // xz tracking NS 740 if ( iDayNight == 1 ) { 741 xzTarget = sunX ; // need to map the coordinate system correctly 742 } else { 743 xzTarget = dxPark ; // night park position 744 } 745 break; 746 case 1: // yz tracking EW 747 if (iDayNight == 1) { 748 yzTarget = ha ; 749 } else { 750 yzTarget = dyPark ; // night park position 751 } 752 break; 753 case -1: // set target to tracking and park both at nigh 754 if (iDayNight == 1) { 755 yzTarget = ha ; 756 xzTarget = sunX ; // need to map the coordinate system correctly 757 } else { 758 yzTarget = dyPark ; // night park position E/W 759 xzTarget = dxPark ; // night park position N/S 760 } 761 break; 762 default: // set target to tracking 763 if (iDayNight == 1) { 764 yzTarget = ha ; 765 xzTarget = sunX ; // need to map the coordinate system correctly 766 } else { 767 yzTarget = dyPark ; // night park position (dont park the other - leave till morning) 768 } 769 break; 770 } 771 xzTarget = constrain(xzTarget,xMinVal,xMaxVal); // constain function... very cool - dont leave home without it ! 772 yzTarget = constrain(yzTarget,yMinVal,yMaxVal); 773 774 lcd.setCursor ( 0, 0 ); // Diags in case there is an LCD display attached 775 lcd.print("X/Z "); 776 if ( xzAng > 0 ) { 777 lcd.print("+"); 778 } 779 lcd.print(xzAng); 780 lcd.setCursor ( 10, 0 ); 781 lcd.print("Y/Z "); 782 if ( yzAng > 0 ) { 783 lcd.print("+"); 784 } 785 lcd.print(yzAng); 786 lcd.setCursor ( 0, 1 ); 787 lcd.print("TX "); 788 if (( xzTarget) > 0 ) { 789 lcd.print("+"); 790 } 791 lcd.print(( xzTarget)); 792 lcd.setCursor ( 10, 1 ); 793 lcd.print("TY "); 794 if (( yzTarget) > 0 ) { 795 lcd.print("+"); 796 } 797 lcd.print(( yzTarget)); 798 lcd.setCursor ( 0, 2 ); 799 lcd.print("DX "); 800 dTmp = ( xzAng - xzTarget) ; 801 if (dTmp > 0 ) { 802 lcd.print("+"); 803 } 804 lcd.print(dTmp); 805 lcd.setCursor ( 10, 2 ); 806 lcd.print("DY "); 807 dTmp = ( yzAng - yzTarget) ; 808 if (dTmp > 0 ) { 809 lcd.print("+"); 810 } 811 lcd.print(dTmp); 812 813 lcd.setCursor ( 0, 3 ); // line 3 814 snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", tc.hour, tc.min, tc.sec); 815 lcd.print(buff) ; 816 817 lcd.setCursor ( 9, 3 ); // line 3 818 lcd.print( "S") ; 819 if ( iDayNight == 0 ) { 820 lcd.print( "-") ; 821 }else{ 822 if (( tc.sec % 2 ) == 0 ) { 823 lcd.print( "<") ; 824 }else{ 825 lcd.print( ">") ; 826 } 827 } 828 if ( gps.satellites() > 9 ){ 829 lcd.print( "-" ); 830 }else{ 831 lcd.print(gps.satellites()) ; 832 } 833 834 lcd.setCursor ( 13, 3 ); // line 3 835 snprintf(buff, BUFF_MAX, "%04X", fixage); 836 lcd.print(buff) ; 837 838 lcd.setCursor ( 18, 3 ); // line 3 839 if ( iPWM_YZ == 0 ) { 840 lcd.print( " ") ; 841 }else{ 842 if (( digitalRead(RELAY_YZ_DIR) == LOW )) { 843 lcd.print( "W") ; 844 }else{ 845 lcd.print( "E") ; 846 } 847 } 848 lcd.setCursor ( 19, 3 ); // line 3 849 if ( iPWM_XZ == 0 ) { 850 lcd.print( " ") ; 851 }else{ 852 if (( digitalRead(RELAY_XZ_DIR) == LOW )) { 853 lcd.print( "N") ; 854 }else{ 855 lcd.print( "S") ; 856 } 857 } 858 859 rtc_sec = second() ; 860 DisplayMeatBall() ; 861 } 862 863 if ( iDoSave == 2 ) { // save them Active via web or 864 LoadParamsFromEEPROM(false); 865 iDoSave = 0 ; // only do once 866 } 867 if ( iDoSave == 3 ) { // load them 868 LoadParamsFromEEPROM(true); 869 iDoSave = 0 ; // only do once 870 } 871 872 if (((tc.hour > 19 ) || ( tc.hour < 5 )) && (iTrackMode < 3)) { 873 if ( iNightShutdown != 0 ){ 874 ActivateRelays(1) ; 875 }else{ 876 ActivateRelays(0) ; // power down at night if in tracking mode 877 } 878 }else{ 879 ActivateRelays(1) ; 880 } 881 882 883 state1 = mb_slave.poll( (uint16_t*)&iMode, MAX_MODBUS_DATA ); 884 885 switch (state1) { 886 case EXC_ADDR_RANGE: 887 Serial.println("EXC_ADDR_RANGE PORT 2"); 888 break; 889 case EXC_FUNC_CODE: 890 Serial.println("EXC_FUNC_CODE PORT 2"); 891 break; 892 case EXC_REGS_QUANT: 893 Serial.println("EXC_REGS_QUANT PORT 2"); 894 break; 895 } 896 897 898 while (Serial1.available()){ // process the gps buffer 899 gps.encode(Serial1.read()); 900 } 901 902 WiFiEspClient client = server.available(); // listen for incoming clients 903 if (client) { // if you get a client, 904 ActivateRelays(0); // deactive motor while we do web 905 Serial.println("New client"); // print a message out the serial port 906 buf.init(); // initialize the circular buffer 907 request = "" ; 908 while (client.connected()) { // loop while the client's connected 909 if (client.available()) { // if there's bytes to read from the client, 910 char c = client.read(); // read a byte, then 911 buf.push(c); // push it to the ring buffer 912 request += c ; 913 914// you got two newline characters in a row 915// that's the end of the HTTP request, so send a response 916 917 if (buf.endsWith("\ \ 918\ \ 919")) { 920// if (request.endsWith("\ \ 921\ \ 922")){ 923// Serial.print(request); 924 processRequest(request); 925 if (request.indexOf("favicon.ico")>0){ 926 sendHttpResponseNG(client); 927 }else{ 928 sendHttpResponse(client); 929 } 930/* Serial.println(request.endsWith("\ \ 931\ \ 932")); 933 Serial.println(request.indexOf("\ \ 934\ \ 935")); */ 936 client.flush(); 937 break; 938 } 939 } 940 } 941 942 // give the web browser time to receive the data 943 delay(10); 944 945 //close the connection 946 client.stop(); 947 Serial.println("Client disconnected"); 948 } 949} // end of loop 950 951 952 953 954 955 956float DayOfYear(uint16_t iYear , uint8_t iMon , uint8_t iDay , uint8_t iHour , uint8_t iMin ) { 957 int i ; 958 float iTDay ; 959 960 iTDay = iDay - 1 ; // this is zero referenced 961 for ( i = 1 ; i < iMon ; i++ ) { 962 switch (i) { 963 case 1: 964 case 3: 965 case 5: 966 case 7: 967 case 8: 968 case 10: 969 case 12: 970 iTDay += 31 ; 971 break; 972 case 4: 973 case 6: 974 case 9: 975 case 11: 976 iTDay += 30 ; 977 break; 978 case 2 : 979 if ((iYear % 4) == 0 ) { 980 iTDay += 29 ; 981 } else { 982 iTDay += 28 ; 983 } 984 break; 985 } 986 } 987 iTDay += (( 1.0 * iHour - 12 ) / 24 ) ; 988 // iDay += 1.0 * iMin / 1440 ; 989 return (iTDay); 990} 991 992 993int HrsSolarTime(float target) { 994 int i ; 995 i = target ; 996 return ( i / 60 ); 997} 998int MinSolarTime(float target) { 999 int i ; 1000 i = target ; 1001 return ( i % 60 ); 1002} 1003 1004float sign(float target) { 1005 if (target > 0 ) { 1006 return (1); 1007 } else { 1008 if (target < 0 ) { 1009 return (-1); 1010 } else { 1011 return (0); 1012 } 1013 } 1014} 1015 1016void DisplayMeatBall() { 1017 int pos , led , x , y; 1018 float dx , dy ; 1019 float dxa , dya ; 1020 1021 HT.setBrightness(15); 1022 1023 dx = xzAng - xzTarget ; 1024 dy = yzAng - yzTarget ; 1025 dxa = abs(dx) ; 1026 dya = abs(dy) ; 1027 if (dxa < 6) { 1028 x = 0 ; 1029 } else { 1030 if (dxa < 12) { 1031 x = sign(dx); 1032 } else { 1033 if (dxa < 50) { 1034 x = 2 * sign(dx); 1035 } else { 1036 x = 3 * sign(dx); 1037 } 1038 } 1039 } 1040 if (dya < 6) { 1041 y = 0 ; 1042 } else { 1043 if (dya < 12) { 1044 y = sign(dy); 1045 } else { 1046 if (dya < 25) { 1047 y = 2 * sign(dy); 1048 } else { 1049 y = 3 * sign(dy); 1050 } 1051 } 1052 } 1053 pos = 27 ; // netral position 1054 pos += (y * 8) ; // add or sumtract the x in range of -3 to +3 1055 pos += (x ) ; // add or sumtract 8 * y or y in range of -3 to +3 1056 for (led = 0; led < 63; led++) { 1057 switch (led){ 1058 case 0: 1059 case 7: 1060 case 56: 1061 case 63: 1062 break; 1063 default: 1064 HT.clearLedNow(MapLedNo(led)); 1065 break; 1066 } 1067 } 1068 1069 if ( ++iPMode > 100 ) { 1070 iPMode = 1 ; 1071 } 1072 switch(gps.satellites()){ 1073 case 255: 1074 HT.clearLedNow(MapLedNo(0)); // turn off four courners 1075 HT.clearLedNow(MapLedNo(7)); // turn off four courners 1076 HT.clearLedNow(MapLedNo(63)); // turn off four courners 1077 HT.clearLedNow(MapLedNo(56)); // turn off four courners 1078 break; 1079 case 1: 1080 case 2: 1081 HT.setLedNow(MapLedNo(0)); // turn on four courners 1082 HT.clearLedNow(MapLedNo(7)); // turn on four courners 1083 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1084 HT.clearLedNow(MapLedNo(56)); // turn on four courners 1085 break; 1086 case 3: 1087 HT.setLedNow(MapLedNo(0)); // turn on four courners 1088 HT.setLedNow(MapLedNo(7)); 1089 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1090 HT.clearLedNow(MapLedNo(56)); // turn on four courners 1091 break; 1092 case 4: 1093 HT.setLedNow(MapLedNo(0)); // turn on four courners 1094 HT.setLedNow(MapLedNo(7)); 1095 HT.setLedNow(MapLedNo(56)); 1096 HT.clearLedNow(MapLedNo(63)); // turn on four courners 1097 break; 1098 default: 1099 HT.setLedNow(MapLedNo(0)); // turn on four courners 1100 HT.setLedNow(MapLedNo(7)); 1101 HT.setLedNow(MapLedNo(56)); 1102 HT.setLedNow(MapLedNo(63)); 1103 break; 1104 } 1105 1106 1107 // HT.setLedNow(MapLedNo(tc.sec)); 1108 if ((iPWM_YZ == 0) && (iPWM_XZ == 0)) { 1109// HT.setBlinkRate(HT16K33_DSP_NOBLINK); // not attempting to move 1110 if ((tc.sec % 2) == 0 ) { 1111 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1112 HT.setLedNow(MapLedNo(pos + 9)); 1113 }else{ 1114 HT.setLedNow(MapLedNo(pos + 1)); 1115 HT.setLedNow(MapLedNo(pos + 8)); 1116 } 1117 } else { 1118// HT.setBlinkRate(HT16K33_DSP_BLINK2HZ); //moving so blink meat ball 1119 if (( iPMode % 2 ) == 0 ){ 1120 HT.setLedNow(MapLedNo(pos + 0)); // display the meatball 1121 HT.setLedNow(MapLedNo(pos + 1)); 1122 HT.setLedNow(MapLedNo(pos + 8)); 1123 HT.setLedNow(MapLedNo(pos + 9)); 1124 } 1125 } 1126} 1127 1128 1129int MapLedNo(int target) // this compensates for the screwy setup of the matrix driver to the chip 1130{ 1131 int row ; 1132 int col ; 1133 row = target / 8 ; 1134 col = target % 8 ; 1135 if (col == 0 ) { 1136 return ((row * 16 ) + 7) ; 1137 } else { 1138 return ((row * 16 ) + col - 1) ; 1139 } 1140} 1141 1142 1143float getPressure(double* Temp) 1144{ 1145 char status; 1146 double T,P; 1147 1148 status = pressure.startTemperature(); 1149 if (status != 0){ 1150 delay(status); // Wait for the measurement to complete: 1151 status = pressure.getTemperature(*Temp); 1152 if (status != 0){ 1153 status = pressure.startPressure(3); 1154 if (status != 0){ 1155 // Wait for the measurement to complete: 1156 delay(status); 1157 status = pressure.getPressure(P,*Temp); 1158 if (status != 0){ 1159 return(float(P)); 1160 } 1161 } 1162 } 1163 } 1164} 1165 1166 1167void processRequest(String req){ 1168unsigned int i , j ; 1169 i = req.indexOf("?tname="); // wanta do this one BEFORE we dick with captialisation of the request 1170 if (i != -1){ 1171 j = req.indexOf("&"); 1172 req.substring(i+7,j).toCharArray(trackername , 16) ; 1173 for (j=0 ; j < 16 ; j++){ 1174 if (trackername[j] == '+' ) { 1175 trackername[j] = ' ' ; 1176 } 1177 } 1178 } 1179 i = req.indexOf("?nssid="); // ssid setup 1180 if (i != -1){ 1181 j = req.indexOf("&"); 1182 req.substring(i+7,j).toCharArray(ssid , sizeof(ssid)) ; 1183 for (j=0 ; j < sizeof(ssid) ; j++){ 1184 if (ssid[j] == '+' ) { 1185 ssid[j] = ' ' ; 1186 } 1187 } 1188 } 1189 i = req.indexOf("?npass="); // password setup 1190 if (i != -1){ // have a request to set the time zone 1191 j = req.indexOf("&"); 1192 req.substring(i+7,j).toCharArray(pass , sizeof(pass)) ; 1193 for (j=0 ; j < sizeof(pass) ; j++){ 1194 if (pass[j] == '+' ) { 1195 pass[j] = ' ' ; 1196 } 1197 } 1198 } 1199 1200 i = req.indexOf("?naddr="); // ip address setup 1201 if (i != -1){ // have a request to set the time zone 1202 j = req.indexOf("&"); 1203 ip[0] = String(req.substring(i+7,j)).substring(0,3).toInt() ; 1204 ip[1] =String(req.substring(i+7,j)).substring(4,7).toInt() ; 1205 ip[2] = String(req.substring(i+7,j)).substring(8,11).toInt() ; 1206 ip[3] =String(req.substring(i+7,j)).substring(12,15).toInt() ; 1207 } 1208 1209 i = req.indexOf("/gpio/"); 1210 if (i != -1){ 1211 switch(req.charAt(i+6)){ 1212 case '0': 1213 break; 1214 case '1': 1215 break; 1216 case '2': 1217 break; 1218 case '3': 1219 break; 1220 case '4': 1221 break; 1222 case '5': 1223 break; 1224 case '6': 1225 break; 1226 case '7': 1227 break; 1228 case 'A': 1229 break; 1230 case 'B': 1231 break; 1232 case 'C': 1233 break; 1234 case 'T': // TssmmhhWDDMMYYYY aka set time same format as example eg T001513624032017 1235 t.sec = req.substring(i+7,i+9).toInt(); // 1 1236 t.min = req.substring(i+9,i+11).toInt(); // 3 1237 t.hour = req.substring(i+11,i+13).toInt(); // 5 1238 t.wday = req.charAt(i+13) - 48; // 7 1239 t.mday = req.substring(i+14,i+16).toInt(); // 8 1240 t.mon = req.substring(i+16,i+18).toInt();; // 10 1241 t.year = req.substring(i+18).toInt(); // 12 1242 // snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", t.year, t.mon, t.mday , t.hour, t.min, t.sec); 1243 // Serial.println(buff) ; 1244 DS3231_set(t); // set external RTC 1245 setTime((int)t.hour,(int)t.min,(int)t.sec,(int)t.mday,(int)t.mon,(int)t.year ) ; // set the internal RTC 1246 1247 break; 1248 case 't': // force NTP packet 1249// sendNTPpacket(timeServer); // send an NTP packet if requested to 1250 break; 1251 case 'S': // save all the params 1252 iDoSave = 2 ; 1253 break; 1254 case 'R': // read params back from eeprom 1255 iDoSave = 3 ; 1256 break; 1257 case 'Y': 1258 break; 1259 case 'X': 1260 break; 1261 default: 1262 break; 1263 } 1264 } 1265 1266 i = req.indexOf("?tmode="); 1267 if (i != -1){ // have a request to set the tracking mode 1268 iTrackMode = req.substring(i+7).toInt() ; 1269 if (( iTrackMode < -1) || ( iTrackMode > 4 )){ 1270 iTrackMode = -1 ; 1271 } 1272 } 1273 i = req.indexOf("?tzone="); 1274 if (i != -1){ // have a request to set the time zone 1275 timezone = req.substring(i+7).toInt() ; 1276 if (( timezone < -23) || ( timezone > 23 )){ 1277 timezone = 10 ; 1278 } 1279 } 1280 i = req.indexOf("?mylat="); //lat 1281 if (i != -1){ // have a request to set the latitude 1282 latitude = req.substring(i+7).toFloat() ; 1283 if (( latitude < -90) || ( latitude > 90 )){ 1284 latitude = -34.051219 ; 1285 } 1286 } 1287 i = req.indexOf("?mylon="); // long 1288 if (i != -1){ // have a request to set the logitude 1289 longitude = req.substring(i+7).toFloat() ; 1290 if (( longitude < -180) || ( longitude > 180 )){ 1291 longitude = 142.013618 ; 1292 } 1293 } 1294 i = req.indexOf("?minay="); 1295 if (i != -1){ // have a request to set minimum angle Y 1296 yMinVal = req.substring(i+7).toFloat() ; 1297 if (( yMinVal < -70) || ( yMinVal > 50 )){ 1298 yMinVal = -65 ; // set to default 1299 } 1300 } 1301 i = req.indexOf("?minax="); 1302 if (i != -1){ // have a request to set minimum angle X 1303 xMinVal = req.substring(i+7).toFloat() ; 1304 if (( xMinVal < -10) || ( xMinVal > 60 )){ 1305 xMinVal = 0 ; // set to default 1306 } 1307 } 1308 i = req.indexOf("?maxay="); 1309 if (i != -1){ // have a request to set maximum angle Y 1310 yMaxVal = req.substring(i+7).toFloat() ; 1311 if (( yMaxVal < -70) || ( yMaxVal > 50 )){ 1312 yMaxVal = 45 ; // set to default 1313 } 1314 } 1315 i = req.indexOf("?maxax="); 1316 if (i != -1){ // have a request to set maximum angle X 1317 xMaxVal = req.substring(i+7).toFloat() ; 1318 if (( xMaxVal < -10) || ( xMaxVal > 60 )){ 1319 xMaxVal = 50 ; // set to default 1320 } 1321 } 1322 i = req.indexOf("?paray="); 1323 if (i != -1){ // have a request to set park angle Y 1324 dyPark = req.substring(i+7).toFloat() ; 1325 if (( dyPark < -70) || ( dyPark > 50 )){ 1326 dyPark = 0 ; // set to default 1327 } 1328 } 1329 i = req.indexOf("?parax="); 1330 if (i != -1){ // have a request to set park angle X 1331 dxPark = req.substring(i+7).toFloat() ; 1332 if (( dxPark < -10) || ( dxPark > 60 )){ 1333 dxPark = 6 ; // set to default 1334 } 1335 } 1336 i = req.indexOf("?offay="); 1337 if (i != -1){ // have a request to set offset angle Y 1338 yzOffset = req.substring(i+7).toFloat() ; 1339 if (( yzOffset < -20) || ( yzOffset > 20 )){ 1340 yzOffset = 0 ; // set to default 1341 } 1342 } 1343 i = req.indexOf("?offax="); 1344 if (i != -1){ // have a request to set offset angle X 1345 xzOffset = req.substring(i+7).toFloat() ; 1346 if (( xzOffset < -20) || ( xzOffset > 20 )){ 1347 xzOffset = 0 ; // set to default 1348 } 1349 } 1350 i = req.indexOf("?hysay="); 1351 if (i != -1){ // have a request to set Hysterisis angle 1352 yzH = req.substring(i+7).toFloat() ; 1353 if (( yzH < -20) || ( yzH > 20 )){ 1354 yzH = 4 ; // set to default 1355 } 1356 } 1357 i = req.indexOf("?hysax="); 1358 if (i != -1){ // have a request to set Hysterisis angle 1359 xzH = req.substring(i+7).toFloat() ; 1360 if (( xzH < -20) || ( xzH > 20 )){ 1361 xzH = 4 ; // set to default 1362 } 1363 } 1364 i = req.indexOf("?taray="); 1365 if (i != -1){ // have a request to set Hysterisis angle 1366 yzTarget = req.substring(i+7).toFloat() ; 1367 if (( yzTarget < -70) || ( yzTarget > 50 )){ 1368 yzTarget = 0 ; // set to default 1369 } 1370 } 1371 i = req.indexOf("?tarax="); 1372 if (i != -1){ // have a request to set Hysterisis angle 1373 xzTarget = req.substring(i+7).toFloat() ; 1374 if (( xzTarget < -10) || ( xzTarget > 60 )){ 1375 xzTarget = 0 ; // set to default 1376 } 1377 } 1378 1379 i = req.indexOf("?mulax="); 1380 if (i != -1){ // have a request to set Axis Multiplier 1381 xMul = req.substring(i+7).toFloat() ; 1382 if (( xMul < -10) || ( xMul > 10 )){ 1383 xMul = 1.0 ; // set to default 1384 } 1385 } 1386 i = req.indexOf("?mulay="); 1387 if (i != -1){ // have a request to set Axis Multiplier 1388 yMul = req.substring(i+7).toFloat() ; 1389 if (( yMul < -10) || ( yMul > 10 )){ 1390 yMul = 1.0 ; // set to default 1391 } 1392 } 1393 i = req.indexOf("?mulaz="); 1394 if (i != -1){ // have a request to set Axis Multiplier 1395 zMul = req.substring(i+7).toFloat() ; 1396 if (( zMul < -10) || ( zMul > 10 )){ 1397 zMul = 1.0 ; // set to default 1398 } 1399 } 1400 i = req.indexOf("?xyswp="); 1401 if (i != -1){ // have a request to set the time zone 1402 iXYS = req.substring(i+7).toInt() ; 1403 if (( iXYS < 0) || ( iXYS > 1 )){ 1404 iXYS = 0 ; 1405 } 1406 } 1407 i = req.indexOf("?nisht="); 1408 if (i != -1){ // have a request to set the time zone 1409 iNightShutdown = req.substring(i+7).toInt() ; 1410 if (( iNightShutdown < 0) || ( iNightShutdown > 1 )){ 1411 iNightShutdown = 0 ; 1412 } 1413 } 1414 i = req.indexOf("?mltdr="); 1415 if (i != -1){ // have a request to set the time zone 1416 iMultiDrive = req.substring(i+7).toInt() ; 1417 if (( iMultiDrive < 0) || ( iMultiDrive > 1 )){ 1418 iMultiDrive = 0 ; 1419 } 1420 } 1421} 1422 1423 1424String sendTDTREnd(){ 1425 return(F("</td></tr>")); 1426} 1427 1428 1429void sendHttpResponse(WiFiEspClient client){ 1430String strOneRow ; 1431boolean currentLineIsBlank = true; 1432long j , i = 0 ; 1433 1434 strOneRow = F("HTTP/1.1 200 OK"); 1435 strOneRow += F("Content-Type: text/html"); 1436 strOneRow += F("Connection: close"); // the connection will be closed after completion of the response 1437 strOneRow += String("\ 1438\ \ 1439\ "); // this blank line be important 1440 strOneRow += F("<!DOCTYPE HTML>"); 1441 strOneRow += F("<head><title>Team Trouble - Solar Tracker</title>"); 1442 strOneRow += F("<meta name=viewport content='width=320, auto inital-scale=1'>"); 1443 strOneRow += F("<link rel='icon' href='data:,'>"); 1444 strOneRow += F("</head><body><html><center><h2>"); 1445 strOneRow += String(trackername).substring(0,16); 1446 strOneRow += F(" Solar Tracker</h2>"); 1447 strOneRow += F("<a href='/'>Refresh</a><br><br>") ; 1448 client.print(strOneRow); 1449 1450 if (hasRTC){ 1451 DS3231_get(&td); 1452 } 1453 strOneRow = F("<b>Clocks</b>") ; 1454 strOneRow += F("<table border=1 title='Clocks'>"); 1455 strOneRow += F("<tr><th>Clock Source</th><th>Time</th></tr>"); 1456 strOneRow += F("<tr><td>Dallas RTC</td><td align=right>"); 1457 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", td.year, td.mon, td.mday , tc.hour, tc.min, tc.sec); 1458 strOneRow += String(buff) ; 1459 strOneRow += sendTDTREnd(); 1460 strOneRow +=F("</td></tr>"); 1461 strOneRow += F("<tr><td>Last GPS</td><td align=right>"); 1462 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d<br>", tg.year, tg.mon, tg.mday , tg.hour, tg.min, tg.sec); 1463 strOneRow += String(buff) ; 1464 strOneRow += sendTDTREnd(); 1465 strOneRow += F("<tr><td><b>Arduino Time</b></td><td align=right><b>"); 1466 snprintf(buff, BUFF_MAX, "%d/%02d/%02d %02d:%02d:%02d", year(), month(), day() , hour(), minute(), second()); 1467 strOneRow += String(buff) ; 1468 strOneRow += sendTDTREnd(); 1469 strOneRow += F("</table>"); 1470 client.print(strOneRow); 1471 1472 strOneRow = F("<br><b>Tracker Control System</b>") ; 1473 strOneRow += F("<table border=1 title='Tracker Control'>"); 1474 strOneRow += F("<tr><th> Parameter</th><th>Value</th></tr>"); 1475 client.print(strOneRow); 1476 1477 strOneRow = F("<form method=get action=/><tr><td>Tracking Mode</td><td align=center>") ; 1478 strOneRow += F("<select name='tmode'>"); 1479 for (i = -1 ; i < 5 ; i++ ){ 1480 strOneRow += F("<option value='"); 1481 strOneRow += String(i) ; 1482 if ( iTrackMode == i ){ 1483 strOneRow +=F("' SELECTED>"); 1484 }else{ 1485 strOneRow += F("'>"); 1486 } 1487 strOneRow += String(i); 1488 strOneRow += " "; 1489 switch (i){ 1490 case -1: 1491 strOneRow += F("Track Both Park Both"); 1492 break; 1493 case 0: 1494 strOneRow += F("Track Both Park Only E/W"); 1495 break; 1496 case 1: 1497 strOneRow += F("Track and Park E/W Only"); 1498 break; 1499 case 2: 1500 strOneRow += F("Track and Park N/S Only"); 1501 break; 1502 case 3: 1503 strOneRow += F("Dont Track Dont Park"); 1504 break; 1505 case 4: 1506 strOneRow += F("Dont Track Park Both"); 1507 break; 1508 } 1509 } 1510 strOneRow += F("</select>") ; 1511 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1512 client.print(strOneRow); 1513 1514 strOneRow = F("<form method=get action=/><tr><td>Time Zone</td><td align=center>") ; 1515 strOneRow += F("<input type='text' name='tzone' value='"); 1516 strOneRow += String(timezone); 1517 strOneRow += F("' size=6 maxlength=2>") ; 1518 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1519 client.print(strOneRow); 1520 1521 strOneRow = F("<form method=get action=/><tr><td>Latitude +N -S</td><td align=center>") ; 1522 strOneRow += F("<input type='text' name='mylat' value='"); 1523 strOneRow += String(latitude,8); 1524 strOneRow += F("' size=12>") ; 1525 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1526 client.print(strOneRow); 1527 1528 strOneRow = F("<form method=get action=/><tr><td>Longitude</td><td align=center>") ; 1529 strOneRow += F("<input type='text' name='mylon' value='"); 1530 strOneRow += String(longitude,8); 1531 strOneRow += F("' size=12>") ; 1532 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1533 client.print(strOneRow); 1534 1535 strOneRow = F("<form method=get action=/><tr><td>X (N/S) Axis Multiplier</td><td align=center>") ; 1536 strOneRow += F("<input type='text' name='mulax' value='"); 1537 strOneRow += String(xMul,2); 1538 strOneRow += F("' size=5>") ; 1539 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1540 client.print(strOneRow); 1541 1542 strOneRow = F("<form method=get action=/><tr><td>Y (E/W) Axis Multiplier</td><td align=center>") ; 1543 strOneRow += F("<input type='text' name='mulay' value='"); 1544 strOneRow += String(yMul,2); 1545 strOneRow += F("' size=5>") ; 1546 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1547 client.print(strOneRow); 1548 1549 strOneRow = F("<form method=get action=/><tr><td>Z (Vert) Axis Multiplier</td><td align=center>") ; 1550 strOneRow += F("<input type='text' name='mulaz' value='"); 1551 strOneRow += String(zMul,2); 1552 strOneRow += F("' size=5>") ; 1553 strOneRow += F("</td><td><input type='submit' value='SET'></td></tr></form>"); 1554 client.print(strOneRow); 1555 1556 strOneRow = F("<form method=get action=/><tr><td>X<->Y Axis Swap</td><td align=center>") ; 1557 strOneRow += F("<select name='xyswp'>"); 1558 if (iXYS == 0 ){ 1559 strOneRow += F("<option value='0' SELECTED>0 Normal"); 1560 strOneRow += F("<option value='1'>1 Swapped"); 1561 }else{ 1562 strOneRow += F("<option value='0'>0 Normal"); 1563 strOneRow += F("<option value='1' SELECTED>1 Swapped"); 1564 } 1565 strOneRow += F("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 1566 client.print(strOneRow); 1567 1568 strOneRow = F("<form method=get action=/><tr><td>Night Shutdown</td><td align=center>") ; 1569 strOneRow += F("<select name='nisht'>"); 1570 if (iNightShutdown == 0 ){ 1571 strOneRow += F("<option value='0' SELECTED>0 Shutdown at Night"); 1572 strOneRow += F("<option value='1'>1 Always Active"); 1573 }else{ 1574 strOneRow += F("<option value='0'>0 Shutdown at Night"); 1575 strOneRow += F("<option value='1' SELECTED>1 Always Active"); 1576 } 1577 strOneRow += F("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 1578 client.print(strOneRow); 1579 1580 strOneRow = F("<form method=get action=/><tr><td>Multi Drive</td><td align=center>") ; 1581 strOneRow += F("<select name='mltdr'>"); 1582 if (iNightShutdown == 0 ){ 1583 strOneRow += F("<option value='0' SELECTED>0 One Axis at a Time"); 1584 strOneRow += F("<option value='1'>1 Both axis active at once"); 1585 }else{ 1586 strOneRow += F("<option value='0'>0 One Axis at a Time"); 1587 strOneRow += F("<option value='1' SELECTED>1 Both axis active at once"); 1588 } 1589 strOneRow += F("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 1590 client.print(strOneRow); 1591 1592 strOneRow = F("<form method=get action=/><tr><td>Tracker Name</td><td align=center><input type='text' name='tname' value='"); 1593 strOneRow += String(trackername) ; 1594 strOneRow += F("' size=16 maxlength=16><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>"); 1595 client.print(strOneRow); 1596 1597 strOneRow = F("<form method=get action=/><tr><td>Config SSID</td><td align=center><input type='text' name='nssid' value='"); 1598 strOneRow += String(ssid) ; 1599 strOneRow += F("' size=24 maxlength=24><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>"); 1600 client.print(strOneRow); 1601 1602 strOneRow = F("<form method=get action=/><tr><td>Config Password</td><td align=center><input type='text' name='npass' value='"); 1603 strOneRow += String(pass) ; 1604 strOneRow += F("' size=16 maxlength=16><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>"); 1605 client.print(strOneRow); 1606 1607 snprintf(buff, BUFF_MAX, "%03d.%03d.%03d.%03d", ip[0],ip[1],ip[2],ip[3]); 1608 strOneRow = F("<form method=get action=/><tr><td>Config IP Address</td><td align=center><input type='text' name='naddr' value='"); 1609 strOneRow += String(buff) ; 1610 strOneRow += F("' size=16 maxlength=24><input type='hidden' name='dummy' value='0'></td><td><input type='submit' value='SET'></td></tr></form>"); 1611 client.print(strOneRow); 1612 1613 if (( ip[0] == 0 )&&( ip[1] == 0 )&&( ip[2] == 0 )&&( ip[3] == 0 )){ 1614 snprintf(buff, BUFF_MAX, "%03d.%03d.%03d.%03d", CurrentIP[0],CurrentIP[1],CurrentIP[2],CurrentIP[3]); 1615 strOneRow = F("<tr><td>Current IP Address</td><td align=center>"); 1616 strOneRow += String(buff) ; 1617 strOneRow += F("</td><td>"); 1618 strOneRow += sendTDTREnd(); 1619 client.print(strOneRow); 1620 1621 strOneRow = F("<tr><td>WiFi RSSI</td><td align=center>"); 1622 strOneRow += String(WiFi.RSSI()) ; 1623 strOneRow += F("</td><td>(dBm)"); 1624 strOneRow += sendTDTREnd(); 1625 client.print(strOneRow); 1626 } 1627 1628 strOneRow = F("<tr><td>Solar Elevation Deg</td><td align=center>"); 1629 strOneRow += String(solar_el_deg,3) ; 1630 strOneRow += F("</td><td>(Deg)"); 1631 strOneRow += sendTDTREnd(); 1632 client.print(strOneRow); 1633 1634 strOneRow = F("<tr><td>Solar Azomuth</td><td align=center>"); 1635 strOneRow += String(solar_az_deg,3) ; 1636 strOneRow += F("</td><td>(Deg)"); 1637 strOneRow += sendTDTREnd(); 1638 client.print(strOneRow); 1639 1640 strOneRow = F("<tr><td>Sunrise</td><td align=center>"); 1641 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunrise), MinSolarTime(sunrise)); 1642 strOneRow += String(buff) ; 1643 strOneRow += F("</td><td>(hh:mm)"); 1644 strOneRow += sendTDTREnd(); 1645 client.print(strOneRow); 1646 1647 strOneRow = F("<tr><td>Sunset</td><td align=center>"); 1648 snprintf(buff, BUFF_MAX, "%02d:%02d", HrsSolarTime(sunset), MinSolarTime(sunset)); 1649 strOneRow += String(buff) ; 1650 strOneRow += F("</td><td>(hh:mm)"); 1651 strOneRow += sendTDTREnd(); 1652 client.print(strOneRow); 1653 1654 strOneRow = F("<tr><td>Day or Night</td><td align=center>"); 1655 if ( iDayNight == 1 ){ 1656 strOneRow += F("DAY"); 1657 }else{ 1658 strOneRow += F("NIGHT"); 1659 } 1660 strOneRow += sendTDTREnd(); 1661 client.print(strOneRow); 1662 1663 strOneRow = F("<tr><td>GPS lock age</td><td align=center>"); 1664 if ( fixage < 10000 ) { 1665 strOneRow += String(fixage) ; 1666 }else{ 1667 strOneRow += F("-- No Lock --") ; 1668 } 1669 strOneRow += F("</td><td>(ms)"); 1670 strOneRow += sendTDTREnd(); 1671 client.print(strOneRow); 1672 1673 strOneRow = F("<tr><td>GPS Satellites</td><td align=center>"); 1674 if ( gps.satellites() == 255 ){ 1675 strOneRow += F("-- No Lock --") ; 1676 }else{ 1677 strOneRow += String(gps.satellites()) ; 1678 } 1679 strOneRow += sendTDTREnd(); 1680 client.print(strOneRow); 1681 1682 strOneRow = F("<tr><td>GPS Chars</td><td align=center>"); 1683 strOneRow += String(gpschars) ; 1684 strOneRow += sendTDTREnd(); 1685 client.print(strOneRow); 1686 1687 strOneRow = F("<tr><td>RTC Temperature</td><td align=center>"); 1688 strOneRow += String(T,2) ; 1689 strOneRow += F("</td><td>(C)"); 1690 strOneRow += sendTDTREnd(); 1691 client.print(strOneRow); 1692 1693 strOneRow = F("<tr><td>P/T temp</td><td align=center>"); 1694 strOneRow += String(gT) ; 1695 strOneRow += F("</td><td>(C)"); 1696 strOneRow += sendTDTREnd(); 1697 client.print(strOneRow); 1698 1699 strOneRow = F("<tr><td>Pressue</td><td align=center>"); 1700 strOneRow += String(Pr) ; 1701 strOneRow += F("</td><td>(mBar)"); 1702 strOneRow += sendTDTREnd(); 1703 client.print(strOneRow); 1704 1705 strOneRow = F("<tr><td>Gyro X</td><td align=center>"); 1706 strOneRow += String(xRoll) ; 1707 strOneRow += sendTDTREnd(); 1708 client.print(strOneRow); 1709 1710 strOneRow = F("<tr><td>Gyro Y</td><td align=center>"); 1711 strOneRow += String(yRoll) ; 1712 strOneRow += sendTDTREnd(); 1713 client.print(strOneRow); 1714 1715 strOneRow = F("<tr><td>Gyro Z</td><td align=center>"); 1716 strOneRow += String(zRoll) ; 1717 strOneRow += sendTDTREnd(); 1718 strOneRow += F("</table><br>"); 1719 client.print(strOneRow); 1720 1721 strOneRow = F("<table border=1 title='Stracker Status'>"); 1722 strOneRow += F("<tr><th>Parameter</th><th>E/W Value</th><th>.</th><th>N/S Value</th><th>.</th></tr>"); 1723 1724 strOneRow += F("<tr><td>Min Angle</td><td><form method=get action=/><input type='text' name='minay' value='"); 1725 strOneRow += String(yMinVal); 1726 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='minax' value='"); 1727 strOneRow += String(xMinVal); 1728 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>"); 1729 client.print(strOneRow); 1730 1731 strOneRow = F("<tr><td>Max Angle</td><td><form method=get action=/><input type='text' name='maxay' value='"); 1732 strOneRow += String(yMaxVal); 1733 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='maxax' value='"); 1734 strOneRow += String(xMaxVal); 1735 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>"); 1736 client.print(strOneRow); 1737 1738 strOneRow = F("<tr><td>Park Angle</td><td><form method=get action=/><input type='text' name='paray' value='"); 1739 strOneRow += String(dyPark); 1740 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='parax' value='"); 1741 strOneRow += String(dxPark); 1742 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>") ; 1743 client.print(strOneRow); 1744 1745 strOneRow = F("<tr><td>Offest Angle</td><td><form method=get action=/><input type='text' name='offay' value='"); 1746 strOneRow += String(yzOffset); 1747 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='offax' value='"); 1748 strOneRow += String(xzOffset); 1749 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>") ; 1750 client.print(strOneRow); 1751 1752 strOneRow = F("<tr><td>Hysteris Angle</td><td><form method=get action=/><input type='text' name='hysay' value='"); 1753 strOneRow += String(yzH); 1754 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='hysax' value='"); 1755 strOneRow += String(xzH); 1756 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>") ; 1757 client.print(strOneRow); 1758 1759 if ( iTrackMode == 3 ){ 1760 strOneRow = F("<tr><td>Target Angle</td><td><form method=get action=/><input type='text' name='taray' value='"); 1761 strOneRow += String(yzTarget); 1762 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td><td><form method=get action=/><input type='text' name='tarax' value='"); 1763 strOneRow += String(xzTarget); 1764 strOneRow += F("' size=12></td><td><input type='submit' value='SET'></form></td></tr>") ; 1765 }else{ 1766 strOneRow = F("<tr><td>Target Angle</td><td>"); 1767 strOneRow += String(yzTarget); 1768 strOneRow += F("</td><td>(Deg)</td><td>") ; 1769 strOneRow += String(xzTarget); 1770 strOneRow += F("</td><td>(Deg)</td></tr>") ; 1771 } 1772 client.print(strOneRow); 1773 1774 strOneRow = F("<tr><td>Current Sensor Angle</td><td>"); 1775 strOneRow += String(yzAng); 1776 strOneRow += F("</td><td>(Deg)</td><td>") ; 1777 strOneRow += String(xzAng); 1778 strOneRow += F("</td><td>(Deg)</td></tr>") ; 1779 strOneRow += F("</table><br>") ; 1780 client.print(strOneRow); 1781 1782 strOneRow = "" ; 1783 if ( hasSD ) { 1784 strOneRow += F("<br><br><a href='index.htm'>Data Logs Files</a><br>") ; 1785 strOneRow += F("<a href='stats.htm'>Last 24 Hours Stats</a><br>") ; 1786 } 1787// strOneRow += F("<a href='/gpio/t'>Force NTP request</a><br>") ; 1788 strOneRow += F("<a href='/gpio/S'>Save Parameters to EEPROM</a><br>") ; 1789 strOneRow += F("<a href='/gpio/R'>Load Parameters from EEPROM</a><br>") ; 1790 strOneRow += F("</body></html>"); 1791 strOneRow += String("\ \ 1792\ \ 1793"); 1794 client.print(strOneRow); 1795} 1796 1797void sendHttpResponseNG(WiFiEspClient client) 1798{ 1799 client.print( 1800 "HTTP/1.1 404 File not found\ \ 1801" 1802 "Connection: close\ \ 1803" // the connection will be closed after completion of the response 1804 "\ \ 1805\ \ 1806You are barking mad - WOOF !!!"); 1807} 1808 1809 1810
Downloadable files
Tracker Schematic (mud map)
Tracker Schematic (mud map)
Tracker Schematic (mud map)
Tracker Schematic (mud map)
Documentation
North Elevation
Remember this was build by someone from the SOUTHERN hemisphere. All you upside down people need to swap things around
North Elevation
East West axis View
East West axis View
PV panel mounting with respect to the frame
PV panel mounting with respect to the frame
Mounting Post
Yeah this is the pointy end... important to get this bit right
Mounting Post
North Elevation
Remember this was build by someone from the SOUTHERN hemisphere. All you upside down people need to swap things around
North Elevation
Frame and Piviot
Frame and Piviot
Mounting Frame
Mounting Frame
Mounting Frame
Mounting Frame
PV panel mounting with respect to the frame
PV panel mounting with respect to the frame
East West axis View
East West axis View
Frame and Piviot
Frame and Piviot
Mounting Post
Yeah this is the pointy end... important to get this bit right
Mounting Post
Comments
Only logged in users can leave comments