Add altitude, pressure, and temperature Warning, some data in the messages are fake

--- Arduino/MPU9150_MS5611_IMU/MPU9150_MS5611_IMU.ino
+++ Arduino/MPU9150_MS5611_IMU/MPU9150_MS5611_IMU.ino
@@ -1,98 +1,588 @@
-// I2C device class (I2Cdev) demonstration Arduino sketch for MPU9150
-// 1/4/2013 original by Jeff Rowberg <jeff@rowberg.net> at https://github.com/jrowberg/i2cdevlib
-//          modified by Aaron Weiss <aaron@sparkfun.com>
-//
-// Changelog:
-//     2011-10-07 - initial release
-//     2013-1-4 - added raw magnetometer output
-
-/* ============================================
-I2Cdev device library code is placed under the MIT license
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-===============================================
+/*****************************************************************
+MPU9150_AHRS_directdata.ino
+SFE_MPU9150 Library AHRS Data Fusion Example Code
+Kris Winer for Sparkfun Electronics
+Original Creation Date: April 8, 2014
+https://github.com/sparkfun/MPU9150_Breakout
+
+The MPU9150 is a versatile 9DOF sensor. It has a built-in
+accelerometer, gyroscope, and magnetometer that
+functions over I2C. It is very similar to the 6 DoF MPU6050 for which an extensive library has already been built.
+Most of the function of the MPU9150 can utilize the MPU6050 library.
+
+This Arduino sketch utilizes Jeff Rowberg's MPU6050 library to generate the basic sensor data
+for use in two sensor fusion algorithms becoming increasingly popular with DIY quadcopter and robotics engineers.
+I have added and slightly modified Jeff's library here.
+
+This simple sketch will demo the following:
+* How to create a MPU6050 object, using a constructor (global variables section).
+* How to use the initialize() function of the MPU6050 class.
+* How to read the gyroscope, accelerometer, and magnetometer
+  using the readAcceleration(), readRotation(), and readMag() functions and the
+  gx, gy, gz, ax, ay, az, mx, my, and mz variables.
+* How to calculate actual acceleration, rotation speed, magnetic
+  field strength using the  specified ranges as described in the data sheet:
+  http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/IMU/PS-MPU-9150A.pdf
+  and
+  http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/IMU/RM-MPU-9150A-00.pdf.
+
+In addition, the sketch will demo:
+* How to check for data updates using the data ready status register
+* How to display output at a rate different from the sensor data update and fusion filter update rates
+* How to specify the accelerometer and gyro sampling and bandwidth rates
+* How to use the data from the MPU9150 to fuse the sensor data into a quaternion representation of the sensor frame
+  orientation relative to a fixed Earth frame providing absolute orientation information for subsequent use.
+* An example of how to use the quaternion data to generate standard aircraft orientation data in the form of
+  Tait-Bryan angles representing the sensor yaw, pitch, and roll angles suitable for any vehicle stablization control application.
+
+Hardware setup: This library supports communicating with the
+MPU9150 over I2C. These are the only connections that need to be made:
+	MPU9150 --------- Arduino
+	 SCL ---------- SCL (A5 on older 'Duinos')
+	 SDA ---------- SDA (A4 on older 'Duinos')
+	 VDD ------------- 3.3V
+	 GND ------------- GND
+
+The LSM9DS0 has a maximum voltage of 3.5V. Make sure you power it
+off the 3.3V rail! And either use level shifters between SCL
+and SDA or just use a 3.3V Arduino Pro.
+
+Development environment specifics:
+	IDE: Arduino 1.0.5
+	Hardware Platform: Arduino Pro 3.3V/8MHz
+	MPU9150 Breakout Version: 1.0
+
+This code is beerware. If you see me (or any other SparkFun
+employee) at the local, and you've found our code helpful, please
+buy us a round!
+
+Distributed as-is; no warranty is given.
+*****************************************************************/
+/*
+MS561101BA_altitude.pde - Computes altitude from sea level using pressure readings from the sensor.
+The algorithm uses the Hypsometric formula as explained in http://keisan.casio.com/has10/SpecExec.cgi?path=06000000.Science%2F02100100.Earth%20science%2F12000300.Altitude%20from%20atmospheric%20pressure%2Fdefault.xml&charset=utf-8
+
+Copyright (C) 2011 Fabio Varesano <fvaresano@yahoo.it>
+
+Development of this code has been supported by the Department of Computer Science,
+Universita' degli Studi di Torino, Italy within the Piemonte Project
+http://www.piemonte.di.unito.it/
+
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the version 3 GNU General Public License as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 */

-// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
-// is used in I2Cdev.h
-#include "Wire.h"
-
-// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
-// for both classes must be in the include path of your project
-#include "I2Cdev.h"
-#include "MPU6050.h"
-
-// class default I2C address is 0x68
-// specific I2C addresses may be passed as a parameter here
-// AD0 low = 0x68 (default for InvenSense evaluation board)
-// AD0 high = 0x69
-MPU6050 accelgyro(0x69);
-
-int16_t ax, ay, az;
-int16_t gx, gy, gz;
-int16_t mx, my, mz;
-
-#define LED_PIN 13
-bool blinkState = false;
-
-void setup() {
-    // join I2C bus (I2Cdev library doesn't do this automatically)
-    Wire.begin();
-
-    // initialize serial communication
-    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
-    // it's really up to you depending on your project)
-    Serial.begin(57600);
-
-    // initialize device
-    Serial.println("Initializing I2C devices...");
-    accelgyro.initialize();
-
-    // verify connection
-    Serial.println("Testing device connections...");
-    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
-
-    // configure Arduino LED for
-    pinMode(LED_PIN, OUTPUT);
+//#define USE_MAVLINK //Uncomment this line to use mavlink
+#ifdef USE_MAVLINK
+  #include "MavlinkForArduino.h"        // Mavlink interface
+#endif
+
+#include <Wire.h>
+#include "I2Cdev.h" //from https://github.com/sparkfun/MPU-9150_Breakout.git
+#include "MPU6050_9Axis_MotionApps41.h"//from https://github.com/sparkfun/MPU-9150_Breakout.git
+#include <MS561101BA.h>
+
+#define MOVAVG_SIZE 32
+
+// Define corrections/offsets for magnetometer
+#define LOCAL_DECLINATION_DEG -3 //at Nantes, France is around 3 degrees in 2014
+#define MAG_X_OFFSET 18.0f
+#define MAG_Y_OFFSET 70.0f
+#define MAG_Z_OFFSET 270.0f
+
+// Declare device MPU6050 class
+MPU6050 mpu(0x69);
+
+// global constants for 9 DoF fusion and AHRS (Attitude and Heading Reference System)
+#define GyroMeasError PI * (40.0f / 180.0f)       // gyroscope measurement error in rads/s (shown as 3 deg/s)
+#define GyroMeasDrift PI * (0.0f / 180.0f)      // gyroscope measurement drift in rad/s/s (shown as 0.0 deg/s/s)
+// There is a tradeoff in the beta parameter between accuracy and response speed.
+// In the original Madgwick study, beta of 0.041 (corresponding to GyroMeasError of 2.7 degrees/s) was found to give optimal accuracy.
+// However, with this value, the LSM9SD0 response time is about 10 seconds to a stable initial quaternion.
+// Subsequent changes also require a longish lag time to a stable output, not fast enough for a quadcopter or robot car!
+// By increasing beta (GyroMeasError) by about a factor of fifteen, the response time constant is reduced to ~2 sec
+// I haven't noticed any reduction in solution accuracy. This is essentially the I coefficient in a PID control sense;
+// the bigger the feedback coefficient, the faster the solution converges, usually at the expense of accuracy.
+// In any case, this is the free parameter in the Madgwick filtering and fusion scheme.
+#define beta sqrt(3.0f / 4.0f) * GyroMeasError   // compute beta
+#define zeta sqrt(3.0f / 4.0f) * GyroMeasDrift   // compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero value
+#define Kp 2.0f * 5.0f // these are the free parameters in the Mahony filter and fusion scheme, Kp for proportional feedback, Ki for integral
+#define Ki 0.0f
+
+int16_t a1, a2, a3, g1, g2, g3, m1, m2, m3;     // raw data arrays reading
+uint16_t count = 0;  // used to control display output rate
+uint16_t delt_t = 0; // used to control display output rate
+uint16_t mcount = 0; // used to control display output rate
+uint8_t MagRate;     // read rate for magnetometer data
+
+float pitch, yaw, roll;
+float deltat = 0.0f;        // integration interval for both filter schemes
+uint16_t lastUpdate = 0; // used to calculate integration interval
+uint16_t time_boot_us = 0;        // used to calculate integration interval
+
+float ax_g, ay_g, az_g, gx_degps, gy_degps, gz_degps, mx, my, mz; // variables to hold latest sensor data values
+float q[4] = {1.0f, 0.0f, 0.0f, 0.0f};    // vector to hold quaternion
+float eInt[3] = {0.0f, 0.0f, 0.0f};       // vector to hold integral error for Mahony method
+
+uint8_t system_id = 100;
+uint8_t component_id = 200;
+long time_boot_ms;
+
+//MS5611
+MS561101BA baro = MS561101BA();
+float movavg_buff[MOVAVG_SIZE];
+int movavg_i=0;
+
+const float sea_press = 1013.25;
+float press, temperature, altitude;
+
+void setup()
+{
+  // join I2C bus (I2Cdev library doesn't do this automatically)
+  Wire.begin();
+  Serial.begin(57600); // Start serial at 57600 bps
+
+  delay(2000);
+
+  // initialize MPU6050 device
+  Serial.println(F("Initializing I2C devices..."));
+  mpu.initialize();
+
+  // verify connection
+  Serial.println(F("Testing device connections..."));
+  Serial.println(mpu.testConnection() ? F("MPU9150 connection successful") : F("MPU9150 connection failed"));
+
+// Set up the accelerometer, gyro, and magnetometer for data output
+
+   mpu.setRate(7); // set gyro rate to 8 kHz/(1 + rate) shows 1 kHz, accelerometer ODR is fixed at 1 KHz
+
+   MagRate = 10; // set magnetometer read rate in Hz; 10 to 100 (max) Hz are reasonable values
+
+// Digital low pass filter configuration.
+// It also determines the internal sampling rate used by the device as shown in the table below.
+// The accelerometer output rate is fixed at 1kHz. This means that for a Sample
+// Rate greater than 1kHz, the same accelerometer sample may be output to the
+// FIFO, DMP, and sensor registers more than once.
+/*
+ *          |   ACCELEROMETER    |           GYROSCOPE
+ * DLPF_CFG | Bandwidth | Delay  | Bandwidth | Delay  | Sample Rate
+ * ---------+-----------+--------+-----------+--------+-------------
+ * 0        | 260Hz     | 0ms    | 256Hz     | 0.98ms | 8kHz
+ * 1        | 184Hz     | 2.0ms  | 188Hz     | 1.9ms  | 1kHz
+ * 2        | 94Hz      | 3.0ms  | 98Hz      | 2.8ms  | 1kHz
+ * 3        | 44Hz      | 4.9ms  | 42Hz      | 4.8ms  | 1kHz
+ * 4        | 21Hz      | 8.5ms  | 20Hz      | 8.3ms  | 1kHz
+ * 5        | 10Hz      | 13.8ms | 10Hz      | 13.4ms | 1kHz
+ * 6        | 5Hz       | 19.0ms | 5Hz       | 18.6ms | 1kHz
+ */
+  mpu.setDLPFMode(4); // set bandwidth of both gyro and accelerometer to ~20 Hz
+
+// Full-scale range of the gyro sensors:
+// 0 = +/- 250 degrees/sec, 1 = +/- 500 degrees/sec, 2 = +/- 1000 degrees/sec, 3 = +/- 2000 degrees/sec
+  mpu.setFullScaleGyroRange(0); // set gyro range to 250 degrees/sec
+
+// Full-scale accelerometer range.
+// The full-scale range of the accelerometer: 0 = +/- 2g, 1 = +/- 4g, 2 = +/- 8g, 3 = +/- 16g
+  mpu.setFullScaleAccelRange(0); // set accelerometer to 2 g range
+
+  mpu.setIntDataReadyEnabled(true); // enable data ready interrupt
+
+  // Suppose that the CSB pin is connected to GND.
+  // You'll have to check this on your breakout schematics
+  baro.init(MS561101BA_ADDR_CSB_LOW);
+  delay(100);
+
+  // populate movavg_buff before starting loop
+  for(int i=0; i<MOVAVG_SIZE; i++) {
+    movavg_buff[i] = baro.getPressure(MS561101BA_OSR_4096);
+  }
 }
-
-void loop() {
-    // read raw accel/gyro measurements from device
-    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
-
-    // these methods (and a few others) are also available
-    //accelgyro.getAcceleration(&ax, &ay, &az);
-    //accelgyro.getRotation(&gx, &gy, &gz);
-
-    // display tab-separated accel/gyro x/y/z values
-    Serial.print("a/g/m:\t");
-    Serial.print(ax); Serial.print("\t");
-    Serial.print(ay); Serial.print("\t");
-    Serial.print(az); Serial.print("\t");
-    Serial.print(gx); Serial.print("\t");
-    Serial.print(gy); Serial.print("\t");
-    Serial.print(gz); Serial.print("\t");
-    Serial.print(mx); Serial.print("\t");
-    Serial.print(my); Serial.print("\t");
-    Serial.println(mz);
-
-    // blink LED to indicate activity
-    blinkState = !blinkState;
-    digitalWrite(LED_PIN, blinkState);
+/*
+  SerialEvent occurs whenever a new data comes in the
+ hardware serial RX.  This routine is run between each
+ time loop() runs, so using delay inside loop can delay
+ response.  Multiple bytes of data may be available.
+ */
+void serialEvent() {
+  while (Serial.available()) {
+    // get the new byte:
+    char inChar = (char)Serial.read();
+  }
 }
+
+void loop()
+{
+    temperature = baro.getTemperature(MS561101BA_OSR_4096);
+    press = baro.getPressure(MS561101BA_OSR_4096);
+    pushAvg(press);
+    press = getAvg(movavg_buff, MOVAVG_SIZE);
+    altitude = getAltitude(press, temperature);
+    if(mpu.getIntDataReadyStatus() == 1) { // wait for data ready status register to update all data registers
+            mcount++;
+           // read the raw sensor data
+            mpu.getAcceleration  ( &a1, &a2, &a3  );
+            ax_g = a1*2.0f/32768.0f; // 2 g full range for accelerometer
+            ay_g = a2*2.0f/32768.0f;
+            az_g = a3*2.0f/32768.0f;
+
+            mpu.getRotation  ( &g1, &g2, &g3  );
+            gx_degps = g1*250.0f/32768.0f; // 250 deg/s full range for gyroscope
+            gy_degps = g2*250.0f/32768.0f;
+            gz_degps = g3*250.0f/32768.0f;
+//  The gyros and accelerometers can in principle be calibrated in addition to any factory calibration but they are generally
+//  pretty accurate. You can check the accelerometer by making sure the reading is +1 g in the positive direction for each axis.
+//  The gyro should read zero for each axis when the sensor is at rest. Small or zero adjustment should be needed for these sensors.
+//  The magnetometer is a different thing. Most magnetometers will be sensitive to circuit currents, computers, and
+//  other both man-made and natural sources of magnetic field. The rough way to calibrate the magnetometer is to record
+//  the maximum and minimum readings (generally achieved at the North magnetic direction). The average of the sum divided by two
+//  should provide a pretty good calibration offset. Don't forget that for the MPU9150, the magnetometer x- and y-axes are switched
+//  compared to the gyro and accelerometer!
+            if (mcount > 1000/MagRate) {  // this is a poor man's way of setting the magnetometer read rate (see below)
+            mpu.getMag  ( &m1, &m2, &m3 );
+            mx = m1*10.0f*1229.0f/4096.0f + MAG_X_OFFSET; // milliGauss (1229 microTesla per 2^12 bits, 10 mG per microTesla)
+            my = m2*10.0f*1229.0f/4096.0f + MAG_Y_OFFSET; // apply calibration offsets in mG that correspond to your environment and magnetometer
+            mz = m3*10.0f*1229.0f/4096.0f + MAG_Z_OFFSET;
+            mcount = 0;
+            }
+         }
+
+  time_boot_us = micros();
+  time_boot_ms = millis();
+  deltat = ((time_boot_us - lastUpdate)/1000000.0f); // set integration time by time elapsed since last filter update
+  lastUpdate = time_boot_us;
+  // Sensors x (y)-axis of the accelerometer is aligned with the y (x)-axis of the magnetometer;
+  // the magnetometer z-axis (+ down) is opposite to z-axis (+ up) of accelerometer and gyro!
+  // We have to make some allowance for this orientationmismatch in feeding the output to the quaternion filter.
+  // For the MPU-9150, we have chosen a magnetic rotation that keeps the sensor forward along the x-axis just like
+  // in the LSM9DS0 sensor. This rotation can be modified to allow any convenient orientation convention.
+  // This is ok by aircraft orientation standards!
+  // Pass gyro rate as rad/s
+   MadgwickQuaternionUpdate(ax_g, ay_g, az_g, gx_degps*PI/180.0f, gy_degps*PI/180.0f, gz_degps*PI/180.0f, my, mx, mz);
+// MahonyQuaternionUpdate(ax_g, ay, az, gx_degps*PI/180.0f, gy_degps*PI/180.0f, gz_degps*PI/180.0f, my, mx, mz);
+
+    // Serial print and/or display at 0.05 s rate independent of data rates
+    delt_t = millis() - count;
+    if (delt_t > 50) { //update at 20Hz
+
+    // Define output variables from updated quaternion---these are Tait-Bryan angles, commonly used in aircraft orientation.
+    // In this coordinate system, the positive z-axis is down toward Earth.
+    // Yaw is the angle between Sensor x-axis and Earth magnetic North (or true North if corrected for local declination, looking down on the sensor positive yaw is counterclockwise.
+    // Pitch is angle between sensor x-axis and Earth ground plane, toward the Earth is positive, up toward the sky is negative.
+    // Roll is angle between sensor y-axis and Earth ground plane, y-axis up is positive roll.
+    // These arise from the definition of the homogeneous rotation matrix constructed from quaternions.
+    // Tait-Bryan angles as well as Euler angles are non-commutative; that is, the get the correct orientation the rotations must be
+    // applied in the correct order which for this configuration is yaw, pitch, and then roll.
+    // For more see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles which has additional links.
+      yaw   = atan2(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
+      pitch = -asin(2.0f * (q[1] * q[3] - q[0] * q[2]));
+      roll  = atan2(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
+      yaw = yaw + LOCAL_DECLINATION_DEG*PI/180.0f; // Declination is difference between magnetic and true north
+
+#ifdef USE_MAVLINK
+      // Initialize the required buffers
+      mavlink_message_t msg;
+      uint8_t buf[MAVLINK_MAX_PACKET_LEN];
+      mavlink_msg_heartbeat_pack(system_id, component_id, &msg, MAV_TYPE_KITE, MAV_AUTOPILOT_GENERIC, MAV_MODE_GUIDED_ARMED, 0, MAV_STATE_ACTIVE);
+      uint16_t len = mavlink_msg_to_send_buffer(buf, &msg);
+      Serial.write(buf, len);
+
+      //mavlink_msg_scaled_imu_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg,
+      // uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag)
+      mavlink_msg_raw_imu_pack(system_id, component_id, &msg, time_boot_ms, a1, a2, a3, g1, g2, g3, m1, m2, m3);
+      len = mavlink_msg_to_send_buffer(buf, &msg);
+      //Serial.write(buf, len);
+
+      mavlink_msg_scaled_imu_pack(system_id, component_id, &msg, time_boot_ms, ax_g*1000, ay_g*1000, az_g*1000, gx_degps*PI/180.0f*1000, gy_degps*PI/180.0f*1000, gz_degps*PI/180.0f*1000, mx, my, mz);
+      len = mavlink_msg_to_send_buffer(buf, &msg);
+      //Serial.write(buf, len);
+
+      //static inline uint16_t mavlink_msg_highres_imu_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg,
+      //						       uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint16_t fields_updated)
+      mavlink_msg_highres_imu_pack(system_id, component_id, &msg, (uint64_t)time_boot_us, ax_g*9.81, ay_g*9.81, az_g*9.81, gx_degps*PI/180.0f, gy_degps*PI/180.0f, gz_degps*PI/180.0f, my, mx, mz, press, press, altitude, temperature, a1);
+      len = mavlink_msg_to_send_buffer(buf, &msg);
+      //Serial.write(buf, len);
+
+      //static inline uint16_t mavlink_msg_attitude_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg,
+      //  uint32_t time_boot_ms, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed)
+      mavlink_msg_attitude_pack(system_id, component_id, &msg, time_boot_ms, roll, pitch, yaw, gx_degps*PI/180.0f, gy_degps*PI/180.0f, gz_degps*PI/180.0f);
+      len = mavlink_msg_to_send_buffer(buf, &msg);
+      Serial.write(buf, len);
+
+#else
+      Serial.print("ax = "); Serial.print((int)1000*ax_g);
+      Serial.print(" ay = "); Serial.print((int)1000*ay_g);
+      Serial.print(" az = "); Serial.print((int)1000*az_g); Serial.println(" mg");
+      Serial.print("gx = "); Serial.print( gx_degps, 2);
+      Serial.print(" gy = "); Serial.print( gy_degps, 2);
+      Serial.print(" gz = "); Serial.print( gz_degps, 2); Serial.println(" deg/s");
+      Serial.print("mx = "); Serial.print( (int)mx );
+      Serial.print(" my = "); Serial.print( (int)my );
+      Serial.print(" mz = "); Serial.print( (int)mz ); Serial.println(" mG");
+
+      Serial.print("q0 = "); Serial.print(q[0]);
+      Serial.print(" qx = "); Serial.print(q[1]);
+      Serial.print(" qy = "); Serial.print(q[2]);
+      Serial.print(" qz = "); Serial.println(q[3]);
+      Serial.print("Yaw, Pitch, Roll: ");
+      Serial.print(yaw*180.0f / PI, 2);
+      Serial.print(", ");
+      Serial.print(pitch*180.0f / PI, 2);
+      Serial.print(", ");
+      Serial.println(roll*180.0f / PI, 2);
+
+      Serial.print("rate = "); Serial.print((float)1.0f/deltat, 2); Serial.println(" Hz");
+
+      Serial.print(" temp: ");
+      Serial.print(temperature);
+      Serial.print(" degC pres: ");
+      Serial.print(press);
+      Serial.print(" mbar altitude: ");
+      Serial.print(altitude);
+      Serial.println(" m");
+#endif
+
+
+      // With these settings the filter is updating at a ~145 Hz rate using the Madgwick scheme and
+      // >200 Hz using the Mahony scheme even though the display refreshes at only 2 Hz.
+      // The filter update rate is determined mostly by the mathematical steps in the respective algorithms,
+      // the processor speed (8 MHz for the 3.3V Pro Mini), and the magnetometer ODR:
+      // an ODR of 10 Hz for the magnetometer produce the above rates, maximum magnetometer ODR of 100 Hz produces
+      // filter update rates of 36 - 145 and ~38 Hz for the Madgwick and Mahony schemes, respectively.
+      // This is presumably because the magnetometer read takes longer than the gyro or accelerometer reads.
+      // This filter update rate should be fast enough to maintain accurate platform orientation for
+      // stabilization control of a fast-moving robot or quadcopter. Compare to the update rate of 200 Hz
+      // produced by the on-board Digital Motion Processor of Invensense's MPU6050 6 DoF and MPU9150 9DoF sensors.
+      // The 3.3 V 8 MHz Pro Mini is doing pretty well!
+
+      count = millis();
+    }
+}
+
+float getAltitude(float press, float temp) {
+  //return (1.0f - pow(press/101325.0f, 0.190295f)) * 4433000.0f;
+  return ((pow((sea_press / press), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065;
+}
+
+void pushAvg(float val) {
+  movavg_buff[movavg_i] = val;
+  movavg_i = (movavg_i + 1) % MOVAVG_SIZE;
+}
+
+float getAvg(float * buff, int size) {
+  float sum = 0.0;
+  for(int i=0; i<size; i++) {
+    sum += buff[i];
+  }
+  return sum / size;
+}
+
+
+// Implementation of Sebastian Madgwick's "...efficient orientation filter for... inertial/magnetic sensor arrays"
+// (see http://www.x-io.co.uk/category/open-source/ for examples and more details)
+// which fuses acceleration, rotation rate, and magnetic moments to produce a quaternion-based estimate of absolute
+// device orientation -- which can be converted to yaw, pitch, and roll. Useful for stabilizing quadcopters, etc.
+// The performance of the orientation filter is at least as good as conventional Kalman-based filtering algorithms
+// but is much less computationally intensive---it can be performed on a 3.3 V Pro Mini operating at 8 MHz!
+        void MadgwickQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
+        {
+            float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3];   // short name local variable for readability
+            float norm;
+            float hx, hy, _2bx, _2bz;
+            float s1, s2, s3, s4;
+            float qDot1, qDot2, qDot3, qDot4;
+
+            // Auxiliary variables to avoid repeated arithmetic
+            float _2q1mx;
+            float _2q1my;
+            float _2q1mz;
+            float _2q2mx;
+            float _4bx;
+            float _4bz;
+            float _2q1 = 2.0f * q1;
+            float _2q2 = 2.0f * q2;
+            float _2q3 = 2.0f * q3;
+            float _2q4 = 2.0f * q4;
+            float _2q1q3 = 2.0f * q1 * q3;
+            float _2q3q4 = 2.0f * q3 * q4;
+            float q1q1 = q1 * q1;
+            float q1q2 = q1 * q2;
+            float q1q3 = q1 * q3;
+            float q1q4 = q1 * q4;
+            float q2q2 = q2 * q2;
+            float q2q3 = q2 * q3;
+            float q2q4 = q2 * q4;
+            float q3q3 = q3 * q3;
+            float q3q4 = q3 * q4;
+            float q4q4 = q4 * q4;
+
+            // Normalise accelerometer measurement
+            norm = sqrt(ax * ax + ay * ay + az * az);
+            if (norm == 0.0f) return; // handle NaN
+            norm = 1.0f/norm;
+            ax *= norm;
+            ay *= norm;
+            az *= norm;
+
+            // Normalise magnetometer measurement
+            norm = sqrt(mx * mx + my * my + mz * mz);
+            if (norm == 0.0f) return; // handle NaN
+            norm = 1.0f/norm;
+            mx *= norm;
+            my *= norm;
+            mz *= norm;
+
+            // Reference direction of Earth's magnetic field
+            _2q1mx = 2.0f * q1 * mx;
+            _2q1my = 2.0f * q1 * my;
+            _2q1mz = 2.0f * q1 * mz;
+            _2q2mx = 2.0f * q2 * mx;
+            hx = mx * q1q1 - _2q1my * q4 + _2q1mz * q3 + mx * q2q2 + _2q2 * my * q3 + _2q2 * mz * q4 - mx * q3q3 - mx * q4q4;
+            hy = _2q1mx * q4 + my * q1q1 - _2q1mz * q2 + _2q2mx * q3 - my * q2q2 + my * q3q3 + _2q3 * mz * q4 - my * q4q4;
+            _2bx = sqrt(hx * hx + hy * hy);
+            _2bz = -_2q1mx * q3 + _2q1my * q2 + mz * q1q1 + _2q2mx * q4 - mz * q2q2 + _2q3 * my * q4 - mz * q3q3 + mz * q4q4;
+            _4bx = 2.0f * _2bx;
+            _4bz = 2.0f * _2bz;
+
+            // Gradient decent algorithm corrective step
+            s1 = -_2q3 * (2.0f * q2q4 - _2q1q3 - ax) + _2q2 * (2.0f * q1q2 + _2q3q4 - ay) - _2bz * q3 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q4 + _2bz * q2) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q3 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+            s2 = _2q4 * (2.0f * q2q4 - _2q1q3 - ax) + _2q1 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q2 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + _2bz * q4 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q3 + _2bz * q1) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q4 - _4bz * q2) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+            s3 = -_2q1 * (2.0f * q2q4 - _2q1q3 - ax) + _2q4 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q3 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + (-_4bx * q3 - _2bz * q1) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q2 + _2bz * q4) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q1 - _4bz * q3) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+            s4 = _2q2 * (2.0f * q2q4 - _2q1q3 - ax) + _2q3 * (2.0f * q1q2 + _2q3q4 - ay) + (-_4bx * q4 + _2bz * q2) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q1 + _2bz * q3) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q2 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+            norm = sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4);    // normalise step magnitude
+            norm = 1.0f/norm;
+            s1 *= norm;
+            s2 *= norm;
+            s3 *= norm;
+            s4 *= norm;
+
+            // Compute rate of change of quaternion
+            qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1;
+            qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - beta * s2;
+            qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - beta * s3;
+            qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - beta * s4;
+
+            // Integrate to yield quaternion
+            q1 += qDot1 * deltat;
+            q2 += qDot2 * deltat;
+            q3 += qDot3 * deltat;
+            q4 += qDot4 * deltat;
+            norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);    // normalise quaternion
+            norm = 1.0f/norm;
+            q[0] = q1 * norm;
+            q[1] = q2 * norm;
+            q[2] = q3 * norm;
+            q[3] = q4 * norm;
+
+        }
+
+
+
+ // Similar to Madgwick scheme but uses proportional and integral filtering on the error between estimated reference vectors and
+ // measured ones.
+            void MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
+        {
+            float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3];   // short name local variable for readability
+            float norm;
+            float hx, hy, bx, bz;
+            float vx, vy, vz, wx, wy, wz;
+            float ex, ey, ez;
+            float pa, pb, pc;
+
+            // Auxiliary variables to avoid repeated arithmetic
+            float q1q1 = q1 * q1;
+            float q1q2 = q1 * q2;
+            float q1q3 = q1 * q3;
+            float q1q4 = q1 * q4;
+            float q2q2 = q2 * q2;
+            float q2q3 = q2 * q3;
+            float q2q4 = q2 * q4;
+            float q3q3 = q3 * q3;
+            float q3q4 = q3 * q4;
+            float q4q4 = q4 * q4;
+
+            // Normalise accelerometer measurement
+            norm = sqrt(ax * ax + ay * ay + az * az);
+            if (norm == 0.0f) return; // handle NaN
+            norm = 1.0f / norm;        // use reciprocal for division
+            ax *= norm;
+            ay *= norm;
+            az *= norm;
+
+            // Normalise magnetometer measurement
+            norm = sqrt(mx * mx + my * my + mz * mz);
+            if (norm == 0.0f) return; // handle NaN
+            norm = 1.0f / norm;        // use reciprocal for division
+            mx *= norm;
+            my *= norm;
+            mz *= norm;
+
+            // Reference direction of Earth's magnetic field
+            hx = 2.0f * mx * (0.5f - q3q3 - q4q4) + 2.0f * my * (q2q3 - q1q4) + 2.0f * mz * (q2q4 + q1q3);
+            hy = 2.0f * mx * (q2q3 + q1q4) + 2.0f * my * (0.5f - q2q2 - q4q4) + 2.0f * mz * (q3q4 - q1q2);
+            bx = sqrt((hx * hx) + (hy * hy));
+            bz = 2.0f * mx * (q2q4 - q1q3) + 2.0f * my * (q3q4 + q1q2) + 2.0f * mz * (0.5f - q2q2 - q3q3);
+
+            // Estimated direction of gravity and magnetic field
+            vx = 2.0f * (q2q4 - q1q3);
+            vy = 2.0f * (q1q2 + q3q4);
+            vz = q1q1 - q2q2 - q3q3 + q4q4;
+            wx = 2.0f * bx * (0.5f - q3q3 - q4q4) + 2.0f * bz * (q2q4 - q1q3);
+            wy = 2.0f * bx * (q2q3 - q1q4) + 2.0f * bz * (q1q2 + q3q4);
+            wz = 2.0f * bx * (q1q3 + q2q4) + 2.0f * bz * (0.5f - q2q2 - q3q3);
+
+            // Error is cross product between estimated direction and measured direction of gravity
+            ex = (ay * vz - az * vy) + (my * wz - mz * wy);
+            ey = (az * vx - ax * vz) + (mz * wx - mx * wz);
+            ez = (ax * vy - ay * vx) + (mx * wy - my * wx);
+            if (Ki > 0.0f)
+            {
+                eInt[0] += ex;      // accumulate integral error
+                eInt[1] += ey;
+                eInt[2] += ez;
+            }
+            else
+            {
+                eInt[0] = 0.0f;     // prevent integral wind up
+                eInt[1] = 0.0f;
+                eInt[2] = 0.0f;
+            }
+
+            // Apply feedback terms
+            gx = gx + Kp * ex + Ki * eInt[0];
+            gy = gy + Kp * ey + Ki * eInt[1];
+            gz = gz + Kp * ez + Ki * eInt[2];
+
+            // Integrate rate of change of quaternion
+            pa = q2;
+            pb = q3;
+            pc = q4;
+            q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltat);
+            q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * deltat);
+            q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * deltat);
+            q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * deltat);
+
+            // Normalise quaternion
+            norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
+            norm = 1.0f / norm;
+            q[0] = q1 * norm;
+            q[1] = q2 * norm;
+            q[2] = q3 * norm;
+            q[3] = q4 * norm;
+
+        }
+
+
+
+
+


corrected wifi mode

corrected wifi mode

--- ESP8266/SoftAPSocketServer/SoftAPSocketServer.ino
+++ ESP8266/SoftAPSocketServer/SoftAPSocketServer.ino
@@ -62,7 +62,7 @@

     Serial.begin(115200);

-    Serial.setDebugOutput(true);
+    //Serial.setDebugOutput(true);

     Serial.println();
     Serial.println();
@@ -74,11 +74,13 @@
         delay(1000);
     }

+    WiFi.mode(WIFI_AP);
+
     Serial.print("Setting soft-AP configuration ... ");
     Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!");

     Serial.print("Setting soft-AP ... ");
-    Serial.println(WiFi.softAP("ESPsoftAP_01") ? "Ready" : "Failed!");
+    Serial.println(WiFi.softAP("ESPsoftAP_04") ? "Ready" : "Failed!");

     Serial.print("Soft-AP IP address = ");
     Serial.println(WiFi.softAPIP());


Cleaned up comments and removed unnecessary code.

--- GY-521-2x-MPU6050-Base/GY-521-2x-MPU6050-Base.ino
+++ GY-521-2x-MPU6050-Base/GY-521-2x-MPU6050-Base.ino
@@ -39,8 +39,7 @@
   #define DPRINTLN(...)      //blank line
 #endif

-// Initialize gyro instance
-// TODO:  Update this to initialize two gyros with +VDC/Ground arguments
+// Initialize gyro instances for both MPUs
 MPU6050 mpus[2] = {MPU6050(0x68), MPU6050(0x69)};

 const int LED_PIN = 13;
@@ -85,7 +84,8 @@
 // ================================================================
 // ===               INTERRUPT DETECTION ROUTINE                ===
 // ================================================================
-volatile bool mpuInterrupt[2] = {false, false};     // indicates whether MPU interrupt pin has gone high
+// indicates whether MPU interrupt pin has gone high
+volatile bool mpuInterrupt[2] = {false, false};

 //Intentional duplication. Interrupt routine cannot pass args.
 void dmpDataReady0() {
@@ -101,12 +101,7 @@
 // ================================================================
 // ===                      MPU DMP SETUP                       ===
 // ================================================================
-// MPU control/status vars
-
-//This isn't used anywhere, I think we can get rid of it.
-//uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
-
-uint8_t devStatus;      // return status after each initialization operation (0 = success, !0 = error)
+uint8_t devStatus; // return status after each initialization operation (0 = success, !0 = error)

 //Containers for each MPU's communication
 int FifoAlive[2] = {0, 0}; // tests if the interrupt is triggering
@@ -119,15 +114,6 @@
 Quaternion q;           // [w, x, y, z]         quaternion container
 VectorFloat gravity;    // [x, y, z]            gravity vector
 float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
-
-
-//Not used anywhere in the code, can probably remove this
-//int IsAlive = -20;     // counts interrupt start at -20 to get 20+ good values before assuming connected
-//VectorInt16 aa;         // [x, y, z]            accel sensor measurements
-//VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
-//VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
-//float euler[3];         // [psi, theta, phi]    Euler angle container
-

@@ -195,19 +181,10 @@
     else {
       attachInterrupt(i, dmpDataReady1, RISING);
     }
-
-    //This isn't used anywhere, I think we can get rid of it.
-    //Also does not appear to be used in the MPU6050 class anywhere?
-    //mpuIntStatus = mpus[i].getIntStatus();

     packetSize[i] = mpus[i].dmpGetFIFOPacketSize();  // get expected DMP packet size for later comparison
     delay(1000); // Let it Stabalize
-    mpus[i].resetFIFO(); // Clear fifo buffer
-
-    //This isn't used anywhere, I think we can get rid of it.
-    //Also does not appear to be used in the MPU6050 class anywhere?
-    //mpus[i].getIntStatus();
-
+    mpus[i].resetFIFO(); // Clear fifo buffer
     mpuInterrupt[i] = false; // wait for next interrupt

   }
@@ -243,7 +220,6 @@
     }
   }

-  //LastGoodPacketTime = millis();  TODO:  This isn't doing anything, remove it?  Not sure why it was here.
   MPUMath(); // Successful!  Do the math and show angles from both MPUs
   digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink the LED on each cycle

@@ -261,12 +237,12 @@
 void MPUMath() {
   for (int i = 0; i < 2; i++) {

-    //Get the raw data from the sensor
+    // Get the raw data from the sensor
     mpus[i].dmpGetQuaternion(&q, fifoBuffer[i]);
     mpus[i].dmpGetGravity(&gravity, &q);
     mpus[i].dmpGetYawPitchRoll(ypr, &q, &gravity);

-    //Calculate readable angles
+    // Calculate readable angles
     Yaw = (ypr[0] * 180.0 / M_PI);
     Pitch = (ypr[1] *  180.0 / M_PI);
     Roll = (ypr[2] *  180.0 / M_PI);


configuration de l'adresse sur le bus

configuration de l'adresse sur le bus

--- sensorSlave/sensorSlave.ino
+++ sensorSlave/sensorSlave.ino
@@ -6,29 +6,40 @@

 //TODO
 //
-// make adress configurable with digital pins or via I2C ?
-
 // store read frequency in EEPROM
 // write read frequency via I2C
 // read frequency via I2C

 const int sensorPins[][2] = {
   {
-    A0,4              }
+    A0,4}
   ,{
-    A1,3              }
+    A1,3}
   ,{
-    A2,2              }
+    A2,2}
   ,{
-    A3,1              }
+    A3,1}
 };

 const int sensor_SIZE = ARRAY_LENGTH(sensorPins);
 unsigned int A_Values[sensor_SIZE];

+const int addressPins[] = {
+  6,7,8,9};
+
 void setup()
 {
-  Wire.begin(4);
+  int i2cAddress = 0;
+  for (int i=0;i<ARRAY_LENGTH(addressPins);i++){
+    pinMode(addressPins[i], INPUT_PULLUP);
+    if (digitalRead(addressPins[i]) == HIGH){
+      i2cAddress += (1<<i);
+    }
+  }
+
+  Wire.begin(i2cAddress);
+
+  Wire.onReceive(receiveEvent);
   Wire.onRequest(requestEvent);

 #ifdef LOG_SERIAL
@@ -80,28 +91,6 @@
 }

+void receiveEvent(int len){

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+}


change arduino BTSerial write msg

change arduino BTSerial write msg

--- Arduino/AlphaChairArduino/AlphaChairArduino.ino
+++ Arduino/AlphaChairArduino/AlphaChairArduino.ino
@@ -100,7 +100,7 @@
   Serial.println("3 : "+ String(backLeft));

   if(frontRight>2000){
-    BTSerial.println("right leg side");
+    BTSerial.println("fr");
   }
 }


Added IR Control

Added IR Control

--- Caravan_Thermostat_TX/Caravan_Thermostat_TX.ino
+++ Caravan_Thermostat_TX/Caravan_Thermostat_TX.ino
@@ -7,13 +7,13 @@
 */

 // Setup the includes
-#include <Wire.h>
+//#include <Wire.h>
 #include <SPI.h>
 #include <TFT.h>  // Arduino LCD library
 #include <dht.h> // DHT11 Library
 #include <TimeLib.h>
 #include <DS1307RTC.h> // RTC Library
-//#include <IRremote.h> // IR Library
+#include <IRremote.h> // IR Library

 // Define the pins.

@@ -31,7 +31,8 @@
 // Create instances
 TFT TFTscreen = TFT(cs, dc, rst);
 dht DHT;
-
+IRrecv irrecv(IRPIN);
+decode_results results;

 // Define Global Variables
 char PreviousTemperature[4];
@@ -39,7 +40,7 @@
 char CurrentTemperature[4];
 char CurrentHumidity[4];
 bool HeatingOn = false;
-int ReqTemp = 28; // Failsafe to 0 incase of powerloss. This may well be changed.
+int ReqTemp = 17; // Failsafe incase of powerloss.
 int TempStartPointX = 5; //44 Center
 int TempStartPointY = 35;
 int TimeStartPointX = 5;
@@ -49,6 +50,8 @@
 int PreviousHour = 0;
 int PreviousMinute = 0;
 String PreviousDate = "";
+uint32_t IRCheckTime = 0;
+
 char *MessageOfTheDay[] =
 {
   "Love you Baby Boo x x x",
@@ -159,14 +162,50 @@
   Serial.begin(115200);
   setSyncProvider(RTC.get);
   SetupDisplayLayout();
-
+  irrecv.enableIRIn();
 }

 void loop() {
   // Read the Temperature
   ReadTemperature();
-  delay(2000);
   ReadTime();
+  CheckIR(); // This has the delay of 2000ms
+}
+
+void CheckIR()
+{
+
+  Serial.println("CheckIR");
+  IRCheckTime = millis() + 2000;
+  while (IRCheckTime > millis())
+  {
+    if (irrecv.decode(&results)) {
+    TFTscreen.setTextSize(1);
+       TFTscreen.stroke(Black);
+      String TempRequested = "";
+      TempRequested += ReqTemp;
+      TFTscreen.text(TempRequested.c_str(), ReqTempStartPointX, ReqTempStartPointY);
+      Serial.println(results.value, HEX);
+      Serial.println(results.value);
+      if (results.value == 2579) //Down
+      {
+        ReqTemp--;
+      }
+      if (results.value == 530) //Up
+      {
+        ReqTemp++;
+      }
+      irrecv.resume(); // Receive the next value
+      memset(PreviousTemperature,0,sizeof(PreviousTemperature));
+      memset(PreviousHumidity,0,sizeof(PreviousHumidity));
+      TempRequested = "";
+      TempRequested += ReqTemp;
+      TFTscreen.stroke(White);
+      TFTscreen.text(TempRequested.c_str(), ReqTempStartPointX, ReqTempStartPointY);
+    }
+  }
+
+  Serial.println("CheckIR - Done");
 }

 // Define Functions.
@@ -206,7 +245,7 @@
         if (sensorVal < ReqTemp - 1)  {
           HeatingOn = true;
         }
-        if (sensorVal > ReqTemp + 1) {
+        if (sensorVal >= ReqTemp) {
           HeatingOn = false;
         }
         DrawFire(HeatingOn);
@@ -267,7 +306,7 @@
   Serial.println(day());
   Serial.println(month());
   // Need to clear the box out first.
-  TFTscreen.fillRect(0,0,TFTscreen.width(),23,Black);
+  TFTscreen.fillRect(0, 0, TFTscreen.width(), 23, Black);
   if (day() == 25 && month() == 12)
   {
     TFTscreen.text(SeasonGreetings[0], 0, 5);
@@ -278,8 +317,8 @@
   }
   else if (day() == 17 && month() == 10)
   {
-    TFTscreen.text(SeasonGreetings[2],0, 5);
-    TFTscreen.text(FamilyName[0],90, 5);
+    TFTscreen.text(SeasonGreetings[2], 0, 5);
+    TFTscreen.text(FamilyName[0], 90, 5);
   }
   else
   {


added sensor reading

added sensor reading

--- aquaponicMCP/aquaponicMCP.ino
+++ aquaponicMCP/aquaponicMCP.ino
@@ -1,5 +1,19 @@
+//L = left sensor, R = right sensor
+const int lightSensorR = A0;
+const int lightSensorL = A1;
+const int waterTempSensor = A2;
+const int waterTurbSensor = A3;
+const int waterPHSensor = A4;
+
+float lightR = 0.0;
+float lightL = 0.0;
+float waterTemp = 0.0;
+float watherTurb = 0.0;
+float waterPH = 0.0;
+
+
 void setup() {
-  //setup analog connections
+  //setup digital connections
   //setup serial
 }

@@ -11,11 +25,16 @@

 }

+/*these will be raw readings, converting from voltage to
+ * degrees or light etc should most likly done in a seperate
+ * function or even in the data logger.
+ */
 void LogData(){
-  //log water temp
-  //log water ph
-  //log water turbidity
-  //log plant light
+  lightR = analogRead(lightSensorR);
+  lightL = analogRead(lightSensorL);
+  waterTemp = analogRead(waterTempSensor);
+  waterTurb = analogRead(waterTurbSensor);
+  waterPH = analogRead(waterPHSensor);
 }

 void SendData(){


[lmr] Attempt to improve accuracy of ADC readings

Use noise-reducing ADC mode
Wait for reference voltage to stabilize using the internal reference
Lower oversampling to 11 total bits
Also makes low battery a percentage

--- arduino/lmremote/lmremote.ino
+++ arduino/lmremote/lmremote.ino
@@ -42,8 +42,10 @@

 #ifdef LMREMOTE_SERIAL
   #define SLEEPMODE_TX    1
+  #define SLEEPMODE_ADC   SLEEP_MODE_IDLE
 #else
   #define SLEEPMODE_TX    2
+  #define SLEEPMODE_ADC   SLEEP_MODE_ADC
 #endif

 static unsigned int _previousReads[RF_PINS_PER_SOURCE];
@@ -52,11 +54,25 @@
 static unsigned char _isRecent = BYTE1_RECENT_BOOT;
 static unsigned char _isBattLow;
 static unsigned char _hygroVal;
+static volatile unsigned char _adcBusy;

 // The WDT is used solely to wake us from sleep
 ISR(WDT_vect) { wdt_disable(); }
-
-static void sleep(uint8_t wdt_period, boolean include_adc) {
+ISR(ADC_vect) { _adcBusy = 0; }
+
+static unsigned int analogReadSleep(unsigned char pin)
+{
+  _adcBusy = 1;
+  ADMUX = (DEFAULT << 6) | pin;
+  bitSet(ADCSRA, ADIE);
+  set_sleep_mode(SLEEPMODE_ADC);
+  while (_adcBusy)
+    sleep_mode();
+  return ADC;
+}
+
+static void sleep(uint8_t wdt_period, boolean include_adc)
+{
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);

   // Disable ADC
@@ -116,12 +132,12 @@
     unsigned int adcSum = 0;
     unsigned char battPct;
     for (unsigned char i=0; i<BATREAD_COUNT; ++i)
-      adcSum += analogRead(_pinBattery);
+      adcSum += analogReadSleep(_pinBattery);
     // Send level as percent of VCC
     battPct = (adcSum * 100UL) / (1024 * BATREAD_COUNT);

 #ifdef LMREMOTE_SERIAL
-    Serial.print("Battery level: "); Serial.print(retVal, DEC); Serial.print('\n');
+    Serial.print("Battery %: "); Serial.print(battPct, DEC); Serial.print('\n');
 #endif

     if (battPct < BATTERY_LOW_PCT)
@@ -197,8 +213,31 @@
     // If using digital lines you will supply your own resistor for the fixed half.
     digitalWrite(_pinProbeSupplyBase + pin, HIGH);
   }
-  // takes about 15uS to stabilize and the enabling process takes 6us per pin at 16MHz
-  delayMicroseconds(10);
+}
+
+static void stabilizeAdc(void)
+{
+  const unsigned char INTERNAL_REF = 0b1110;
+  unsigned int last;
+  unsigned int totalCnt = 0;
+  unsigned int sameCnt = 0;
+  unsigned int curr = analogReadSleep(INTERNAL_REF);
+  // Reads the adc a bunch of times until the value settles
+  // Usually you hear "discard the first few ADC readings after sleep"
+  // but this seems a bit more scientific as we wait for the AREF cap to charge
+  do {
+    ++totalCnt;
+#ifdef LMREMOTE_SERIAL
+    Serial.print(curr, DEC);
+    Serial.print(' ');
+#endif
+    last = curr;
+    curr = analogReadSleep(INTERNAL_REF);
+    if (last == curr)
+      ++sameCnt;
+    else
+      sameCnt = 0;
+  } while ((totalCnt < 64) && (sameCnt < 4));
 }

 static void checkTemps(void)
@@ -213,6 +252,7 @@
 #endif

   enableAdcPullups();
+  stabilizeAdc();
   for (unsigned char pin=0; pin < RF_PINS_PER_SOURCE; ++pin)
   {
     if (PIN_DISABLED(pin))
@@ -220,7 +260,7 @@

     for (unsigned char o=0; o<OVERSAMPLE_COUNT[TEMP_OVERSAMPLE_BITS]; ++o)
     {
-      unsigned int adc = analogRead(pin);
+      unsigned int adc = analogReadSleep(pin);
       if (adc == 0 || adc >= 1023)
       {
         oversampled_adc = 0;
@@ -266,35 +306,8 @@
   }
 }

-static void stabilizeAdc(void)
-{
-  if (_pinBattery != 0xff)
-  {
-    unsigned int last;
-    unsigned int curr = analogRead(_pinBattery);
-    unsigned int cnt = 0;
-    // Reads the adc a bunch of times until the value settles
-    // Usually you hear "discard the first few ADC readings after sleep"
-    // but this seems a bit more scientific as we wait for the AREF cap to charge
-    do {
-      ++cnt;
-      last = curr;
-#ifdef LMREMOTE_SERIAL
-      Serial.print(curr,DEC);
-      Serial.print(' ');
-#endif
-      curr = analogRead(_pinBattery);
-    } while ((cnt < 10) && (abs(last - curr) > 2));
-  }
-#ifdef LMREMOTE_SERIAL
-  Serial.print('\n'); delay(10);
-#endif
-}
-
 void setup(void)
 {
-  stabilizeAdc();
-
   // Turn off the units we never use (this only affects non-sleep power)
   PRR = bit(PRUSART0) | bit(PRTWI) | bit(PRTIM1) | bit(PRTIM2);
   // Disable digital input buffers on the analog in ports
@@ -321,10 +334,9 @@

 void loop(void)
 {
-  //stabilizeAdc();
   checkTemps();
 #ifdef LMREMOTE_SERIAL
-  delay(10);
+  Serial.flush(); delay(2);
 #endif
   sleepSeconds(_sleepInterval);
   ++_loopCnt;


[lmr] Shift around some power saving defines to prep for better decoupling

--- arduino/lmremote/lmremote.ino
+++ arduino/lmremote/lmremote.ino
@@ -2,7 +2,11 @@
 #include <avr/sleep.h>
 #include <rf12_itplus.h>

-// Enabling LMREMOTE_SERIAL also disables several power saving features
+// Power down CPU as much as possible, and attempt to sync receiver at exact
+// transmit time. Can't be used with LMREMOTE_SERIAL
+// Or if an output is defined (fan/servo)
+#define MINIMAL_POWER_MODE
+// Enabling LMREMOTE_SERIAL also disables MINIMAL_POWER_MODE
 #define LMREMOTE_SERIAL 38400

 // Base Idenfier for the RFM12B (0-63)
@@ -45,11 +49,15 @@
 #define HYGRO_LMREMOTE_KEY 0x7F

 #ifdef LMREMOTE_SERIAL
+#undef MINIMAL_POWER_MODE
+#endif
+
+#if defined(MINIMAL_POWER_MODE)
+  #define SLEEPMODE_TX    2
+  #define SLEEPMODE_ADC   SLEEP_MODE_ADC
+#else
   #define SLEEPMODE_TX    1
   #define SLEEPMODE_ADC   SLEEP_MODE_IDLE
-#else
-  #define SLEEPMODE_TX    2
-  #define SLEEPMODE_ADC   SLEEP_MODE_ADC
 #endif

 #define RECV_CYCLE_TIME  5000    // expected receive cycle, millisecond
@@ -67,13 +75,6 @@
 static unsigned int _recvWindow;
 static unsigned long _recvLast;
 static bool _recvSynced;
-
-static volatile bool _adcBusy;
-static volatile bool _watchdogWaiting;
-
-// The WDT is used solely to wake us from sleep
-ISR(WDT_vect) { _watchdogWaiting = false; }
-ISR(ADC_vect) { _adcBusy = false; }

 static bool packetReceived(unsigned char nodeId, unsigned int val)
 {
@@ -107,6 +108,9 @@
   return false;
 }

+static volatile bool _adcBusy;
+ISR(ADC_vect) { _adcBusy = false; }
+
 static unsigned int analogReadSleep(unsigned char pin)
 {
   _adcBusy = true;
@@ -117,6 +121,11 @@
     sleep_mode();
   return ADC;
 }
+
+// The WDT is used solely to wake us from sleep
+#if defined(MINIMAL_POWER_MODE)
+static volatile bool _watchdogWaiting;
+ISR(WDT_vect) { _watchdogWaiting = false; }

 static void sleepPeriod(uint8_t wdt_period)
 {
@@ -140,7 +149,7 @@
   sleep_disable();
 }

-static void sleep(unsigned int msec)
+static void sleepPwrDown(unsigned int msec)
 // Code copied from Sleepy::loseSomeSleep(), jeelib
 {
   unsigned int msleft = msec;
@@ -169,10 +178,28 @@
     timer0_millis += msec - msleft;
 #endif
 }
+#endif
+
+static void sleepIdle(unsigned int msec)
+{
+  unsigned long start = millis();
+  set_sleep_mode(SLEEP_MODE_IDLE);
+  while (millis() - start < msec)
+    sleep_mode();
+}
+
+static void sleep(unsigned int msec)
+{
+#if defined(MINIMAL_POWER_MODE)
+  sleepPwrDown(msec);
+#else
+  sleepIdle(msec);
+#endif /* SLEEP_MODE_PWR_DOWN */
+}

 static void resetEstimate(void)
 {
-#if _DEBUG
+#if defined(LMREMOTE_SERIAL) && defined(_DEBUG)
   Serial.print(F("Resetting Estimate\n"));
 #endif
   _recvCycleAct = RECV_CYCLE_TIME;
@@ -195,10 +222,6 @@
     resetEstimate();
     return false;
   }
-
-  // double the window every N packets lost
-  if (lost > 0 && lost % 2 == 0 && _recvWindow < MAX_RECV_WIN)
-    _recvWindow *= 2;

   unsigned long predict = _recvLast + (lost + 1) * _recvCycleAct;
   unsigned int sleepDur =  predict - _recvWindow - millis();
@@ -211,7 +234,7 @@
     recvTime = millis();
     if ((long)(recvTime - timeout) >= 0)
     {
-#if _DEBUG
+#if defined(LMREMOTE_SERIAL) && defined(_DEBUG)
       Serial.print(" f "); Serial.print(lost);
       Serial.print(" s "); Serial.print(sleepDur);
       Serial.print(" e "); Serial.print(_recvCycleAct);
@@ -220,6 +243,11 @@
       Serial.print(" r "); Serial.println(recvTime);
       Serial.flush();
 #endif
+      // double the window every N packets lost
+      ++lost;
+      if (lost % 2 == 0 && _recvWindow < MAX_RECV_WIN)
+        _recvWindow *= 2;
+
       return false;
     }
   } while (!rf12_doWork());
@@ -231,7 +259,7 @@
     _recvCycleAct = newEst;
   _recvLast = recvTime;

-#if _DEBUG
+#if defined(LMREMOTE_SERIAL) && defined(_DEBUG)
   Serial.print(" n "); Serial.print(lost);
   Serial.print(" e "); Serial.print(_recvCycleAct);
   Serial.print(" E "); Serial.print(newEst);
@@ -419,10 +447,10 @@

 #ifdef LMREMOTE_SERIAL
   PRR &= ~bit(PRUSART0);
-  Serial.begin(LMREMOTE_SERIAL); Serial.println("$UCID,lmremote"); delay(10);
-#endif
-
-  rf12_initialize(1, _rfBand);
+  Serial.begin(LMREMOTE_SERIAL); Serial.println("$UCID,lmremote"); Serial.flush();
+#endif
+
+  rf12_initialize(_rfBand);
   // Crystal 1.66MHz Low Battery Detect 2.2V
   rf12_control(0xC040);

@@ -441,7 +469,7 @@
     checkTemps();

 #ifdef LMREMOTE_SERIAL
-  Serial.flush(); delay(2);
+  Serial.flush();
 #endif

   if (_recvLast == 0)


[lmr] Add temperature oversampling (1 bit), early wake RFM chip, transmit every 30s, sleep mode 2 while waiting for TX

--- arduino/lmremote/lmremote.ino
+++ arduino/lmremote/lmremote.ino
@@ -6,7 +6,7 @@
 #define LMREMOTE_SERIAL 115200

 // Node Idenfier for the RFM12B (2-30)
-const unsigned char _rfNodeId = 2;
+const unsigned char _rfNodeId = 2;
 // RFM12B band RF12_433MHZ, RF12_868MHZ, RF12_915MHZ
 const unsigned char _rfBand = RF12_915MHZ;
 // How long to sleep between probe measurments, in seconds
@@ -20,6 +20,8 @@
 const unsigned char _pinLedTx = 9;
 // Digital pins used for sourcing power to the probe dividers
 const unsigned char _pinProbeSupplyBase = 4;
+// Number of oversampling bits when measuring temperature [0-3]
+#define TEMP_OVERSAMPLE_BITS 1

 #define RF_PINS_PER_SOURCE 6
 #define PIN_DISABLED(pin) ((_enabledProbePins & (1 << pin)) == 0)
@@ -111,6 +113,9 @@

 void transmitTemps(unsigned char txCount)
 {
+  // Enable the transmitter because it takes 1-5ms to turn on (3ms in my testing)
+  rf12_sleep(RF12_WAKEUP);
+
   char outbuf[
     sizeof(rf12_probe_update_hdr_t) +
     RF_PINS_PER_SOURCE * sizeof(rf12_probe_update_t)
@@ -120,7 +125,10 @@
   hdr = (rf12_probe_update_hdr_t *)outbuf;
   hdr->seqNo = _seqNo++;
   hdr->batteryLevel = getBatteryLevel();
-  hdr->adcBits = 10;
+  hdr->adcBits = 10 + TEMP_OVERSAMPLE_BITS;
+
+  // We're done with the ADC shut it down until the next wake cycle
+  ADCSRA &= ~bit(ADEN);

   // Send all values regardless of if they've changed or not
   rf12_probe_update_t *up = (rf12_probe_update_t *)&hdr[1];
@@ -138,16 +146,15 @@
   unsigned char len = (unsigned int)up - (unsigned int)outbuf;

   if (_pinLedTx != 0xff) digitalWrite(_pinLedTx, HIGH);
-  rf12_sleep(RF12_WAKEUP);

   while (txCount--)
   {
-    while (!rf12_canSend())
-      rf12_doWork();
-
+    // Don't check for air to be clear, we just woke from sleep and it will be milliseconds before
+    // the RFM chip is actually up and running
+
     // HDR=0 means to broadcast, no ACK requested
     rf12_sendStart(0, outbuf, len);
-    rf12_sendWait(1);
+    rf12_sendWait(2);
   }  /* while txCount */

   rf12_sleep(RF12_SLEEP);
@@ -181,7 +188,9 @@

 void checkTemps(void)
 {
+  const unsigned char OVERSAMPLE_COUNT[] = {1, 4, 16, 64};  // 4^n
   boolean modified = false;
+  unsigned int oversampled_adc = 0;

   enableAdcPullups();
   for (unsigned char pin=0; pin < RF_PINS_PER_SOURCE; ++pin)
@@ -189,19 +198,29 @@
     if (PIN_DISABLED(pin))
       continue;

-    unsigned int newRead = analogRead(pin);
-
-#ifdef LMREMOTE_SERIAL
-    Serial.println(newRead, DEC);
-#endif
-    if (newRead != _previousReads[pin])
+    for (unsigned char o=0; o<OVERSAMPLE_COUNT[TEMP_OVERSAMPLE_BITS]; ++o)
+    {
+      unsigned int adc = analogRead(pin);
+      if (adc == 0 || adc >= 1023)
+      {
+        oversampled_adc = 0;
+        break;
+      }
+      oversampled_adc += adc;
+    }
+    oversampled_adc = oversampled_adc >> TEMP_OVERSAMPLE_BITS;
+
+#ifdef LMREMOTE_SERIAL
+    Serial.println(oversampled_adc, DEC);
+#endif
+    if (oversampled_adc != _previousReads[pin])
       modified = true;
-    _previousReads[pin] = newRead;
+    _previousReads[pin] = oversampled_adc;

     digitalWrite(_pinProbeSupplyBase + pin, LOW);
   }

-  if (modified || (_sameCount > (60 / _sleepInterval)))
+  if (modified || (_sameCount > (30 / _sleepInterval)))
   {
     _sameCount = 0;
     newTempsAvailable();


pwm frequency

pwm frequency

--- knot/arduino/tank.ino
+++ knot/arduino/tank.ino
@@ -5,18 +5,20 @@
 #include <Ticker.h>
 #include <DHT.h>

-#define DALLAS_PIN                            2
-#define DHT_PIN                               4
+#define USER_PIN                             D0
+#define NIX_PIN                              D1
+#define DHT_PIN                              D2
+#define WATER_LEVEL_PIN                      D3
+#define DALLAS_PIN                           D4
+#define BLUE_LED_PIN                         D5
+#define WHITE_LED_PIN                        D6
+#define HEATER_PIN                           D7
+#define FURTILIZER_PIN                       D8
 #define DHT_TYPE                          DHT22
-#define FURTILIZER_PIN                       15
 #define FURTILIZER_TIME                     1.3
-#define HEATER_PIN                           13
 #define HEATER_DELTA                        0.0
-#define WHITE_LED_PIN                        12
-#define BLUE_LED_PIN                         14
-#define WATER_LEVEL_PIN                       5
-#define SSID                        "XXX"
-#define SSID_PASSWD      "XXX"
+#define SSID                        "xxx"
+#define SSID_PASSWD      "xxx"
 #define MQTT_SERVER                    "cortex"
 #define MQTT_CLIENT                "TankClient"
 #define TEMP_CAL                          23.00
@@ -41,15 +43,16 @@

 void setup() {
   Serial.begin(115200);
-  pinMode(     LED_BUILTIN,     OUTPUT      );
-  digitalWrite(LED_BUILTIN,     FALSE       );
-  pinMode(     FURTILIZER_PIN,  OUTPUT      );
-  digitalWrite(FURTILIZER_PIN,  TRUE        );
-  pinMode(     HEATER_PIN,      OUTPUT      );
-  digitalWrite(HEATER_PIN,      FALSE       );
-  analogWrite( WHITE_LED_PIN,   PWMRANGE    );
-  analogWrite( BLUE_LED_PIN,    PWMRANGE    );
-  pinMode(     WATER_LEVEL_PIN, INPUT       ); //Pullup in hardware
+  analogWriteFreq(100);
+  pinMode(     LED_BUILTIN,     OUTPUT   );
+  digitalWrite(LED_BUILTIN,     FALSE    );
+  pinMode(     FURTILIZER_PIN,  OUTPUT   );
+  digitalWrite(FURTILIZER_PIN,  TRUE     );
+  pinMode(     HEATER_PIN,      OUTPUT   );
+  digitalWrite(HEATER_PIN,      FALSE    );
+  analogWrite( WHITE_LED_PIN,   PWMRANGE );
+  analogWrite( BLUE_LED_PIN,    PWMRANGE );
+  pinMode(     WATER_LEVEL_PIN, INPUT    );
   setup_wifi();
   delay(100);
   mqtt.setServer(MQTT_SERVER, 1883);
@@ -166,7 +169,6 @@

 void measure(){
   waterOK = digitalRead(WATER_LEVEL_PIN);
-
   dallas.requestTemperatures();

   float t = 0;


Now using a semicolon separated format for the logging. [nSensor];[temp};[humidity]: 0;17.10;55.10 1;17.60;63.10 2;17.40;56.70 3;17.90;63.50 4;18.00;62.20 5;17.50;60.00

--- moisture/moisture.ino
+++ moisture/moisture.ino
@@ -80,16 +80,15 @@
   // Read all sensors
   for(i=0;i<N_SENSORS;i++)
   {
-    Serial.print("Sensor ");
-    Serial.println(i);
+    Serial.print(i);
+    Serial.print(";");
     dht_array[i]->temperature().getEvent(&event);
     if (isnan(event.temperature)) {
-      Serial.println("Error reading temperature!");
+      Serial.print("Error reading temperature!");
     }
     else {
-      Serial.print("Temperature: ");
       Serial.print(event.temperature);
-      Serial.println(" *C");
+      Serial.print(";");
     }
     // Get humidity event and print its value.
     dht_array[i]->humidity().getEvent(&event);
@@ -97,9 +96,7 @@
       Serial.println("Error reading humidity!");
     }
     else {
-      Serial.print("Humidity: ");
-      Serial.print(event.relative_humidity);
-      Serial.println("%");
+      Serial.println(event.relative_humidity);
     }
   }
 }


bugfix

bugfix

--- RGB_matrix.ino
+++ RGB_matrix.ino
@@ -57,7 +57,7 @@
     pattern[7]=B001;    //２進数で直接指定でも可[RED:B001,GREEN:B010,BLUE:B100]
     pattern[8]=B000;    //(=OFF)[0~8]の9個のLEDの色を指定可能

-    while(1) lighting(pattern);
+    while(1) lighting(pattern,10);
 }


Reverting progmem again. Compiles successfully, but responses are garbage

--- projects/SumpPumpController/Arduino/Arduino.ino
+++ projects/SumpPumpController/Arduino/Arduino.ino
@@ -35,68 +35,6 @@
 // Buffer for char conversions
 char buf [100];

-// PROGMEM string definitions
-const char str_alertPresent[] PROGMEM = "alertPresent";
-const char str_alarmPresent[] PROGMEM = "alarmPresent";
-const char str_YES_Ack_ed[] PROGMEM = "YES, Ack'ed";
-const char str_YES[] PROGMEM = "YES";
-const char str_NO[] PROGMEM = "NO";
-const char str_alertReason[] PROGMEM = "alertReason";
-const char str_getDistance[] PROGMEM = "getDistance";
-const char str_getPressure[] PROGMEM = "getPressure";
-const char str_getBattVoltage[] PROGMEM = "getBattVoltage";
-const char str_dmV[] PROGMEM = "%dmV";
-const char str_getAcPumpOnTime[] PROGMEM = "getAcPumpOnTime";
-const char str_d[] PROGMEM = "%d";
-const char str_getLastSelfTest[] PROGMEM = "getLastSelfTest";
-const char str_forceAlert[] PROGMEM = "forceAlert";
-const char str_Force_command[] PROGMEM = "Force command";
-const char str_OK[] PROGMEM = "OK";
-const char str_resetAlert[] PROGMEM = "resetAlert";
-const char str_startSelfTest[] PROGMEM = "startSelfTest";
-const char str_set[] PROGMEM = "set";
-const char str_debug[] PROGMEM = "debug";
-const char str_Unrecognized_command[] PROGMEM = "Unrecognized command";
-const char str_setAlertBatteryVoltage[] PROGMEM = "setAlertBatteryVoltage:";
-const char str_ERROR[] PROGMEM = "ERROR";
-const char str_setAlertWaterLevel[] PROGMEM = "setAlertWaterLevel:";
-const char str_setBaudRate[] PROGMEM = "setBaudRate:";
-const char str_setAcPumpOnThreshold[] PROGMEM = "setAcPumpOnThreshold:";
-const char str_setAlertPressureLevel[] PROGMEM = "setAlertPressureLevel:";
-const char str_setAcPumpOnTimeWarning[] PROGMEM = "setAcPumpOnTimeWarning:";
-const char str_setSelftestTimeBetween[] PROGMEM = "setSelftestTimeBetween:";
-const char str_setSelfTestTimeLimit[] PROGMEM = "setSelfTestTimeLimit:";
-const char str_setSelfTestMinDepth[] PROGMEM = "setSelfTestMinDepth:";
-const char str_setSelfTestDepthDiff[] PROGMEM = "setSelfTestDepthDiff:";
-const char str_setDepthMeasureTime[] PROGMEM = "setDepthMeasureTime:";
-const char str_setBuzzerEnabled[] PROGMEM = "setBuzzerEnabled:";
-const char str_setZeroPressure[] PROGMEM = "setZeroPressure:";
-const char str_setPointsPerCm[] PROGMEM = "setPointsPerCm:";
-const char str_setDcPumpOnTimeWarning[] PROGMEM = "setDcPumpOnTimeWarning:";
-const char str_ERROR_1_3600_expected[] PROGMEM = "ERROR: 1-3600 expected.";
-const char str_time_lu[] PROGMEM = "time=%lu";
-const char str_rangeLH_0_d_d[] PROGMEM = "rangeLH[0]=%d,%d";
-const char str_rangeLH_1_d_d[] PROGMEM = "&rangeLH[1]=%d,%d";
-const char str_DcHeight_d_d[] PROGMEM = "&DcHeight=%d,%d";
-const char str_pressure_d[] PROGMEM = "&pressure=%d";
-const char str_AcPumpCycles_d[] PROGMEM = "&AcPumpCycles=%d";
-const char str_lastAlertTime_lu[] PROGMEM = "&lastAlertTime=%lu";
-const char str_rawDepthPressure_d[] PROGMEM = "&rawDepthPressure=%d";
-const char str_timeSince_lu[] PROGMEM = "timeSince=%lu&";
-const char str_cyclesSince_d[] PROGMEM = "cyclesSince=%d&";
-const char str_voltage_d[] PROGMEM = "voltage=%d&";
-const char str_length_d[] PROGMEM = "length=%d&";
-const char str_pumpedHeight_d[] PROGMEM = "pumpedHeight=%d&";
-const char str_result_d[] PROGMEM = "result=%d";
-const char str_Weak_battery_dmV[] PROGMEM = "Weak battery: %dmV";
-const char str_DC_Pump_failure_dCM_pumped_in_d_sec[] PROGMEM = "DC Pump failure: %dCM pumped in %d sec.";
-const char str_DC_Pump_ON[] PROGMEM = "DC Pump ON";
-const char str_DC_pump_ON_too_long[] PROGMEM = "DC pump ON too long";
-const char str_Battery_voltage[] PROGMEM = "Battery voltage";
-const char str_Water_level_d[] PROGMEM = "Water level: %d";
-const char str_High_pressure[] PROGMEM = "High pressure";
-const char str_AC_pump_ON_for_too_long[] PROGMEM = "AC pump ON for too long";
-
 void setup()
 {
   readConfig();
@@ -144,49 +82,49 @@
 {
   // Process RS-485 commands
   if (net.messageReceived()) {
-    if (net.assertCommand((char*)pgm_read_word(&(str_alertPresent))) || net.assertCommand((char*)pgm_read_word(&(str_alarmPresent)))) {
+    if (net.assertCommand("alertPresent") || net.assertCommand("alarmPresent")) {
       if (alert.present) {
         if (alert.acknowledged) {
-          net.sendResponse((char*)pgm_read_word(&(str_YES_Ack_ed)));
+          net.sendResponse("YES, Ack'ed");
         } else {
-          net.sendResponse((char*)pgm_read_word(&(str_YES)));
+          net.sendResponse("YES");
         }
       } else {
-        net.sendResponse((char*)pgm_read_word(&(str_NO)));
+        net.sendResponse("NO");
       }
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_alertReason)))) {
+    } else if (net.assertCommand("alertReason")) {
       net.sendResponse(alert.condition);
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_getDistance)))) {
+    } else if (net.assertCommand("getDistance")) {
       net.sendResponse(itoa(readDistance(), buf, 10));
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_getPressure)))) {
+    } else if (net.assertCommand("getPressure")) {
       net.sendResponse(itoa(readPressure(), buf, 10));
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_getBattVoltage)))) {
-      sprintf(buf, (char*)pgm_read_word(&(str_dmV)), readBatteryVoltage());
+    } else if (net.assertCommand("getBattVoltage")) {
+      sprintf(buf, "%dmV", readBatteryVoltage());
       net.sendResponse(buf);
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_getAcPumpOnTime)))) {
+    } else if (net.assertCommand("getAcPumpOnTime")) {
       if (acpump.currentlyOn) {
-        sprintf(buf, (char*)pgm_read_word(&(str_d)), acpump.onSeconds + (now() - acpump.switchOnTime));
+        sprintf(buf, "%d", acpump.onSeconds + (now() - acpump.switchOnTime));
       } else {
-        sprintf(buf, (char*)pgm_read_word(&(str_d)), acpump.onSeconds);
+        sprintf(buf, "%d", acpump.onSeconds);
       }
       net.sendResponse(buf);
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_getLastSelfTest)))) {
+    } else if (net.assertCommand("getLastSelfTest")) {
       sendSelfTestResponse();
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_forceAlert)))) {
-      raiseAlert(ExternallyForced, (char*)pgm_read_word(&(str_Force_command)));
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_resetAlert)))) {
+    } else if (net.assertCommand("forceAlert")) {
+      raiseAlert(ExternallyForced, "Force command");
+      net.sendResponse("OK");
+    } else if (net.assertCommand("resetAlert")) {
       resetAlert();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_startSelfTest)))) {
+      net.sendResponse("OK");
+    } else if (net.assertCommand("startSelfTest")) {
       dcSelfTestStart();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_set)), buf)) {
+      net.sendResponse("OK");
+    } else if (net.assertCommandStarts("set", buf)) {
       processSetCommands();
-    } else if (net.assertCommand((char*)pgm_read_word(&(str_debug)))) {
+    } else if (net.assertCommand("debug")) {
       sendDebugResponse();
     } else {
-      net.sendResponse((char*)pgm_read_word(&(str_Unrecognized_command)));
+      net.sendResponse("Unrecognized command");
     }
   }

@@ -231,25 +169,25 @@
 // Write to the configuration when we receive new parameters
 void processSetCommands()
 {
-  if (net.assertCommandStarts((char*)pgm_read_word(&(str_setAlertBatteryVoltage)), buf)) {
+  if (net.assertCommandStarts("setAlertBatteryVoltage:", buf)) {
     unsigned int tmp = strtol(buf, NULL, 10);
     if (tmp > 9000 && tmp < 15000) {
       conf.alertBatteryVoltage = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setAlertWaterLevel)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setAlertWaterLevel:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > -100 && tmp < 100) {
       conf.alertWaterLevel = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setBaudRate)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setBaudRate:", buf)) {
     long tmp = strtol(buf, NULL, 10);
     // Supported: 9600, 14400, 19200, 28800, 38400, 57600, or 115200
     if (tmp == 9600 ||
@@ -262,143 +200,143 @@
     ) {
       conf.baudRate = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
+      net.sendResponse("OK");
       Serial.end();
       Serial.begin(tmp);
     } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setAcPumpOnThreshold)), buf)) {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setAcPumpOnThreshold:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > 0 && tmp < 1025) {
       conf.acPumpOnThreshold = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setAlertPressureLevel)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setAlertPressureLevel:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > 0 && tmp < 1025) {
       conf.alertPressureLevel = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setAcPumpOnTimeWarning)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setAcPumpOnTimeWarning:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > 0 && tmp < 30000) {
       conf.acPumpOnTimeWarning = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setSelftestTimeBetween)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setSelftestTimeBetween:", buf)) {
     long tmp = strtol(buf, NULL, 10);
     if (tmp > 0 && tmp < 1000000L) {
       conf.selftestTimeBetween = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setSelfTestTimeLimit)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setSelfTestTimeLimit:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     // More than 6 seconds, as we're checking that DC pump is on at 6 second mark.
     if (tmp > 6 && tmp < 200) {
       conf.selfTestTimeLimit = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setSelfTestMinDepth)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setSelfTestMinDepth:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > -100 && tmp < 100) {
       conf.selfTestMinDepth = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setSelfTestDepthDiff)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setSelfTestDepthDiff:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp > 0 && tmp < 100) {
       conf.selfTestDepthDiff = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setDepthMeasureTime)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setDepthMeasureTime:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp >= 0 && tmp < 120) {
       conf.depthMeasureTime = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setBuzzerEnabled)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setBuzzerEnabled:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp == 1 || tmp == 0) {
       conf.buzzerEnabled = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setZeroPressure)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setZeroPressure:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp >= 0 && tmp < 1023) {
       conf.zeroPressure = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setPointsPerCm)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setPointsPerCm:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp >= -1024 && tmp < 1024) {
       conf.pointsPerCm = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR)));
-    }
-  } else if (net.assertCommandStarts((char*)pgm_read_word(&(str_setDcPumpOnTimeWarning)), buf)) {
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR");
+    }
+  } else if (net.assertCommandStarts("setDcPumpOnTimeWarning:", buf)) {
     int tmp = strtol(buf, NULL, 10);
     if (tmp >= 1 && tmp < 3600) {
       conf.dcPumpOnTimeWarning = tmp;
       saveConfig();
-      net.sendResponse((char*)pgm_read_word(&(str_OK)));
-    } else {
-      net.sendResponse((char*)pgm_read_word(&(str_ERROR_1_3600_expected)));
+      net.sendResponse("OK");
+    } else {
+      net.sendResponse("ERROR: 1-3600 expected.");
     }
   } else {
-    net.sendResponse((char*)pgm_read_word(&(str_Unrecognized_command)));
+    net.sendResponse("Unrecognized command");
   }
 }

 void sendDebugResponse()
 {
-  sprintf(buf, ((char*)pgm_read_word(&(str_time_lu))), now());
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_rangeLH_0_d_d))), range.lows[0], range.highs[0]);
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_rangeLH_1_d_d))), range.lows[1], range.highs[1]);
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_DcHeight_d_d))), selftest.startingHeight, selftest.endingHeight);
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_pressure_d))), analogRead(PRESSURE_SENSOR_PIN));
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_AcPumpCycles_d))), acpump.onCycles);
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_lastAlertTime_lu))), alert.timeTriggered);
-  net.responseSendPart(buf);
-  sprintf(buf, ((char*)pgm_read_word(&(str_rawDepthPressure_d))), analogRead(DEPTH_PRESSURE_SENSOR_PIN));
+  sprintf(buf, ("time=%lu"), now());
+  net.responseSendPart(buf);
+  sprintf(buf, ("rangeLH[0]=%d,%d"), range.lows[0], range.highs[0]);
+  net.responseSendPart(buf);
+  sprintf(buf, ("&rangeLH[1]=%d,%d"), range.lows[1], range.highs[1]);
+  net.responseSendPart(buf);
+  sprintf(buf, ("&DcHeight=%d,%d"), selftest.startingHeight, selftest.endingHeight);
+  net.responseSendPart(buf);
+  sprintf(buf, ("&pressure=%d"), analogRead(PRESSURE_SENSOR_PIN));
+  net.responseSendPart(buf);
+  sprintf(buf, ("&AcPumpCycles=%d"), acpump.onCycles);
+  net.responseSendPart(buf);
+  sprintf(buf, ("&lastAlertTime=%lu"), alert.timeTriggered);
+  net.responseSendPart(buf);
+  sprintf(buf, ("&rawDepthPressure=%d"), analogRead(DEPTH_PRESSURE_SENSOR_PIN));
   net.responseSendPart(buf);
 //  sprintf(buf, );
 //  net.responseSendPart(buf);
@@ -412,17 +350,17 @@

 void sendSelfTestResponse()
 {
-   sprintf(buf, ((char*)pgm_read_word(&(str_timeSince_lu))), (now() - selftest.lastTestTime));
+   sprintf(buf, ("timeSince=%lu&"), (now() - selftest.lastTestTime));
    net.responseSendPart(buf);
-   sprintf(buf, ((char*)pgm_read_word(&(str_cyclesSince_d))), acpump.onCycles-selftest.acCycles);
+   sprintf(buf, ("cyclesSince=%d&"), acpump.onCycles-selftest.acCycles);
    net.responseSendPart(buf);
-   sprintf(buf, ((char*)pgm_read_word(&(str_voltage_d))), selftest.batteryVoltageMv);
+   sprintf(buf, ("voltage=%d&"), selftest.batteryVoltageMv);
    net.responseSendPart(buf);
-   sprintf(buf, ((char*)pgm_read_word(&(str_length_d))), (int)selftest.testLength);
+   sprintf(buf, ("length=%d&"), (int)selftest.testLength);
    net.responseSendPart(buf);
-   sprintf(buf, ((char*)pgm_read_word(&(str_pumpedHeight_d))), selftest.startingHeight - selftest.endingHeight);
+   sprintf(buf, ("pumpedHeight=%d&"), selftest.startingHeight - selftest.endingHeight);
    net.responseSendPart(buf);
-   sprintf(buf, ((char*)pgm_read_word(&(str_result_d))), selftest.passed);
+   sprintf(buf, ("result=%d"), selftest.passed);
    net.responseSendPart(buf);
    net.responseEnd();
 }
@@ -484,14 +422,14 @@
     // Battery voltage should not drop too much
     if (selftest.batteryVoltageMv < conf.alertBatteryVoltage) {
       selftest.passed = false;
-      sprintf(buf, ((char*)pgm_read_word(&(str_Weak_battery_dmV))), selftest.batteryVoltageMv);
+      sprintf(buf, ("Weak battery: %dmV"), selftest.batteryVoltageMv);
       raiseAlert(DcPumpMalfunction, buf);
       return;
     }
     // Determine if water level was reduced enough
     if (selftest.startingHeight - selftest.endingHeight < 5) {
       selftest.passed = false;
-      sprintf(buf, ((char*)pgm_read_word(&(str_DC_Pump_failure_dCM_pumped_in_d_sec))), (selftest.startingHeight - selftest.endingHeight), (int)selftest.testLength);
+      sprintf(buf, ("DC Pump failure: %dCM pumped in %d sec."), (selftest.startingHeight - selftest.endingHeight), (int)selftest.testLength);
       raiseAlert(DcPumpMalfunction, buf);
       return;
     }
@@ -530,13 +468,13 @@
   // If voltage is more than 0, then pump is on, and we need to sound an alert
   // Need to make sure to wait a few seconds after self test to see if DC pump is ON
   if (mv > 9000 && (now() - selftest.lastTestTime) > (conf.selfTestTimeLimit + 6)) {
-    raiseAlert(DcPumpActivated, ((char*)pgm_read_word(&(str_DC_Pump_ON))));
+    raiseAlert(DcPumpActivated, ("DC Pump ON"));
     // Record that the pump is on, or process alert, if it was already on.
     if (!dcpump.currentlyOn) {
       dcpump.currentlyOn = true;
       dcpump.switchOnTime = now();
     } else if ((now() - dcpump.switchOnTime) > conf.dcPumpOnTimeWarning) {
-      raiseAlert(DcPumpOverload, ((char*)pgm_read_word(&(str_DC_pump_ON_too_long))));
+      raiseAlert(DcPumpOverload, ("DC pump ON too long"));
     }
   } else {
     dcpump.currentlyOn = false;
@@ -549,7 +487,7 @@
 {
   unsigned int mv = getVoltage( BATTERY_VOLTAGE_PIN );
   if (mv < conf.alertBatteryVoltage) {
-    raiseAlert(DischargedBattery, ((char*)pgm_read_word(&(str_Battery_voltage))));
+    raiseAlert(DischargedBattery, ("Battery voltage"));
   }
   return mv;
 }
@@ -573,7 +511,7 @@

   if (range.distance > conf.alertWaterLevel) {
     char tmp[40];
-    sprintf(tmp, ((char*)pgm_read_word(&(str_Water_level_d))), range.distance);
+    sprintf(tmp, ("Water level: %d"), range.distance);
     raiseAlert(WaterLevel, tmp);
   }
   return range.distance;
@@ -585,7 +523,7 @@

   // Alert business
   if (acpump.lastPressure > conf.alertPressureLevel) {
-    raiseAlert(HighPressure, ((char*)pgm_read_word(&(str_High_pressure))));
+    raiseAlert(HighPressure, ("High pressure"));
   }

   boolean currentlyOn;
@@ -621,7 +559,7 @@
   // Check if AC pump was on for too long
   if (currentlyOn) {
     if ((now() - acpump.switchOnTime) > conf.acPumpOnTimeWarning) {
-      raiseAlert(AcPumpOverload, ((char*)pgm_read_word(&(str_AC_pump_ON_for_too_long))));
+      raiseAlert(AcPumpOverload, ("AC pump ON for too long"));
     }
   }


Remove pre-filled DevAddr and Keys

Remove pre-filled DevAddr and Keys

--- basic/TheThingsUno/workshop/project/project.ino
+++ basic/TheThingsUno/workshop/project/project.ino
@@ -2,9 +2,9 @@

 #include "TheThingsUno.h"

-const byte devAddr[4] = { 0x02, 0xDE, 0xAE, 0x00 };
-const byte appSKey[16] = { 0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F, 0x0C, 0x0A, 0x0F, 0x0E, 0x0B, 0x0A, 0x0B, 0x0E };
-const byte nwkSKey[16] = { 0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F, 0x0C, 0x0A, 0x0F, 0x0E, 0x0B, 0x0A, 0x0B, 0x0E };
+const byte devAddr[4] = { /* copy DevAddr here */ };
+const byte appSKey[16] = { /* copy AppSKey here */ };
+const byte nwkSKey[16] = { /* copy NwkSKey here */ };

 #define debugSerial Serial
 #define loraSerial Serial1


Removing low limits on configuration enviroment control as they are not needed and allow the system to get up to 100%  humidity.

--- Arduino/AutomatedGreenhouse/AutomatedGreenhouse.ino
+++ Arduino/AutomatedGreenhouse/AutomatedGreenhouse.ino
@@ -1,160 +1,147 @@
-/**
- * Fisher Innovation Automated Greenhouse Controller
- * @author Matt Fisher (Fisher Innovation) [fisher.matt@gmail.com]
- *
- * Copyright (c) 2012 Fisher Innovation
- * Licensed the MIT license.
- *
- * http://www.fisherinnovation.com
- * https://github.com/fisherinnovation/FI-Automated-Greenhouse
- */
-
-#include <Wire.h>
-#include "RTClib.h" // DS1307 Real Time Clock.
-#include <DHT22.h>  // DHT22 Temperature and Humidity Sensor.
-#include <stdio.h>  // Only used for sprintf.
-
-#include <Arduino.h>
-#include <Time.h>
-#include <SoftwareSerial.h>
-#include <Streaming.h>
-#include <PString.h>
-#include <WiFlySerial.h>
-#include "Credentials.h"
-#include "MemoryFree.h"
-
-#define DHT22_PIN 7     // DHT22 Temperature and Humidity Sensor to pin D7.
-
-DHT22 myDHT22(DHT22_PIN); // Setup a DHT22 instance.
-RTC_Millis RTC;           // Setup a DS1307 instance.
-
-int CURRENT_TEMP = 0;      // Global reference to the current system temperature.
-int CURRENT_HUMIDITY = 0;  // Global reference to the current system humidity.
-int CURRENT_TIME[3];       // Global reference to the current system date.
-int CURRENT_DATE[3];       // Global reference to the current system time.
-int WIFI_LOG_INTERVAL = 0;
-
-/***********************************************************************************/
-
-/* System Configuration */
-// Temperature Configuration
-const int MIN_GREENHOUSE_TEMP = 20; // Minmum greenhouse temperature. Anything lower then this value will result in a alarm.
-const int MAX_GREENHOUSE_TEMP = 26; // Maximum greenhouse temperature.
-
-// Humidity Configuration
-const int MIN_GREENHOUSE_HUMIDITY = 50; // Minimum greenhouse humidity (as percentage)
-const int MAX_GREENHOUSE_HUMIDITY = 70; // Maximum greenhouse humidity (as percentage)
-
-// Lighting Configuration
-const int LIGHTS_ON_TIME = 12; // What hour (24h format) to turn the lights on. (-1 = 24h lights on).
-
-// LCD Display Configuration
-const boolean LCD_ENABLED = true; // Enable or disable the use of a LCD on Serial1.
-
-// Serial Communications Configuration
-const int SERIAL_BAUD_RATE = 9600;  // Serial baud rate for external debug connections (USB).
-const int LCD_BAUD_RATE = 9600;     // Serial baud rate for connected LCD display (default 9600 baud).
-
-// Wifi Configuration
-const int WIFI_BAUD_RATE = 9600;
-const char WIFI_PASSPHRASE[] = "passphrase";
-const char WIFI_SSID[] = "ssid";
-
-/***********************************************************************************/
-
-/**
- * Application Setup
- */
-void setup () {
-  Serial.begin(SERIAL_BAUD_RATE);  // Serial communications
-  Serial1.begin(LCD_BAUD_RATE);    // LCD Display
-
-  Serial.println("--------------------------------------------------------");
-  Serial.println("Fisher Innovation - Automated Greenhouse Controller");
-  Serial.println("Created By: Matt Fisher <fisher.matt@gmail.com>");
-  Serial.println("https://github.com/fisherinnovation/FI-Automated-Greenhouse");
-  Serial.println("--------------------------------------------------------");
-  Serial.println("");
-  Serial.println("> NOTICE: Activating system...");
-
-  displayLCDMessage("     Fisher     ", "   Innovation   ", true, 1);
-  displayLCDMessage("   Automated    ", "   Greenhouse   ", true, 1);
-
-  // Following line sets the RTC to the date & time this sketch was compiled.
-  // Note: Comment out this after initial setting of time on the RTC.
-  //Serial.println("> NOTICE: Setting System Date and Time...");
-  RTC.begin(DateTime(__DATE__, __TIME__));
-
-  // Init controllers
-  //setupWifiController();   // Wifi controller
-  setupLightController();  // Light controller
-  setupFanController();    // Fan controller
-
-  Serial.println("> NOTICE: System Startup Complete.");
-  Serial.println("> NOTICE: Greenhouse Startup Complete!");
+/**
+ * Fisher Innovation Automated Greenhouse Controller
+ * @author Matt Fisher (Fisher Innovation) [fisher.matt@gmail.com]
+ *
+ * Copyright (c) 2012 Fisher Innovation
+ * Licensed the MIT license.
+ *
+ * http://www.fisherinnovation.com
+ * https://github.com/fisherinnovation/FI-Automated-Greenhouse
+ */
+
+#include <Wire.h>
+#include "RTClib.h" // DS1307 Real Time Clock.
+#include <DHT22.h>  // DHT22 Temperature and Humidity Sensor.
+#include <stdio.h>  // Only used for sprintf.
+
+#include <Arduino.h>
+#include <Time.h>
+#include <SoftwareSerial.h>
+#include <Streaming.h>
+#include <PString.h>
+#include <WiFlySerial.h>
+#include "Credentials.h"
+#include "MemoryFree.h"
+
+#define DHT22_PIN 7     // DHT22 Temperature and Humidity Sensor to pin D7.
+
+DHT22 myDHT22(DHT22_PIN); // Setup a DHT22 instance.
+RTC_Millis RTC;           // Setup a DS1307 instance.
+
+int CURRENT_TEMP = 0;      // Global reference to the current system temperature.
+int CURRENT_HUMIDITY = 0;  // Global reference to the current system humidity.
+int CURRENT_TIME[3];       // Global reference to the current system date.
+int CURRENT_DATE[3];       // Global reference to the current system time.
+int WIFI_LOG_INTERVAL = 0;
+
+/***********************************************************************************/
+
+/* System Configuration */
+// Temperature Configuration
+const int MAX_GREENHOUSE_TEMP = 26; // Maximum greenhouse temperature.
+
+// Humidity Configuration
+const int MAX_GREENHOUSE_HUMIDITY = 70; // Maximum greenhouse humidity (as percentage)
+
+// Lighting Configuration
+const int LIGHTS_ON_TIME = 12; // What hour (24h format) to turn the lights on. (-1 = 24h lights on).
+
+// LCD Display Configuration
+const boolean LCD_ENABLED = true; // Enable or disable the use of a LCD on Serial1.
+
+// Serial Communications Configuration
+const int SERIAL_BAUD_RATE = 9600;  // Serial baud rate for external debug connections (USB).
+const int LCD_BAUD_RATE = 9600;     // Serial baud rate for connected LCD display (default 9600 baud).
+
+// Wifi Configuration
+const int WIFI_BAUD_RATE = 9600;
+const char WIFI_PASSPHRASE[] = "passphrase";
+const char WIFI_SSID[] = "ssid";
+
+/***********************************************************************************/
+
+/**
+ * Application Setup
+ */
+void setup () {
+  Serial.begin(SERIAL_BAUD_RATE);  // Serial communications
+  Serial1.begin(LCD_BAUD_RATE);    // LCD Display
+
+  Serial.println("--------------------------------------------------------");
+  Serial.println("Fisher Innovation - Automated Greenhouse Controller");
+  Serial.println("Created By: Matt Fisher <fisher.matt@gmail.com>");
+  Serial.println("https://github.com/fisherinnovation/FI-Automated-Greenhouse");
+  Serial.println("--------------------------------------------------------");
+  Serial.println("");
+  Serial.println("> NOTICE: Activating system...");
+
+  displayLCDMessage("     Fisher     ", "   Innovation   ", true, 1);
+  displayLCDMessage("   Automated    ", "   Greenhouse   ", true, 1);
+
+  // Following line sets the RTC to the date & time this sketch was compiled.
+  // Note: Comment out this after initial setting of time on the RTC.
+  //Serial.println("> NOTICE: Setting System Date and Time...");
+  RTC.begin(DateTime(__DATE__, __TIME__));
+
+  // Init controllers
+  //setupWifiController();   // Wifi controller
+  setupLightController();  // Light controller
+  setupFanController();    // Fan controller
+
+  Serial.println("> NOTICE: System Startup Complete.");
+  Serial.println("> NOTICE: Greenhouse Startup Complete!");
+}
+
+/**
+ * System Loop.
+ */
+void loop() {
+  checkSerialInput(); // Check for serial input.
+  updateLCDDisplay(); // Update the LCD display.
+
+  mainLoop();
+}
+
+/**
+ * Main Application Loop
+ */
+void mainLoop() {
+  // Update the clock values.
+  readDS1307();
+
+  // Aquire the latest DHT22 dataset (temperature & humidity).
+  // Calling this method will result in the 'CURRENT_TEMP' and 'CURRENT_HUMIDITY'
+  // varibles to be updated. The sensor also requires a cool down time which will
+  // result in a 2 second delay during the call.
+  getDHT22Data();
+
+  // Check if the system temperature is higher then configured.
+  if(CURRENT_TEMP > MAX_GREENHOUSE_TEMP) {
+    // Temperature is too high.
+    // Make sure fans are on.
+    turnFanOn();
+  } else {
+    // Temperature is at a stable reading.
+    if(CURRENT_HUMIDITY > MAX_GREENHOUSE_HUMIDITY) {
+      turnFanOn(); // Humidity is too high. Make sure fans are on.
+    } else {
+      turnFanOff(); // Humidity is at a stable reading. Make sure fans are off.
+    }
+  }
+
+  // Check lighting system conditions.
+  // Check if it is time to turn on the lights.
+  if(CURRENT_TIME[0] >= LIGHTS_ON_TIME) {
+    turnLightsOn(); // Turn lights on.
+  } else {
+    turnLightsOff(); // Turn lights off.
+  }
+
+  // Wifi
+  WIFI_LOG_INTERVAL++;
+  if(WIFI_LOG_INTERVAL == 100) {
+    Serial.println("Attempting to log data over wifi...");
+    logSystemData();
+    WIFI_LOG_INTERVAL = 0;
+  }
 }
-
-/**
- * System Loop.
- */
-void loop() {
-  checkSerialInput(); // Check for serial input.
-  updateLCDDisplay(); // Update the LCD display.
-
-  mainLoop();
-}
-
-/**
- * Main Application Loop
- */
-void mainLoop() {
-  // Update the clock values.
-  readDS1307();
-
-  // Aquire the latest DHT22 dataset (temperature & humidity).
-  // Calling this method will result in the 'CURRENT_TEMP' and 'CURRENT_HUMIDITY'
-  // varibles to be updated. The sensor also requires a cool down time which will
-  // result in a 2 second delay during the call.
-  getDHT22Data();
-
-  // Check if the system temperature is lower then configured.
-  if(CURRENT_TEMP < MIN_GREENHOUSE_TEMP) {
-    // Temperature is too low.
-    // Make sure fans are off.
-    turnFanOff();
-  }
-  // Check if the system temperature is higher then configured.
-  else if(CURRENT_TEMP > MAX_GREENHOUSE_TEMP) {
-    // Temperature is too high.
-    // Make sure fans are on.
-    turnFanOn();
-  } else {
-    // Temperature is at a stable reading.
-    // Check if the system humidity is lower then configured.
-    if(CURRENT_HUMIDITY < MIN_GREENHOUSE_HUMIDITY) {
-      turnFanOff(); // Humidity is too low. Make sure fans are off.
-    }
-    // Check if the system humidity is higher then configured.
-    else if(CURRENT_HUMIDITY > MAX_GREENHOUSE_HUMIDITY) {
-      turnFanOn(); // Humidity is too high. Make sure fans are on.
-    } else {
-      turnFanOff(); // Humidity is at a stable reading. Make sure fans are off.
-    }
-  }
-
-  // Check lighting system conditions.
-  // Check if it is time to turn on the lights.
-  if(CURRENT_TIME[0] >= LIGHTS_ON_TIME) {
-    turnLightsOn(); // Turn lights on.
-  } else {
-    turnLightsOff(); // Turn lights off.
-  }
-
-  // Wifi
-  WIFI_LOG_INTERVAL++;
-  if(WIFI_LOG_INTERVAL == 100) {
-    Serial.println("Attempting to log data over wifi...");
-    logSystemData();
-    WIFI_LOG_INTERVAL = 0;
-  }
-}


CHANGED - The auto break system should now trigger if no command is received within a second.

--- Arduino/MotorController_v05/MotorController_v05.ino
+++ Arduino/MotorController_v05/MotorController_v05.ino
@@ -29,10 +29,10 @@
 }
 void loop() {

-time = millis();
+timer = millis();

-    // If the car dosent recive a command for 2 seconds stop
-   if(!Complete && (timer - lastCommand) > 2000){
+    // If the car dosent recive a command for 1 seconds stop
+   if(!Complete && (timer - lastCommand) > 1000){
     speed = 0;
     angle = 0;
     // Carry out Instructions


Internal & External Write

Internal & External Write

--- arduino.ino
+++ arduino.ino
@@ -5,7 +5,8 @@

 // MANUAL SETUP
 #define INTERNAL_EEPROM_SIZE 1024   // Internal EEPROM Max Size.
-#define EXTERNAL_EEPROM_SIZE 64000  // EEPROM Max Size.
+#define EXTERNAL_EEPROM_SIZE 64000  // External EEPROM Max Size.
+#define EXTERNAL_EPROM_ADDRS 0x50   // External EEPROM I2C Address.
 #define INDICATOR_LED 13            // Main LED Indicator.
 #define DEBUG_SWITCH 6              // Toggle Switch Digital Pin.
 #define SAMPLING 3                  // Samples Per Second.
@@ -41,13 +42,13 @@
 void uploadMemory() {
   for(uint32_t i=0; i<entriesCounter; i++) {
     float f = 0.00f;
-    EEPROM.get(i*sizeof(float), f);
+    EEPROM.get(i*sizeof(float), f); // External Memory
     serialFloatPrint(f);
   }
 }

 void updateEntriesCount(uint32_t count) {
-  EEPROM.put(EEPROM_SIZE-4, count);
+  EEPROM.put(0, count); // Internal Memory
 }

 void listenCommanader() {
@@ -71,7 +72,7 @@
       break;
       case '9':
         updateEntriesCount(0);
-        EEPROM.get(EEPROM_SIZE-4, entriesCounter);
+        EEPROM.get(0, entriesCounter); // Internal Memory
       break;
     }
     Serial.flush();
@@ -97,7 +98,7 @@
   pinMode(DEBUG_SWITCH, INPUT_PULLUP);
   pinMode(INDICATOR_LED, OUTPUT);

-  EEPROM.get(EEPROM_SIZE-4, entriesCounter);
+  EEPROM.get(0, entriesCounter); // Internal Memory

   if(digitalRead(DEBUG_SWITCH) == LOW) {
     digitalWrite(INDICATOR_LED, LOW); // Debug mode ON.
@@ -133,7 +134,7 @@
     Serial.print("Current Altitude (m): ");
     Serial.println(lastAlt);

-    EEPROM.put(entriesCounter*sizeof(float), lastAlt);
+    EEPROM.put(entriesCounter*sizeof(float), lastAlt); // External Memory
     entriesCounter++;

     updateEntriesCount(entriesCounter);


Adjust for Mega.

Adjust for Mega.

--- examples/Drivers/CosaDHTevent/CosaDHTevent.ino
+++ examples/Drivers/CosaDHTevent/CosaDHTevent.ino
@@ -23,7 +23,7 @@
  *                       DHT11/dht
  *                       +------------+
  * (VCC)---------------1-|VCC  ====== |
- * (D2/EXT0)-----------2-|DATA ====== |
+ * (D2/EXT0/EXT4)------2-|DATA ====== |
  *                     3-|     ====== |
  * (GND)---------------4-|GND  ====== |
  *                       +------------+
@@ -42,7 +42,11 @@
 // on_sample_completed() prints current value to the trace stream.
 class DHTevent : public DHT11 {
 public:
+#if defined(ARDUINO_MEGA_2560)
+  DHTevent(Board::ExternalInterruptPin pin = Board::EXT4) : DHT11(pin) {}
+#else
   DHTevent(Board::ExternalInterruptPin pin = Board::EXT0) : DHT11(pin) {}
+#endif
   virtual void on_sample_completed() { trace << *this << endl; }
 };


Update MultipleSteppers.ino

Update MultipleSteppers.ino

--- examples/MultipleSteppers/MultipleSteppers.ino
+++ examples/MultipleSteppers/MultipleSteppers.ino
@@ -65,10 +65,11 @@
   motor_3.setTargetRel(-800);
   controller.move(motor_2, motor_3);

-  // move motor_1 and motor_3 back to their start positions
+  // move all motors back to their start positions
   motor_1.setTargetAbs(0);
+  motor_2.setTargetAbs(0);
   motor_3.setTargetAbs(0);
-  controller.move(motor_1, motor_3);
+  controller.move(motor_1, motor_2, motor_3);

   delay(1000);
 }


Fixed GPIO numbers for rear sonar sensors

--- sensor-hub/sensor-hub.ino
+++ sensor-hub/sensor-hub.ino
@@ -22,9 +22,9 @@
 const int ultraSound1TrigPin = 2;
 const int ultraSound2TrigPin = 3;
 const int ultraSound3TrigPin = 4;
-const int ultraSound4TrigPin = 5;
-const int ultraSound5TrigPin = 6;
-const int ultraSound6TrigPin = 7;
+const int ultraSound4TrigPin = 10;
+const int ultraSound5TrigPin = 11;
+const int ultraSound6TrigPin = 12;
 const int sonarPins[] = {ultraSound1TrigPin,
                          ultraSound2TrigPin,
                          ultraSound3TrigPin,