Move to WeMos, etc

Move to WeMos, etc

Cleaned up a lot of code while transitioning to WeMos D1 Mini. Added over-the-air (OTA) support. Reworked EEPROM logic a bit. Workaround for RTC sync delay (line 502). Added a lot of comments.

--- hvacMonitor.ino
+++ hvacMonitor.ino
@@ -1,24 +1,25 @@
-#include <SimpleTimer.h>        // Timer library http://playground.arduino.cc/Code/SimpleTimer
-#define BLYNK_PRINT Serial      // Comment this out to disable prints and save space
-//#define BLYNK_DEBUG           // Turn this on to see everything Blynk is doing
+#include <SimpleTimer.h>        // Timer library
+#define BLYNK_PRINT Serial      // Turn this on to see basic Blynk activities
+//#define BLYNK_DEBUG           // Turn this on to see *everything* Blynk is doing... really fills up serial monitor!
 #include <ESP8266WiFi.h>
-#include <BlynkSimpleEsp8266.h>
+#include <ESP8266mDNS.h>        // Required for OTA
+#include <WiFiUdp.h>            // Required for OTA
+#include <ArduinoOTA.h>         // Required for OTA
+#include <BlynkSimpleEsp8266.h> // 6/22/16 Rev: Includes edit of this file to expand virtual pins
+#include <TimeLib.h>            // Used by WidgetRTC.h
+#include <WidgetRTC.h>          // Blynk's RTC
+#include <EEPROM.h>             // EEPROM library - keep HVAC total runtime values to survive restarts
+
 #include <OneWire.h>            // Temperature sensor library
 #include <DallasTemperature.h>  // Temperature sensor library
-#include <TimeLib.h>            // Used by WidgetRTC.h
-#include <WidgetRTC.h>          // Blynk's RTC
-#define ONE_WIRE_BUS 0          // GPIO location of the temperature sensors
-//#include <ArduinoJson.h>        // For parsing information from Weather Underground API
-#include <EEPROM.h>
-
+#define ONE_WIRE_BUS 13          // WeMos pin D7
 OneWire oneWire(ONE_WIRE_BUS);
 DallasTemperature sensors(&oneWire);

 DeviceAddress ds18b20RA = { 0x28, 0xEF, 0x97, 0x1E, 0x00, 0x00, 0x80, 0x54 }; // Return air probe - Device address found by going to File -> Examples -> DallasTemperature -> oneWireSearch
 DeviceAddress ds18b20SA = { 0x28, 0xF1, 0xAC, 0x1E, 0x00, 0x00, 0x80, 0xE8 }; // Supply air probe

-char auth[] = "fromBlynkApp"; // Assigned by Blynk's app
-
+char auth[] = "fromBlynkApp";
 char ssid[] = "ssid";
 char pass[] = "pw";

@@ -28,55 +29,51 @@

 SimpleTimer timer;

-WiFiClient client; // Try running without... might not need? I see this down already in the various subroutines
-
-WidgetLED led1(V2); // Heartbeat (status)
+WidgetLED led1(V2);        // Heartbeat (status)
 WidgetRTC rtc;
 BLYNK_ATTACH_WIDGET(rtc, V8);
 WidgetTerminal terminal(V26);

-int blowerPin = 2;  // 3.3V logic source from blower
-int xStop = 1;
-int xStart = 1;
-int alarmTrigger = 0;
-int alarmFor = 0;
-int xFirstRun = 0;
-int resetTattle = 0;
-int splitAlarmTime = 180; // 180s (3 min) timeout after a high split reading
-
-unsigned long onNow = now();
-unsigned long offNow = now(); // To prevent error on first Tweet after blower starts - NOT WORKING YET
-
-int offHour, offHour24, onHour, onHour24, offMinute, onMinute, offSecond, onSecond, offMonth, onMonth,
-    offDay, onDay, runTime, tempSplit, secondsCount, alarmTime, startHour, startMin, startMonth, startDay;
-
-int resetLatch = 0;
-
-int currentRuntimeSec;      // Sum of today's blower runtime in seconds
-int currentOfftimeSec = 0;
-int currentRuntimeMin;      // Sum of today's blower runtime in minutes
-int currentRuntimeStint;    // Current (last) duration of a blower fan run "cycle/session"
-int currentRuntimeStintMin; // Current (last) duration of a blower fan run "cycle/session"
-int yesterdayRuntime;       // Sum of yesterday's blower runtime in minutes
-int totalRuntimeLatch = 0;
-
-int dayCountLatch = 0;
-int todaysDate, yesterdaysDate, yesterdaysMonth;
-int msgLatch = 0;
-
-float tempRA, tempSA;       // Return and supply air temperatures
-
-// For EEPROM
-int eeIndex = 0;  // This is the EEPROM address location that keeps track of next EEPROM address available for storing a blower runtime.
-int eeCurrent;    // This is the next EEPROM address location that runtime will be stored to.
-int eeWBsum;      // This is the sum of all EEPROM addresses (total runtime stored).
+const int blowerPin = 12;  // WeMos pin D6. Todo: Change blowerPin to coolingPin (also, fanOnlyPin and heatingPin for future).
+int xStop = 1;             // Provides "latching" associated with recording unit start/stop time.
+int xStart = 1;            // Provides "latching" associated with recording unit start/stop time.
+int xFirstRun = 0;         // Think these kinds of things can be their own routines and triggred from void setup().
+int resetTattle = 0;       // Same as above, but might keep this to lockout other things.
+int resetLatch = 0;        // Same! This only functions to set the time and date displayed in-app after hardware restart.
+int rtcWait = 0;           // Due to Blynk RTC start delay...
+
+int offHour, offHour24,  // All used to send an HVAC run status string to Blynk's app.
+    onHour, onHour24, offMinute, onMinute, offMonth, onMonth, offDay, onDay;
+
+int tempSplit;                    // Difference between return and supply air.
+const int tempSplitSetpoint = 20; // Split lower than this value will send alarm notification.
+int alarmFor = 0;                 // Provides "latching" for high split alarm counting & functionality. 0 is normal. 1 is prealarm. 5 is alarmed and lockout.
+const int splitAlarmTime = 180;   // If a high split persists for this duration (in seconds), notification is sent.
+int alarmTime;                    // Seconds that high split alarm has been active.
+int resetHour, resetMin,          // ALSO BE MOVED to void setup() runOnce deal. Sets the date/time the hardware was reset.
+    resetMonth, resetDay;
+
+int todaysAccumRuntimeSec;            // Today's accumulated runtime in seconds - displays in app.
+int todaysAccumRuntimeMin;            // Today's accumulated runtime in minutes - displays in app.
+int currentCycleSec, currentCycleMin; // If HVAC is running, the duration of the current cycle (non-accumulating).
+int yesterdayRuntime;                 // Sum of yesterday's runtime in minutes - displays in app.
+int todaysDate;                       // Sets today's date related to things that reset at EOD.
+
+float tempRA, tempSA;  // Return and supply air temperatures
+
+const int eeIndex = 0;    // This is the EEPROM address location that keeps track of next EEPROM address available for storing a single blower cycle runtime.
+int eeCurrent = 1;        // This is the next EEPROM address location that cycle runtime will be stored to.
+int eeWBsum;              // This is the sum of all EEPROM addresses (total runtime stored).
+int eeTodaysStartsCount;  // Records how many times the unit has started today.
+

 void setup()
 {
   Serial.begin(9600);
+   WiFi.mode(WIFI_STA);
+
+  //WiFi.softAPdisconnect(true); // Per https://github.com/esp8266/Arduino/issues/676 this turns off AP
   Blynk.begin(auth, ssid, pass);
-
-  EEPROM.begin(201); // Reminder: "201" means addresses 0 to 200 are available (not 1 to 201 or 0 to 201).

   sensors.begin();
   sensors.setResolution(ds18b20RA, 10);
@@ -86,41 +83,65 @@
     // Wait until connected
   }

+    ArduinoOTA.onStart([]() {
+    Serial.println("Start");
+  });
+  ArduinoOTA.onEnd([]() {
+    Serial.println("\nEnd");
+  });
+  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
+  });
+  ArduinoOTA.onError([](ota_error_t error) {
+    Serial.printf("Error[%u]: ", error);
+    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
+    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
+    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
+    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
+    else if (error == OTA_END_ERROR) Serial.println("End Failed");
+  });
+  ArduinoOTA.begin();
+  Serial.println("Ready");
+  Serial.print("IP address: ");
+  Serial.println(WiFi.localIP());
+
+  rtc.begin();
+
+  EEPROM.begin(201); // EEPROM is zero-index: means addresses 0 to 200 are available (not 1 to 201 or 0 to 201).
+
   // START EEPROM WRITEBACK ROUTINE
-  if (EEPROM.read(eeIndex) > 1) // If this is true, than the index has advanced beyond the first position (meaning something was stored there (and maybe higher) to be written back.
-  {
-    for (int i = 1 ; i < 200 ; i++) {
-      eeWBsum += EEPROM.read(i);
-    }
-  }
-
-  // If there's something in EEPROM, write it to Today's Runtime
-  if (eeWBsum > 0) {
-    currentRuntimeSec = (eeWBsum * 60);
-  }
-
-  yesterdayRuntime = (EEPROM.read(200) * 4);
+  if (EEPROM.read(eeIndex) > 1)              // If this is true, than the index has advanced beyond the first position (meaning something was stored there (and maybe higher) to be written back.
+  {
+    for (int i = 1 ; i < 199 ; i++) {
+      eeWBsum += EEPROM.read(i);             // Add up values in addresses 1 through 198 and stick into eeWBsum.
+
+    }
+    eeTodaysStartsCount = EEPROM.read(199);    // Reads how many times the unit has started today (if any runs have been recorded).
+  }
+
+  todaysAccumRuntimeSec = (eeWBsum * 60);    // Writes seconds of today's accumulated runtime back to variable.
+  todaysAccumRuntimeMin = eeWBsum;           // Writes minutes of today's accumulated runtime back to variable (used for app runtime display only).
+  yesterdayRuntime = (EEPROM.read(200) * 4); // Writes minutes of yesterday's accumulated runtime back to variable (use for app runtime display only).
   // END EEPROM WRITEBACK ROUTINE

-  rtc.begin();
-
-  timer.setInterval(2500L, sendTemps);        // Temperature sensor polling interval
-  timer.setInterval(2500L, sendBlowerStatus); // Blower fan status polling interval
+  timer.setInterval(2500L, sendTemps);        // Temperature sensor polling and app display refresh interval.
+  timer.setInterval(2500L, sendStatus);       // Unit run status polling interval (for app Current Status display only).
   timer.setInterval(1000L, countRuntime);     // Counts blower runtime for daily accumulation displays.
   timer.setInterval(1000L, totalRuntime);     // Counts blower runtime for daily EEPROM storage.
-  timer.setInterval(500L, timeKeeper);
+  timer.setInterval(500L, timeKeeper);        // Track a cycle start/end time for app display.
   timer.setInterval(15432L, sfUpdate);        // ~15 sec run status updates to data.sparkfun.com

   heartbeatOn();
 }

-void loop()
+void loop()  // To keep Blynk happy, keep Blynk tasks out of the loop.
 {
   Blynk.run();
   timer.run();
-}
-
-void sfUpdate()  //  data.sparkfun update when unit is on
+  ArduinoOTA.handle();
+}
+
+void sfUpdate()
 {
   if (digitalRead(blowerPin) == LOW)
   {
@@ -161,8 +182,8 @@
     Serial.println();
     Serial.println("closing connection");
   }
-
- else if (digitalRead(blowerPin) == HIGH)
+
+  else if (digitalRead(blowerPin) == HIGH)
   {
     int runStatus = NULL;

@@ -212,15 +233,8 @@
   {
     long minDur = millis() / 60000L;
     long hourDur = millis() / 3600000L;
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
-    terminal.println(" ");
+    terminal.println(" "); terminal.println(" "); terminal.println(" "); terminal.println(" "); // Will CR work with terminal?
+    terminal.println(" "); terminal.println(" "); terminal.println(" "); terminal.println(" ");
     terminal.println("------------ UPTIME REPORT ------------");

     if (minDur < 121)
@@ -247,7 +261,7 @@
   timer.setTimeout(2500L, heartbeatOn);
 }

-BLYNK_WRITE(V19) // App button to reset EEPROM stored total and address
+BLYNK_WRITE(V19) // App button to reset EEPROM 0-200
 {
   int pinData = param.asInt();

@@ -257,12 +271,18 @@
     for (int i = 0 ; i < 201 ; i++) {
       EEPROM.write(i, 0);
     }
-    EEPROM.write(eeIndex, 1); // Defined address 1 as the starting location.
+    EEPROM.write(eeIndex, 1); // Define address 1 as the starting location.
     EEPROM.commit();
-  }
-}
-
-BLYNK_WRITE(V20) // App button to reset ESP
+
+    todaysAccumRuntimeSec = 0;  // Also zeros out variables so display is correct.
+    todaysAccumRuntimeMin = 0;
+    yesterdayRuntime = 0;
+    eeTodaysStartsCount = 0;
+    eeWBsum = 0;
+  }
+}
+
+BLYNK_WRITE(V20) // App button to reset hardware // THIS WORKING RIGHT HAS SOMETHING TO DO WITH GPIO0. Worked when I had DS18B20 on that pin!
 {
   int pinData = param.asInt();

@@ -274,26 +294,26 @@

 void sendTemps()
 {
-  sensors.requestTemperatures(); // Polls the sensors
+  sensors.requestTemperatures();                                            // Polls the sensors
   tempRA = sensors.getTempF(ds18b20RA);
   tempSA = sensors.getTempF(ds18b20SA);
   tempSplit = tempRA - tempSA;

-  // RETURN AIR - Blower pin logic voltage reversed due to high pull required on ESP8266-01 GPIOs at startup. Done with a BJT.
-  if (tempRA >= 0 && tempRA <= 120 && digitalRead(blowerPin) == LOW) // If temp 0-120F and blower running...
-  {
-    Blynk.virtualWrite(0, tempRA); // ...display the temp...
-  }
-  else if (tempRA >= 0 && tempRA <= 120 && digitalRead(blowerPin) == HIGH) // ...unless it's not running, then...
-  {
-    Blynk.virtualWrite(0, "OFF"); // ...display OFF, unless...
+  // RETURN AIR
+  if (tempRA >= 0 && tempRA <= 120 && digitalRead(blowerPin) == LOW)        // If temp 0-120F and blower running...
+  {
+    Blynk.virtualWrite(0, tempRA);                                          // ...display the temp...
+  }
+  else if (tempRA >= 0 && tempRA <= 120 && digitalRead(blowerPin) == HIGH)  // ...unless it's not running, then...
+  {
+    Blynk.virtualWrite(0, "OFF");                                           // ...display OFF, unless...
   }
   else
   {
-    Blynk.virtualWrite(0, "ERR"); // ...there's an error, then display ERR.
-  }
-
-  //SUPPLY AIR
+    Blynk.virtualWrite(0, "ERR");                                           // ...there's an error, then display ERR.
+  }
+
+  // SUPPLY AIR
   if (tempSA >= 0 && tempSA <= 120 && digitalRead(blowerPin) == LOW)
   {
     Blynk.virtualWrite(1, tempSA);
@@ -308,32 +328,34 @@
   }
 }

-void sendBlowerStatus()
+void sendStatus()
 {
   if (resetLatch == 0) // Sets ESP start/reset time and date to display in app until blower activity.
   {
-    startHour = hour();
-    startMin = minute();
-    startMonth = month();
-    startDay = day();
-    resetLatch++;
-  }
-
-  if (digitalRead(blowerPin) == HIGH && resetTattle == 0 && startMin > 9)
-  {
-    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + startHour + ":" + startMin + " " + startMonth + "/" + startDay);
-  }
-  else if (digitalRead(blowerPin) == HIGH && resetTattle == 0 && startMin < 10)
-  {
-    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + startHour + ":0" + startMin + " " + startMonth + "/" + startDay);
-  }
-  else if (digitalRead(blowerPin) == LOW && resetTattle == 0 && startMin > 9)
-  {
-    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + startHour + ":" + startMin + " " + startMonth + "/" + startDay);
-  }
-  else if (digitalRead(blowerPin) == LOW && resetTattle == 0 && startMin < 10)
-  {
-    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + startHour + ":0" + startMin + " " + startMonth + "/" + startDay);
+    resetHour = hour();
+    resetMin = minute();
+    resetMonth = month();
+    resetDay = day();
+    ++resetLatch;
+  }
+
+  // This wonderful mess displays what I need with AM/PM and leading zeros for minutes (for different scenarios).
+  // I've tried more elegant or lean solutions, but they ended up more complex with more lines of code!
+  if (digitalRead(blowerPin) == HIGH && resetTattle == 0 && resetMin > 9)
+  {
+    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + resetHour + ":" + resetMin + " on " + resetMonth + "/" + resetDay);
+  }
+  else if (digitalRead(blowerPin) == HIGH && resetTattle == 0 && resetMin < 10)
+  {
+    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + resetHour + ":0" + resetMin + " on " + resetMonth + "/" + resetDay);
+  }
+  else if (digitalRead(blowerPin) == LOW && resetTattle == 0 && resetMin > 9)
+  {
+    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + resetHour + ":" + resetMin + " on " + resetMonth + "/" + resetDay);
+  }
+  else if (digitalRead(blowerPin) == LOW && resetTattle == 0 && resetMin < 10)
+  {
+    Blynk.virtualWrite(16, String("SYSTEM RESET at ") + resetHour + ":0" + resetMin + " on " + resetMonth + "/" + resetDay);
   }
   else if (digitalRead(blowerPin) == HIGH && resetTattle == 1) // Runs when blower is OFF.
   {
@@ -375,104 +397,96 @@
   }
 }

-void totalRuntime() // Counts the current blower run session.
-{
-  if (digitalRead(blowerPin) == HIGH && currentRuntimeStint == 0) // Runs ONCE after reset if fan is OFF, or returns to OFF after being ON.
-  {
-    totalRuntimeLatch = 0;
-  }
-  else if (digitalRead(blowerPin) == LOW && totalRuntimeLatch == 0) // Runs while blower is ON (after reset or normal operation).
-  {
-    currentRuntimeStint++;
-  }
-  else if (digitalRead(blowerPin) == HIGH && currentRuntimeStint > 0) // Runs once after blower turns OFF (only after running and logging some runtime).
-  {
-    // INTENT IS TO ONLY READ FROM THIS IN THE EVENT OF A DEVICE RESET ehhh.... then.. why not put this in setup?!
-
-    currentRuntimeStintMin = (currentRuntimeStint / 60);
-    eeCurrent = EEPROM.read(eeIndex);
-    EEPROM.write(eeCurrent, currentRuntimeStintMin);
+void totalRuntime()
+{
+  if (digitalRead(blowerPin) == LOW) // If fan is running...
+  {
+    ++currentCycleSec;                          // accumulate the running time, however...
+    currentCycleMin = (currentCycleSec / 60);
+  }
+  else if (digitalRead(blowerPin) == HIGH && currentCycleSec > 0) // if fan is off but recorded some runtime...
+  {
+    EEPROM.write(199, ++eeTodaysStartsCount);   // Stores how many times the unit has started today... adds one start.
     EEPROM.commit();
-    eeCurrent++;
-    EEPROM.write(eeIndex, eeCurrent);
-    EEPROM.commit();
-    currentRuntimeStint = 0;
+
+    eeCurrent = EEPROM.read(eeIndex);           // Set eeCurrent as the value of the next available register. (Also, allows display of number of runs to survive reset.)
+    EEPROM.write(eeCurrent, currentCycleMin);   // Write runtime to EEPROM
+    EEPROM.commit();                            // Make it so  CAN WE JUST COMMIT ONCE? TESSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+
+    //eeCurrent++;                              // Advance to next EEPROM register for next run
+    EEPROM.write(eeIndex, ++eeCurrent);         // Advance to next EEPROM register (for next run) and write that next register to EEPROM
+    EEPROM.commit();                            // Make it so
+
+    currentCycleSec = 0;                        // Reset the current cycle clock
+    currentCycleMin = 0;
   }
 }

 void timeKeeper()
 {
-  if (digitalRead(blowerPin) == HIGH) // Runs when blower is OFF.
+  if (digitalRead(blowerPin) == HIGH) // Runs when unit is OFF.
   {
     // The following records the time the blower started.
     onHour24 = hour();
     onHour = hourFormat12();
     onMinute = minute();
-    onSecond = second();
     onMonth = month();
     onDay = day();

     if (xStop == 0) // This variable isn't set to zero until the blower runs for the first time after ESP reset.
     {
-      runTime = ( (offNow - onNow) / 60 );
-      xStop++;
+      ++xStop;
       resetTattle = 1;
     }
     xStart = 0;
-    onNow = now();
-  }
-  else
+  }
+  else if (digitalRead(blowerPin) == LOW) // Runs when unit is ON.  DEV: Why don't I run once on state change and just lock it out?
   {
     // The following records the time the blower stopped.
     offHour24 = hour();
     offHour = hourFormat12();
     offMinute = minute();
-    offSecond = second();
     offMonth = month();
     offDay = day();

     if (xStart == 0)
     {
-      runTime = ( (onNow - offNow) / 60 ); // Still need to make this report 'right' time on first run!
-
-      // After ESP startup (first run) this displays a message so RTC error doesn't mess with clock.
       if (xFirstRun == 0)
       {
-        xFirstRun++;
-        xStart++;
+        ++xFirstRun;
+        ++xStart;
         resetTattle = 1;
       }
       else
       {
-        //Blynk.tweet(String("A/C ON after ") + runTime + " minutes of inactivity. " + hour() + ":" + minute() + ":" + second() + " " + month() + "/" + day() + "/" + year());
-        xStart++;
+        ++xStart;
       }
     }
     xStop = 0;
-    offNow = now();
-  }
-
-  // Does the timing for the RA/SA split temperature alarm/notification.
+  }
+
+  // Does the timing for the RA/SA split temperature alarm.
   if (digitalRead(blowerPin) == LOW) // Blower is running.
   {
-    secondsCount = (millis() / 1000); // Start the clock that the alarm will reference.
-    if (tempSplit > 15) // > 15F is an acceptable split for alarm purposes (usually 20F in real life).
-    {
-      alarmFor = 0; // Resets alarm counting "latch."
-      alarmTime = 0; // Resets splitAlarmTime alarm.
-    }
-    else
+    int secondsCount = (millis() / 1000); // Running count that the alarm will reference after the first high split is noticed.
+
+    if (tempSplit > tempSplitSetpoint) // Condition normal. Reset any previous alarm if there was one.
+    {
+      alarmFor = 0;
+      alarmTime = 0;
+    }
+    else // Condition abnormal.
     {
       if (alarmFor == 0)
       {
         alarmTime = secondsCount + splitAlarmTime; // This sets the alarm time (from split out of spec to notification being sent)
-        alarmFor++; // Locks out alarm clock reset until alarmFor == 0.
+        ++alarmFor; // Locks out alarm clock reset until alarmFor == 0.
       }
     }
-    if (tempSplit <= 15 && secondsCount > alarmTime && alarmFor == 1)
+    if (tempSplit <= tempSplitSetpoint && secondsCount > alarmTime && alarmFor == 1)
     {
       Blynk.tweet(String("Low split (") + tempSplit + "°F) " + "recorded at " + hour() + ":" + minute() + ":" + second() + " " + month() + "/" + day() + "/" + year());
-      Blynk.notify(String("Low HVAC split: ") + tempSplit + "°F. Call Wolfgang's");
+      Blynk.notify(String("Low HVAC split: ") + tempSplit + "°F. Call Wolfgang's"); // ALT + 248 = °
       alarmFor = 5; // Arbitrary value indicating notification sent and locking out repetitive notifications.
     }
   }
@@ -485,93 +499,60 @@

 void countRuntime()
 {
-  // This makes sure the right numerical date for yesterday is shown for the first of any month.
-  if (day() == 1)
-  {
-    if (month() == 3) // The date before 3/1 is 29 (2/29), and so on below.
-    {
-      yesterdaysDate = 29;
-      yesterdaysMonth = month() - 1;
-    }
-    else if (month() == 5 || month() == 7 || month() == 10 || month() == 12)
-    {
-      yesterdaysDate = 30;
-      yesterdaysMonth = month() - 1;
-    }
-    else if (month() == 2 || month() == 4 || month() == 6 || month() == 8 || month() == 9 || month() == 11)
-    {
-      yesterdaysDate = 31;
-      yesterdaysMonth = month() - 1;
-    }
-    else if (month() == 1)
-    {
-      yesterdaysDate = 31;
-      yesterdaysMonth = 12;
-    }
-  }
-  else
-  {
-    yesterdaysDate = day() - 1; // Subtracts 1 day to get to yesterday unless it's the first of the month (see above)
-    yesterdaysMonth = month();
-  }
-
-  // Sets the date once after reset/boot up, or when the date actually changes.
-  if (dayCountLatch == 0)
-  {
-    todaysDate = day();
-    dayCountLatch++;
-  }
-
-  // Runs today's blower timer when the blower starts.
-  if (digitalRead(blowerPin) == LOW && todaysDate == day())
-  {
-    currentRuntimeSec++;
-  }
-  // Resets the timer on the next day if the blower is running.
-  else if (digitalRead(blowerPin) == LOW && todaysDate != day())
-  {
-    yesterdayRuntime = currentRuntimeMin; // Moves today's runtime to yesterday for the app display.
-    dayCountLatch = 0; // Allows today's date to be reset.
-    currentRuntimeSec = 0; // Reset today's sec timer.
-    currentRuntimeMin = 0; // Reset today's min timer.
-
-    // Resets EEPROM at the end of the day (except for yesterday's runtime)
-    for (int i = 0 ; i < 200 ; i++) {
-      EEPROM.write(i, 0);
-    }
-    EEPROM.write(eeIndex, 1); // Defined address 1 as the starting location.
-    EEPROM.write(200, (yesterdayRuntime / 4)); // Write yesterday's runtime to EEPROM
-    EEPROM.commit();
-  }
-  // Resets the timer on the next day if the blower isn't running.
-  else if (digitalRead(blowerPin) == HIGH && todaysDate != day())
-  {
-    yesterdayRuntime = currentRuntimeMin;
-    dayCountLatch = 0;
-    currentRuntimeSec = 0;
-    currentRuntimeMin = 0;
-
-    // Resets EEPROM at the end of the day (except for yesterday's runtime)
-    for (int i = 0 ; i < 200 ; i++) {
-      EEPROM.write(i, 0);
-    }
-    EEPROM.write(eeIndex, 1); // Defined address 1 as the starting location.
-    EEPROM.write(200, (yesterdayRuntime / 4)); // Write yesterday's runtime to EEPROM
-    EEPROM.commit();
-  }
-
-  currentRuntimeMin = (currentRuntimeSec / 60);
-  Blynk.virtualWrite(14, String(yesterdayRuntime) + " minutes");
-  if (currentRuntimeMin < 1)
-  {
-    Blynk.virtualWrite(15, "None");
-  }
-  else if (currentRuntimeMin > 0 && eeCurrent < 1)
-  {
-    Blynk.virtualWrite(15, String(currentRuntimeMin) + " minutes");
-  }
-  else if (currentRuntimeMin > 0 && eeCurrent > 0)
-  {
-    Blynk.virtualWrite(15, String(currentRuntimeMin) + " mins (" + (eeCurrent - 1) + " runs)");
-  }
-}
+  if (year() != 1970) // Doesn't start counting until RTC is started correctly.
+  {
+
+    if (rtcWait == 0) // Sets the date (once per hardware restart) now that RTC is correct.
+    {
+      todaysDate = day();
+      ++rtcWait;
+    }
+
+    if (digitalRead(blowerPin) == LOW && todaysDate == day()) // Accumulates seconds unit is running today.
+    {
+      ++todaysAccumRuntimeSec;
+      todaysAccumRuntimeMin = (todaysAccumRuntimeSec / 60);
+    }
+    else if (todaysDate != day())
+    {
+      yesterdayRuntime = todaysAccumRuntimeMin; // Moves today's runtime to yesterday for the app display.
+      todaysAccumRuntimeSec = 0; // Reset today's sec timer.
+      todaysAccumRuntimeMin = 0; // Reset today's min timer.
+      eeTodaysStartsCount = 0;   // Reset how many times unit has started today.
+      todaysDate = day();
+
+      // Resets EEPROM at the end of the day (except for yesterday's runtime)
+      for (int i = 0 ; i < 200 ; i++) {
+        EEPROM.write(i, 0);
+      }
+      EEPROM.write(eeIndex, 1);                  // Define address 1 as the starting location.
+      EEPROM.write(200, (yesterdayRuntime / 4)); // Write yesterday's runtime to EEPROM
+      EEPROM.write(199, 0);                      // Resets how many times the unit has started today.
+      EEPROM.commit();
+    }
+
+
+    if (yesterdayRuntime < 1)
+    {
+      Blynk.virtualWrite(14, "None");
+    }
+    else
+    {
+      Blynk.virtualWrite(14, String(yesterdayRuntime) + " minutes");
+    }
+
+
+    if (todaysAccumRuntimeSec < 1)
+    {
+      Blynk.virtualWrite(15, "None");
+    }
+    else if (todaysAccumRuntimeMin > 0 && eeCurrent < 1)
+    {
+      Blynk.virtualWrite(15, String(todaysAccumRuntimeMin) + " minutes");
+    }
+    else if (todaysAccumRuntimeMin > 0 && eeCurrent > 0)
+    {
+      Blynk.virtualWrite(15, String(todaysAccumRuntimeMin) + " mins (" + (eeTodaysStartsCount) + " runs)");
+    }
+  }
+}


added calibration by axis

added calibration by axis

--- software/Arduino/ServoController/ServoController.ino
+++ software/Arduino/ServoController/ServoController.ino
@@ -17,8 +17,9 @@
 const int motorUpdateRate = 50; // gyro sample rate
 const int calibrationSamples = 1000;

-// Initial calibration value
-float calibratedOffset;
+// Initial calibration value [x, y, z]
+char dims[] = {'x', 'y', 'z'};
+float calibrationOffset[] = {0, 0, 0};

 // Indicator LED
 const int LED = 13;
@@ -56,10 +57,10 @@
   setupIMU(); // Gyro

   // Calibrate the gyro
-  calibratedOffset = zeroGyro(calibrationSamples);
+  zeroGyro();

   // Find the sun to center on
-  findSun(); // comment this line out for basic testing
+  // findSun(); // comment this line out for basic testing

   // Setup motor update interval timer
   MsTimer2::set(motorUpdateRate, updateMotor);
@@ -88,7 +89,7 @@
   int currentTime = millis();

   int deltaT = currentTime - timer;
-  positionChange += deltaT * (readGyro()) / 1000; // Gyro data is given in 1000ths of a degree, so we divide by 1000
+  positionChange += deltaT * (readGyro('z')) / 1000; // Gyro data is given in 1000ths of a degree, so we divide by 1000
   timer = currentTime;

   // Update motor position
@@ -139,12 +140,26 @@
     Reads the IMU's gyro
     @return rate in degrees / ms
 */
-float readGyro() {
+float readGyro(char dim) {
   if (imu.gyroAvailable()) {
     imu.readGyro();
   }
-  return imu.calcGyro(imu.gz) - calibratedOffset;
-}
+  switch (dim) {
+  case 'x':
+    return imu.calcGyro(imu.gx) - calibrationOffset[0];
+    break;
+  case 'y':
+    return imu.calcGyro(imu.gy) - calibrationOffset[1];
+    break;
+  case 'z':
+    return imu.calcGyro(imu.gz) - calibrationOffset[2];
+    break;
+  default:
+    return 0;
+    break;
+  }
+}
+

 /**
@@ -153,15 +168,21 @@
     @param number of calibration samples
     @returns degrees of gyro drift per second
 */
-float zeroGyro(int calibrationSamples) {
-  float gyroSum = 0;
+void zeroGyro() {
+  float gyroSum;
+  char active_dim;
   digitalWrite(LED, HIGH);
-  for (int i = 0; i < calibrationSamples; i++) {
-    gyroSum += readGyro();
-  }
-  blinkLED(300, 5);
-  Serial.println(gyroSum / calibrationSamples);
-  return gyroSum / calibrationSamples;
+  for (int j = 0; j < 3; j++) {
+    active_dim = dims[j];
+    gyroSum = 0;
+    for (int i = 0; i < calibrationSamples; i++) {
+      gyroSum += readGyro(active_dim);
+      }
+    Serial.println(active_dim);
+    Serial.println(gyroSum / calibrationSamples);
+    calibrationOffset[j] = gyroSum / calibrationSamples;
+    blinkLED(300, 5);
+  }
 }

 /**


Update RS485_SP485EEN.ino

Update RS485_SP485EEN.ino

--- examples/Unit/RS485_SP485EEN/RS485_SP485EEN.ino
+++ examples/Unit/RS485_SP485EEN/RS485_SP485EEN.ino
@@ -27,7 +27,6 @@
   M5.Power.begin();
   M5.Lcd.setTextSize(1);
   M5.Lcd.drawString("RS485 Unit test", 75, 3, 4);
-  Serial.begin(115200);
   Serial2.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);  //Set the baud rate of serial port 2 to 115200,8 data bits, no parity bits, and 1 stop bit, and set RX to 16 and TX to 17.  设置串口二的波特率为115200,8位数据位,没有校验位,1位停止位,并设置RX为16,TX为17
 }

@@ -39,4 +38,4 @@
     M5.Lcd.print(char(Serial2.read()));
  }
   delay(100);
-}+}


highbuad rate works fine, but arduino monitor can't deal with it. I used picocom and my 3GHz laptop had no problems keeping up with 2.65MBaud

--- arduino/due/due.ino
+++ arduino/due/due.ino
@@ -1,5 +1,17 @@
-//#include "sam3xcounter.h"
+
 Print &dbg(Serial);
+
+template <Print &one,Print &two> struct PrintFork {
+  template <typename Any> void print(Any thing){
+    one.print(thing);
+    two.print(thing);
+  }
+  template <typename Any> void println(Any thing){
+    one.println(thing);
+    two.println(thing);
+  }
+
+};

 //use a macro to get variable name:
 #define Show(arg) dbg.print("\n" #arg ":");dbg.print(arg)
@@ -160,7 +172,7 @@

 void setup() {
   SerialUSB.begin(230400);//'native' usb port
-  Serial.begin(115200);//an actual uart
+  Serial.begin(2625000);//an actual uart, on DUE DMA is used so we should be able to push the baud rate quite high without choking the processor with interrupts.
   //Pin structs take care of themselves, unless you need special modes outside arduino's libraries.
   b2irq.attach(true);//we don't build in attach() to the constructor as in many cases the isr needs stuff that isn't initialized until setup() is run.
   b1irq.attach(true);
@@ -173,9 +185,9 @@
 int lastlocation=0;
 void loop() {
   __WFE();
-  //dbg.print("+");
   if(changed(lastlocation,location)){
-    dbg.print('\t');
+    //initially this printed sequential values, but eventually only every 6 or 7, then choked.Will try usbserial again, maybe it can keep up.
+    dbg.print('\n');
     dbg.print(location);
   }
 }


Korrektur nun 1

Korrektur nun 1

--- netzfrequenz.ino
+++ netzfrequenz.ino
@@ -6,7 +6,8 @@

 #define PROBE_COUNT 50
 #define MICROS 1000000.
-#define KORREKTUR 1.001341341
+// #define KORREKTUR 1.001341341
+#define KORREKTUR 1.

 #define DEBUG 0


Trailing spaces in Hello_World deleted

Trailing spaces in Hello_World deleted

--- libraries/BLE/examples/ble_A_Hello_World_Program/ble_A_Hello_World_Program.ino
+++ libraries/BLE/examples/ble_A_Hello_World_Program/ble_A_Hello_World_Program.ino
@@ -18,7 +18,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-
+

 /** @defgroup ble_uart_project_template ble_uart_project_template
 @{
@@ -26,7 +26,7 @@
 @brief Empty project that can be used as a template for new projects.

 @details
-This project is a firmware template for new projects.
+This project is a firmware template for new projects.
 The project will run correctly in its current state.
 It can send data on the UART TX characteristic
 It can receive data on the UART RX characterisitc.
@@ -34,7 +34,7 @@

 The following instructions describe the steps to be made on the Windows PC:

- -# Install the Master Control Panel on your computer. Connect the Master Emulator
+ -# Install the Master Control Panel on your computer. Connect the Master Emulator
     (nRF2739) and make sure the hardware drivers are installed.

 -# You can use the nRF UART app in the Apple iOS app store and Google Play for Android 4.3 for Samsung Galaxy S4
@@ -49,15 +49,15 @@
  * The loop() function as the name implies is called in a loop.
  *
  * The setup() and loop() function are called in this way.
- * main()
+ * main()
  *  {
- *   setup();
+ *   setup();
  *   while(1)
  *   {
  *     loop();
  *   }
  * }
- *
+ *
  */
 #include <SPI.h>
 #include <avr/pgmspace.h>
@@ -87,7 +87,7 @@
 /* Store the setup for the nRF8001 in the flash of the AVR to save on RAM */
 static hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM = SETUP_MESSAGES_CONTENT;

-// aci_struct that will contain
+// aci_struct that will contain
 // total initial credits
 // current credit
 // current state of the aci (setup/standby/active/sleep)
@@ -142,23 +142,23 @@
 When a command it received a response(s) are transmitted back.
 Since the response is done using a Notification the peer must have opened it(subscribed to it) before any packet is transmitted.
 The pipe for the UART_TX becomes available once the peer opens it.
-See section 20.4.1 -> Opening a Transmit pipe
+See section 20.4.1 -> Opening a Transmit pipe
 In the master control panel, clicking Enable Services will open all the pipes on the nRF8001.

 The ACI Evt Data Credit provides the radio level ack of a transmitted packet.
 */
 void setup(void)
-{
+{
 	Serial.begin(115200);
 	//Wait until the serial port is available (useful only for the leonardo)
 	while(!Serial)
-	{}
+	{}
 	Serial.println(F("Arduino setup"));
 	Serial.println(F("Set line ending to newline to send data from the serial monitor"));
-
+
 	/**
 	Point ACI data structures to the the setup data that the nRFgo studio generated for the nRF8001
-	*/
+	*/
 	if (NULL != services_pipe_type_mapping)
 	{
 	aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0];
@@ -174,23 +174,23 @@
 	/*
 	Tell the ACI library, the MCU to nRF8001 pin connections.
 	The Active pin is optional and can be marked UNUSED
-	*/
+	*/
 	aci_state.aci_pins.board_name = BOARD_DEFAULT; //See board.h for details REDBEARLAB_SHIELD_V1_1 or BOARD_DEFAULT
 	aci_state.aci_pins.reqn_pin   = 9; //SS for Nordic board, 9 for REDBEARLAB_SHIELD_V1_1
 	aci_state.aci_pins.rdyn_pin   = 8; //3 for Nordic board, 8 for REDBEARLAB_SHIELD_V1_1
 	aci_state.aci_pins.mosi_pin   = MOSI;
 	aci_state.aci_pins.miso_pin   = MISO;
 	aci_state.aci_pins.sck_pin    = SCK;
-
+
 	aci_state.aci_pins.spi_clock_divider          = SPI_CLOCK_DIV8;
-
+
 	aci_state.aci_pins.reset_pin             = 4; //4 for Nordic board, UNUSED for REDBEARLAB_SHIELD_V1_1
 	aci_state.aci_pins.active_pin            = UNUSED;
 	aci_state.aci_pins.optional_chip_sel_pin = UNUSED;
-
+
 	aci_state.aci_pins.interface_is_interrupt	  = true;
 	aci_state.aci_pins.interrupt_number			  = 1;
-
+
 	//We reset the nRF8001 here by toggling the RESET line connected to the nRF8001
 	//If the RESET line is not available we call the ACI Radio Reset to soft reset the nRF8001
 	//then we initialize the data structures required to setup the nRF8001
@@ -205,7 +205,7 @@
 bool uart_tx(uint8_t *buffer, uint8_t buffer_len)
 {
 	bool status = false;
-
+
 	if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) &&
 	    (aci_state.data_credit_available >= 1))
 	{
@@ -215,7 +215,7 @@
 			aci_state.data_credit_available--;
 		}
 	}
-
+
 	return status;
 }

@@ -223,7 +223,7 @@
 {
     bool status = false;
     aci_ll_conn_params_t *conn_params;
-
+
 	if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_TX) )
     {
         Serial.println(*byte, HEX);
@@ -237,12 +237,12 @@
                 /*
                 Parameters:
                 None
-                */
+                */
                 lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE);
                 status = true;
                 break;
-
-
+
+
             /*
             Queues an ACI Change Timing to the nRF8001
             */
@@ -254,17 +254,17 @@
                 Slave latency:           2 bytes
                 Timeout:                 2 bytes
                 Same format as Peripheral Preferred Connection Parameters (See nRFgo studio -> nRF8001 Configuration -> GAP Settings
-                Refer to the ACI Change Timing Request in the nRF8001 Product Specifications
+                Refer to the ACI Change Timing Request in the nRF8001 Product Specifications
                 */
                 conn_params = (aci_ll_conn_params_t *)(byte+1);
-                lib_aci_change_timing( conn_params->min_conn_interval,
-                                        conn_params->max_conn_interval,
-                                        conn_params->slave_latency,
+                lib_aci_change_timing( conn_params->min_conn_interval,
+                                        conn_params->max_conn_interval,
+                                        conn_params->slave_latency,
                                         conn_params->timeout_mult);
                 status = true;
                 break;
-
-
+
+
             /*
             Clears the RTS of the UART over BLE
             */
@@ -274,10 +274,10 @@
                 None
                 */
                 uart_over_ble.uart_rts_local = false;
-                status = true;
+                status = true;
                 break;
-
-
+
+
             /*
             Set the RTS of the UART over BLE
             */
@@ -287,11 +287,11 @@
                 None
                 */
                 uart_over_ble.uart_rts_local = true;
-                status = true;
+                status = true;
                 break;
         }
     }
-
+
     return status;
 }

@@ -303,8 +303,8 @@
   if (lib_aci_event_get(&aci_state, &aci_data))
   {
     aci_evt_t * aci_evt;
-
-    aci_evt = &aci_data.evt;
+
+    aci_evt = &aci_data.evt;
     switch(aci_evt->evt_opcode)
     {
         /**
@@ -322,7 +322,7 @@
               Serial.println(F("Evt Device Started: Setup"));
               setup_required = true;
               break;
-
+
             case ACI_DEVICE_STANDBY:
               Serial.println(F("Evt Device Started: Standby"));
               //Looking for an iPhone by sending radio advertisements
@@ -336,12 +336,12 @@
               lib_aci_connect(0/* in seconds : 0 means forever */, 0x0050 /* advertising interval 50ms*/);
               Serial.println(F("Advertising started : Tap Connect on the nRF UART app"));
               }
-
+
               break;
           }
         }
         break; //ACI Device Started Event
-
+
       case ACI_EVT_CMD_RSP:
         //If an ACI command response event comes with an error -> stop
         if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status)
@@ -357,7 +357,7 @@
         if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode)
         {
           //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic
-          lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET,
+          lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET,
             (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t));
         }

@@ -365,54 +365,54 @@
         {
            char hello[]="Hello World, works";
            uart_tx((uint8_t *)&hello[0], strlen(hello));
-           Serial.print(F("Sending :"));
+           Serial.print(F("Sending :"));
            Serial.println(hello);
         }
         break;
-
+
       case ACI_EVT_CONNECTED:
         Serial.println(F("Evt Connected"));
         uart_over_ble_init();
         timing_change_done              = false;
         aci_state.data_credit_available = aci_state.data_credit_total;
-
+
         /*
         Get the device version of the nRF8001 and store it in the Hardware Revision String
         */
         lib_aci_device_version();
         break;
-
+
       case ACI_EVT_PIPE_STATUS:
         Serial.println(F("Evt Pipe Status"));
         if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done))
         {
-          lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP.
+          lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP.
                                             // Used to increase or decrease bandwidth
           timing_change_done = true;
         }
         break;
-
+
       case ACI_EVT_TIMING:
         Serial.println(F("Evt link connection interval changed"));
-        lib_aci_set_local_data(&aci_state,
+        lib_aci_set_local_data(&aci_state,
                                 PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET,
                                 (uint8_t *)&(aci_evt->params.timing.conn_rf_interval), /* Byte aligned */
                                 PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET_MAX_SIZE);
         break;
-
+
       case ACI_EVT_DISCONNECTED:
         Serial.println(F("Evt Disconnected/Advertising timed out"));
         lib_aci_connect(0/* in seconds  : 0 means forever */, 0x0050 /* advertising interval 50ms*/);
-        Serial.println(F("Advertising started. Tap Connect on the nRF UART app"));
-        break;
-
+        Serial.println(F("Advertising started. Tap Connect on the nRF UART app"));
+        break;
+
       case ACI_EVT_DATA_RECEIVED:
-		Serial.print(F("Pipe Number: "));
+		Serial.print(F("Pipe Number: "));
 		Serial.println(aci_evt->params.data_received.rx_data.pipe_number, DEC);

-		if (PIPE_UART_OVER_BTLE_UART_RX_RX == aci_evt->params.data_received.rx_data.pipe_number)
+		if (PIPE_UART_OVER_BTLE_UART_RX_RX == aci_evt->params.data_received.rx_data.pipe_number)
 			{
-
+
 			  Serial.print(F(" Data(Hex) : "));
 			  for(int i=0; i<aci_evt->len - 2; i++)
 			  {
@@ -420,11 +420,11 @@
 				uart_buffer[i] = aci_evt->params.data_received.rx_data.aci_data[i];
 				Serial.print(F(" "));
 			  }
-			  uart_buffer_len = aci_evt->len - 2;
+			  uart_buffer_len = aci_evt->len - 2;
 			  Serial.println(F(""));
 			  if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX))
 			  {
-
+
 					/*Do this to test the loopback otherwise comment it out
 					*/
 					/*
@@ -444,31 +444,31 @@
             uart_process_control_point_rx(&aci_evt->params.data_received.rx_data.aci_data[0], aci_evt->len - 2); //Subtract for Opcode and Pipe number
         }
         break;
-
+
       case ACI_EVT_DATA_CREDIT:
         aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit;
         break;
-
+
       case ACI_EVT_PIPE_ERROR:
         //See the appendix in the nRF8001 Product Specication for details on the error codes
         Serial.print(F("ACI Evt Pipe Error: Pipe #:"));
         Serial.print(aci_evt->params.pipe_error.pipe_number, DEC);
         Serial.print(F("  Pipe Error Code: 0x"));
         Serial.println(aci_evt->params.pipe_error.error_code, HEX);
-
+
         //Increment the credit available as the data packet was not sent.
-        //The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted
+        //The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted
         //for the credit.
         if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aci_evt->params.pipe_error.error_code)
         {
           aci_state.data_credit_available++;
         }
         break;
-
+
       case ACI_EVT_HW_ERROR:
         Serial.print(F("HW error: "));
         Serial.println(aci_evt->params.hw_error.line_num, DEC);
-
+
         for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++)
         {
         Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20];
@@ -477,7 +477,7 @@
         lib_aci_connect(0/* in seconds, 0 means forever */, 0x0050 /* advertising interval 50ms*/);
         Serial.println(F("Advertising started. Tap Connect on the nRF UART app"));
         break;
-
+
     }
   }
   else
@@ -508,13 +508,13 @@

   //Process any ACI commands or events
   aci_loop();
-
+
   // print the string when a newline arrives:
   if (stringComplete) {
     Serial.print(F("Sending: "));
     Serial.println(inputString);
     inputString.toCharArray((char*)uart_buffer,20);
-
+
     if (inputString.length() > 20)
     {
         uart_buffer_len = 20;
@@ -525,7 +525,7 @@
     {
         uart_buffer_len = inputString.length();
     }
-
+
     if (!lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, uart_buffer, uart_buffer_len))
       {
         Serial.println(F("Serial input dropped"));


Arduino

Arduino

--- arduino_script/arduino_script.ino
+++ arduino_script/arduino_script.ino
@@ -24,12 +24,22 @@

 // Loop function that gets executed after setup
 void loop() {
-  // Update Potentiometer and Button Value and check for a Request
+  // Update Values
   updatePotentiometerValue();
   updateButtonValue();
   checkRequestAndReturn();
   // Stop the program for some time
   delay(updateRate);
+}
+
+// Update the Potentiometer Value
+void updatePotentiometerValue() {
+  valPoti = analogRead(potPin);
+}
+
+// Update the Button Value
+void updateButtonValue() {
+  valButton = digitalRead(switchPin);
 }

 // Actual Request Pattern. Check if there was an Input and send the right Value via Serial Connection if there was one
@@ -45,16 +55,6 @@
   }
 }

-// Update the Potentiometer Value
-void updatePotentiometerValue() {
-  valPoti = analogRead(potPin);
-}
-
-// Update the Button Value
-void updateButtonValue() {
-  valButton = digitalRead(switchPin);
-}
-
 // Convert int to a String to Write it to the serial Connection
 String formatReturn(int returned_val) {
   return String(returned_val);


Use correct talker ID for temperature and pressure (WI - weather instrument) rather than made up one.

--- device.ino
+++ device.ino
@@ -1238,7 +1238,7 @@
   //
   //

-  a_string = F("$FHMTA,");
+  a_string = F("$WIMTA,");
   append_float_to_string(a_string, temperature);
   a_string += F(",F*");

@@ -1264,7 +1264,7 @@
   //
   //

-  a_string = F("$FHMDA,");
+  a_string = F("$WIMDA,");
   append_float_to_string(a_string, pressure);
   a_string += F(",I,");
   append_float_to_string(a_string, pressure * 0.03386388158);
@@ -1290,7 +1290,7 @@
   // 	Then the old school MMB for Air Pressure
   //

-  a_string = F("$FHMMB,");
+  a_string = F("$WIMMB,");
   append_float_to_string(a_string, pressure);
   a_string += F(",I,");
   append_float_to_string(a_string, pressure * 0.03386388158);
@@ -1314,7 +1314,7 @@
   // 	Finally new school XDR (Type, Data, Units, ID)
   //

-  a_string = F("$FHXDR,C,");
+  a_string = F("$WIXDR,C,");
   append_float_to_string(a_string, (temperature - 32.0) * (5.0 / 9.0));
   a_string += F(",C,FHUB_TEMP,P,");
   append_float_to_string(a_string, pressure * 0.03386388158);


Push out well formatted nmea strings for air temp and barometric pressure on the nmea out port.

--- device.ino
+++ device.ino
@@ -190,6 +190,7 @@
 #define MAX_NEW_MESSAGE_SIZE 256
 String latest_message_to_send = "";
 String new_message = "";
+String a_string = "";
 char   temp_string[20];
 char temp_string_a[41];
 char temp_string_b[41];
@@ -925,6 +926,7 @@
   nmea_read_buffer.reserve(MAX_NMEA_BUFFER);
   new_message.reserve(MAX_NEW_MESSAGE_SIZE);
   latest_message_to_send.reserve(MAX_LATEST_MESSAGE_SIZE);
+  a_string.reserve(MAX_LATEST_MESSAGE_SIZE);

   bmp_setup();
   gps_setup();
@@ -1101,6 +1103,7 @@
 void bmp_read()
 {

+
   //
   //	On some boards we very occasionally get an odd reading, so this
   //	history, average thing is just there to get rid of outliers
@@ -1149,7 +1152,6 @@

-
   for(i =0; i < BARO_HISTORY_LENGTH - 1 ; i++)
   {
     if(pressure_history[i] > 1)
@@ -1189,13 +1191,152 @@

   //
-  //	Seems more accurate of you read temperature first
-  //
-
-  //temperature = (1.8 * bmp.readTemperature()) + 32 - 5.6;
-  //temperature = (1.8 * bmp.readTemperature()) + 32;
-  //pressure = bmp.readPressure() * 0.000295300;
-
+  //	Output Temperature and Pressure as NMEA sentences in case anyone is listening
+  //
+
+  //  NMEA tags _can_ be like this in the old version of the protocol:
+  //
+  // 	Barometer
+  //
+  //	  MMB
+  //
+  // 	    $--MMB,x.x,I,y.y,B*hh<CR><LF>
+  //
+  //		x.x Barometric pressure, inches of mercury
+  // 		y.y Barometric pressure, bars
+  //
+  //    Air (Abmient) Temperature
+  //
+  //	  MTA
+  //
+  //        $--MTA,x.x,C*hh<CR><LF>
+  //
+  //	      x.x Temperature, degrees C
+  //
+  //
+  //  And there's the combined MDA, which does pressure and air temp (and a bunch of other things)
+  //
+  //  But "right way" now is apparently XDR like this:
+  //
+  //    $IIXDR,C,24.24,C,ENV_OUTSIDE_T,P,100700,P,ENV_ATMOS_P,H,64.356,P,ENV_OUTSIDE_H*37
+  //
+  //
+
+
+
+
+
+
+  //
+  //
+  //	So first the MTA Air Temperature
+  //
+  //
+
+  a_string = F("$FHMTA,");
+  append_float_to_string(a_string, temperature);
+  a_string += F(",F*");
+
+  byte_zero = 0;
+  for(i = a_string.indexOf('$') + 1; i < a_string.lastIndexOf('*'); i++)
+  {
+    byte_zero = byte_zero ^ a_string.charAt(i);
+  }
+  Serial2.print(a_string);
+  a_string = String(byte_zero, HEX);
+  a_string.toUpperCase();
+  if(a_string.length() < 2)
+  {
+    Serial2.print("0");
+  }
+  Serial2.println(a_string);
+
+
+
+  //
+  //
+  //	Now the MDA combined
+  //
+  //
+
+  a_string = F("$FHMDA,");
+  append_float_to_string(a_string, pressure);
+  a_string += F(",I,");
+  append_float_to_string(a_string, pressure * 0.03386388158);
+  a_string += F(",B,");
+  append_float_to_string(a_string, (temperature - 32.0) * (5.0 / 9.0));
+  a_string += F(",C,,,,,,,,,,,,,,*");
+
+  byte_zero = 0;
+  for(i = a_string.indexOf('$') + 1; i < a_string.lastIndexOf('*'); i++)
+  {
+    byte_zero = byte_zero ^ a_string.charAt(i);
+  }
+  Serial2.print(a_string);
+  a_string = String(byte_zero, HEX);
+  a_string.toUpperCase();
+  if(a_string.length() < 2)
+  {
+    Serial2.print("0");
+  }
+  Serial2.println(a_string);
+
+  //
+  // 	Then the old school MMB for Air Pressure
+  //
+
+  a_string = F("$FHMMB,");
+  append_float_to_string(a_string, pressure);
+  a_string += F(",I,");
+  append_float_to_string(a_string, pressure * 0.03386388158);
+  a_string += F(",B*");
+
+  byte_zero = 0;
+  for(i = a_string.indexOf('$') + 1; i < a_string.lastIndexOf('*'); i++)
+  {
+    byte_zero = byte_zero ^ a_string.charAt(i);
+  }
+  Serial2.print(a_string);
+  a_string = String(byte_zero, HEX);
+  a_string.toUpperCase();
+  if(a_string.length() < 2)
+  {
+    Serial2.print("0");
+  }
+  Serial2.println(a_string);
+
+  //
+  // 	Finally new school XDR (Type, Data, Units, ID)
+  //
+
+  a_string = F("$FHXDR,C,");
+  append_float_to_string(a_string, (temperature - 32.0) * (5.0 / 9.0));
+  a_string += F(",C,FHUB_TEMP,P,");
+  append_float_to_string(a_string, pressure * 0.03386388158);
+  a_string += F(",B,FHUB_BARO*");
+
+  byte_zero = 0;
+  for(i = a_string.indexOf('$') + 1; i < a_string.lastIndexOf('*'); i++)
+  {
+    byte_zero = byte_zero ^ a_string.charAt(i);
+  }
+  Serial2.print(a_string);
+  a_string = String(byte_zero, HEX);
+  a_string.toUpperCase();
+  if(a_string.length() < 2)
+  {
+    Serial2.print("0");
+  }
+  Serial2.println(a_string);
+
+
+  //Serial2.println("$IIMMB,29.9870,I,1.012,B*46");
+
+
+
+  //Serial2.println("$IIXDR,P,1.0155,B,0*72");
+  //Serial2.println("$IIXDR,P,100700,P,ENV_ATMOS_P*01");
+  //Serial2.println("$IIXDR,C,24.24,C,ENV_OUTSIDE_T,P,100700,P,ENV_ATMOS_P,H,64.356,P,ENV_OUTSIDE_H*37");

 }

@@ -1466,7 +1607,7 @@

 bool validate_gps_buffer()
 {
-  String a_string;
+  //String a_string;
   byte_zero = 0;
   for(i = gps_read_buffer.indexOf('$') + 1; i < gps_read_buffer.lastIndexOf('*'); i++)
   {
@@ -1503,7 +1644,7 @@

 bool validate_nmea_buffer()
 {
-  String a_string;
+  //String a_string;
   byte_zero = 0;
   for(i = nmea_read_buffer.indexOf('$') + 1; i < nmea_read_buffer.lastIndexOf('*'); i++)
   {


Now with RX/TX on every device

Now with RX/TX on every device

--- pitch_notes/pitch_notes.ino
+++ pitch_notes/pitch_notes.ino
@@ -34,8 +34,9 @@
   int vsolPin = 29;
   int led_state = 1;

-  #define ADCREFVOLTAGE 3.3
   #define NODE_ID 300
+  #define RX_BUFSIZE 1000
+  unsigned char radio_buf[RX_BUFSIZE];
 //

 //// globals spells
@@ -152,11 +153,6 @@
   // set up high gain mode pin
   pinMode(hgmPin, OUTPUT);
   digitalWrite(hgmPin, LOW);
-  // set up battery monitoring
-  pinMode(vbatPin, INPUT);
-  // set up LED
-  pinMode(ledPin, OUTPUT);
-  digitalWrite(ledPin, LOW);
   // Initialize the chibi command line and set the speed to 57600 bps
   chibiCmdInit(115200);
   // Initialize the chibi wireless stack
@@ -225,7 +221,7 @@
     note = notef/accum;*/
 }

-
+char sbuf[100];

 void loop() {
     int note;
@@ -235,7 +231,7 @@
     note = (int)(notef);
     //Serial.print("\n");

-    if((note>=10) &&(note<117))
+    /*if((note>=10) &&(note<117))
     {
       Serial.print(" ");
       Serial.print(notef);
@@ -244,7 +240,7 @@
       Serial.print(" ");
       Serial.print(volume);
       Serial.println(" ");
-    }
+    }*/
     if(note<10)
     {
       // then it is not a note
@@ -267,6 +263,11 @@

     if(note_duration==4)
     {
+    sprintf(sbuf, "note=%d volume=%d", note, (int)volume);
+    Serial.println(sbuf);
+    chibiTx(BROADCAST_ADDR, (unsigned char*)(&sbuf), strlen(sbuf)+1);
+
+
       cur_sequence[seq_index]=current_note;
       /*if((abs(cur_sequence[(10+seq_index-4)%10]-23)<=1) &&
          (abs(cur_sequence[(10+seq_index-3)%10]-25)<=1) &&
@@ -313,11 +314,6 @@
            else
              pin13_state=LOW;
            digitalWrite(13, pin13_state);
-           char sbuf[100];
-           sprintf(sbuf, "SPELL:%s", spell_name[spell]);
-           Serial.println(sbuf);
-           chibiTx(BROADCAST_ADDR, (unsigned char*)(&sbuf), strlen(sbuf)+1);
-           free(sbuf);
           }
           if(spell==1)
           {
@@ -330,8 +326,26 @@
         }
         seq_index=(seq_index+1)%10;
     }
-
-     //Serial.print(current_note);
-     //Serial.print("\t");
-     //Serial.println(note_duration);
-}
+
+    // Radio receive
+    if (chibiDataRcvd() == true)
+    {
+      int rssi, src_addr, len;
+      len = chibiGetData(radio_buf);
+      if (len == 0) {
+        Serial.println("Null packet received");
+        return;
+      }
+
+      // retrieve the data and the signal strength
+      rssi = chibiGetRSSI();
+      src_addr = chibiGetSrcAddr();
+      Serial.print("Signal strength: ");
+      Serial.print(rssi);
+      Serial.print("\t");
+      if (len)
+      {
+        Serial.println((char*)(radio_buf));
+      }
+    }
+}


Almost completely rewritten

Almost completely rewritten

Changed temp+hum sensor from dht11 to AM2320.
Changed to send datat to thingspeak instead of
hosting own web server. Introduced debug-logs,
so that serial is not used at all if DEBUG is less
than 1 --> saves a lot of memory.

--- greenhouse/greenhouse.ino
+++ greenhouse/greenhouse.ino
@@ -1,299 +1,249 @@
+/**
+ * Greenhouse-project
+ * - monitor temperature and humidity. If temperature rises too high (or humidity), then open the window
+ * - monitor also soil humidity
+ * - send data to thingspeak every 10 minutes
+ * - note the "state" is just state of display
+ */
 #include <SoftwareSerial.h>
 #include <LiquidCrystal595.h>
-#include <Dht11.h>
 #include <Servo.h>
-
-
-int8_t maxC=0, minC=100;
-const byte buttonPin = 5;
-int8_t tempSensorValue = 0;
+#include <Wire.h>
+#include <AM2320.h>
+AM2320 th;
+
+/**
+   only print stuff to serial if DEBUG-build,
+   disabling Serial frees alot of memory!
+*/
+
+#define DEBUG 0
+
+#if (DEBUG > 0)
+#define SERIAL_BEGIN(_sbaud)\
+  Serial.begin(_sbaud);
+#else
+#define SERIAL_BEGIN(_sbaud)
+#endif
+
+#if (DEBUG > 0)
+#define LOG_DEBUGLN(_log)\
+  Serial.println(_log);
+#define LOG_DEBUG(_log)\
+  Serial.print(_log);
+#else
+#define LOG_DEBUGLN(_log)
+#define LOG_DEBUG(_log)
+#endif
+
+#if (DEBUG > 1)
+#define LOG_DEBUGLN2(_log)\
+  Serial.println(_log);
+#define LOG_DEBUG2(_log)\
+  Serial.print(_log);
+#else
+#define LOG_DEBUGLN2(_log)
+#define LOG_DEBUG2(_log)
+#endif
+
+//state handling
+#define STATE_INITIAL   0
+#define STATE_WORKING   1
+#define STATE_SETUP     2
+byte state = STATE_INITIAL;
+
+//analog pin assignments
+#define TEMP_POT_PIN     A0
+#define HUM_POT_PIN      A1
+#define MOIST_SENS1_PIN  A2
+
+//digital pin assignments
+#define LCDPIN1       2
+#define LCDPIN2       3
+#define LCDPIN3       4
+#define BTNPIN        5
+#define SERVOPIN      10
+#define SSERIALTX     11  //to RX on ESP-05
+#define SSERIALRX     12  //to TX on ESP-05
+#define ESPRESETPIN   13
+
+// The baud rate of the serial interface
+#define SERIAL_BAUD  9600
+#define ESP8266_BAUD 9600
+
+//global variables
+int8_t  maxC = 125, minC = -125;
+float   tempSensorValue = 0;
 uint8_t tempLimitPotValue = 0;
-uint8_t humSensorValue = 0;
+float   humSensorValue = 0;
 uint8_t humLimitPotValue = 0;
 uint8_t buttonState = LOW;
 uint8_t alertLevel  = 30;
 uint8_t humLevel = 80;
 uint8_t wifiCheckCntr = 0;
 boolean hatchOpen = false;
-
-//state handling
-const byte STATE_INITIAL = 0;
-const byte STATE_WORKING = 1;
-const byte STATE_SETUP   = 2;
-byte state = STATE_INITIAL;
-
-//analog pin assignments
-const byte tempPotPin    = 0;
-const byte humPotPin     = 1;
-
-// The data I/O pin connected to the DHT11 sensor
-const byte DHT_DATA_PIN = 6;
-//digital pin assignments
-const byte servo1Pin     = 10;
-const byte wifiResetPin  = 13;
-
-// The baud rate of the serial interface
-const uint16_t SERIAL_BAUD  = 9600;
-const uint16_t ESP8266_BAUD = 9600;
-
+uint8_t updateValuesCntr = 0;
+uint8_t moisture = 100;
+
+unsigned long lastConnectionTime = 0;
+const unsigned long updateThingSpeakInterval = 600000; //send values to thingspeak every 10 minutes

 // Initialize the library with the numbers of the interface pins
-LiquidCrystal595 lcd(2,3,4);
+LiquidCrystal595 lcd(LCDPIN1, LCDPIN2, LCDPIN3);
 Servo servo1; // Create a servo object
-Dht11 sensor(DHT_DATA_PIN); //Create

 //wifi esp8266
-SoftwareSerial espSerial(12, 11); // TX, RX
-
-#define BUFFER_SIZE 50
+SoftwareSerial espSerial(SSERIALRX, SSERIALTX); // RX, TX
+
+#define BUFFER_SIZE 100
 char buffer[BUFFER_SIZE];

-uint16_t staticContLen = 0;
-#define HOME_PAGE_STATIC_ARR_SZ  9
-const uint8_t CONTENT_LEN_PLACE = 2;
-String homePageArray[HOME_PAGE_STATIC_ARR_SZ]={
-  "HTTP/1.1 200 OK\r\n",
-  "Connection: close\r\n",
-//  "Content-Length:",
-  "Content-Type: text/html; charset=UTF-8\r\n\r\n",
-  "<!DOCTYPE html PUBLIC>\r\n",
-//  "\"-//W3C//DTD XHTML 1.0 Strict//EN\"\r\n",
-//  "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n",
-  "\r\n",
-//  "\r\n",
-//  "<title>The Greenhouse</title>\r\n",
-//  "\r\n",
-  "\r\n",
-  "
Greenhouse
\r\n",
-  "\r\n",
-  "\r\n\r\n",
-};
+#define WIFI_APN "WLANAPN1"
+#define WIFI_PWD "THISISYOURPWD1"
+#define THINGSPEAK_IP "184.106.153.149"
+#define TS_GET "GET /update?key=TSWRITEKEY123456"

 //functions

-String GetResponse(String AT_Command, int wait, char *waitFor=NULL) {
-  String tmpData="";
-  String dbgData="";
-  byte cntr=0;
+void sendCommand ( const char * cmd,  uint16_t wait){
+  String tmpData = "";
+  byte cntr = 0;
+  LOG_DEBUGLN(cmd);
 resend:
-  espSerial.println(AT_Command);
+  espSerial.println(cmd);
   delay(10);
   while (espSerial.available() > 0 )  {
     char c = espSerial.read();
     tmpData += c;

-    if ( tmpData.indexOf(AT_Command) > -1 )
+    if ( tmpData.indexOf(cmd) > -1 )
       tmpData = "";
     else
       tmpData.trim();
   }
-  dbgData=tmpData;
-  if (tmpData.indexOf("busy") > -1 ){
-      delay(100);
-      dbgData+="...busy...\n";
-      tmpData="";
-      if (++cntr < 10) goto resend;
- }
- delay(wait);
- return dbgData;
-}
-
-void sendCommand ( char * cmd,  uint16_t wait, bool cipsend=false ) {
-  Serial.println(cmd);
-  Serial.println(GetResponse(cmd, wait));
+  if (tmpData.indexOf("busy") > -1 ) {
+    LOG_DEBUGLN("busy");
+    delay(100);
+    tmpData = "";
+    if (++cntr < 10) goto resend;
+  }
+  LOG_DEBUGLN(tmpData);
+  delay(wait);
 }

 void setupWifi()
 {
-  //connect wifi
-  Serial.println("Restarting ESP");
-  digitalWrite (wifiResetPin, LOW);
-  delay(10000);
-  digitalWrite (wifiResetPin, HIGH);
+  LOG_DEBUGLN("Restarting ESP");
+  digitalWrite (ESPRESETPIN, LOW);
+  delay(5000);
+  digitalWrite (ESPRESETPIN, HIGH);
   delay(10000);
   clearSerialBuffer();
   sendCommand ("AT+CIOBAUD=9600", 1000);
   sendCommand ("AT+RST", 8000);
-  delay(10000);
-  sendCommand ( "AT+CWMODE=1", 2000 );
-  sendCommand ( "AT+CWJAP=\"SSID\",\"passwd\"", 10000);
-  sendCommand ( "AT+CIPMUX=1", 2000 );
-  sendCommand ( "AT+CIPSERVER=1,8080\r", 8000 );
-  sendCommand ( "AT+CIPSTO=120\r", 2000 );
-  sendCommand ( "AT+CIPSTO?\r", 2000 );
-  sendCommand ( "AT+CIFSR\r", 3000);
-  sendCommand ( "AT+GMR\r", 3000);
+  sendCommand ("AT+CWMODE=1", 2000 );
+  sendCommand ("AT+CWJAP=\""
+                WIFI_APN
+                "\",\""
+                WIFI_PWD
+                "\"", 15000);
+  sendCommand ("AT+CIFSR\r", 3000);
+  sendCommand ("AT+GMR\r", 3000);
 }

 void setup() {
-  uint8_t cntr;
-  for (cntr=3;cntr < HOME_PAGE_STATIC_ARR_SZ;cntr++){
-    staticContLen+=homePageArray[cntr].length();
-  }
-
-  Serial.begin(SERIAL_BAUD);
-
-  servo1.attach(servo1Pin); // Attaches the servo on pin 14 to the servo1 object
+  SERIAL_BEGIN(SERIAL_BAUD);
+  servo1.attach(SERVOPIN); // Attaches the servo on pin 14 to the servo1 object
   servo1.write(180);  // Put servo1 at home position
   delay(2000);
   servo1.detach();

   // Open serial communications and wait for port to open:
-  espSerial.begin(9600);
+  espSerial.begin(ESP8266_BAUD);
   espSerial.setTimeout(15000);
   delay(3000);
-  Serial.println("\nStarting up...");
-  Serial.print("Dht11 Lib version ");
-  Serial.println(Dht11::VERSION);
-  analogReference(INTERNAL);
-  pinMode(buttonPin, INPUT);
-  pinMode(wifiResetPin, OUTPUT);
-  digitalWrite (wifiResetPin, HIGH);
+  LOG_DEBUGLN("\nStarting up...");
+  analogReference(DEFAULT);
+  pinMode(BTNPIN, INPUT);
+  pinMode(ESPRESETPIN, OUTPUT);
+  digitalWrite (ESPRESETPIN, HIGH);

   lcd.begin(16, 2); // Set the display to 16 columns and 2 rows
   lcd.clear();
-  lcd.setCursor(0,0);
-
+  lcd.setCursor(0, 0);
+
   lcd.print("Setting up Wifi.");
   setupWifi();
-
-  lcd.setCursor(0,0);
+
+  lcd.setCursor(0, 0);
   lcd.print("Wifi is set up.");
   delay(5000);
   lcd.clear();
-
+
+  pinMode(MOIST_SENS1_PIN, INPUT);
+
   state = STATE_INITIAL;
 }

-void loop()
-{
-  uint8_t ch_id=0;
-  uint16_t packet_len;
-  char *pb;
-
-  lcd.setCursor(0,0); // Set cursor to home position
+void loop()
+{
+  lcd.setCursor(0, 0); // Set cursor to home position
   readValues();
   handleState();
-  if(espSerial.available()) // check if the esp is sending a message
-  {
-    espSerial.readBytesUntil('\n', buffer, BUFFER_SIZE);
-    if (strncmp(buffer, "+IPD,", 5) == 0) {
-      // request: +IPD,ch,len:data
-      sscanf(buffer + 5, "%d,%d", &ch_id, &packet_len);
-      if (packet_len > 0) {
-        // read serial until packet_len character received
-        // start from :
-        pb = buffer + 5;
-        while (*pb != ':') pb++;
-        pb++;
-        if (strncmp(pb, "GET / ", 6) == 0) {
-          //Serial.println(buffer);
-          //Serial.print( "get Status from ch:" );
-          //Serial.println(ch_id);
-          delay(100);
-          clearSerialBuffer();
-          homepage(ch_id);
-        }
-      }
-    }
-  }
-  clearBuffer();
-  if (!(++wifiCheckCntr)){
+  if (!(++wifiCheckCntr)) {
     espSerial.println("AT+GMR\r");
-    if(espSerial.find("OK")){
-      Serial.println("Wifi OK");
-    }else{
-      Serial.println("Wifi NOK, restart WIfi");
+    if (espSerial.find((char*)"OK")) {
+      LOG_DEBUGLN("Wifi OK");
+    } else {
+      LOG_DEBUGLN("Wifi NOK, restart WIfi");
       setupWifi();
     }
   }
-  delay(500);
-}
-
-void sendToClient(String *data, uint8_t ch_id)
-{
-  char command[20] = {0};
-  snprintf(command,19,"AT+CIPSEND=%d,%d", ch_id, data->length());
-  espSerial.println(command);
-  if(espSerial.find(">")){
-    espSerial.print(*data);
-    delay(200);
-    if (espSerial.find("OK")){
-        while(espSerial.available()) // check if the esp is sending a message
-        {
-          char temp=espSerial.read();
-          Serial.print(temp);
-        }
-    }
-    else{
-      Serial.println("send data failed!");
-    }
-  }else{
-    Serial.println("D'OH! Conn. fail!");
-    setupWifi();
-  }
-  //esp seems wery slow at times, so just in case...
-  delay(500);
-}
-
-char *get_temp_warn()
-{
-  if (tempSensorValue <=5) return "WARN!";
-  if (tempSensorValue < 15 && tempSensorValue >5) return "cold";
-  if (tempSensorValue < 20 && tempSensorValue >14) return "chilly";
-  if (tempSensorValue < 31 && tempSensorValue >19) return "OK";
-  if (tempSensorValue > 30) return "HOT!";
-  return "";
-}
-
-void homepage(uint8_t ch_id) {
-  //create dynamic content first, so that we get the length.
-  String tempstr = "
Temperature:";
-  tempstr += tempSensorValue;
-  tempstr += "°C ";
-  tempstr += get_temp_warn();
-  tempstr += "
min:";
-  tempstr += minC;
-  tempstr += " max:";
-  tempstr += maxC;
-  tempstr += " ";
-  tempstr += "
\r\n";
-  String humstr = "
Hum:";
-  humstr += humSensorValue;
-  humstr += "%
\r\n";
-  String windowstr = "
Window is ";
-  windowstr += ((hatchOpen)?"Open
\r\n":"Closed
\r\n");
-  //count dynamic lengts together and Set Content Len in header
-  String hdrContLen = "Content-Length: ";
-  hdrContLen += String((tempstr.length() +
-                        humstr.length() +
-                        windowstr.length()+
-                        staticContLen), DEC);
-  hdrContLen += "\r\n";
-
-  Serial.println("Show page");
-  Serial.println(hdrContLen);
-  sendToClient(&homePageArray[0], ch_id);
-  sendToClient(&homePageArray[1], ch_id);
-  sendToClient(&hdrContLen, ch_id);
-  sendToClient(&homePageArray[2], ch_id);
-  sendToClient(&homePageArray[3], ch_id);
-  sendToClient(&homePageArray[4], ch_id);
-  sendToClient(&homePageArray[5], ch_id);
-  sendToClient(&homePageArray[6], ch_id);
-  //dynamic part
-  sendToClient(&tempstr, ch_id);
-  sendToClient(&humstr, ch_id);
-  sendToClient(&windowstr, ch_id);
-  //end of html page
-  sendToClient(&homePageArray[7], ch_id);
-  sendToClient(&homePageArray[8], ch_id);
-  Serial.println("Show done");
+  long temp = millis();
+  if ((temp - lastConnectionTime) > updateThingSpeakInterval) {
+    updateValues();
+    lastConnectionTime = millis();
+  }
+
+  delay(1000);
+}
+
+void updateValues()
+{
+  char cmd[60] = {0};
+  char float_str[10] = {0};
+  char hum_str[10] = {0};
+  char moist_str[10] = {0};
+
+  snprintf(cmd, 59, "AT+CIPSTART=\"TCP\",\"%s\",80", THINGSPEAK_IP);
+  espSerial.println(cmd);
+  delay(2000);
+  if (espSerial.find((char*)"Error")) {
+    LOG_DEBUG("Error1");
+    return;
+  }
+  snprintf(buffer, BUFFER_SIZE - 1, "%s&field1=%s&field2=%s&field3=%u&field4=%s\r\n",
+           TS_GET,
+           dtostrf(tempSensorValue, 4, 2, float_str),
+           dtostrf(humSensorValue, 4, 2, hum_str),
+           (hatchOpen) ? 1 : 0,
+           dtostrf(moisture, 4, 2, moist_str));
+
+  LOG_DEBUG(buffer);
+  espSerial.print("AT+CIPSEND=");
+  espSerial.println(strlen(buffer));
+
+  if (espSerial.find((char*)">")) {
+    espSerial.print(buffer);
+  }
+  else {
+    espSerial.println("AT+CIPCLOSE");
+  }
 }

 void clearSerialBuffer(void) {
   while ( espSerial.available() > 0 ) {
-     espSerial.read();
+    espSerial.read();
   }
 }

@@ -306,9 +256,9 @@
 void handleState()
 {
   if (buttonState == HIGH) { // Change scale state if pressed
-    Serial.print("button pressed, state is");
-    Serial.println(state);
-    if (state == STATE_INITIAL || state == STATE_WORKING){
+    LOG_DEBUG("button pressed, state is");
+    LOG_DEBUGLN(state);
+    if (state == STATE_INITIAL || state == STATE_WORKING) {
       state = STATE_SETUP;
       lcd.setLED2Pin(LOW);
       lcd.setLED1Pin(LOW);
@@ -323,60 +273,96 @@
       humLevel = humLimitPotValue;
     }
   }
-
-  if (state == STATE_SETUP){
-    stateSetup();
-  }
-  if (state == STATE_WORKING||state == STATE_INITIAL){
+
+  if (state == STATE_SETUP) {
+    stateSetup();
+  }
+  if (state == STATE_WORKING || state == STATE_INITIAL) {
     stateWorking();
   }
 }

+bool read_from_am2320() {
+  switch (th.Read()) {
+    case 2:
+      LOG_DEBUGLN("CRC failed");
+      return false;
+      break;
+    case 1:
+      LOG_DEBUGLN("Sensor offline");
+      return false;
+      break;
+    default:
+
+      break;
+  }
+  return true;
+
+}
+
+void readSoilMoisture() {
+  uint16_t tempAnalogValue = 0;
+  tempAnalogValue = analogRead(MOIST_SENS1_PIN);
+  delay(10);
+  tempAnalogValue = analogRead(MOIST_SENS1_PIN);
+  LOG_DEBUGLN(tempAnalogValue);
+  moisture = uint8_t(100 * (1 - ((double)(tempAnalogValue) / 1023)));
+}
+
+void readTemperatureLimit() {
+  uint16_t tempAnalogReadVal = 0;
+  //read twice because of reading issues (sometimes)
+  tempAnalogReadVal = analogRead(TEMP_POT_PIN); // Read the pot value
+  delay(10);
+  tempAnalogReadVal = analogRead(TEMP_POT_PIN); // Read the pot value
+  tempLimitPotValue = map(tempAnalogReadVal, 0, 1023, 10, 100); // Map the values from 10 to 100 degrees
+}
+
+void readHumidityLimit() {
+  uint16_t tempAnalogReadVal = 0;
+  //read twice because of reading issues (sometimes)
+  tempAnalogReadVal = analogRead(HUM_POT_PIN); // Read the pot value
+  delay(10);
+  tempAnalogReadVal = analogRead(HUM_POT_PIN); // Read the pot value
+  humLimitPotValue = map(tempAnalogReadVal, 0, 1023, 20, 100); // Map the values from 20 to 100%
+}
+
 void readValues()
 {
-    switch (sensor.read()) {
-    case Dht11::OK:
-      humSensorValue = sensor.getHumidity();
-      tempSensorValue = sensor.getTemperature();
-      //Serial.print("\nTemperature (C): ");
-      //Serial.print(tempSensorValue);
-      //Serial.print("\nHumidity (%): ");
-      //Serial.print(humSensorValue);
-      //Serial.println();
-      break;
-    case Dht11::ERROR_CHECKSUM:
-      Serial.println("Checksum error");
-      break;
-    case Dht11::ERROR_TIMEOUT:
-      Serial.println("Timeout error");
-     break;
-    default:
-      Serial.println("Unknown error");
-      break;
-  }
-
-  delay(10);
-  tempLimitPotValue = analogRead(tempPotPin); // Read the pot value
-  delay(10);
-  tempLimitPotValue = analogRead(tempPotPin); // Read the pot value
-  tempLimitPotValue = map(tempLimitPotValue, 0, 1023, 20, 40); // Map the values from 20 to 40 degrees
-  //Serial.print("tp:");
-  //Serial.println(tempLimitPotValue);
-
-  delay(10);
-  humLimitPotValue = analogRead(humPotPin); // Read the pot value
-  delay(10);
-  humLimitPotValue = analogRead(humPotPin); // Read the pot value
-  humLimitPotValue = map(humLimitPotValue, 0, 1023, 20, 100); // Map the values from 20 to 100%
-  //Serial.print("hp:");
-  //Serial.println(humLimitPotValue);
-
-  buttonState = digitalRead(buttonPin); // Check for button press
+  if (true == read_from_am2320()) {
+    if (isnan(th.h) || isnan(th.t)) {
+      LOG_DEBUGLN("Invalid values from AM2320");
+    } else {
+      humSensorValue = th.h;
+      tempSensorValue = th.t;
+    }
+  } else {
+    LOG_DEBUGLN("Failed to get values from AM2320");
+  }
+
+  LOG_DEBUG("HUM: ");
+  LOG_DEBUGLN(humSensorValue);
+  LOG_DEBUG("TEMP: ");
+  LOG_DEBUGLN(tempSensorValue);
+
+  readSoilMoisture();
+  LOG_DEBUG("SOIL: ");
+  LOG_DEBUGLN(moisture);
+  delay(10);
+  readTemperatureLimit();
+  LOG_DEBUG2("tp:");
+  LOG_DEBUGLN2(tempLimitPotValue);
+  delay(10);
+  readHumidityLimit();
+  LOG_DEBUG2("hp:");
+  LOG_DEBUGLN2(humLimitPotValue);
+
+  buttonState = digitalRead(BTNPIN); // Check for button press
 }

 void turnServo(uint16_t degree)
 {
-  servo1.attach(servo1Pin); // Attaches the servo on pin 14 to the servo1 object
+  servo1.attach(SERVOPIN); // Attaches the servo on pin 14 to the servo1 object
   servo1.write(degree);  // Put servo1 at home position
   delay(3000);
   servo1.detach();  //detach not to disturb SoftwareSerial
@@ -384,48 +370,53 @@

 void stateWorking()
 {
-
+
   writeTempAndHumToLcd();

-  if (!hatchOpen && (tempSensorValue >= alertLevel ||( humSensorValue >= humLevel && tempSensorValue >= 20))){
-    //Serial.print("Alert! over ");
-    //Serial.print(alertLevel);
-    //Serial.print("degrees, open hatch\n");
+  if (!hatchOpen && (tempSensorValue >= alertLevel || ( humSensorValue >= humLevel && tempSensorValue >= 20))) {
+    LOG_DEBUG2("Alert! over ");
+    LOG_DEBUG2(alertLevel);
+    LOG_DEBUG2("degrees, open hatch\n");
     turnServo(90);
-    hatchOpen=true;
-  }
-  if (hatchOpen && ((tempSensorValue <= alertLevel-2 && humSensorValue <= humLevel) || tempSensorValue <= 20)){
-    //Serial.print("Alert! less than ");
-    //Serial.print(alertLevel);
-    //Serial.print("(");
-    //Serial.print(tempSensorValue);
-    //Serial.print(") degrees, close hatch\n");
+    hatchOpen = true;
+  }
+  if (hatchOpen && ((tempSensorValue <= (alertLevel - 2) && humSensorValue <= (humLevel-2)) || tempSensorValue <= 20)) {
+    LOG_DEBUG2("Alert! less than ");
+    LOG_DEBUG2(alertLevel);
+    LOG_DEBUG2("(");
+    LOG_DEBUG2(tempSensorValue);
+    LOG_DEBUG2(") degrees, close hatch\n");
     turnServo(180);
-    hatchOpen=false;
-  }
+    hatchOpen = false;
+  }
 }

 void writeTempAndHumToLcd() {
-  lcd.setCursor(0,0);
-  int temp = (int)tempSensorValue;
-  lcd.print(temp);
+  char float_str[10] = {0};
+  lcd.setCursor(0, 0);
+  dtostrf(tempSensorValue, 4, 1, float_str);
+  lcd.print(float_str);
   lcd.write(B11011111); // Degree symbol
   lcd.print("C ");
-  lcd.print("HUM=");
-  lcd.print(humSensorValue);
+  memset(&float_str, 0, sizeof(float_str));
+  dtostrf(humSensorValue, 3, 1, float_str);
+  lcd.print("H=");
+  lcd.print(float_str);
   lcd.print("\%");
-
-  if (temp>maxC) {
-    maxC=temp;
-  }
-  if (temp<minC) {
-    minC=temp;
-  }
-  lcd.setCursor(0,1);
-  lcd.print("H=");
+
+  if ((int)tempSensorValue > maxC ||
+      ((int)tempSensorValue < maxC && maxC == 125 && (int)tempSensorValue != 0 )) {
+    maxC = (int)tempSensorValue;
+  }
+  if ((int)tempSensorValue < minC && minC != -125 ||
+      ((int)tempSensorValue > minC && minC == -125 && (int)tempSensorValue != 0 )) {
+    minC = (int)tempSensorValue;
+  }
+  lcd.setCursor(0, 1);
+  lcd.print("Hi=");
   lcd.print(maxC);
   lcd.write(B11011111);
-  lcd.print("C L=");
+  lcd.print("C Lo=");
   lcd.print(minC);
   lcd.write(B11011111);
   lcd.print("C ");
@@ -433,13 +424,13 @@

 void displaySetup() {
   lcd.clear();
-  lcd.setCursor(0,0);
+  lcd.setCursor(0, 0);
   lcd.print("T:");
   lcd.print(tempLimitPotValue);
   lcd.print("(");
   lcd.print(alertLevel);
   lcd.print(")          ");
-  lcd.setCursor(0,1);
+  lcd.setCursor(0, 1);
   lcd.print("H:");
   lcd.print(humLimitPotValue);
   lcd.print("(");
@@ -449,7 +440,7 @@
 }

 void stateSetup()
-{
+{
   displaySetup();
 }


UI updated

UI updated

--- hal100/hal100.ino
+++ hal100/hal100.ino
@@ -26,6 +26,8 @@
 */
 #include "proto/device_id.h"
 #include <TFT_ST7735.h> // Graphics and font library for ST7735 driver chip
+#include <TFT_FastPin.h>
+#include <User_Setup.h>
 #include <SPI.h>    // SPI library
 #include <Keypad.h> // Keypad library
 #include <math.h>   // Math library
@@ -39,12 +41,12 @@
 };

 // TFT display CS, RS and RST pins definition for Mega2560
-#define cs   10
-#define dc   9
-#define rst  8
+//#define cs   10
+//#define dc   9
+//#define rst  8

 // create an instance of the TFT library
-TFT_ST7735 tft = TFT_ST7735(128, 128);
+TFT_ST7735 tft = TFT_ST7735();

 #define DISPLAY_REFRESH_L   0x01
 #define DISPLAY_REFRESH_C1  0x02
@@ -148,8 +150,10 @@
   Serial.begin(115200);
   Serial2.begin(TS_PORT_BITRATE);
   pinMode(40, OUTPUT);
-  tft.begin();                                // initialise TFT screen
+  tft.init();
+  tft.setRotation(1);                               // initialise TFT screen
   busInit(busReceiver, 2, &Serial2);
+  tft.fillScreen(TFT_BLACK);
   displayInitialScreen();

 }
@@ -157,32 +161,32 @@
 void displayInitialScreen() {                      // displays "Wait Calibrating at start. To be linked to Motors "L" and "C" calibration process
   // Displays SWR
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);                         // set the font size 2
-  tft.drawString("SWR", 5, 5, 1);             // write the text to coordinates
+  tft.setTextSize(1);                         // set the font size 2
+  tft.drawString("SWR", 10, 10, 2);             // write the text to coordinates
   // Displays L
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("L", 5, 25, 1);
+  tft.setTextSize(1);
+  tft.drawString("L", 7, 37, 2);
   // Displays uH
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("uH", 105, 25, 1);
+  tft.setTextSize(1);
+  tft.drawString("uH", 117, 49, 2);
   // Displays C1
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("C1", 5, 55, 1);
+  tft.setTextSize(1);
+  tft.drawString("C1", 7, 70, 2);
   // Displays pF for C1
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("pF", 105, 55, 1);
+  tft.setTextSize(1);
+  tft.drawString("pF", 117, 81, 2);
   // Displays C2
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("C2", 5, 85, 1);
+  tft.setTextSize(1);
+  tft.drawString("C2", 7, 101, 2);
   // Displays pF for C2
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString("pF", 105, 85, 1);
+  tft.setTextSize(1);
+  tft.drawString("pF", 117, 112, 2);

   keypad.addEventListener(keypadEvent);             //add an event listener for this keypad
@@ -209,8 +213,8 @@
 void displaySWR() {                                         // display SWR values
   dtostrf(valueSWR, 5, 2, DisplayValueSWR);
   tft.setTextColor(TFT_GREEN);
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueSWR, 40, 5, 1);
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueSWR, 50, 5, 4);
 }

 void EraseDisplaySWR() {                                   // erase display SWR values
@@ -231,38 +235,39 @@
         +  7.0123651511795207e-039 * pow(x,8);
 }

+void displayValueLuH() {                                         // display L values in uH
+  dtostrf(stepsToUH(valueRotateL), 4, 3, DisplayValueL1uH);
+  if (isBusy) {
+    tft.setTextColor(TFT_YELLOW);
+  } else {
+    tft.setTextColor(TFT_GREEN);
+  }
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueL1uH, 50, 42, 4);
+}
+
+void ErasDisplayValueLuH() {                                   // erase display L values in uH
+  tft.setTextColor(TFT_BLACK);
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueL1uH, 50, 42, 4);
+}
+
 void displayLSteps() {                                         // display L steps values
   dtostrf(valueRotateL, 6, 0, DisplayValueL);
   if (isBusy) {
     tft.setTextColor(TFT_YELLOW);
+
   } else {
     tft.setTextColor(TFT_GREEN);
   }
   tft.setTextSize(1);
-  tft.drawString(DisplayValueL, 55, 42, 1);
+  tft.drawString(DisplayValueL, 0, 51, 2);
 }

 void EraseDisplayLSteps() {                                   // erase display L steps values
   tft.setTextColor(TFT_BLACK);
   tft.setTextSize(1);
-  tft.drawString(DisplayValueL, 55, 42, 1);
-}
-
-void displayValueLuH() {                                         // display L values in uH
-  dtostrf(stepsToUH(valueRotateL), 4, 2, DisplayValueL1uH);
-  if (isBusy) {
-    tft.setTextColor(TFT_YELLOW);
-  } else {
-    tft.setTextColor(TFT_GREEN);
-  }
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueL1uH, 40, 25, 1);
-}
-
-void ErasDisplayValueLuH() {                                   // erase display L values in uH
-  tft.setTextColor(TFT_BLACK);
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueL1uH, 40, 25, 1);
+  tft.drawString(DisplayValueL, 0, 51, 2);
 }

 void displayL() {                                             // display L steps and uH
@@ -288,6 +293,23 @@
           +  1.0154127876671653e-024 * pow(x, 9);
 }

+void displayValueC1pF() {                                         // display C1 values in pF
+  dtostrf(stepsC1topF(valueRotateC1), 4, 1, DisplayValueC1pF);
+  if (isBusy) {
+    tft.setTextColor(TFT_YELLOW);
+  } else {
+    tft.setTextColor(TFT_GREEN);
+  }
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueC1pF, 50, 75, 4);
+}
+
+void ErasDisplayValueC1pF() {                                   // erase display C1 values in pF
+  tft.setTextColor(TFT_BLACK);
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueC1pF, 50, 75, 4);
+}
+
 void displayC1steps() {                                       // display C1 steps values
   dtostrf(valueRotateC1, 5, 0, DisplayValueC1);
   if (isBusy) {
@@ -296,30 +318,13 @@
     tft.setTextColor(TFT_GREEN);
   }
   tft.setTextSize(1);
-  tft.drawString(DisplayValueC1, 55, 72, 1);
+  tft.drawString(DisplayValueC1, 0, 83, 2);
 }

 void EraseDisplayC1steps() {                                   // erase display C1 steps values
   tft.setTextColor(TFT_BLACK);
   tft.setTextSize(1);
-  tft.drawString(DisplayValueC1, 55, 72, 1);
-}
-
-void displayValueC1pF() {                                         // display C1 values in pF
-  dtostrf(stepsC1topF(valueRotateC1), 4, 1, DisplayValueC1pF);
-  if (isBusy) {
-    tft.setTextColor(TFT_YELLOW);
-  } else {
-    tft.setTextColor(TFT_GREEN);
-  }
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueC1pF, 40, 55, 1);
-}
-
-void ErasDisplayValueC1pF() {                                   // erase display C1 values in pF
-  tft.setTextColor(TFT_BLACK);
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueC1pF, 40, 55, 1);
+  tft.drawString(DisplayValueC1, 0, 83, 2);
 }

 void displayC1() {                                             // display C1 values
@@ -345,6 +350,23 @@
           +  1.0154127876671653e-024 * pow(x, 9);
 }

+void displayValueC2pF() {                                         // display C2 values in pF
+  dtostrf(stepsC2topF(valueRotateC2), 4, 1, DisplayValueC2pF);
+  if (isBusy) {
+    tft.setTextColor(TFT_YELLOW);
+  } else {
+    tft.setTextColor(TFT_GREEN);
+  }
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueC2pF, 50, 107, 4);
+}
+
+void ErasDisplayValueC2pF() {                                   // erase display C1 values in pF
+  tft.setTextColor(TFT_BLACK);
+  tft.setTextSize(1);
+  tft.drawString(DisplayValueC2pF, 50, 107, 4);
+}
+
 void displayC2steps() {                                       // display C2 steps values
   dtostrf(valueRotateC2, 5, 0, DisplayValueC2);
   if (isBusy) {
@@ -353,30 +375,13 @@
     tft.setTextColor(TFT_GREEN);
   }
   tft.setTextSize(1);
-  tft.drawString(DisplayValueC2, 55, 102, 1);
+  tft.drawString(DisplayValueC2, 0, 115, 2);
 }

 void EraseDisplayC2steps() {                                   // erase display C2 steps values
   tft.setTextColor(TFT_BLACK);
   tft.setTextSize(1);
-  tft.drawString(DisplayValueC2, 55, 102, 1);
-}
-
-void displayValueC2pF() {                                         // display C2 values in pF
-  dtostrf(stepsC2topF(valueRotateC2), 4, 1, DisplayValueC2pF);
-  if (isBusy) {
-    tft.setTextColor(TFT_YELLOW);
-  } else {
-    tft.setTextColor(TFT_GREEN);
-  }
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueC2pF, 40, 85, 1);
-}
-
-void ErasDisplayValueC2pF() {                                   // erase display C1 values in pF
-  tft.setTextColor(TFT_BLACK);
-  tft.setTextSize(2);
-  tft.drawString(DisplayValueC2pF, 40, 85, 1);
+  tft.drawString(DisplayValueC2, 0, 115, 2);
 }

 void displayC2() {                                             // display C1 values
@@ -491,9 +496,9 @@
         tft.setTextColor(TFT_BLACK);
         digitalWrite(40, HIGH);
       }
-      tft.setTextSize(1);
-      tft.drawString("Ready", 50, 115, 1);                // write the text to coordinates
-      displayRefreshFlags &= ~DISPLAY_REFRESH_BSY;
+//      tft.setTextSize(1);
+//      tft.drawString("Ready", 50, 115, 1);                // write the text to coordinates
+//      displayRefreshFlags &= ~DISPLAY_REFRESH_BSY;
     }
   }
 }


L/C corrections.

L/C corrections.

--- hal100/hal100.ino
+++ hal100/hal100.ino
@@ -51,6 +51,8 @@
 float pi;                   // π constant
 float valueC = 0;           // calculated value C float
 float valueL = 0;           // calculated value L float
+float valueCorr = 0;        // calculated value C float
+float valueLcorr = 0;       // calculated value L float
 float Cmult;                // constant multiplier to calculate C value
 float Lmult;                // constant multiplier to calculate L value
 float valueRotateC;
@@ -130,27 +132,30 @@
   keypad.addEventListener(keypadEvent);             //add an event listener for this keypad
 }

+void SetFrequencyStage1() {
+	// STAGE 1 tuning process
+	calculateC();                                     // calculate C value at selected frequency
+	calculateStepsC();                                // calculate steps needed to move C to value C
+	CmoveStage1();                                    // send command to nano to move motor "C" to C step value
+	calculateL();                                     // calculate L value at given frequency and C value
+	calculateStepsL();                                // calculate steps needed to move C to value L
+	LmoveStage1();                                    // send command to nano to move motor "L" to L step value
+	EraseDisplayC(), EraseDisplayL();                 // clear previous values L and C at display
+	displayC(), displayL();                           // display current values L and C at display
+	tuningDisplay();                                  // flashing tuning - this to be changed to start at CmoveStage1 and finish after LmoveStage1
+	displayTunedFreqTopScreen();                      // emulation of Green Tuned after motors in place
+	mechSetPosition(round (valueRotateL), round (valueRotateC));
+	// End STAGE 1 tuning process
+}
+
 void SetFrequency() {                               // when # pressed - sets frequency value at the top of the screen
-
   // Pre-STAGE 1 (coarse tuning process) cleanups and displays
   eraseFreqTopScreen();                             // clear previously entered drequesncy at display top
   displayFreqTopScreen();                           // display desired frequesncy at display top
   eraseEnteredFrequency();                          // clear entered frequency at display bottom
-
-  // STAGE 1 tuning process
-  calculateC();                                     // calculate C value at selected frequency
-  calculateStepsC();                                // calculate steps needed to move C to value C
-  CmoveStage1();                                    // send command to nano to move motor "C" to C step value
-  calculateL();                                     // calculate L value at given frequency and C value
-  calculateStepsL();                                // calculate steps needed to move C to value L
-  LmoveStage1();                                    // send command to nano to move motor "L" to L step value
-  EraseDisplayC(), EraseDisplayL();                 // clear previous values L and C at display
-  displayC(), displayL();                           // display current values L and C at display
-  tuningDisplay();                                  // flashing tuning - this to be changed to start at CmoveStage1 and finish after LmoveStage1
-  displayTunedFreqTopScreen();                      // emulation of Green Tuned after motors in place
-  mechSetPosition(round (valueRotateL), round (valueRotateC));
-  // End STAGE 1 tuning process
-}
+  SetFrequencyStage1();
+}
+

 void incL(float diff) {
 	valueRotateL = valueRotateL + diff;
@@ -161,6 +166,19 @@
 	valueRotateC = valueRotateC + diff;
 	mechSetPosition(round (valueRotateL), round (valueRotateC));
 }
+
+void incLCorr(float diff) {
+	valueLcorr = valueLcorr + diff;
+	SetFrequencyStage1();
+
+}
+
+void incCCorr(float diff) {
+	valueCorr = valueCorr + diff;
+	SetFrequencyStage1();
+}
+
+
 void LtoCCW() {                                   // when L pressed - moves motor L 1 step CCW and displays left arrows
   TFTscreen.stroke(255, 255, 0);
   TFTscreen.setTextSize(1);
@@ -289,7 +307,7 @@
   KHz = 1000;
   PlanckTime = 299792458;
   Cmult = 1.5;
-  valueC = PlanckTime / ( tuningFreqCalc * KHz ) * Cmult;
+  valueC = PlanckTime / ( tuningFreqCalc * KHz ) * Cmult + valueCorr;
   Serial.print("Value C pF=");
   Serial.println(valueC);
 }
@@ -297,7 +315,7 @@
 void calculateL () {                            // Calculate "L" value from formula L=((1/(2*π*f*C))/(2*π*f))*1000000000000 (where f in KHz and C in pF)
   pi = 3.14159;
   Lmult = 1000000000000;
-  valueL = ((1 / (2 * pi * tuningFreqCalc * valueC)) / (2 * pi * tuningFreqCalc)) * Lmult;
+  valueL = ((1 / (2 * pi * tuningFreqCalc * valueC)) / (2 * pi * tuningFreqCalc)) * Lmult + valueLcorr;
   Serial.print("Value L uH=");
   Serial.println(valueL);
 }


Changed data packet to build in the ISR to avoid transmitting bad data.

--- Arduino/ADIS16448_RoboRIO_Teensy_Interface/ADIS16448_RoboRIO_Teensy_Interface.ino
+++ Arduino/ADIS16448_RoboRIO_Teensy_Interface/ADIS16448_RoboRIO_Teensy_Interface.ino
@@ -169,6 +169,50 @@
 	    if (resetGyroFlag == 1) {
 	      resetGyroFlag = 0;
 	    }
+
+     // Insert data into datapacket in the ISR to avoid transmitting partial data
+        // Gather packet data...
+        pitch = AHRS.getPitch();
+        roll = AHRS.getRoll();
+        yaw = AHRS.getYaw();
+        xdelta = SGI.getX();
+        ydelta = SGI.getY();
+        zdelta = SGI.getZ();
+
+        // Build data packet for frame
+        datapacket += pitch;
+        datapacket += separator;
+        datapacket += roll;
+        datapacket += separator;
+        datapacket += yaw;
+        datapacket += separator;
+        datapacket += xdelta;
+        datapacket += separator;
+        datapacket += ydelta;
+        datapacket += separator;
+        datapacket += zdelta;
+        datapacket += separator;
+        datapacket += scaledData[0];
+        datapacket += separator;
+        datapacket += scaledData[1];
+        datapacket += separator;
+        datapacket += scaledData[2];
+        datapacket += separator;
+        datapacket += scaledData[3];
+        datapacket += separator;
+        datapacket += scaledData[4];
+        datapacket += separator;
+        datapacket += scaledData[5];
+        datapacket += separator;
+        datapacket += scaledData[6];
+        datapacket += separator;
+        datapacket += scaledData[7];
+        datapacket += separator;
+        datapacket += scaledData[8];
+        datapacket += separator;
+        datapacket += scaledData[9];
+        datapacket += separator;
+        datapacket += scaledData[10];
 	}
 }

@@ -291,50 +335,6 @@
   printCounter ++;
     if (printCounter >= 10000) // Delay for writing data to the serial port
     {
-
-        // Gather packet data...
-        pitch = AHRS.getPitch();
-        roll = AHRS.getRoll();
-        yaw = AHRS.getYaw();
-        xdelta = SGI.getX();
-        ydelta = SGI.getY();
-        zdelta = SGI.getZ();
-
-        // Build data packet for frame
-        datapacket += pitch;
-        datapacket += separator;
-        datapacket += roll;
-        datapacket += separator;
-        datapacket += yaw;
-        datapacket += separator;
-        datapacket += xdelta;
-        datapacket += separator;
-        datapacket += ydelta;
-        datapacket += separator;
-        datapacket += zdelta;
-        datapacket += separator;
-        datapacket += scaledData[0];
-        datapacket += separator;
-        datapacket += scaledData[1];
-        datapacket += separator;
-        datapacket += scaledData[2];
-        datapacket += separator;
-        datapacket += scaledData[3];
-        datapacket += separator;
-        datapacket += scaledData[4];
-        datapacket += separator;
-        datapacket += scaledData[5];
-        datapacket += separator;
-        datapacket += scaledData[6];
-        datapacket += separator;
-        datapacket += scaledData[7];
-        datapacket += separator;
-        datapacket += scaledData[8];
-        datapacket += separator;
-        datapacket += scaledData[9];
-        datapacket += separator;
-        datapacket += scaledData[10];
-
         // Print data packet to serial port
         HWSERIAL.println(datapacket);

@@ -346,7 +346,7 @@
         #endif

         // Clear data packet... just in case
-        datapacket = "";
+        //datapacket = "";

         // Reset print counter
         printCounter = 0;


Updated Arduino sketch for ESP8266 integration.

--- 0302_IoT_Integrations/0302-11_ESP8266_REST_API/sketch/REXYGEN_REST_API_example.ino
+++ 0302_IoT_Integrations/0302-11_ESP8266_REST_API/sketch/REXYGEN_REST_API_example.ino
@@ -1,6 +1,6 @@
 // Developed and tested with following boards/library versions:
-//    esp8266 boards    2.4.2
-//    ArduinoJson       5.13.4
+//    esp8266 boards    2.5.0
+//    ArduinoJson       6.10.0
 //    ESP8266HTTPClient 1.1.0
 //    ESP8266WiFi       1.0.0
 #include <ESP8266WiFi.h>
@@ -81,17 +81,15 @@
   Serial.println(urlGet);

   http.begin(urlGet);
-  //http.addHeader("Content-Type", "application/json");
   http.addHeader("Accept", "application/json");
   http.setAuthorization(rexygenLogin,rexygenPassword);
   httpCode = http.GET(); // Returns http response code

   if (httpCode == 200) { // Check the returning code
     const size_t bufferSize = JSON_OBJECT_SIZE(1) + 30;
-    DynamicJsonBuffer jsonBuffer(bufferSize);
-
-    JsonObject& root = jsonBuffer.parseObject(http.getString());
-    v = root["v"];
+    DynamicJsonDocument doc(bufferSize);
+    deserializeJson(doc, http.getString());
+    v = doc["v"];
   }
   else{
     v = -1;
@@ -116,16 +114,15 @@
   Serial.println(urlGet);

   http.begin(urlGet);
-  //http.addHeader("Content-Type", "application/json");
   http.addHeader("Accept", "application/json");
   http.setAuthorization(rexygenLogin,rexygenPassword);
   httpCode = http.GET(); // Returns http response code

   if (httpCode == 200) { // Check the returning code
     const size_t bufferSize = JSON_OBJECT_SIZE(1) + 30;
-    DynamicJsonBuffer jsonBuffer(bufferSize);
-    JsonObject& root = jsonBuffer.parseObject(http.getString());
-    v = root["v"].as<String>();
+    DynamicJsonDocument doc(bufferSize);
+    deserializeJson(doc, http.getString());
+    v = doc["v"].as<String>();
   }
   else{
     v = "null";


Update ArduCAM_Mini_4CAM_Capture2SD.ino

Update ArduCAM_Mini_4CAM_Capture2SD.ino

--- ArduCAM/examples/mini/ArduCAM_Mini_4CAM_Capture2SD/ArduCAM_Mini_4CAM_Capture2SD.ino
+++ ArduCAM/examples/mini/ArduCAM_Mini_4CAM_Capture2SD/ArduCAM_Mini_4CAM_Capture2SD.ino
@@ -72,7 +72,11 @@
 pinMode(SD_CS, OUTPUT);
 // initialize SPI:
 SPI.begin();
-
+//Reset the CPLD
+myCAM.write_reg(0x07, 0x80);
+delay(100);
+myCAM.write_reg(0x07, 0x00);
+delay(100);
   //Check if the 4 ArduCAM Mini 2MP Cameras' SPI bus is OK
   while(1){
   myCAM1.write_reg(ARDUCHIP_TEST1, 0x55);


Pushing IMU refresh rate to 25Hz
Using Bluetooth library to autoconnect to Sphero

Signed-off-by: Cruz Monrreal II <663375bc5b4c6ed13a95cc63b2dd9f1e16363f4e@gmail.com>

--- examples/ReadIMU/ReadIMU.ino
+++ examples/ReadIMU/ReadIMU.ino
@@ -8,20 +8,27 @@
 ************************************************/

 #include <Sphero.h>
+#include <Bluetooth.h>

 Sphero sphero;
+Bluetooth bluetooth;

 void setup() {
   Serial.begin(115200);

+  // Connect to Sphero
+  bluetooth.beginCMD();
+  bluetooth.connect();
+  bluetooth.endCMD();
+
   // Indicator LED
   sphero.setBackLED(0xFF);

   // Lock motors
   sphero.setStabilization(0);

-  // Get Pitch @ 10Hz
-  sphero.setStreamingData(10, 1, SPHERO_IMU_PITCH | SPHERO_IMU_ROLL | SPHERO_IMU_YAW);
+  // Get Pitch @ 25Hz
+  sphero.setStreamingData(25, 1, SPHERO_IMU_PITCH | SPHERO_IMU_ROLL | SPHERO_IMU_YAW);
 }

 void loop() {
@@ -33,4 +40,4 @@
   Serial.print((signed short)sphero.getData(2) << 8 | sphero.getData(3));
   Serial.print(", ");
   Serial.println((signed short)sphero.getData(4) << 8 | sphero.getData(5));
-}
+}


Add Dylan's second mouse click check before parity check

--- pi_interrupt_mouse/pi_interrupt_mouse.ino
+++ pi_interrupt_mouse/pi_interrupt_mouse.ino
@@ -11,10 +11,6 @@

 AltSoftSerial mySerial;
 int missedPackets = 0;
-
-// commands from the pi terminate with '.'
-char cmd[11] = "";
-char cmd2[11] = ""; // sse parity \o/

 enum states {
   NO_CLICK,
@@ -46,13 +42,11 @@
   while (!Serial);
   AbsoluteMouse.begin();
   attachInterrupt(digitalPinToInterrupt(2), interrupt, RISING); //interrupt pin from Mega
-  //Serial.println("Ready");
+  Serial.println("Ready");
 }

-
-
-void loop() {
-  if (state == CLICK){
+void clickMouse(){
+    if (state == CLICK){
     delay(500); //delay so if there's another interrupt it will change state
   }

@@ -70,11 +64,22 @@
       state = NO_CLICK;
       break;
   }
+}
+
+void loop() {
+
+  clickMouse();
+
+  // commands from the pi terminate with '.'
+  char cmd[11] = "";
+  char cmd2[11] = ""; // sse parity \o/

   // check if byte available on the software serial port
   //receives zero-padded string of 16 bit coordinates (xy) ending with a '.'
   if (mySerial.available()) {
     mySerial.readBytesUntil('.', cmd, 11);
+    clickMouse();
+    while (!mySerial.available()) {}
     mySerial.readBytesUntil('.', cmd2, 11);

     String cmdStr = String(cmd);
@@ -94,6 +99,7 @@
       if (missedPackets >= 15){
         missedPackets = 0;
         mySerial.readBytesUntil('.', cmd, 11);
+        loop();
       }
       //Serial.println("Packet miss");
     }