Browse Source

initial checkin

FloKra 1 year ago
commit
1b6aaed35f

+ 87 - 0
HomeServerIOExt_Arduino/Adafruit_Sensor.cpp

@@ -0,0 +1,87 @@
+#include "Adafruit_Sensor.h"
+
+/**************************************************************************/
+/*!
+    @brief  Prints sensor information to serial console
+*/
+/**************************************************************************/
+void Adafruit_Sensor::printSensorDetails(void) {
+  sensor_t sensor;
+  getSensor(&sensor);
+  Serial.println(F("------------------------------------"));
+  Serial.print(F("Sensor:       "));
+  Serial.println(sensor.name);
+  Serial.print(F("Type:         "));
+  switch ((sensors_type_t)sensor.type) {
+  case SENSOR_TYPE_ACCELEROMETER:
+    Serial.print(F("Acceleration (m/s2)"));
+    break;
+  case SENSOR_TYPE_MAGNETIC_FIELD:
+    Serial.print(F("Magnetic (uT)"));
+    break;
+  case SENSOR_TYPE_ORIENTATION:
+    Serial.print(F("Orientation (degrees)"));
+    break;
+  case SENSOR_TYPE_GYROSCOPE:
+    Serial.print(F("Gyroscopic (rad/s)"));
+    break;
+  case SENSOR_TYPE_LIGHT:
+    Serial.print(F("Light (lux)"));
+    break;
+  case SENSOR_TYPE_PRESSURE:
+    Serial.print(F("Pressure (hPa)"));
+    break;
+  case SENSOR_TYPE_PROXIMITY:
+    Serial.print(F("Distance (cm)"));
+    break;
+  case SENSOR_TYPE_GRAVITY:
+    Serial.print(F("Gravity (m/s2)"));
+    break;
+  case SENSOR_TYPE_LINEAR_ACCELERATION:
+    Serial.print(F("Linear Acceleration (m/s2)"));
+    break;
+  case SENSOR_TYPE_ROTATION_VECTOR:
+    Serial.print(F("Rotation vector"));
+    break;
+  case SENSOR_TYPE_RELATIVE_HUMIDITY:
+    Serial.print(F("Relative Humidity (%)"));
+    break;
+  case SENSOR_TYPE_AMBIENT_TEMPERATURE:
+    Serial.print(F("Ambient Temp (C)"));
+    break;
+  case SENSOR_TYPE_OBJECT_TEMPERATURE:
+    Serial.print(F("Object Temp (C)"));
+    break;
+  case SENSOR_TYPE_VOLTAGE:
+    Serial.print(F("Voltage (V)"));
+    break;
+  case SENSOR_TYPE_CURRENT:
+    Serial.print(F("Current (mA)"));
+    break;
+  case SENSOR_TYPE_COLOR:
+    Serial.print(F("Color (RGBA)"));
+    break;
+  case SENSOR_TYPE_TVOC:
+    Serial.print(F("Total Volatile Organic Compounds (ppb)"));
+    break;
+  case SENSOR_TYPE_VOC_INDEX:
+    Serial.print(F("Volatile Organic Compounds (Index)"));
+    break;
+  case SENSOR_TYPE_NOX_INDEX:
+    Serial.print(F("Nitrogen Oxides (Index)"));
+    break;
+  }
+
+  Serial.println();
+  Serial.print(F("Driver Ver:   "));
+  Serial.println(sensor.version);
+  Serial.print(F("Unique ID:    "));
+  Serial.println(sensor.sensor_id);
+  Serial.print(F("Min Value:    "));
+  Serial.println(sensor.min_value);
+  Serial.print(F("Max Value:    "));
+  Serial.println(sensor.max_value);
+  Serial.print(F("Resolution:   "));
+  Serial.println(sensor.resolution);
+  Serial.println(F("------------------------------------\n"));
+}

+ 196 - 0
HomeServerIOExt_Arduino/Adafruit_Sensor.h

@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software< /span>
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
+ * extended sensor support to include color, voltage and current */
+
+#ifndef _ADAFRUIT_SENSOR_H
+#define _ADAFRUIT_SENSOR_H
+
+#ifndef ARDUINO
+#include <stdint.h>
+#elif ARDUINO >= 100
+#include "Arduino.h"
+#include "Print.h"
+#else
+#include "WProgram.h"
+#endif
+
+/* Constants */
+#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
+#define SENSORS_GRAVITY_MOON (1.6F)      /**< The moon's gravity in m/s^2 */
+#define SENSORS_GRAVITY_SUN (275.0F)     /**< The sun's gravity in m/s^2 */
+#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
+#define SENSORS_MAGFIELD_EARTH_MAX                                             \
+  (60.0F) /**< Maximum magnetic field on Earth's surface */
+#define SENSORS_MAGFIELD_EARTH_MIN                                             \
+  (30.0F) /**< Minimum magnetic field on Earth's surface */
+#define SENSORS_PRESSURE_SEALEVELHPA                                           \
+  (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
+#define SENSORS_DPS_TO_RADS                                                    \
+  (0.017453293F) /**< Degrees/s to rad/s multiplier                            \
+                  */
+#define SENSORS_RADS_TO_DPS                                                    \
+  (57.29577793F) /**< Rad/s to degrees/s  multiplier */
+#define SENSORS_GAUSS_TO_MICROTESLA                                            \
+  (100) /**< Gauss to micro-Tesla multiplier */
+
+/** Sensor types */
+typedef enum {
+  SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
+  SENSOR_TYPE_MAGNETIC_FIELD = (2),
+  SENSOR_TYPE_ORIENTATION = (3),
+  SENSOR_TYPE_GYROSCOPE = (4),
+  SENSOR_TYPE_LIGHT = (5),
+  SENSOR_TYPE_PRESSURE = (6),
+  SENSOR_TYPE_PROXIMITY = (8),
+  SENSOR_TYPE_GRAVITY = (9),
+  SENSOR_TYPE_LINEAR_ACCELERATION =
+      (10), /**< Acceleration not including gravity */
+  SENSOR_TYPE_ROTATION_VECTOR = (11),
+  SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
+  SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
+  SENSOR_TYPE_OBJECT_TEMPERATURE = (14),
+  SENSOR_TYPE_VOLTAGE = (15),
+  SENSOR_TYPE_CURRENT = (16),
+  SENSOR_TYPE_COLOR = (17),
+  SENSOR_TYPE_TVOC = (18),
+  SENSOR_TYPE_VOC_INDEX = (19),
+  SENSOR_TYPE_NOX_INDEX = (20)
+} sensors_type_t;
+
+/** struct sensors_vec_s is used to return a vector in a common format. */
+typedef struct {
+  union {
+    float v[3]; ///< 3D vector elements
+    struct {
+      float x; ///< X component of vector
+      float y; ///< Y component of vector
+      float z; ///< Z component of vector
+    };         ///< Struct for holding XYZ component
+    /* Orientation sensors */
+    struct {
+      float roll; /**< Rotation around the longitudinal axis (the plane body, 'X
+                     axis'). Roll is positive and increasing when moving
+                     downward. -90 degrees <= roll <= 90 degrees */
+      float pitch;   /**< Rotation around the lateral axis (the wing span, 'Y
+                        axis'). Pitch is positive and increasing when moving
+                        upwards. -180 degrees <= pitch <= 180 degrees) */
+      float heading; /**< Angle between the longitudinal axis (the plane body)
+                        and magnetic north, measured clockwise when viewing from
+                        the top of the device. 0-359 degrees */
+    };               ///< Struct for holding roll/pitch/heading
+  };                 ///< Union that can hold 3D vector array, XYZ components or
+                     ///< roll/pitch/heading
+  int8_t status;     ///< Status byte
+  uint8_t reserved[3]; ///< Reserved
+} sensors_vec_t;
+
+/** struct sensors_color_s is used to return color data in a common format. */
+typedef struct {
+  union {
+    float c[3]; ///< Raw 3-element data
+    /* RGB color space */
+    struct {
+      float r;   /**< Red component */
+      float g;   /**< Green component */
+      float b;   /**< Blue component */
+    };           ///< RGB data in floating point notation
+  };             ///< Union of various ways to describe RGB colorspace
+  uint32_t rgba; /**< 24-bit RGBA value */
+} sensors_color_t;
+
+/* Sensor event (36 bytes) */
+/** struct sensor_event_s is used to provide a single sensor event in a common
+ * format. */
+typedef struct {
+  int32_t version;   /**< must be sizeof(struct sensors_event_t) */
+  int32_t sensor_id; /**< unique sensor identifier */
+  int32_t type;      /**< sensor type */
+  int32_t reserved0; /**< reserved */
+  int32_t timestamp; /**< time is in milliseconds */
+  union {
+    float data[4];              ///< Raw data
+    sensors_vec_t acceleration; /**< acceleration values are in meter per second
+                                   per second (m/s^2) */
+    sensors_vec_t
+        magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
+    sensors_vec_t orientation; /**< orientation values are in degrees */
+    sensors_vec_t gyro;        /**< gyroscope values are in rad/s */
+    float temperature; /**< temperature is in degrees centigrade (Celsius) */
+    float distance;    /**< distance in centimeters */
+    float light;       /**< light in SI lux units */
+    float pressure;    /**< pressure in hectopascal (hPa) */
+    float relative_humidity; /**< relative humidity in percent */
+    float current;           /**< current in milliamps (mA) */
+    float voltage;           /**< voltage in volts (V) */
+    float tvoc;              /**< Total Volatile Organic Compounds, in ppb */
+    float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is
+                          normal (unitless) */
+    float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal
+                          (unitless) */
+    sensors_color_t color; /**< color in RGB component values */
+  };                       ///< Union for the wide ranges of data we can carry
+} sensors_event_t;
+
+/* Sensor details (40 bytes) */
+/** struct sensor_s is used to describe basic information about a specific
+ * sensor. */
+typedef struct {
+  char name[12];     /**< sensor name */
+  int32_t version;   /**< version of the hardware + driver */
+  int32_t sensor_id; /**< unique sensor identifier */
+  int32_t type;      /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
+  float max_value;   /**< maximum value of this sensor's value in SI units */
+  float min_value;   /**< minimum value of this sensor's value in SI units */
+  float resolution; /**< smallest difference between two values reported by this
+                       sensor */
+  int32_t min_delay; /**< min delay in microseconds between events. zero = not a
+                        constant rate */
+} sensor_t;
+
+/** @brief Common sensor interface to unify various sensors.
+ * Intentionally modeled after sensors.h in the Android API:
+ * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h
+ */
+class Adafruit_Sensor {
+public:
+  // Constructor(s)
+  Adafruit_Sensor() {}
+  virtual ~Adafruit_Sensor() {}
+
+  // These must be defined by the subclass
+
+  /*! @brief Whether we should automatically change the range (if possible) for
+     higher precision
+      @param enabled True if we will try to autorange */
+  virtual void enableAutoRange(bool enabled) {
+    (void)enabled; /* suppress unused warning */
+  };
+
+  /*! @brief Get the latest sensor event
+      @returns True if able to fetch an event */
+  virtual bool getEvent(sensors_event_t *) = 0;
+  /*! @brief Get info about the sensor itself */
+  virtual void getSensor(sensor_t *) = 0;
+
+  void printSensorDetails(void);
+
+private:
+  bool _autoRange;
+};
+
+#endif

+ 390 - 0
HomeServerIOExt_Arduino/DHT.cpp

@@ -0,0 +1,390 @@
+/*!
+ *  @file DHT.cpp
+ *
+ *  @mainpage DHT series of low cost temperature/humidity sensors.
+ *
+ *  @section intro_sec Introduction
+ *
+ *  This is a library for DHT series of low cost temperature/humidity sensors.
+ *
+ *  You must have Adafruit Unified Sensor Library library installed to use this
+ * class.
+ *
+ *  Adafruit invests time and resources providing this open source code,
+ *  please support Adafruit andopen-source hardware by purchasing products
+ *  from Adafruit!
+ *
+ *  @section author Author
+ *
+ *  Written by Adafruit Industries.
+ *
+ *  @section license License
+ *
+ *  MIT license, all text above must be included in any redistribution
+ */
+
+#include "DHT.h"
+
+#define MIN_INTERVAL 2000 /**< min interval value */
+#define TIMEOUT                                                                \
+  UINT32_MAX /**< Used programmatically for timeout.                           \
+                   Not a timeout duration. Type: uint32_t. */
+
+/*!
+ *  @brief  Instantiates a new DHT class
+ *  @param  pin
+ *          pin number that sensor is connected
+ *  @param  type
+ *          type of sensor
+ *  @param  count
+ *          number of sensors
+ */
+DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
+  (void)count; // Workaround to avoid compiler warning.
+  _pin = pin;
+  _type = type;
+#ifdef __AVR
+  _bit = digitalPinToBitMask(pin);
+  _port = digitalPinToPort(pin);
+#endif
+  _maxcycles =
+      microsecondsToClockCycles(1000); // 1 millisecond timeout for
+                                       // reading pulses from DHT sensor.
+  // Note that count is now ignored as the DHT reading algorithm adjusts itself
+  // based on the speed of the processor.
+}
+
+/*!
+ *  @brief  Setup sensor pins and set pull timings
+ *  @param  usec
+ *          Optionally pass pull-up time (in microseconds) before DHT reading
+ *starts. Default is 55 (see function declaration in DHT.h).
+ */
+void DHT::begin(uint8_t usec) {
+  // set up the pins!
+  pinMode(_pin, INPUT_PULLUP);
+  // Using this value makes sure that millis() - lastreadtime will be
+  // >= MIN_INTERVAL right away. Note that this assignment wraps around,
+  // but so will the subtraction.
+  _lastreadtime = millis() - MIN_INTERVAL;
+  DEBUG_PRINT("DHT max clock cycles: ");
+  DEBUG_PRINTLN(_maxcycles, DEC);
+  pullTime = usec;
+}
+
+/*!
+ *  @brief  Read temperature
+ *  @param  S
+ *          Scale. Boolean value:
+ *					- true = Fahrenheit
+ *					- false = Celcius
+ *  @param  force
+ *          true if in force mode
+ *	@return Temperature value in selected scale
+ */
+float DHT::readTemperature(bool S, bool force) {
+  float f = NAN;
+
+  if (read(force)) {
+    switch (_type) {
+    case DHT11:
+      f = data[2];
+      if (data[3] & 0x80) {
+        f = -1 - f;
+      }
+      f += (data[3] & 0x0f) * 0.1;
+      if (S) {
+        f = convertCtoF(f);
+      }
+      break;
+    case DHT12:
+      f = data[2];
+      f += (data[3] & 0x0f) * 0.1;
+      if (data[2] & 0x80) {
+        f *= -1;
+      }
+      if (S) {
+        f = convertCtoF(f);
+      }
+      break;
+    case DHT22:
+    case DHT21:
+      f = ((word)(data[2] & 0x7F)) << 8 | data[3];
+      f *= 0.1;
+      if (data[2] & 0x80) {
+        f *= -1;
+      }
+      if (S) {
+        f = convertCtoF(f);
+      }
+      break;
+    }
+  }
+  return f;
+}
+
+/*!
+ *  @brief  Converts Celcius to Fahrenheit
+ *  @param  c
+ *					value in Celcius
+ *	@return float value in Fahrenheit
+ */
+float DHT::convertCtoF(float c) { return c * 1.8 + 32; }
+
+/*!
+ *  @brief  Converts Fahrenheit to Celcius
+ *  @param  f
+ *					value in Fahrenheit
+ *	@return float value in Celcius
+ */
+float DHT::convertFtoC(float f) { return (f - 32) * 0.55555; }
+
+/*!
+ *  @brief  Read Humidity
+ *  @param  force
+ *					force read mode
+ *	@return float value - humidity in percent
+ */
+float DHT::readHumidity(bool force) {
+  float f = NAN;
+  if (read(force)) {
+    switch (_type) {
+    case DHT11:
+    case DHT12:
+      f = data[0] + data[1] * 0.1;
+      break;
+    case DHT22:
+    case DHT21:
+      f = ((word)data[0]) << 8 | data[1];
+      f *= 0.1;
+      break;
+    }
+  }
+  return f;
+}
+
+/*!
+ *  @brief  Compute Heat Index
+ *          Simplified version that reads temp and humidity from sensor
+ *  @param  isFahrenheit
+ * 					true if fahrenheit, false if celcius
+ *(default true)
+ *	@return float heat index
+ */
+float DHT::computeHeatIndex(bool isFahrenheit) {
+  float hi = computeHeatIndex(readTemperature(isFahrenheit), readHumidity(),
+                              isFahrenheit);
+  return hi;
+}
+
+/*!
+ *  @brief  Compute Heat Index
+ *  				Using both Rothfusz and Steadman's equations
+ *					(http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml)
+ *  @param  temperature
+ *          temperature in selected scale
+ *  @param  percentHumidity
+ *          humidity in percent
+ *  @param  isFahrenheit
+ * 					true if fahrenheit, false if celcius
+ *	@return float heat index
+ */
+float DHT::computeHeatIndex(float temperature, float percentHumidity,
+                            bool isFahrenheit) {
+  float hi;
+
+  if (!isFahrenheit)
+    temperature = convertCtoF(temperature);
+
+  hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) +
+              (percentHumidity * 0.094));
+
+  if (hi > 79) {
+    hi = -42.379 + 2.04901523 * temperature + 10.14333127 * percentHumidity +
+         -0.22475541 * temperature * percentHumidity +
+         -0.00683783 * pow(temperature, 2) +
+         -0.05481717 * pow(percentHumidity, 2) +
+         0.00122874 * pow(temperature, 2) * percentHumidity +
+         0.00085282 * temperature * pow(percentHumidity, 2) +
+         -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);
+
+    if ((percentHumidity < 13) && (temperature >= 80.0) &&
+        (temperature <= 112.0))
+      hi -= ((13.0 - percentHumidity) * 0.25) *
+            sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);
+
+    else if ((percentHumidity > 85.0) && (temperature >= 80.0) &&
+             (temperature <= 87.0))
+      hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
+  }
+
+  return isFahrenheit ? hi : convertFtoC(hi);
+}
+
+/*!
+ *  @brief  Read value from sensor or return last one from less than two
+ *seconds.
+ *  @param  force
+ *          true if using force mode
+ *	@return float value
+ */
+bool DHT::read(bool force) {
+  // Check if sensor was read less than two seconds ago and return early
+  // to use last reading.
+  uint32_t currenttime = millis();
+  if (!force && ((currenttime - _lastreadtime) < MIN_INTERVAL)) {
+    return _lastresult; // return last correct measurement
+  }
+  _lastreadtime = currenttime;
+
+  // Reset 40 bits of received data to zero.
+  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
+
+#if defined(ESP8266)
+  yield(); // Handle WiFi / reset software watchdog
+#endif
+
+  // Send start signal.  See DHT datasheet for full signal diagram:
+  //   http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf
+
+  // Go into high impedence state to let pull-up raise data line level and
+  // start the reading process.
+  pinMode(_pin, INPUT_PULLUP);
+  delay(1);
+
+  // First set data line low for a period according to sensor type
+  pinMode(_pin, OUTPUT);
+  digitalWrite(_pin, LOW);
+  switch (_type) {
+  case DHT22:
+  case DHT21:
+    delayMicroseconds(1100); // data sheet says "at least 1ms"
+    break;
+  case DHT11:
+  default:
+    delay(20); // data sheet says at least 18ms, 20ms just to be safe
+    break;
+  }
+
+  uint32_t cycles[80];
+  {
+    // End the start signal by setting data line high for 40 microseconds.
+    pinMode(_pin, INPUT_PULLUP);
+
+    // Delay a moment to let sensor pull data line low.
+    delayMicroseconds(pullTime);
+
+    // Now start reading the data line to get the value from the DHT sensor.
+
+    // Turn off interrupts temporarily because the next sections
+    // are timing critical and we don't want any interruptions.
+    InterruptLock lock;
+
+    // First expect a low signal for ~80 microseconds followed by a high signal
+    // for ~80 microseconds again.
+    if (expectPulse(LOW) == TIMEOUT) {
+      DEBUG_PRINTLN(F("DHT timeout waiting for start signal low pulse."));
+      _lastresult = false;
+      return _lastresult;
+    }
+    if (expectPulse(HIGH) == TIMEOUT) {
+      DEBUG_PRINTLN(F("DHT timeout waiting for start signal high pulse."));
+      _lastresult = false;
+      return _lastresult;
+    }
+
+    // Now read the 40 bits sent by the sensor.  Each bit is sent as a 50
+    // microsecond low pulse followed by a variable length high pulse.  If the
+    // high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds
+    // then it's a 1.  We measure the cycle count of the initial 50us low pulse
+    // and use that to compare to the cycle count of the high pulse to determine
+    // if the bit is a 0 (high state cycle count < low state cycle count), or a
+    // 1 (high state cycle count > low state cycle count). Note that for speed
+    // all the pulses are read into a array and then examined in a later step.
+    for (int i = 0; i < 80; i += 2) {
+      cycles[i] = expectPulse(LOW);
+      cycles[i + 1] = expectPulse(HIGH);
+    }
+  } // Timing critical code is now complete.
+
+  // Inspect pulses and determine which ones are 0 (high state cycle count < low
+  // state cycle count), or 1 (high state cycle count > low state cycle count).
+  for (int i = 0; i < 40; ++i) {
+    uint32_t lowCycles = cycles[2 * i];
+    uint32_t highCycles = cycles[2 * i + 1];
+    if ((lowCycles == TIMEOUT) || (highCycles == TIMEOUT)) {
+      DEBUG_PRINTLN(F("DHT timeout waiting for pulse."));
+      _lastresult = false;
+      return _lastresult;
+    }
+    data[i / 8] <<= 1;
+    // Now compare the low and high cycle times to see if the bit is a 0 or 1.
+    if (highCycles > lowCycles) {
+      // High cycles are greater than 50us low cycle count, must be a 1.
+      data[i / 8] |= 1;
+    }
+    // Else high cycles are less than (or equal to, a weird case) the 50us low
+    // cycle count so this must be a zero.  Nothing needs to be changed in the
+    // stored data.
+  }
+
+  DEBUG_PRINTLN(F("Received from DHT:"));
+  DEBUG_PRINT(data[0], HEX);
+  DEBUG_PRINT(F(", "));
+  DEBUG_PRINT(data[1], HEX);
+  DEBUG_PRINT(F(", "));
+  DEBUG_PRINT(data[2], HEX);
+  DEBUG_PRINT(F(", "));
+  DEBUG_PRINT(data[3], HEX);
+  DEBUG_PRINT(F(", "));
+  DEBUG_PRINT(data[4], HEX);
+  DEBUG_PRINT(F(" =? "));
+  DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) & 0xFF, HEX);
+
+  // Check we read 40 bits and that the checksum matches.
+  if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
+    _lastresult = true;
+    return _lastresult;
+  } else {
+    DEBUG_PRINTLN(F("DHT checksum failure!"));
+    _lastresult = false;
+    return _lastresult;
+  }
+}
+
+// Expect the signal line to be at the specified level for a period of time and
+// return a count of loop cycles spent at that level (this cycle count can be
+// used to compare the relative time of two pulses).  If more than a millisecond
+// ellapses without the level changing then the call fails with a 0 response.
+// This is adapted from Arduino's pulseInLong function (which is only available
+// in the very latest IDE versions):
+//   https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c
+uint32_t DHT::expectPulse(bool level) {
+// F_CPU is not be known at compile time on platforms such as STM32F103.
+// The preprocessor seems to evaluate it to zero in that case.
+#if (F_CPU > 16000000L) || (F_CPU == 0L)
+  uint32_t count = 0;
+#else
+  uint16_t count = 0; // To work fast enough on slower AVR boards
+#endif
+// On AVR platforms use direct GPIO port access as it's much faster and better
+// for catching pulses that are 10's of microseconds in length:
+#ifdef __AVR
+  uint8_t portState = level ? _bit : 0;
+  while ((*portInputRegister(_port) & _bit) == portState) {
+    if (count++ >= _maxcycles) {
+      return TIMEOUT; // Exceeded timeout, fail.
+    }
+  }
+// Otherwise fall back to using digitalRead (this seems to be necessary on
+// ESP8266 right now, perhaps bugs in direct port access functions?).
+#else
+  while (digitalRead(_pin) == level) {
+    if (count++ >= _maxcycles) {
+      return TIMEOUT; // Exceeded timeout, fail.
+    }
+  }
+#endif
+
+  return count;
+}

+ 109 - 0
HomeServerIOExt_Arduino/DHT.h

@@ -0,0 +1,109 @@
+/*!
+ *  @file DHT.h
+ *
+ *  This is a library for DHT series of low cost temperature/humidity sensors.
+ *
+ *  You must have Adafruit Unified Sensor Library library installed to use this
+ * class.
+ *
+ *  Adafruit invests time and resources providing this open source code,
+ *  please support Adafruit andopen-source hardware by purchasing products
+ *  from Adafruit!
+ *
+ *  Written by Adafruit Industries.
+ *
+ *  MIT license, all text above must be included in any redistribution
+ */
+
+#ifndef DHT_H
+#define DHT_H
+
+#include "Arduino.h"
+
+/* Uncomment to enable printing out nice debug messages. */
+//#define DHT_DEBUG
+
+#define DEBUG_PRINTER                                                          \
+  Serial /**< Define where debug output will be printed.                       \
+          */
+
+/* Setup debug printing macros. */
+#ifdef DHT_DEBUG
+#define DEBUG_PRINT(...)                                                       \
+  { DEBUG_PRINTER.print(__VA_ARGS__); }
+#define DEBUG_PRINTLN(...)                                                     \
+  { DEBUG_PRINTER.println(__VA_ARGS__); }
+#else
+#define DEBUG_PRINT(...)                                                       \
+  {} /**< Debug Print Placeholder if Debug is disabled */
+#define DEBUG_PRINTLN(...)                                                     \
+  {} /**< Debug Print Line Placeholder if Debug is disabled */
+#endif
+
+/* Define types of sensors. */
+static const uint8_t DHT11{11};  /**< DHT TYPE 11 */
+static const uint8_t DHT12{12};  /**< DHY TYPE 12 */
+static const uint8_t DHT21{21};  /**< DHT TYPE 21 */
+static const uint8_t DHT22{22};  /**< DHT TYPE 22 */
+static const uint8_t AM2301{21}; /**< AM2301 */
+
+#if defined(TARGET_NAME) && (TARGET_NAME == ARDUINO_NANO33BLE)
+#ifndef microsecondsToClockCycles
+/*!
+ * As of 7 Sep 2020 the Arduino Nano 33 BLE boards do not have
+ * microsecondsToClockCycles defined.
+ */
+#define microsecondsToClockCycles(a) ((a) * (SystemCoreClock / 1000000L))
+#endif
+#endif
+
+/*!
+ *  @brief  Class that stores state and functions for DHT
+ */
+class DHT {
+public:
+  DHT(uint8_t pin, uint8_t type, uint8_t count = 6);
+  void begin(uint8_t usec = 55);
+  float readTemperature(bool S = false, bool force = false);
+  float convertCtoF(float);
+  float convertFtoC(float);
+  float computeHeatIndex(bool isFahrenheit = true);
+  float computeHeatIndex(float temperature, float percentHumidity,
+                         bool isFahrenheit = true);
+  float readHumidity(bool force = false);
+  bool read(bool force = false);
+
+private:
+  uint8_t data[5];
+  uint8_t _pin, _type;
+#ifdef __AVR
+  // Use direct GPIO access on an 8-bit AVR so keep track of the port and
+  // bitmask for the digital pin connected to the DHT.  Other platforms will use
+  // digitalRead.
+  uint8_t _bit, _port;
+#endif
+  uint32_t _lastreadtime, _maxcycles;
+  bool _lastresult;
+  uint8_t pullTime; // Time (in usec) to pull up data line before reading
+
+  uint32_t expectPulse(bool level);
+};
+
+/*!
+ *  @brief  Class that defines Interrupt Lock Avaiability
+ */
+class InterruptLock {
+public:
+  InterruptLock() {
+#if !defined(ARDUINO_ARCH_NRF52)
+    noInterrupts();
+#endif
+  }
+  ~InterruptLock() {
+#if !defined(ARDUINO_ARCH_NRF52)
+    interrupts();
+#endif
+  }
+};
+
+#endif

+ 131 - 0
HomeServerIOExt_Arduino/HomeServerIOExt_Arduino.ino

@@ -0,0 +1,131 @@
+
+#define INTERVAL 60000
+
+// define how many input pins should be used
+#define IN_PINS 3
+// which pin number to start at (default = 2)
+#define START_AT_PIN 2
+// 
+// if START_AT_PIN = 2 and IN_PINS 3 is defined:
+// pins 2, 3, 4 are used as inputs
+
+// input debounce time in ms
+#define DEBOUNCETIME 250
+
+
+
+#define USE_SENSOR_DHT
+
+#ifdef USE_SENSOR_DHT
+#include "DHT.h"
+
+#define DHTPIN A3     // Digital pin connected to the DHT sensor
+// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
+// Pin 15 can work but DHT must be disconnected during program upload.
+
+// Uncomment whatever type you're using!
+//#define DHTTYPE DHT11   // DHT 11
+#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
+//#define DHTTYPE DHT21   // DHT 21 (AM2301)
+
+// Initialize DHT sensor.
+// Note that older versions of this library took an optional third parameter to
+// tweak the timings for faster processors.  This parameter is no longer needed
+// as the current DHT reading algorithm adjusts itself to work on faster procs.
+DHT dht(DHTPIN, DHTTYPE);
+#endif
+
+
+unsigned long intervalMillis;
+
+
+bool state_pin[IN_PINS];
+bool state_pin_pending[IN_PINS];
+unsigned long lastPinChange[IN_PINS];
+
+void setup() {
+  Serial.begin(57600);
+  Serial.print(F("HomeServerIOExt v"));
+  Serial.println("0.1");
+
+  for (uint8_t i = START_AT_PIN; i < (IN_PINS + START_AT_PIN); i++) {
+    pinMode(i, INPUT_PULLUP);
+  }
+
+  for (uint8_t i = START_AT_PIN; i < (IN_PINS + START_AT_PIN); i++) {
+    state_pin[i - START_AT_PIN] = digitalRead(i);
+  }
+
+  dht.begin();
+}
+
+void loop() {
+
+  getInputs();
+
+  if ( (millis() - intervalMillis) > INTERVAL) {
+    intervalMillis = millis();
+
+    sendPinStates_all();
+
+#ifdef USE_SENSOR_DHT
+    // Reading temperature or humidity takes about 250 milliseconds!
+    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
+    float h = dht.readHumidity();
+    // Read temperature as Celsius (the default)
+    float t = dht.readTemperature();
+
+    if (isnan(h) || isnan(t)) {
+      Serial.println(F("ERR: DHT failed to read"));
+      return;
+    }
+    else {
+      Serial.print(F("{\"T\":"));
+      Serial.print(t);
+      Serial.print(F(",\"H\":"));
+      Serial.print((int)h);
+      Serial.println(F("}"));
+      delay(5);
+    }
+#endif
+
+  }
+
+}
+
+void getInputs() {
+  bool _pinState;
+
+  for (uint8_t i = START_AT_PIN; i < (IN_PINS + START_AT_PIN); i++) {
+    _pinState = digitalRead(i);
+
+    // check if pin state has changed since last loop
+    if ( state_pin_pending[i - START_AT_PIN] != _pinState ) {
+      // if changed -> set last pin change time to now
+      lastPinChange[i - START_AT_PIN] = millis();
+      state_pin_pending[i - START_AT_PIN] = _pinState;
+    }
+
+    // check if pin is still in changed state after debounce timeout
+    if ( (state_pin[i - START_AT_PIN] != _pinState) && (millis() - lastPinChange[i - START_AT_PIN]) > DEBOUNCETIME ) {
+      state_pin[i - START_AT_PIN] = _pinState;
+      lastPinChange[i - START_AT_PIN] = millis();
+      sendPinState(i);
+    }
+  }
+}
+
+void sendPinState(uint8_t _pin) {
+  Serial.print(F("P"));
+  Serial.print(_pin);
+  Serial.print("=");
+  if (state_pin[_pin - START_AT_PIN]) Serial.println("H");
+  else Serial.println("L");
+  delay(5);
+}
+
+void sendPinStates_all() {
+  for (uint8_t i = START_AT_PIN; i < (IN_PINS + START_AT_PIN); i++) {
+    sendPinState(i);
+  }
+}

+ 338 - 0
HomeServerIOExt_Arduino/HomeServerIOExt_Arduino.ino.eightanaloginputs.hex

@@ -0,0 +1,338 @@
+:100000000C947F000C94A7000C94A7000C94A700FC
+:100010000C94A7000C94A7000C94A7000C94A700C4
+:100020000C94A7000C94A7000C94A7000C94A700B4
+:100030000C94A7000C94A7000C94A7000C94A700A4
+:100040000C94F8040C94A7000C94C6040C94A0041F
+:100050000C94A7000C94A7000C94A7000C94A70084
+:100060000C94A7000C94A70050000000000024008E
+:1000700027002A00486F6D65536572766572494F97
+:100080004578742076007D002C2248223A007B229D
+:1000900054223A004552523A20444854206661693D
+:1000A0006C656420746F207265616400000000005C
+:1000B000250028002B0000000008000201000003BA
+:1000C0000407000000000000000000000000230002
+:1000D00026002900040404040404040402020202A9
+:1000E00002020303030303030102040810204080FB
+:1000F0000102040810200102040810204205112406
+:100100001FBECFEFD8E0DEBFCDBF11E0A0E0B1E071
+:10011000E4EDF4E102C005900D92A832B107D9F7E1
+:1001200021E0A8E2B1E001C01D92A73FB207E1F7CC
+:1001300010E0CFE7D0E004C02197FE010E94620AE0
+:10014000CE37D107C9F70E948F050C94680A0C942A
+:100150000000CF92DF92EF92FF92CF93DF93B091A6
+:10016000EB01A0E08111AB2F8091EC0190E0880FB2
+:10017000991FAC0146535F4FC090F101D090F2013E
+:10018000E090F301F090F40130E020E0FA01C59135
+:10019000D491E881B90190E080E0EB23EA130AC032
+:1001A0002F5F3F4F6C157D058E059F0578F36FEF30
+:1001B0007FEFCB01DF91CF91FF90EF90DF90CF9059
+:1001C0000895AF92BF92CF92DF92EF92FF920F937A
+:1001D0001F93CF93DF936C017B018B01040F151FDD
+:1001E000EB015E01AE18BF08C017D10759F0699145
+:1001F000D601ED91FC910190F081E02DC6010995A9
+:10020000892B79F7C501DF91CF911F910F91FF9055
+:10021000EF90DF90CF90BF90AF900895FC01538D89
+:10022000448D252F30E0842F90E0821B930B5417D0
+:1002300010F0CF96089501970895FC01918D828D5D
+:10024000981761F0A28DAE0FBF2FB11D5D968C91F6
+:10025000928D9F5F9F73928F90E008958FEF9FEF35
+:100260000895FC01918D828D981731F0828DE80FF1
+:10027000F11D858D90E008958FEF9FEF0895FC01AB
+:10028000918D228D892F90E0805C9F4F821B910978
+:100290008F739927089587E491E00E943F0121E040
+:1002A000892B09F420E0822F089580E090E0892BCB
+:1002B00029F00E944B0181110C9400000895FC016B
+:1002C000A48DA80FB92FB11DA35ABF4F2C91848DB7
+:1002D00090E001968F739927848FA689B7892C9314
+:1002E000A089B1898C91837080648C93938D848D67
+:1002F000981306C00288F389E02D80818F7D80836A
+:100300000895EF92FF920F931F93CF93DF93EC0129
+:1003100081E0888F9B8D8C8D98131AC0E889F989AC
+:10032000808185FF15C09FB7F894EE89FF896083AF
+:10033000E889F98980818370806480839FBF81E030
+:1003400090E0DF91CF911F910F91FF90EF90089572
+:10035000F62E0B8D10E00F5F1F4F0F731127E02E4D
+:100360008C8D8E110CC00FB607FCFACFE889F98985
+:10037000808185FFF5CFCE010E945F01F1CFEB8D2B
+:10038000EC0FFD2FF11DE35AFF4FF0829FB7F89459
+:100390000B8FEA89FB8980818062CFCF0F931F93F7
+:1003A000CF93DF938C01D0E0C0E0F801EC0FFD1F8C
+:1003B0006491662341F087E491E00E948101892BDA
+:1003C00011F02196F2CFCE01DF91CF911F910F91C5
+:1003D0000895CF93DF93EC01888D8823B9F0AA8923
+:1003E000BB89E889F9898C9185FD03C0808186FDF0
+:1003F0000DC00FB607FCF7CF8C9185FFF2CF80813F
+:1004000085FFEDCFCE010E945F01E9CFDF91CF9153
+:100410000895833081F028F4813099F08230A9F07A
+:1004200008958730A9F08830C9F08430B1F4809104
+:1004300080008F7D03C0809180008F778093800043
+:10044000089584B58F7784BD089584B58F7DFBCFE3
+:100450008091B0008F778093B00008958091B000B4
+:100460008F7DF9CFCF93DF93282F30E0F901EA5445
+:10047000FF4F8491F901E851FF4FD491F901EC52FB
+:10048000FF4FC491CC23A1F081110E940902EC2FEF
+:10049000F0E0EE0FFF1FE653FF4FA591B491EC91F2
+:1004A000ED2381E090E009F480E0DF91CF910895A1
+:1004B00080E090E0FACFCF93DF9390E0FC01E85129
+:1004C000FF4F24918C529F4FFC0184918823D1F0DF
+:1004D00090E0880F991FFC01E659FF4FA591B49158
+:1004E000FC01E455FF4FC591D491623071F49FB780
+:1004F000F8943C91822F809583238C93E8812E2B56
+:1005000028839FBFDF91CF9108958FB7F894EC9126
+:100510002E2B2C938FBFF6CF3FB7F89480912D01EF
+:1005200090912E01A0912F01B091300126B5A89B8A
+:1005300005C02F3F19F00196A11DB11D3FBFBA2F75
+:10054000A92F982F8827BC01CD01620F711D811D35
+:10055000911D42E0660F771F881F991F4A95D1F7BA
+:1005600008958F929F92AF92BF92CF92DF92EF92B7
+:10057000FF924B015C010E948C026B017C010E9486
+:100580008C026C197D098E099F09683E73408105B4
+:100590009105A8F321E0821A9108A108B10888EE1C
+:1005A000C80E83E0D81EE11CF11C81149104A10443
+:1005B000B10429F7FF90EF90DF90CF90BF90AF90FC
+:1005C0009F908F9008952FB7F894609129017091B2
+:1005D0002A0180912B0190912C012FBF08958F92B9
+:1005E0009F92AF92BF92CF92DF92EF92FF920F93C2
+:1005F0001F93CF93DF93CDB7DEB7C054D1400FB672
+:10060000F894DEBF0FBECDBF0E94E3020091ED0162
+:100610001091EE012091EF013091F0016B017C010E
+:10062000C01AD10AE20AF30A97018601003D174079
+:1006300021053105B0F48091F501C05CDE4F0FB6A5
+:10064000F894DEBF0FBECDBFDF91CF911F910F9108
+:10065000FF90EF90DF90CF90BF90AF909F908F90E2
+:1006600008956093ED017093EE018093EF019093F4
+:10067000F0011092E8011092E7011092E601109249
+:10068000E5011092E40162E08091E9010E945B02C1
+:1006900061E070E080E090E00E94B10261E0809152
+:1006A000E9010E945B022091E90130E0F901EA547E
+:1006B000FF4F8491F901E851FF4F0491F901EC5289
+:1006C000FF4F1491112391F081110E940902E12F33
+:1006D000F0E0EE0FFF1FE455FF4FA591B4918FB7E7
+:1006E000F894EC9100950E230C938FBF8091EA0152
+:1006F0008551823020F58BE291E10197F1F762E0BC
+:100700008091E9010E945B028091F60190E08230C5
+:10071000910538F0880F991F880F991F0597019749
+:10072000F1F7F89480E00E94A9006F3F7F4F8F4F50
+:100730009F4F61F41092F501789480E07ECF64E1E0
+:1007400070E080E090E00E94B102D9CF81E00E9489
+:10075000A9006F3F7F4F8F4F9F4F61F3CE010196EE
+:100760007C015E019FEBA91A9EEFB90A870180E028
+:100770000E94A900F801608371838283938381E0E2
+:100780000E94A900F8016483758386839783085FBC
+:100790001F4FA016B10659F7789430E020E0F7011A
+:1007A00080809180A280B380448155816681778169
+:1007B000FFEF8F169F06AF06BF0631F04F3F8FEF5A
+:1007C00058076807780719F41092F501B6CFF901B8
+:1007D00083E0F595E7958A95E1F7EC51FE4F80812E
+:1007E000880F84169506A606B70618F180832F5F3A
+:1007F0003F4F98E0E90EF11C2832310581F6409117
+:10080000E8012091E4018091E501280F3327331F8F
+:100810008091E601280F311D8091E701820F932F0F
+:10082000911D99274817190679F681E08093F50103
+:1008300004CF8160DBCFFC0101900020E9F7319704
+:10084000AF01481B590BBC0187E491E00C94E10017
+:100850008F929F92AF92BF920F931F93CF93DF938C
+:10086000CDB7DEB7A1970FB6F894DEBF0FBECDBFF0
+:1008700019A2423008F44AE08E010F5D1F4F842E0A
+:10088000912CB12CA12CA50194010E94400AE62FC5
+:10089000B901CA01EA30F4F4E05DD801EE938D01AC
+:1008A000232B242B252B79F790E080E0109719F06B
+:1008B000CD010E941B04A1960FB6F894DEBF0FBEB7
+:1008C000CDBFDF91CF911F910F91BF90AF909F90BF
+:1008D0008F900895E95CE1CFCF93DF930E941B04D2
+:1008E000EC0182E191E00E941B048C0F9D1FDF91BF
+:1008F000CF910895CF93C82F88E690E00E94CE0153
+:100900006C2F70E090E080E04AE00E94280485E1CE
+:1009100091E00E941B04EC2FF0E0E15DFE4F80812E
+:10092000882359F087E191E00E946C0465E070E053
+:1009300080E090E0CF910C94B10289E191E0F4CF96
+:100940001F920F920FB60F9211242F933F934F9344
+:100950005F936F937F938F939F93AF93BF93EF9327
+:10096000FF9387E491E00E945F01FF91EF91BF91B7
+:10097000AF919F918F917F916F915F914F913F9137
+:100980002F910F900FBE0F901F9018951F920F92EE
+:100990000FB60F9211242F938F939F93EF93FF9392
+:1009A000E0915701F09158018081E0915D01F09153
+:1009B0005E0182FD1BC09081809160018F5F8F730B
+:1009C00020916101821741F0E0916001F0E0E95B64
+:1009D000FE4F958F80936001FF91EF919F918F91D2
+:1009E0002F910F900FBE0F901F9018958081F4CF1C
+:1009F0001F920F920FB60F9211242F933F938F9354
+:100A00009F93AF93BF938091290190912A01A09168
+:100A10002B01B0912C013091280123E0230F2D37B9
+:100A200058F50196A11DB11D20932801809329013D
+:100A300090932A01A0932B01B0932C0180912D015A
+:100A400090912E01A0912F01B09130010196A11D2E
+:100A5000B11D80932D0190932E01A0932F01B0938F
+:100A60003001BF91AF919F918F913F912F910F9046
+:100A70000FBE0F901F90189526E8230F0296A11D18
+:100A8000B11DD2CFE7E4F1E01382128288EE93E049
+:100A9000A0E0B0E084839583A683B78384E091E0EF
+:100AA0009183808385EC90E09587848784EC90E047
+:100AB0009787868780EC90E0918B808B81EC90E02B
+:100AC000938B828B82EC90E0958B848B86EC90E00C
+:100AD000978B868B118E128E138E148EA4EEB1E03E
+:100AE00081E115968C93159786E116968C9316974F
+:100AF000E9EFF0E0E4911796EC931797E5EEF0E05C
+:100B0000E4911896EC93189740E85EE360E070E09B
+:100B10001D964D935D936D937C93509708957894B3
+:100B200084B5826084BD84B5816084BD85B58260F2
+:100B300085BD85B5816085BD80916E0081608093A3
+:100B40006E0010928100809181008260809381000C
+:100B5000809181008160809381008091800081601C
+:100B6000809380008091B10084608093B100809177
+:100B7000B00081608093B00080917A00846080939F
+:100B80007A0080917A00826080937A0080917A0066
+:100B9000816080937A0080917A00806880937A00E7
+:100BA0001092C100E0915701F091580182E08083DA
+:100BB000E0915701F09158011082E0915301F091BA
+:100BC00054011082E0915501F091560180E180833B
+:100BD00010925F01E0915B01F0915C0186E08083FF
+:100BE000E0915901F0915A01808180618083E09108
+:100BF0005901F0915A01808188608083E091590108
+:100C0000F0915A01808180688083E0915901F091D0
+:100C10005A0180818F7D808384E790E00E94CE011D
+:100C20008BE191E00E946C0462E082E00E945B0232
+:100C300062E083E00E945B0262E084E00E945B026B
+:100C400082E00E94320221E0892B09F420E0209307
+:100C5000310183E00E94320221E0892B09F420E077
+:100C60002093320184E00E94320221E0892B09F4B2
+:100C700020E02093330162E08091E9010E945B0251
+:100C80000E94E302605D7740810991096093ED0164
+:100C90007093EE018093EF019093F00187E38093CE
+:100CA000F601C0E0D0E030E4A32E31E0B32E41E302
+:100CB000C42E41E0D42E54E3E52E51E0F52E12E08F
+:100CC000812F0E94320201E0892B09F400E0F50136
+:100CD00081915F01081751F00E94E302F7016083E0
+:100CE000718382839383F50131970083F6018081BC
+:100CF0000817E1F00E94E302F70140805180628012
+:100D0000738064197509860997096B3F7105810520
+:100D1000910560F0F60100830E94E302F701608311
+:100D2000718382839383812F0E947A041F5FFFEF78
+:100D3000CF1ADF0A24E0E20EF11C153009F60E94FA
+:100D4000E30200914301109144012091450130914B
+:100D50004601601B710B820B930B61367A4E810545
+:100D6000910508F4C6C00E94E302609343017093AA
+:100D70004401809345019093460182E00E947A04E9
+:100D800083E00E947A0484E00E947A040E94EF02C9
+:100D9000882349F08091EA018B3028F08D3050F0A3
+:100DA00085518230C8F1812C912C20ECA22E2FE7A6
+:100DB000B22E1EC06091E50170E090E080E00E94DC
+:100DC00019092DEC3CEC4CEC5DE30E94CE096B0163
+:100DD0007C016091E40170E090E080E00E941909DC
+:100DE0009B01AC01C701B6010E9470084B015C0178
+:100DF0000E94EF02882309F474C08091EA018C30CC
+:100E000009F482C0D8F48B3091F1C12CD12C80EC44
+:100E1000E82E8FE7F82E55C06091E4017091E5014E
+:100E200076276727762790E080E00E9417092DEC4F
+:100E30003CEC4CEC5DE30E94CE09D8CF855182306A
+:100E400020F71091E601612F70E0762F6627662764
+:100E50007F778091E701682B90E080E00E9417097E
+:100E60002DEC3CEC4CEC5DE30E94CE0969C0609136
+:100E7000E60170E090E080E00E9417096B017C01C0
+:100E80001091E70117FF0AC0AC019B0160E070E020
+:100E900080E89FEB0E946F086B017C011F70612F3F
+:100EA00070E090E080E00E9419092DEC3CEC4CECE5
+:100EB0005DE30E94CE09A70196010E9470086B01B4
+:100EC0007C01A5019401C501B4010E943B0A811176
+:100ED00008C0A7019601C701B6010E943B0A8823FA
+:100EE000C1F184E990E00E94CE0182E191E00E948C
+:100EF0001B04209709F4D7CE0E944B01882309F4E4
+:100F0000D2CE0E940000CFCE1091E601612F70E09A
+:100F100090E080E00E9417096B017C016091E7017D
+:100F20006F7070E090E080E00E9419092DEC3CECBD
+:100F30004CEC5DE30E94CE09A70196010E94700867
+:100F40006B017C0117FFBDCFF7FAF094F7F8F0942E
+:100F5000B8CF8EE890E00E94CE0126013701E894D8
+:100F600077F82FEF3FEF4FE75FE7C301B2010E9431
+:100F70003B0A81113DC02FEF3FEF4FE75FE7C30111
+:100F8000B2010E94DC0818169CF58FE191E00E94E6
+:100F90001B0488E890E00E94CE01C501B4010E94C4
+:100FA000E1086B01770FEE08FF084AE0C701B601C0
+:100FB000F7FE0DC06DE287E491E00E948101662793
+:100FC0007727CB016C197D098E099F094AE00E94A1
+:100FD000280486E890E00E94CE0182E191E00E9420
+:100FE0001B0465E070E080E090E00E94B10281CFD8
+:100FF0002FEF3FEF4FE75FE4C701B6010E94C90939
+:1010000018161CF483E291E0C2CF2FEF3FEF4FE7B9
+:101010005FECC701B6010E94DC0887FDF3CF20E03A
+:1010200030E0A901C701B6010E94DC0887FF09C0B2
+:101030006DE287E491E00E948101F7FAF094F7F8FD
+:10104000F0942AE037ED43EA5BE3C701B6010E9462
+:1010500070082B013C010E94E8086B017C010E9492
+:1010600017099B01AC01C301B2010E946F082B015B
+:101070003C014AE0C701B6010E9428046EE287E401
+:1010800091E00E94810120E030E040E251E4C301A0
+:10109000B2010E94CE092B013C010E94E8086B01BD
+:1010A000F12CE12C4AE0C701B6010E942804C701D7
+:1010B000B6010E9417099B01AC01C301B2010E9455
+:1010C0006F0820E030E040E251E40E94CE090E9427
+:1010D000E80890E080E04AE00E9428045ACF505887
+:1010E000BB27AA270E9487080C948F090E948109B8
+:1010F00038F00E94880920F039F49F3F19F426F453
+:101100000C947E090EF4E095E7FB0C947809E92F26
+:101110000E94A00958F3BA1762077307840795075E
+:1011200020F079F4A6F50C94C2090EF4E0950B2E8C
+:10113000BA2FA02D0B01B90190010C01CA01A00129
+:101140001124FF27591B99F0593F50F4503E68F184
+:101150001A16F040A22F232F342F4427585FF3CFC5
+:10116000469537952795A795F0405395C9F77EF496
+:101170001F16BA0B620B730B840BBAF09150A1F0DF
+:10118000FF0FBB1F661F771F881FC2F70EC0BA0F65
+:10119000621F731F841F48F4879577956795B795ED
+:1011A000F7959E3F08F0B0CF9395880F08F09927E8
+:1011B000EE0F9795879508950E94540908F481E0F1
+:1011C00008950E94E8086894B1110C94C309089529
+:1011D0000E94A80988F09F5798F0B92F9927B75116
+:1011E000B0F0E1F0660F771F881F991F1AF0BA95CB
+:1011F000C9F714C0B13091F00E94C209B1E008955E
+:101200000C94C209672F782F8827B85F39F0B93F4F
+:10121000CCF3869577956795B395D9F73EF490957D
+:101220008095709561957F4F8F4F9F4F0895E894FB
+:1012300009C097FB3EF490958095709561957F4F1E
+:101240008F4F9F4F9923A9F0F92F96E9BB279395CC
+:10125000F695879577956795B795F111F8CFFAF4DC
+:10126000BB0F11F460FF1BC06F5F7F4F8F4F9F4F0D
+:1012700016C0882311F096E911C0772321F09EE86B
+:10128000872F762F05C0662371F096E8862F70E0D1
+:1012900060E02AF09A95660F771F881FDAF7880FAB
+:1012A0009695879597F90895990F0008550FAA0B01
+:1012B000E0E8FEEF16161706E807F907C0F0121669
+:1012C0001306E407F50798F0621B730B840B950B6C
+:1012D00039F40A2661F0232B242B252B21F40895C1
+:1012E0000A2609F4A140A6958FEF811D811D08955E
+:1012F00097F99F6780E870E060E008959FEF80ECC9
+:10130000089500240A94161617061806090608956B
+:1013100000240A9412161306140605060895092ED1
+:101320000394000C11F4882352F0BB0F40F4BF2B40
+:1013300011F460FF04C06F5F7F4F8F4F9F4F089580
+:1013400057FD9058440F551F59F05F3F71F0479576
+:10135000880F97FB991F61F09F3F79F0879508955B
+:10136000121613061406551FF2CF4695F1DF08C07A
+:10137000161617061806991FF1CF86957105610597
+:1013800008940895E894BB2766277727CB0197F93F
+:1013900008950E94540908F48FEF08950E94E1090E
+:1013A0000C948F090E94810938F00E94880920F06E
+:1013B000952311F00C9478090C947E0911240C9457
+:1013C000C3090E94A00970F3959FC1F3950F50E0E7
+:1013D000551F629FF001729FBB27F00DB11D639FE7
+:1013E000AA27F00DB11DAA1F649F6627B00DA11D8D
+:1013F000661F829F2227B00DA11D621F739FB00D33
+:10140000A11D621F839FA00D611D221F749F3327A2
+:10141000A00D611D231F849F600D211D822F762F3B
+:101420006A2F11249F5750409AF0F1F088234AF018
+:10143000EE0FFF1FBB1F661F771F881F9150504084
+:10144000A9F79E3F510580F00C9478090C94C309CC
+:101450005F3FE4F3983ED4F3869577956795B7950B
+:10146000F795E7959F5FC1F7FE2B880F911D969525
+:10147000879597F908950E945409880B990B089550
+:10148000A1E21A2EAA1BBB1BFD010DC0AA1FBB1F88
+:10149000EE1FFF1FA217B307E407F50720F0A21BFA
+:1014A000B30BE40BF50B661F771F881F991F1A9467
+:1014B00069F760957095809590959B01AC01BD0191
+:1014C000CF010895EE0FFF1F0590F491E02D0994D0
+:0414D000F894FFCFBE
+:1014D400000000008101E1000E01E9013F011D014E
+:1014E40031010D0A003D0048004C00302E310069E6
+:0814F4006E66006F76660000D1
+:00000001FF

+ 371 - 0
HomeServerIOExt_Arduino/HomeServerIOExt_Arduino.ino.with_bootloader.eightanaloginputs.hex

@@ -0,0 +1,371 @@
+:020000040000FA
+:100000000C947F000C94A7000C94A7000C94A700FC
+:100010000C94A7000C94A7000C94A7000C94A700C4
+:100020000C94A7000C94A7000C94A7000C94A700B4
+:100030000C94A7000C94A7000C94A7000C94A700A4
+:100040000C94F8040C94A7000C94C6040C94A0041F
+:100050000C94A7000C94A7000C94A7000C94A70084
+:100060000C94A7000C94A70050000000000024008E
+:1000700027002A00486F6D65536572766572494F97
+:100080004578742076007D002C2248223A007B229D
+:1000900054223A004552523A20444854206661693D
+:1000A0006C656420746F207265616400000000005C
+:1000B000250028002B0000000008000201000003BA
+:1000C0000407000000000000000000000000230002
+:1000D00026002900040404040404040402020202A9
+:1000E00002020303030303030102040810204080FB
+:1000F0000102040810200102040810204205112406
+:100100001FBECFEFD8E0DEBFCDBF11E0A0E0B1E071
+:10011000E4EDF4E102C005900D92A832B107D9F7E1
+:1001200021E0A8E2B1E001C01D92A73FB207E1F7CC
+:1001300010E0CFE7D0E004C02197FE010E94620AE0
+:10014000CE37D107C9F70E948F050C94680A0C942A
+:100150000000CF92DF92EF92FF92CF93DF93B091A6
+:10016000EB01A0E08111AB2F8091EC0190E0880FB2
+:10017000991FAC0146535F4FC090F101D090F2013E
+:10018000E090F301F090F40130E020E0FA01C59135
+:10019000D491E881B90190E080E0EB23EA130AC032
+:1001A0002F5F3F4F6C157D058E059F0578F36FEF30
+:1001B0007FEFCB01DF91CF91FF90EF90DF90CF9059
+:1001C0000895AF92BF92CF92DF92EF92FF920F937A
+:1001D0001F93CF93DF936C017B018B01040F151FDD
+:1001E000EB015E01AE18BF08C017D10759F0699145
+:1001F000D601ED91FC910190F081E02DC6010995A9
+:10020000892B79F7C501DF91CF911F910F91FF9055
+:10021000EF90DF90CF90BF90AF900895FC01538D89
+:10022000448D252F30E0842F90E0821B930B5417D0
+:1002300010F0CF96089501970895FC01918D828D5D
+:10024000981761F0A28DAE0FBF2FB11D5D968C91F6
+:10025000928D9F5F9F73928F90E008958FEF9FEF35
+:100260000895FC01918D828D981731F0828DE80FF1
+:10027000F11D858D90E008958FEF9FEF0895FC01AB
+:10028000918D228D892F90E0805C9F4F821B910978
+:100290008F739927089587E491E00E943F0121E040
+:1002A000892B09F420E0822F089580E090E0892BCB
+:1002B00029F00E944B0181110C9400000895FC016B
+:1002C000A48DA80FB92FB11DA35ABF4F2C91848DB7
+:1002D00090E001968F739927848FA689B7892C9314
+:1002E000A089B1898C91837080648C93938D848D67
+:1002F000981306C00288F389E02D80818F7D80836A
+:100300000895EF92FF920F931F93CF93DF93EC0129
+:1003100081E0888F9B8D8C8D98131AC0E889F989AC
+:10032000808185FF15C09FB7F894EE89FF896083AF
+:10033000E889F98980818370806480839FBF81E030
+:1003400090E0DF91CF911F910F91FF90EF90089572
+:10035000F62E0B8D10E00F5F1F4F0F731127E02E4D
+:100360008C8D8E110CC00FB607FCFACFE889F98985
+:10037000808185FFF5CFCE010E945F01F1CFEB8D2B
+:10038000EC0FFD2FF11DE35AFF4FF0829FB7F89459
+:100390000B8FEA89FB8980818062CFCF0F931F93F7
+:1003A000CF93DF938C01D0E0C0E0F801EC0FFD1F8C
+:1003B0006491662341F087E491E00E948101892BDA
+:1003C00011F02196F2CFCE01DF91CF911F910F91C5
+:1003D0000895CF93DF93EC01888D8823B9F0AA8923
+:1003E000BB89E889F9898C9185FD03C0808186FDF0
+:1003F0000DC00FB607FCF7CF8C9185FFF2CF80813F
+:1004000085FFEDCFCE010E945F01E9CFDF91CF9153
+:100410000895833081F028F4813099F08230A9F07A
+:1004200008958730A9F08830C9F08430B1F4809104
+:1004300080008F7D03C0809180008F778093800043
+:10044000089584B58F7784BD089584B58F7DFBCFE3
+:100450008091B0008F778093B00008958091B000B4
+:100460008F7DF9CFCF93DF93282F30E0F901EA5445
+:10047000FF4F8491F901E851FF4FD491F901EC52FB
+:10048000FF4FC491CC23A1F081110E940902EC2FEF
+:10049000F0E0EE0FFF1FE653FF4FA591B491EC91F2
+:1004A000ED2381E090E009F480E0DF91CF910895A1
+:1004B00080E090E0FACFCF93DF9390E0FC01E85129
+:1004C000FF4F24918C529F4FFC0184918823D1F0DF
+:1004D00090E0880F991FFC01E659FF4FA591B49158
+:1004E000FC01E455FF4FC591D491623071F49FB780
+:1004F000F8943C91822F809583238C93E8812E2B56
+:1005000028839FBFDF91CF9108958FB7F894EC9126
+:100510002E2B2C938FBFF6CF3FB7F89480912D01EF
+:1005200090912E01A0912F01B091300126B5A89B8A
+:1005300005C02F3F19F00196A11DB11D3FBFBA2F75
+:10054000A92F982F8827BC01CD01620F711D811D35
+:10055000911D42E0660F771F881F991F4A95D1F7BA
+:1005600008958F929F92AF92BF92CF92DF92EF92B7
+:10057000FF924B015C010E948C026B017C010E9486
+:100580008C026C197D098E099F09683E73408105B4
+:100590009105A8F321E0821A9108A108B10888EE1C
+:1005A000C80E83E0D81EE11CF11C81149104A10443
+:1005B000B10429F7FF90EF90DF90CF90BF90AF90FC
+:1005C0009F908F9008952FB7F894609129017091B2
+:1005D0002A0180912B0190912C012FBF08958F92B9
+:1005E0009F92AF92BF92CF92DF92EF92FF920F93C2
+:1005F0001F93CF93DF93CDB7DEB7C054D1400FB672
+:10060000F894DEBF0FBECDBF0E94E3020091ED0162
+:100610001091EE012091EF013091F0016B017C010E
+:10062000C01AD10AE20AF30A97018601003D174079
+:1006300021053105B0F48091F501C05CDE4F0FB6A5
+:10064000F894DEBF0FBECDBFDF91CF911F910F9108
+:10065000FF90EF90DF90CF90BF90AF909F908F90E2
+:1006600008956093ED017093EE018093EF019093F4
+:10067000F0011092E8011092E7011092E601109249
+:10068000E5011092E40162E08091E9010E945B02C1
+:1006900061E070E080E090E00E94B10261E0809152
+:1006A000E9010E945B022091E90130E0F901EA547E
+:1006B000FF4F8491F901E851FF4F0491F901EC5289
+:1006C000FF4F1491112391F081110E940902E12F33
+:1006D000F0E0EE0FFF1FE455FF4FA591B4918FB7E7
+:1006E000F894EC9100950E230C938FBF8091EA0152
+:1006F0008551823020F58BE291E10197F1F762E0BC
+:100700008091E9010E945B028091F60190E08230C5
+:10071000910538F0880F991F880F991F0597019749
+:10072000F1F7F89480E00E94A9006F3F7F4F8F4F50
+:100730009F4F61F41092F501789480E07ECF64E1E0
+:1007400070E080E090E00E94B102D9CF81E00E9489
+:10075000A9006F3F7F4F8F4F9F4F61F3CE010196EE
+:100760007C015E019FEBA91A9EEFB90A870180E028
+:100770000E94A900F801608371838283938381E0E2
+:100780000E94A900F8016483758386839783085FBC
+:100790001F4FA016B10659F7789430E020E0F7011A
+:1007A00080809180A280B380448155816681778169
+:1007B000FFEF8F169F06AF06BF0631F04F3F8FEF5A
+:1007C00058076807780719F41092F501B6CFF901B8
+:1007D00083E0F595E7958A95E1F7EC51FE4F80812E
+:1007E000880F84169506A606B70618F180832F5F3A
+:1007F0003F4F98E0E90EF11C2832310581F6409117
+:10080000E8012091E4018091E501280F3327331F8F
+:100810008091E601280F311D8091E701820F932F0F
+:10082000911D99274817190679F681E08093F50103
+:1008300004CF8160DBCFFC0101900020E9F7319704
+:10084000AF01481B590BBC0187E491E00C94E10017
+:100850008F929F92AF92BF920F931F93CF93DF938C
+:10086000CDB7DEB7A1970FB6F894DEBF0FBECDBFF0
+:1008700019A2423008F44AE08E010F5D1F4F842E0A
+:10088000912CB12CA12CA50194010E94400AE62FC5
+:10089000B901CA01EA30F4F4E05DD801EE938D01AC
+:1008A000232B242B252B79F790E080E0109719F06B
+:1008B000CD010E941B04A1960FB6F894DEBF0FBEB7
+:1008C000CDBFDF91CF911F910F91BF90AF909F90BF
+:1008D0008F900895E95CE1CFCF93DF930E941B04D2
+:1008E000EC0182E191E00E941B048C0F9D1FDF91BF
+:1008F000CF910895CF93C82F88E690E00E94CE0153
+:100900006C2F70E090E080E04AE00E94280485E1CE
+:1009100091E00E941B04EC2FF0E0E15DFE4F80812E
+:10092000882359F087E191E00E946C0465E070E053
+:1009300080E090E0CF910C94B10289E191E0F4CF96
+:100940001F920F920FB60F9211242F933F934F9344
+:100950005F936F937F938F939F93AF93BF93EF9327
+:10096000FF9387E491E00E945F01FF91EF91BF91B7
+:10097000AF919F918F917F916F915F914F913F9137
+:100980002F910F900FBE0F901F9018951F920F92EE
+:100990000FB60F9211242F938F939F93EF93FF9392
+:1009A000E0915701F09158018081E0915D01F09153
+:1009B0005E0182FD1BC09081809160018F5F8F730B
+:1009C00020916101821741F0E0916001F0E0E95B64
+:1009D000FE4F958F80936001FF91EF919F918F91D2
+:1009E0002F910F900FBE0F901F9018958081F4CF1C
+:1009F0001F920F920FB60F9211242F933F938F9354
+:100A00009F93AF93BF938091290190912A01A09168
+:100A10002B01B0912C013091280123E0230F2D37B9
+:100A200058F50196A11DB11D20932801809329013D
+:100A300090932A01A0932B01B0932C0180912D015A
+:100A400090912E01A0912F01B09130010196A11D2E
+:100A5000B11D80932D0190932E01A0932F01B0938F
+:100A60003001BF91AF919F918F913F912F910F9046
+:100A70000FBE0F901F90189526E8230F0296A11D18
+:100A8000B11DD2CFE7E4F1E01382128288EE93E049
+:100A9000A0E0B0E084839583A683B78384E091E0EF
+:100AA0009183808385EC90E09587848784EC90E047
+:100AB0009787868780EC90E0918B808B81EC90E02B
+:100AC000938B828B82EC90E0958B848B86EC90E00C
+:100AD000978B868B118E128E138E148EA4EEB1E03E
+:100AE00081E115968C93159786E116968C9316974F
+:100AF000E9EFF0E0E4911796EC931797E5EEF0E05C
+:100B0000E4911896EC93189740E85EE360E070E09B
+:100B10001D964D935D936D937C93509708957894B3
+:100B200084B5826084BD84B5816084BD85B58260F2
+:100B300085BD85B5816085BD80916E0081608093A3
+:100B40006E0010928100809181008260809381000C
+:100B5000809181008160809381008091800081601C
+:100B6000809380008091B10084608093B100809177
+:100B7000B00081608093B00080917A00846080939F
+:100B80007A0080917A00826080937A0080917A0066
+:100B9000816080937A0080917A00806880937A00E7
+:100BA0001092C100E0915701F091580182E08083DA
+:100BB000E0915701F09158011082E0915301F091BA
+:100BC00054011082E0915501F091560180E180833B
+:100BD00010925F01E0915B01F0915C0186E08083FF
+:100BE000E0915901F0915A01808180618083E09108
+:100BF0005901F0915A01808188608083E091590108
+:100C0000F0915A01808180688083E0915901F091D0
+:100C10005A0180818F7D808384E790E00E94CE011D
+:100C20008BE191E00E946C0462E082E00E945B0232
+:100C300062E083E00E945B0262E084E00E945B026B
+:100C400082E00E94320221E0892B09F420E0209307
+:100C5000310183E00E94320221E0892B09F420E077
+:100C60002093320184E00E94320221E0892B09F4B2
+:100C700020E02093330162E08091E9010E945B0251
+:100C80000E94E302605D7740810991096093ED0164
+:100C90007093EE018093EF019093F00187E38093CE
+:100CA000F601C0E0D0E030E4A32E31E0B32E41E302
+:100CB000C42E41E0D42E54E3E52E51E0F52E12E08F
+:100CC000812F0E94320201E0892B09F400E0F50136
+:100CD00081915F01081751F00E94E302F7016083E0
+:100CE000718382839383F50131970083F6018081BC
+:100CF0000817E1F00E94E302F70140805180628012
+:100D0000738064197509860997096B3F7105810520
+:100D1000910560F0F60100830E94E302F701608311
+:100D2000718382839383812F0E947A041F5FFFEF78
+:100D3000CF1ADF0A24E0E20EF11C153009F60E94FA
+:100D4000E30200914301109144012091450130914B
+:100D50004601601B710B820B930B61367A4E810545
+:100D6000910508F4C6C00E94E302609343017093AA
+:100D70004401809345019093460182E00E947A04E9
+:100D800083E00E947A0484E00E947A040E94EF02C9
+:100D9000882349F08091EA018B3028F08D3050F0A3
+:100DA00085518230C8F1812C912C20ECA22E2FE7A6
+:100DB000B22E1EC06091E50170E090E080E00E94DC
+:100DC00019092DEC3CEC4CEC5DE30E94CE096B0163
+:100DD0007C016091E40170E090E080E00E941909DC
+:100DE0009B01AC01C701B6010E9470084B015C0178
+:100DF0000E94EF02882309F474C08091EA018C30CC
+:100E000009F482C0D8F48B3091F1C12CD12C80EC44
+:100E1000E82E8FE7F82E55C06091E4017091E5014E
+:100E200076276727762790E080E00E9417092DEC4F
+:100E30003CEC4CEC5DE30E94CE09D8CF855182306A
+:100E400020F71091E601612F70E0762F6627662764
+:100E50007F778091E701682B90E080E00E9417097E
+:100E60002DEC3CEC4CEC5DE30E94CE0969C0609136
+:100E7000E60170E090E080E00E9417096B017C01C0
+:100E80001091E70117FF0AC0AC019B0160E070E020
+:100E900080E89FEB0E946F086B017C011F70612F3F
+:100EA00070E090E080E00E9419092DEC3CEC4CECE5
+:100EB0005DE30E94CE09A70196010E9470086B01B4
+:100EC0007C01A5019401C501B4010E943B0A811176
+:100ED00008C0A7019601C701B6010E943B0A8823FA
+:100EE000C1F184E990E00E94CE0182E191E00E948C
+:100EF0001B04209709F4D7CE0E944B01882309F4E4
+:100F0000D2CE0E940000CFCE1091E601612F70E09A
+:100F100090E080E00E9417096B017C016091E7017D
+:100F20006F7070E090E080E00E9419092DEC3CECBD
+:100F30004CEC5DE30E94CE09A70196010E94700867
+:100F40006B017C0117FFBDCFF7FAF094F7F8F0942E
+:100F5000B8CF8EE890E00E94CE0126013701E894D8
+:100F600077F82FEF3FEF4FE75FE7C301B2010E9431
+:100F70003B0A81113DC02FEF3FEF4FE75FE7C30111
+:100F8000B2010E94DC0818169CF58FE191E00E94E6
+:100F90001B0488E890E00E94CE01C501B4010E94C4
+:100FA000E1086B01770FEE08FF084AE0C701B601C0
+:100FB000F7FE0DC06DE287E491E00E948101662793
+:100FC0007727CB016C197D098E099F094AE00E94A1
+:100FD000280486E890E00E94CE0182E191E00E9420
+:100FE0001B0465E070E080E090E00E94B10281CFD8
+:100FF0002FEF3FEF4FE75FE4C701B6010E94C90939
+:1010000018161CF483E291E0C2CF2FEF3FEF4FE7B9
+:101010005FECC701B6010E94DC0887FDF3CF20E03A
+:1010200030E0A901C701B6010E94DC0887FF09C0B2
+:101030006DE287E491E00E948101F7FAF094F7F8FD
+:10104000F0942AE037ED43EA5BE3C701B6010E9462
+:1010500070082B013C010E94E8086B017C010E9492
+:1010600017099B01AC01C301B2010E946F082B015B
+:101070003C014AE0C701B6010E9428046EE287E401
+:1010800091E00E94810120E030E040E251E4C301A0
+:10109000B2010E94CE092B013C010E94E8086B01BD
+:1010A000F12CE12C4AE0C701B6010E942804C701D7
+:1010B000B6010E9417099B01AC01C301B2010E9455
+:1010C0006F0820E030E040E251E40E94CE090E9427
+:1010D000E80890E080E04AE00E9428045ACF505887
+:1010E000BB27AA270E9487080C948F090E948109B8
+:1010F00038F00E94880920F039F49F3F19F426F453
+:101100000C947E090EF4E095E7FB0C947809E92F26
+:101110000E94A00958F3BA1762077307840795075E
+:1011200020F079F4A6F50C94C2090EF4E0950B2E8C
+:10113000BA2FA02D0B01B90190010C01CA01A00129
+:101140001124FF27591B99F0593F50F4503E68F184
+:101150001A16F040A22F232F342F4427585FF3CFC5
+:10116000469537952795A795F0405395C9F77EF496
+:101170001F16BA0B620B730B840BBAF09150A1F0DF
+:10118000FF0FBB1F661F771F881FC2F70EC0BA0F65
+:10119000621F731F841F48F4879577956795B795ED
+:1011A000F7959E3F08F0B0CF9395880F08F09927E8
+:1011B000EE0F9795879508950E94540908F481E0F1
+:1011C00008950E94E8086894B1110C94C309089529
+:1011D0000E94A80988F09F5798F0B92F9927B75116
+:1011E000B0F0E1F0660F771F881F991F1AF0BA95CB
+:1011F000C9F714C0B13091F00E94C209B1E008955E
+:101200000C94C209672F782F8827B85F39F0B93F4F
+:10121000CCF3869577956795B395D9F73EF490957D
+:101220008095709561957F4F8F4F9F4F0895E894FB
+:1012300009C097FB3EF490958095709561957F4F1E
+:101240008F4F9F4F9923A9F0F92F96E9BB279395CC
+:10125000F695879577956795B795F111F8CFFAF4DC
+:10126000BB0F11F460FF1BC06F5F7F4F8F4F9F4F0D
+:1012700016C0882311F096E911C0772321F09EE86B
+:10128000872F762F05C0662371F096E8862F70E0D1
+:1012900060E02AF09A95660F771F881FDAF7880FAB
+:1012A0009695879597F90895990F0008550FAA0B01
+:1012B000E0E8FEEF16161706E807F907C0F0121669
+:1012C0001306E407F50798F0621B730B840B950B6C
+:1012D00039F40A2661F0232B242B252B21F40895C1
+:1012E0000A2609F4A140A6958FEF811D811D08955E
+:1012F00097F99F6780E870E060E008959FEF80ECC9
+:10130000089500240A94161617061806090608956B
+:1013100000240A9412161306140605060895092ED1
+:101320000394000C11F4882352F0BB0F40F4BF2B40
+:1013300011F460FF04C06F5F7F4F8F4F9F4F089580
+:1013400057FD9058440F551F59F05F3F71F0479576
+:10135000880F97FB991F61F09F3F79F0879508955B
+:10136000121613061406551FF2CF4695F1DF08C07A
+:10137000161617061806991FF1CF86957105610597
+:1013800008940895E894BB2766277727CB0197F93F
+:1013900008950E94540908F48FEF08950E94E1090E
+:1013A0000C948F090E94810938F00E94880920F06E
+:1013B000952311F00C9478090C947E0911240C9457
+:1013C000C3090E94A00970F3959FC1F3950F50E0E7
+:1013D000551F629FF001729FBB27F00DB11D639FE7
+:1013E000AA27F00DB11DAA1F649F6627B00DA11D8D
+:1013F000661F829F2227B00DA11D621F739FB00D33
+:10140000A11D621F839FA00D611D221F749F3327A2
+:10141000A00D611D231F849F600D211D822F762F3B
+:101420006A2F11249F5750409AF0F1F088234AF018
+:10143000EE0FFF1FBB1F661F771F881F9150504084
+:10144000A9F79E3F510580F00C9478090C94C309CC
+:101450005F3FE4F3983ED4F3869577956795B7950B
+:10146000F795E7959F5FC1F7FE2B880F911D969525
+:10147000879597F908950E945409880B990B089550
+:10148000A1E21A2EAA1BBB1BFD010DC0AA1FBB1F88
+:10149000EE1FFF1FA217B307E407F50720F0A21BFA
+:1014A000B30BE40BF50B661F771F881F991F1A9467
+:1014B00069F760957095809590959B01AC01BD0191
+:1014C000CF010895EE0FFF1F0590F491E02D0994D0
+:1014D000F894FFCF000000008101E1000E01E90156
+:1014E0003F011D0131010D0A003D0048004C003054
+:0C14F0002E3100696E66006F7666000009
+:107E0000112484B714BE81FFF0D085E080938100F7
+:107E100082E08093C00088E18093C10086E0809377
+:107E2000C20080E18093C4008EE0C9D0259A86E02C
+:107E300020E33CEF91E0309385002093840096BBD3
+:107E4000B09BFECF1D9AA8958150A9F7CC24DD24C4
+:107E500088248394B5E0AB2EA1E19A2EF3E0BF2EE7
+:107E6000A2D0813461F49FD0082FAFD0023811F036
+:107E7000013811F484E001C083E08DD089C08234E0
+:107E800011F484E103C0853419F485E0A6D080C0E4
+:107E9000853579F488D0E82EFF2485D0082F10E0AE
+:107EA000102F00270E291F29000F111F8ED06801E7
+:107EB0006FC0863521F484E090D080E0DECF843638
+:107EC00009F040C070D06FD0082F6DD080E0C81688
+:107ED00080E7D80618F4F601B7BEE895C0E0D1E017
+:107EE00062D089930C17E1F7F0E0CF16F0E7DF06D8
+:107EF00018F0F601B7BEE89568D007B600FCFDCFD4
+:107F0000A601A0E0B1E02C9130E011968C91119780
+:107F100090E0982F8827822B932B1296FA010C0160
+:107F200087BEE89511244E5F5F4FF1E0A038BF0790
+:107F300051F7F601A7BEE89507B600FCFDCF97BE46
+:107F4000E89526C08437B1F42ED02DD0F82E2BD052
+:107F50003CD0F601EF2C8F010F5F1F4F84911BD097
+:107F6000EA94F801C1F70894C11CD11CFA94CF0C13
+:107F7000D11C0EC0853739F428D08EE10CD085E9AC
+:107F80000AD08FE07ACF813511F488E018D01DD067
+:107F900080E101D065CF982F8091C00085FFFCCF94
+:107FA0009093C60008958091C00087FFFCCF809118
+:107FB000C00084FD01C0A8958091C6000895E0E648
+:107FC000F0E098E1908380830895EDDF803219F02E
+:107FD00088E0F5DFFFCF84E1DECF1F93182FE3DFCA
+:107FE0001150E9F7F2DF1F91089580E0E8DFEE27F6
+:047FF000FF270994CA
+:027FFE00040479
+:00000001FF

+ 218 - 0
ioext/ioext.py

@@ -0,0 +1,218 @@
+#!/usr/bin/python3 -u
+#
+import serial
+from time import sleep
+import os
+import sys
+import paho.mqtt.client as mqtt
+import json
+
+# --- CONFIGURATION ---
+
+# timeout in s to end script when nothing is received (will be restarted by systemd then)
+# must be higher than getStatusInterval 
+quitOnNoReceiveTimeout = 75
+
+# status file - on ramdrive (/tmp on RasPi by default)
+# is "touched" every time a serial message comes in so that working communication can be monitored easily
+statusFile = '/tmp/ioext_running'
+
+# serial port config
+serialPort = '/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0'
+serialBaud = 57600
+serialTimeout = 1 # should be 1 as above interval/timeout relies on it
+
+# MQTT config
+mqtt_server = "mqtt.lan"
+mqtt_port = 1883
+mqtt_user = "user"
+mqtt_password = "password"
+
+mqtt_base_topic = "T5/HomeSvrIOExt"
+
+mqtt_topic_tuerkontakt = "T5/Wohnungstuer/Tuerkontakt"
+mqtt_topic_pir1 = "T5/VZ/PIR1"
+mqtt_topic_pir2 = "T5/VZ/PIR2"
+mqtt_topic_out_temp = "T5/Abstr/Sensors/temp"
+mqtt_topic_out_hum = "T5/Abstr/Sensors/hum"
+
+# --- END CONFIGURATION ---
+
+
+
+# --- GLOBAL VARS ---
+noReceiveCount = 0  # increase everytime the serial readline times out (1s timeout)
+#getStatusCount = 0  # used as heartbeat, get status every 30s
+verbose = False
+debug = False
+quiet = True
+
+
+lastState_tk = None
+lastState_pir1 = None
+lastState_pir2 = None
+
+# --- END GLOBAL VARS ---
+
+if len(sys.argv) >= 2:
+    if sys.argv[1] == "-q":
+        verbose = False
+        debug = False
+        quiet = True
+        #print("VERBOSE=ON")
+    elif sys.argv[1] == "-v":
+        verbose = True
+        debug = False
+        quiet = False
+        #print("VERBOSE=ON")
+    elif sys.argv[1] == "-d":
+        verbose = True
+        quiet = False
+        debug = True
+        #print("DEBUG=ON")
+
+
+def on_connect(client, userdata, flags, rc):
+    if not quiet:
+        print("MQTT connected with result code " + str(rc))
+    #client.subscribe(mqtt_topic_cmd)
+    
+#def on_message(client, userdata, msg):    
+#    if msg.topic == mqtt_topic_cmd:
+#        payload = msg.payload.decode('ascii')
+#        if payload == "status" or payload == "get conf" or payload == "clear" or payload == "open door" or payload.startswith("set prof ") or payload.startswith("set conf "):
+#            if verbose:
+#                print("serCmd: " + payload)
+#            serCmd = payload + '\n'
+#            ser.write(serCmd.encode('ascii'))
+#        elif verbose:
+#            print("unknown command:", payload)
+
+def touch(fname, times=None):
+    with open(fname, 'a'):
+        os.utime(fname, times)
+
+mqttc = mqtt.Client()
+mqttc.on_connect = on_connect
+#mqttc.on_disconnect = on_disconnect
+#mqttc.on_message = on_message
+
+mqttc.username_pw_set(mqtt_user, mqtt_password)
+mqttc.connect(mqtt_server, mqtt_port, 60)
+
+mqttc.loop_start()
+
+ser = serial.Serial(port=serialPort,
+    baudrate = serialBaud,
+    parity=serial.PARITY_NONE,
+    stopbits=serial.STOPBITS_ONE,
+    bytesize=serial.EIGHTBITS,
+    timeout=serialTimeout)
+    
+
+
+try:
+    while True:
+        ##ser.flushInput()        ## attention truncates incoming strings if there is little time between them 
+        #read buffer until cr/lf
+        serLine = ser.readline().strip()
+        # catch exception on invalid char coming in: UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128)
+        try: 
+            serLine = serLine.decode('ascii')
+        except:
+            serLine = ""
+        
+        # if there came something in...
+        if(serLine):
+            noReceiveCount = 0
+            touch(statusFile)
+            #serLine = serLine.strip('\'')
+            #serLine = serLine.strip('\r')
+            #serLine = serLine.strip('\n')
+            if verbose:
+                print ('RX: ' + repr(serLine))    #Echo the serial buffer bytes up to the CRLF back to screen
+            mqttc.publish(mqtt_base_topic + "/RX", str(serLine), qos=0, retain=False)
+            
+            # Tuerkontakt
+            if serLine.startswith('P2='):
+                newState = None
+                if serLine == "P2=L":
+                    newState = "OFF"
+                elif serLine == "P2=H":
+                    newState = "ON"
+                    
+                if newState is not None and lastState_tk != newState:
+                    lastState_tk = newState
+                    mqttc.publish(mqtt_topic_tuerkontakt, newState, qos=0, retain=False)
+                    
+            # PIR #1
+            if serLine.startswith('P3='):
+                newState = None
+                if serLine == "P3=L":
+                    newState = "OFF"
+                elif serLine == "P3=H":
+                    newState = "ON"
+                    
+                if newState is not None and lastState_pir1 != newState:
+                    lastState_pir1 = newState
+                    mqttc.publish(mqtt_topic_pir1, newState, qos=0, retain=False)
+            
+            # PIR #2
+            if serLine.startswith('P4='):
+                newState = None
+                if serLine == "P4=L":
+                    newState = "OFF"
+                elif serLine == "P4=H":
+                    newState = "ON"
+                
+                if newState is not None and lastState_pir2 != newState:
+                    lastState_pir2 = newState
+                    mqttc.publish(mqtt_topic_pir2, newState, qos=0, retain=False)
+                   
+            # DHT TH sensor
+            # {"T":26.60,"H":36}
+            if serLine.startswith('{"T":'):
+                th = json.loads(serLine)
+                t = round(float(th["T"]), 1)
+                h = int(th["H"])
+                if t >= -20 and t <= 50:
+                    mqttc.publish(mqtt_topic_out_temp, str(t), qos=0, retain=False)
+                if h >= 0 and h <= 100:
+                    mqttc.publish(mqtt_topic_out_hum, str(h), qos=0, retain=False)
+                
+            
+            ## publish MQTT messages
+            #if serLine.startswith('EVENT_'):
+            #    mqttc.publish(mqtt_topic_event, serLine, qos=0, retain=False)
+            #    #os.system(os.path.dirname(os.path.realpath(__file__))+'/event_top5_klingel.py')
+            #
+            #elif serLine.startswith('OK'):
+            #    mqttc.publish(mqtt_topic_cmdresponse, serLine, qos=0, retain=False)
+            #    
+            #elif serLine.startswith('{"'):
+            #    mqttc.publish(mqtt_topic_cmdresponse, serLine, qos=0, retain=False)
+            #    #os.system(os.path.dirname(os.path.realpath(__file__))+'/event_top5_klingel.py')
+                
+        # nothing came in this time...
+        else:
+            noReceiveCount += 1
+            if debug:
+                print("noReceiveCount=" + str(noReceiveCount))
+            
+            # quit script if nothing has been received for some time - will be restarted by systemd
+            if noReceiveCount >= quitOnNoReceiveTimeout:
+                quit()
+            
+        
+        ## get status every [getStatusInterval] seconds
+        #getStatusCount += 1
+        #if getStatusCount >= getStatusInterval:
+        #    getStatusCount = 0
+        #    serCmd = 'status\n'
+        #    ser.write(serCmd.encode('ascii'))
+        #if debug:
+        #    print("getStatusCount=" + str(getStatusCount))
+
+            
+except KeyboardInterrupt:
+    print('\n')

+ 13 - 0
ioext/ioext.service

@@ -0,0 +1,13 @@
+[Unit]
+Description=HomeSvrIOExt
+StartLimitInterval=0
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+ExecStart=/home/pi/ioext/ioext.py
+User=pi
+
+[Install]
+WantedBy=multi-user.target

+ 9 - 0
ioext/ioext_flashAVR.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ "$EUID" -ne 0 ]
+  then echo "must be run as root."
+  exit
+fi
+systemctl stop ioext.service
+avrdude -v -patmega328p -carduino -P/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 -b115200 -D -Uflash:w:HomeServerIOExt_Arduino.ino.eightanaloginputs.hex:i
+systemctl start ioext.service

+ 2 - 0
ioext/requirements.txt

@@ -0,0 +1,2 @@
+pyserial
+paho-mqtt